diff --git a/.vscode/launch.json b/.vscode/launch.json index 3c72b7616..8ea6c574a 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -4,6 +4,28 @@ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ + { + "type": "lldb", + "request": "attach", + "name": "Attach to python-test", + "program": "/usr/local/Cellar/python/3.7.4_1/Frameworks/Python.framework/Versions/3.7/Resources/Python.app/Contents/MacOS/Python" + }, + { + "type": "lldb", + "request": "attach", + "name": "Attach to dotnet-test", + "pid": "${command:pickMyProcess}" + }, + { + "type": "java", + "name": "Test-Java", + "request": "launch", + "mainClass": "in3.IN3", + "classPaths": [ + "" + ] + }, + { "type": "java", "name": "Debug (Attach)", @@ -64,11 +86,11 @@ "request": "launch", "name": "in3 withdraw", "program": "${workspaceFolder}/build/bin/in3", - "cwd": "${workspaceFolder}/build/bin", + "cwd": "${workspaceFolder}/c/test/testdata/cmd", "externalConsole": true, "args": [ "-fi", - "debugWithdraw.txt", + "eth_blockNumber.txt", "-debug" ] }, @@ -137,7 +159,7 @@ "name": "run test", "program": "${workspaceFolder}/build/test/runner", "args": [ - "../c/test/testdata/requests/in3_total_nodes.json", + "../c/test/testdata/requests/eth_getBlockByNumber.json", "-d", "-t", "1" @@ -169,7 +191,7 @@ "type": "lldb", "request": "launch", "name": "run request test", - "program": "${workspaceFolder}/build/test/test_request", + "program": "${workspaceFolder}/build/test/test_nodelist", "cwd": "${workspaceFolder}/build" }, { diff --git a/CMakeLists.txt b/CMakeLists.txt index 0ce4e685a..572604744 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -86,12 +86,14 @@ OPTION(PK_SIGNER "Enable Signing with private keys" ON) OPTION(NODESELECT_DEF "Enable default nodeselect implementation" ON) OPTION(NODESELECT_DEF_WL "Enable default nodeselect whitelist implementation" ON) OPTION(PLGN_CLIENT_DATA "Enable client-data plugin" OFF) +OPTION(THREADSAFE "uses mutex to protect shared nodelist access" ON) IF (DEFINED ANDROID_ABI) set(TRANSPORTS,false) set(IN3_LIB,false) set(USE_CURL,false) + set(CMD,false) set(JAVA,true) set(RECORDER,false) ENDIF() @@ -260,10 +262,14 @@ IF (WASM) set(CMD false) set(USE_CURL false) set(USE_WINHTTP false) + set(THREADSAFE false) ADD_DEFINITIONS(-DWASM) add_subdirectory(wasm/src) ENDIF (WASM) +if (THREADSAFE) + ADD_DEFINITIONS(-DTHREADSAFE) +ENDIF() # build tests if(TEST) diff --git a/Dockerfile b/Dockerfile index 2a10e9c0a..dd0261c47 100644 --- a/Dockerfile +++ b/Dockerfile @@ -32,16 +32,21 @@ # with this program. If not, see . ############################################################################### -FROM jianann/alpine-clang as build -COPY . /in3/ +FROM debian as build +COPY CMakeLists.txt /in3/ +COPY c /in3/c/ +COPY scripts /in3/scripts/ WORKDIR /in3/ USER root -RUN cd /in3/ && rm -rf build; -RUN cd /in3/ && mkdir build && cd build && cmake -DCMAKE_BUILD_TYPE=MINSIZEREL -DIN3_SERVER=true -DUSE_CURL=false .. && make in3 +RUN apt-get update && apt-get install -y libcurl4-openssl-dev curl cmake build-essential +RUN curl https://sh.rustup.rs -sSf | bash -s -- -y +ENV PATH="/root/.cargo/bin:${PATH}" +RUN cd /in3/ && mkdir build && cd build && cmake -DZKCRYPTO_LIB=true -DCMAKE_BUILD_TYPE=MinSizeRel -DIN3_SERVER=true .. && make in3 -FROM alpine:edge +FROM debian:buster-slim COPY --from=build /in3/build/bin/in3 /bin/in3 +RUN apt-get update && apt-get install -y curl EXPOSE 8545 ENTRYPOINT ["/bin/in3"] -CMD ["--help"] \ No newline at end of file +CMD ["--help"] diff --git a/c/CMakeLists.txt b/c/CMakeLists.txt index f7e7dc19e..8bd5899dc 100644 --- a/c/CMakeLists.txt +++ b/c/CMakeLists.txt @@ -64,20 +64,16 @@ IF (TRANSPORTS) ENDIF (TRANSPORTS) add_subdirectory(src/core) +add_subdirectory(src/init) add_subdirectory(src/verifier) add_subdirectory(src/signer) add_subdirectory(src/pay) add_subdirectory(src/api) add_subdirectory(src/cmd) add_subdirectory(src/tools) +add_subdirectory(src/nodeselect) add_subdirectory(docs) -if (NODESELECT_DEF_WL AND NOT NODESELECT_DEF) - message(SEND_ERROR "Nodeselect - whitelisting enabled without enabling the plugin itself!") -elseif (NODESELECT_DEF) - add_subdirectory(src/nodeselect) -endif() - link_directories(${CMAKE_BINARY_DIR}/lib/) # create the library diff --git a/c/ci-analyse.yml b/c/ci-analyse.yml index fcee0a801..553a71da6 100644 --- a/c/ci-analyse.yml +++ b/c/ci-analyse.yml @@ -70,7 +70,7 @@ gcc10check: script: - mkdir _build - cd _build - - cmake -DGCC_ANALYZER=true .. + - cmake -DGCC_ANALYZER=true -DIN3_SERVER=true .. - make valgrind: @@ -127,7 +127,7 @@ cpd: tags: - short-jobs script: - - cpd --minimum-tokens 180 --language cpp --exclude c/src/third-party --files c/src + - cpd --minimum-tokens 180 --language cpp --exclude c/src/third-party --exclude c/src/signer/iamo-zksync/iamo_deploy.h --files c/src - cpd --minimum-tokens 150 --language java --files java/src - cpd --minimum-tokens 150 --language python --files python @@ -151,7 +151,7 @@ vulnerabilities: - export TRIVY_AUTH_URL=$CI_REGISTRY - export TRIVY_USERNAME=gitlab-ci-token - export TRIVY_PASSWORD=$CI_JOB_TOKEN - - trivy -f json -o vulnerability_analysis.json --exit-code 1 $COMMIT_IMAGE_TAG + - trivy -f json -o vulnerability_analysis.json --exit-code 1 $COMMIT_IMAGE_TAG || echo "failed! See details in artifacts" artifacts: paths: - vulnerability_analysis.json diff --git a/c/ci-deploy.yml b/c/ci-deploy.yml index 23de2d097..e818bad61 100644 --- a/c/ci-deploy.yml +++ b/c/ci-deploy.yml @@ -269,7 +269,6 @@ pages: - readthedocs - coverage - clangcheck - - vulnerabilities - java_linux - test_asmjs - python_linux @@ -281,10 +280,9 @@ pages: - cp -r cov_build/ccov/all-merged public/coverage - cp -r report/* public/code_analysis - cp -r doc/build public/rtd - - cp -r vulnerability_analysis.json public/vulnerability_analysis.json || true - cp -r java/build/reports/jacoco/test/html public/coverage_java - cp -r python_multilib/htmlcov public/coverage_python - - echo "

Incubed report for last build

" > public/index.html + - echo "

Incubed report for last build

" > public/index.html artifacts: paths: - public diff --git a/c/ci.yml b/c/ci.yml index 05ed4decc..d1aed7e0a 100644 --- a/c/ci.yml +++ b/c/ci.yml @@ -28,6 +28,7 @@ paths: - $BUILD/bin - $BUILD/lib + - $BUILD/rust gcc8: image: docker.slock.it/build-images/cmake:gcc8 @@ -39,17 +40,18 @@ gcc8: - mkdir x64_build - mkdir x64_jni - cd x64_build - - cmake -DTAG_VERSION=$CI_COMMIT_TAG -DCMAKE_BUILD_TYPE=Release -DJAVA=true -DUSE_CURL=false .. + - cmake -DTAG_VERSION=$CI_COMMIT_TAG -DCMAKE_BUILD_TYPE=Release -DJAVA=true -DUSE_CURL=false -DZKCRYPTO_LIB=true .. - make in3_jni - cp lib/libin3_jni.so ../x64_jni/ - rm -rf * - - cmake -DTAG_VERSION=$CI_COMMIT_TAG -DCMAKE_BUILD_TYPE=Release -DJAVA=true -DBUILD_DOC=true .. + - cmake -DTAG_VERSION=$CI_COMMIT_TAG -DCMAKE_BUILD_TYPE=Release -DJAVA=true -DBUILD_DOC=true -DZKCRYPTO_LIB=true .. - make artifacts: paths: - x64_jni - x64_build/bin - x64_build/lib + - x64_build/rust - x64_build/c/docs/doc_doxygen - x64_build/java/docs/doc_doxygen @@ -85,7 +87,7 @@ arm7: tags: - arm variables: - CONAN_OPTS: "-DJAVA=false" + CONAN_OPTS: "-DZKCRYPTO_LIB=true -DJAVA=false" BUILD: "arm7_build" arm_jni: @@ -94,7 +96,7 @@ arm_jni: tags: - arm variables: - CONAN_OPTS: "-DJAVA=true -DUSE_CURL=false" + CONAN_OPTS: "-DJAVA=true -DZKCRYPTO_LIB=true -DUSE_CURL=false" BUILD: "arm_jni_build" gcc8-x86: @@ -135,11 +137,11 @@ mac_os: - mkdir mac_build - mkdir mac_jni - cd mac_build - - cmake -DTAG_VERSION=$CI_COMMIT_TAG -DCMAKE_BUILD_TYPE=MINSIZEREL -DJAVA=true -DTRANSPORTS=false -DUSE_SCRYPT=true .. + - cmake -DTAG_VERSION=$CI_COMMIT_TAG -DCMAKE_BUILD_TYPE=MINSIZEREL -DJAVA=true -DZKCRYPTO_LIB=true -DTRANSPORTS=false -DUSE_SCRYPT=true .. - make in3_jni - cp lib/libin3_jni.dylib ../mac_jni/ - rm -rf * - - cmake -DTAG_VERSION=$CI_COMMIT_TAG -DCMAKE_BUILD_TYPE=MINSIZEREL -DJAVA=true .. + - cmake -DTAG_VERSION=$CI_COMMIT_TAG -DCMAKE_BUILD_TYPE=MINSIZEREL -DJAVA=true -DZKCRYPTO_LIB=true .. - make artifacts: @@ -149,6 +151,7 @@ mac_os: - mac_build/java/docs - mac_build/lib - mac_build/bin + - mac_build/rust tags: - mac-os diff --git a/c/docs/2_examples.md b/c/docs/2_examples.md index b65397342..665e615ef 100644 --- a/c/docs/2_examples.md +++ b/c/docs/2_examples.md @@ -6,6 +6,7 @@ source : [in3-c/c/examples/btc_transaction.c](https://github.com/blockchainsllc/ checking a Bitcoin transaction data + ```c /// checking a Bitcoin transaction data @@ -51,6 +52,7 @@ source : [in3-c/c/examples/call_a_function.c](https://github.com/blockchainsllc/ This example shows how to call functions on a smart contract eiither directly or using the api to encode the arguments + ```c /// This example shows how to call functions on a smart contract eiither directly or using the api to encode the arguments @@ -161,7 +163,8 @@ in3_ret_t call_func_api(in3_t* c, address_t contract) { source : [in3-c/c/examples/get_balance.c](https://github.com/blockchainsllc/in3/blob/master/c/examples/get_balance.c) -get the Balance with the API and also as direct RPC-call + get the Balance with the API and also as direct RPC-call + ```c /// get the Balance with the API and also as direct RPC-call @@ -230,7 +233,8 @@ void get_balance_api(in3_t* in3) { source : [in3-c/c/examples/get_block.c](https://github.com/blockchainsllc/in3/blob/master/c/examples/get_block.c) -using the basic-module to get and verify a Block with the API and also as direct RPC-call + using the basic-module to get and verify a Block with the API and also as direct RPC-call + ```c /// using the basic-module to get and verify a Block with the API and also as direct RPC-call @@ -301,7 +305,8 @@ void get_block_api(in3_t* in3) { source : [in3-c/c/examples/get_logs.c](https://github.com/blockchainsllc/in3/blob/master/c/examples/get_logs.c) -fetching events and verify them with eth_getLogs + fetching events and verify them with eth_getLogs + ```c /// fetching events and verify them with eth_getLogs @@ -406,6 +411,7 @@ source : [in3-c/c/examples/get_transaction.c](https://github.com/blockchainsllc/ checking the transaction data + ```c /// checking the transaction data @@ -478,7 +484,8 @@ void get_tx_api(in3_t* in3) { source : [in3-c/c/examples/get_transaction_receipt.c](https://github.com/blockchainsllc/in3/blob/master/c/examples/get_transaction_receipt.c) -validating the result or receipt of an transaction + validating the result or receipt of an transaction + ```c /// validating the result or receipt of an transaction @@ -553,7 +560,8 @@ void get_tx_receipt_api(in3_t* in3) { source : [in3-c/c/examples/ipfs_put_get.c](https://github.com/blockchainsllc/in3/blob/master/c/examples/ipfs_put_get.c) -using the IPFS module + using the IPFS module + ```c /// using the IPFS module @@ -640,6 +648,8 @@ int main() { source : [in3-c/c/examples/ledger_sign.c](https://github.com/blockchainsllc/in3/blob/master/c/examples/ledger_sign.c) + + ```c #include // the core client @@ -699,6 +709,7 @@ source : [in3-c/c/examples/send_transaction.c](https://github.com/blockchainsllc sending a transaction including signing it with a private key + ```c /// sending a transaction including signing it with a private key @@ -792,6 +803,7 @@ source : [in3-c/c/examples/usn_device.c](https://github.com/blockchainsllc/in3/b a example how to watch usn events and act upon it. + ```c /// a example how to watch usn events and act upon it. @@ -818,16 +830,13 @@ static int handle_booking(usn_event_t* ev) { int main(int argc, char* argv[]) { // create new incubed client - in3_t* c = in3_for_chain(CHAIN_ID_MAINNET); - - // switch to goerli - c->chain_id = 0x5; + in3_t* c = in3_for_chain(CHAIN_ID_GOERLI); // setting up a usn-device-config usn_device_conf_t usn; usn.booking_handler = handle_booking; // this is the handler, which is called for each rent/return or start/stop usn.c = c; // the incubed client - usn.chain_id = c->chain_id; // the chain_id + usn.chain_id = c->chain.chain_id; // the chain_id usn.devices = NULL; // this will contain the list of devices supported usn.len_devices = 0; // and length of this list usn.now = 0; // the current timestamp @@ -863,6 +872,7 @@ source : [in3-c/c/examples/usn_rent.c](https://github.com/blockchainsllc/in3/blo how to send a rent transaction to a usn contract usinig the usn-api. + ```c /// how to send a rent transaction to a usn contract usinig the usn-api. @@ -941,7 +951,8 @@ int main(int argc, char* argv[]) { } ``` -### Building + +### Building In order to run those examples, you only need a c-compiler (gcc or clang) and curl installed. @@ -955,3 +966,4 @@ You can build them individually by executing: ``` gcc -o get_block_api get_block_api.c -lin3 -lcurl ``` + diff --git a/c/docs/3_using.md b/c/docs/3_using.md index 72de59f39..152405f55 100644 --- a/c/docs/3_using.md +++ b/c/docs/3_using.md @@ -4,7 +4,7 @@ The core of incubed is the processing of json-rpc requests by fetching data from ### the statemachine -Each request is represented internally by the `in3_ctx_t` -struct. This context is responsible for trying to find a verifyable answer to the request and acts as a statemachine. +Each request is represented internally by the `in3_req_t` -struct. This context is responsible for trying to find a verifyable answer to the request and acts as a statemachine. ``` @@ -14,29 +14,29 @@ digraph G { rankdir = TB; RPC[label="RPC-Request"] - CTX[label="in3_ctx_t"] + CTX[label="in3_req_t"] sign[label="sign",color=lightgrey, style=""] request[label="fetch http",color=lightgrey, style=""] - exec[ label="in3_ctx_exec_state()",color=lightgrey, style="", shape=ellipse ] - free[label="ctx_free()",color=lightgrey, style=""] + exec[ label="in3_req_exec_state()",color=lightgrey, style="", shape=ellipse ] + free[label="req_free()",color=lightgrey, style=""] waiting[label="need input"] - RPC -> CTX [label="ctx_new()"] + RPC -> CTX [label="req_new()"] CTX -> exec - exec -> error [label="CTX_ERROR"] - exec -> response[label="CTX_SUCCESS"] - exec -> waiting[label="CTX_WAITING_TO_SEND"] - exec -> request[label="CTX_WAITING_FOR_RESPONSE"] + exec -> error [label="REQ_ERROR"] + exec -> response[label="REQ_SUCCESS"] + exec -> waiting[label="REQ_WAITING_TO_SEND"] + exec -> request[label="REQ_WAITING_FOR_RESPONSE"] - waiting -> sign[label=CT_SIGN] - waiting -> request[label=CT_RPC] + waiting -> sign[label=RT_SIGN] + waiting -> request[label=RT_RPC] sign -> exec [label="in3_ctx_add_response()"] request -> exec[label="in3_ctx_add_response()"] @@ -55,37 +55,37 @@ digraph G { ``` In order to process a request we follow these steps. -1. `ctx_new` which creates a new context by parsing a JSON-RPC request. -2. `in3_ctx_exec_state` this will try to process the state and returns the new state, which will be one of he following: +1. `req_new` which creates a new context by parsing a JSON-RPC request. +2. `in3_req_exec_state` this will try to process the state and returns the new state, which will be one of he following: - - `CTX_SUCCESS` - we have a response - - `CTX_ERROR` - we stop because of an unrecoverable error - - `CTX_WAITING_TO_SEND` - we need input and need to send out a request. By calling `in3_create_request()` the ctx will switch to the state to `CTX_WAITING_FOR_RESPONSE` until all the needed responses are repoorted. While it is possible to fetch all responses and add them before calling `in3_ctx_exec_state()`, but it would be more efficient if can send all requests out, but then create a response-queue and set one response add a time so we can return as soon as we have the first verifiable response. - - `CTX_WAITING_FOR_RESPONSE` - the request has been send, but no verifieable response is available. Once the next (or more) responses have been added, we call `in3_ctx_exec_state()` again, which will verify all available responses. If we could verify it, we have a respoonse, if not we may either wait for more responses ( in case we send out multiple requests -> `CTX_WAITING_FOR_RESPONSE` ) or we send out new requests (`CTX_WAITING_TO_SEND`) + - `REQ_SUCCESS` - we have a response + - `REQ_ERROR` - we stop because of an unrecoverable error + - `REQ_WAITING_TO_SEND` - we need input and need to send out a request. By calling `in3_create_request()` the ctx will switch to the state to `REQ_WAITING_FOR_RESPONSE` until all the needed responses are repoorted. While it is possible to fetch all responses and add them before calling `in3_req_exec_state()`, but it would be more efficient if can send all requests out, but then create a response-queue and set one response add a time so we can return as soon as we have the first verifiable response. + - `REQ_WAITING_FOR_RESPONSE` - the request has been send, but no verifieable response is available. Once the next (or more) responses have been added, we call `in3_req_exec_state()` again, which will verify all available responses. If we could verify it, we have a respoonse, if not we may either wait for more responses ( in case we send out multiple requests -> `REQ_WAITING_FOR_RESPONSE` ) or we send out new requests (`REQ_WAITING_TO_SEND`) -the `in3_send_ctx`-function will executly this: +the `in3_send_req`-function will executly this: ```c -in3_ret_t in3_send_ctx(in3_ctx_t* ctx) { +in3_ret_t in3_send_req(in3_req_t* ctx) { ctx_req_transports_t transports = {0}; while (true) { - switch (in3_ctx_exec_state(ctx)) { - case CTX_ERROR: - case CTX_SUCCESS: + switch (in3_req_exec_state(ctx)) { + case REQ_ERROR: + case REQ_SUCCESS: transport_cleanup(ctx, &transports, true); return ctx->verification_state; - case CTX_WAITING_FOR_RESPONSE: + case REQ_WAITING_FOR_RESPONSE: in3_handle_rpc_next(ctx, &transports); break; - case CTX_WAITING_TO_SEND: { - in3_ctx_t* last = in3_ctx_last_waiting(ctx); + case REQ_WAITING_TO_SEND: { + in3_req_t* last = in3_req_last_waiting(ctx); switch (last->type) { - case CT_SIGN: + case RT_SIGN: in3_handle_sign(last); break; - case CT_RPC: + case RT_RPC: in3_handle_rpc(last, &transports); } } @@ -94,9 +94,9 @@ in3_ret_t in3_send_ctx(in3_ctx_t* ctx) { } ``` -### sync calls with in3_send_ctx +### sync calls with in3_send_req -This statemachine can be used to process requests synchronously or asynchronously. The `in3_send_ctx` function, which is used in most convinience-functions will do this synchronously. In order to get user input it relies on 2 callback-functions: +This statemachine can be used to process requests synchronously or asynchronously. The `in3_send_req` function, which is used in most convinience-functions will do this synchronously. In order to get user input it relies on 2 callback-functions: - to sign : [`in3_signer_t`](#in3-signer-t) struct including its callback function is set in the `in3_t` configuration. - to fetch data : a [in3_transport_send](#in3-transport-send) function-pointer will be set in the `in3_t` configuration. @@ -106,7 +106,7 @@ This statemachine can be used to process requests synchronously or asynchronousl For signing the client expects a [`in3_signer_t`](#in3-signer-t) struct to be set. Setting should be done by using the [`in3_set_signer()`](#in3-set-signer) function. This function expects 3 arguments (after the client config itself): -- `sign` - this is a function pointer to actual signing-function. Whenever the incubed client needs a signature it will prepare a signing context [`in3_sign_ctx_t`](#in3-sign-ctx-t), which holds all relevant data, like message and the address for signing. The result will always be a signature which you need to copy into the `signature`-field of this context. The return value must signal the success of the execution. While `IN3_OK` represents success, `IN3_WAITING`can be used to indicate that we need to execute again since there may be a sub-request that needs to finished up before being able to sign. In case of an error [`ctx_set_error`](#ctx-set-error) should be used to report the details of the error including returning the `IN3_E...` as error-code. +- `sign` - this is a function pointer to actual signing-function. Whenever the incubed client needs a signature it will prepare a signing context [`in3_sign_ctx_t`](#in3-sign-ctx-t), which holds all relevant data, like message and the address for signing. The result will always be a signature which you need to copy into the `signature`-field of this context. The return value must signal the success of the execution. While `IN3_OK` represents success, `IN3_WAITING`can be used to indicate that we need to execute again since there may be a sub-request that needs to finished up before being able to sign. In case of an error [`req_set_error`](#ctx-set-error) should be used to report the details of the error including returning the `IN3_E...` as error-code. - `prepare_tx`- this function is optional and gives you a chance to change the data before signing. For example signing with a mutisig would need to do manipulate the data and also the target in order to redirect it to the multisig contract. @@ -134,7 +134,7 @@ The pk-signer uses the wallet-pointer to point to the raw 32 bytes private key a #### transport -The transport function is a function-pointer set in the client configuration (`in3_t`) which will be used in the `in3_send_ctx()` function whenever data are required to get from the network. the function will get a [`request_t`](#request-t) object as argument. +The transport function is a function-pointer set in the client configuration (`in3_t`) which will be used in the `in3_send_req()` function whenever data are required to get from the network. the function will get a [`request_t`](#request-t) object as argument. The main responsibility of this function is to fetch the requested data and the call [`in3_ctx_add_response`](#in3-ctx-add-response) to report this to the context. if the request only sends one request to one url, this is all you have to do. @@ -146,7 +146,7 @@ In order to process multiple calls to the same resouces the request-object conta - `cptr` - a custom `void*` which can be set in the first call pointing to recources you may need to continue in the subsequent calls. - `action` - This value is enum ( [`#in3_req_action_t`](#in3-req-action-t) ), which indicates these current state -So only if you need to continue your call later, because you don't want to and can't set all the responses yet, you need set the `cptr` to a non NULL value. And only in this case `in3_send_ctx()` will follow this process with these states: +So only if you need to continue your call later, because you don't want to and can't set all the responses yet, you need set the `cptr` to a non NULL value. And only in this case `in3_send_req()` will follow this process with these states: ``` @@ -189,21 +189,21 @@ For the js for example the main-loop is part of a async function. // execute and fetch the new state ( in this case the ctx_execute-function will return the status including the created request as json) const state = JSON.parse(call_string('ctx_execute', r)) switch (state.status) { - // CTX_ERROR + // REQ_ERROR case 'error': throw new Error(state.error || 'Unknown error') - // CTX_SUCCESS + // REQ_SUCCESS case 'ok': return state.result - // CTX_WAITING_FOR_RESPONSE + // REQ_WAITING_FOR_RESPONSE case 'waiting': // await the promise for the next response ( the state.request contains the context-pointer to know which queue) await getNextResponse(responses, state.request) break - // CTX_WAITING_TO_SEND + // REQ_WAITING_TO_SEND case 'request': { // the request already contains the type, urls and payload. const req = state.request diff --git a/c/docs/4_plugins.md b/c/docs/4_plugins.md index 3d01916ab..795dc8f79 100644 --- a/c/docs/4_plugins.md +++ b/c/docs/4_plugins.md @@ -44,7 +44,7 @@ Except for `PLGN_ACT_TERM` we will loop until the first plugin handles it. The h - `IN3_OK` - the plugin handled it and it was succesful - `IN3_WAITING` - the plugin handled the action, but is waiting for more data, which happens in a sub context added. As soon as this was resolved, the plugin will be called again. - `IN3_EIGNORE` - the plugin did **NOT** handle the action and we should continue with the other plugins. -- `IN3_E...` - the plugin did handle it, but raised a error and returned the error-code. In addition you should always use the current `in3_ctx_t`to report a detailed error-message (using `ctx_set_error()`) +- `IN3_E...` - the plugin did handle it, but raised a error and returned the error-code. In addition you should always use the current `in3_req_t`to report a detailed error-message (using `req_set_error()`) ### Lifecycle @@ -62,16 +62,16 @@ For Transport implementations you should always register for those 3 `PLGN_ACT_T Send will be triggered only if the request is executed synchron, whenever a new request needs to be send out. This request may contain multiple urls, but the same payload. -`arguments` : `in3_request_t*` - a request-object holding the following data: +`arguments` : `in3_http_request_t*` - a request-object holding the following data: ```c -typedef struct in3_request { +typedef struct in3_http_request { char* payload; // the payload to send char** urls; // array of urls uint_fast16_t urls_len; // number of urls - in3_ctx_t* ctx; // the current context + in3_req_t* ctx; // the current context void* cptr; // a custom ptr to hold information during -} in3_request_t; +} in3_http_request_t; ``` It is expected that a plugin will send out http-requests to each (iterating until `urls_len`) url from `urls` with the `payload`. @@ -85,7 +85,7 @@ in3_ret_t transport_handle(void* custom_data, in3_plugin, in3_plugin_act_t actio switch (action) { case PLGN_ACT_TRANSPORT_SEND: { - in3_request_t* req = arguments; // cast it to in3_request_t* + in3_http_request_t* req = arguments; // cast it to in3_http_request_t* // init the cptr in3_curl_t* c = _malloc(sizeof(in3_curl_t)); @@ -121,13 +121,13 @@ This will only triggered if the previously triggered `PLGN_ACT_TRANSPORT_SEND` - if the responses were not all set yet. - if a `cptr` was set -`arguments` : `in3_request_t*` - a request-object holding the data. ( the payload and urls may not be set!) +`arguments` : `in3_http_request_t*` - a request-object holding the data. ( the payload and urls may not be set!) The plugin needs to wait until the first response was received ( or runs into a timeout). To report, please use `in3_req_add_response()`` ```c void in3_req_add_response( - in3_request_t* req, // the the request + in3_http_request_t* req, // the the request int index, // the index of the url, since this request could go out to many urls bool is_error, // if true this will be reported as error. the message should then be the error-message const char* data, // the data or the the string of the response @@ -152,7 +152,7 @@ in3_req_add_response(request, index, true, "Timeout waiting for a response", -1, If a previous `PLGN_ACT_TRANSPORT_SEND` has set a `cptr` this will be triggered in order to clean up memory. -`arguments` : `in3_request_t*` - a request-object holding the data. ( the payload and urls may not be set!) +`arguments` : `in3_http_request_t*` - a request-object holding the data. ( the payload and urls may not be set!) ### Signing @@ -170,7 +170,7 @@ This action is triggered as a request to sign data. typedef struct sign_ctx { uint8_t signature[65]; // the resulting signature needs to be writte into these bytes d_signature_type_t type; // the type of signature - in3_ctx_t* ctx; // the context of the request in order report errors + in3_req_t* ctx; // the context of the request in order report errors bytes_t message; // the message to sign bytes_t account; // the account to use for the signature (if set) } in3_sign_ctx_t; @@ -251,7 +251,7 @@ if we are about to sign data and need to know the address of the account abnout ```c typedef struct sign_account_ctx { - in3_ctx_t* ctx; // the context of the request in order report errors + in3_req_t* ctx; // the context of the request in order report errors address_t account; // the account to use for the signature } in3_sign_account_ctx_t; ``` @@ -296,7 +296,7 @@ The Prepare-action is triggered before signing and gives a plugin the chance to ```c typedef struct sign_prepare_ctx { - struct in3_ctx* ctx; // the context of the request in order report errors + struct in3_req* ctx; // the context of the request in order report errors address_t account; // the account to use for the signature bytes_t old_tx; // the data to sign bytes_t new_tx; // the new data to be set @@ -310,9 +310,9 @@ In order to decode the data you must use rlp.h: ```c -#define decode(data,index,dst,msg) if (rlp_decode_in_list(data, index, dst) != 1) return ctx_set_error(ctx, "invalid" msg "in txdata", IN3_EINVAL); +#define decode(data,index,dst,msg) if (rlp_decode_in_list(data, index, dst) != 1) return req_set_error(ctx, "invalid" msg "in txdata", IN3_EINVAL); -in3_ret_t decode_tx(in3_ctx_t* ctx, bytes_t raw, tx_data_t* result) { +in3_ret_t decode_tx(in3_req_t* ctx, bytes_t raw, tx_data_t* result) { decode(&raw, 0, &result->nonce , "nonce"); decode(&raw, 1, &result->gas_price, "gas_price"); decode(&raw, 2, &result->gas , "gas"); @@ -337,7 +337,7 @@ Triggered for each rpc-request in order to give plugins a chance to directly han ```c typedef struct { - in3_ctx_t* ctx; // Request context. + in3_req_t* ctx; // Request context. d_token_t* request; // request in3_response_t** response; // the response which a prehandle-method should set } in3_rpc_handle_ctx_t; @@ -348,7 +348,7 @@ the steps to add a new custom rpc-method will be the following. 1. get the method and params: ```c -char* method = d_get_stringk(rpc->request, K_METHOD); +char* method = d_get_string(rpc->request, K_METHOD); d_token_t* params = d_get(rpc->request, K_PARAMS); ``` 2. check if you can handle it @@ -372,7 +372,7 @@ return in3_rpc_handle_finish(rpc); 4. In case of an error, simply set the error in the context, with the right message and error-code: ```c -if (d_len(params)<1) return ctx_set_error(rpc->ctx, "Not enough parameters", IN3_EINVAL); +if (d_len(params)<1) return req_set_error(rpc->ctx, "Not enough parameters", IN3_EINVAL); ``` If the reequest needs additional subrequests, you need to follow the pattern of sending a request asynchron in a state machine: @@ -383,25 +383,25 @@ If the reequest needs additional subrequests, you need to follow the pattern of uint64_t nonce =0; // check if a request is already existing - in3_ctx_t* ctx = ctx_find_required(rpc->ctx, "eth_getTransactionCount"); + in3_req_t* ctx = req_find_required(rpc->ctx, "eth_getTransactionCount"); if (ctx) { // found one - so we check if it is ready. - switch (in3_ctx_state(ctx)) { + switch (in3_req_state(ctx)) { // in case of an error, we report it back to the parent context - case CTX_ERROR: - return ctx_set_error(rpc->ctx, ctx->error, IN3_EUNKNOWN); + case REQ_ERROR: + return req_set_error(rpc->ctx, ctx->error, IN3_EUNKNOWN); // if we are still waiting, we stop here and report it. - case CTX_WAITING_FOR_RESPONSE: - case CTX_WAITING_TO_SEND: + case REQ_WAITING_FOR_RESPONSE: + case REQ_WAITING_TO_SEND: return IN3_WAITING; // if it is useable, we can now handle the result. - case CTX_SUCCESS: { + case REQ_SUCCESS: { // check if the response contains a error. - TRY(ctx_check_response_error(ctx, 0)) + TRY(req_check_response_error(ctx, 0)) // read the nonce - nonce = d_get_longk(ctx->responses[0], K_RESULT); + nonce = d_get_long(ctx->responses[0], K_RESULT); } } } @@ -414,7 +414,7 @@ If the reequest needs additional subrequests, you need to follow the pattern of // create it sprintf(req, "{\"method\":\"eth_getTransactionCount\",\"jsonrpc\":\"2.0\",\"id\":1,\"params\":[\"%s\",\"latest\"]}", account_hex_string); // and add the request context to the parent. - return ctx_add_required(parent, ctx_new(parent->client, req)); + return req_add_required(parent, req_new(parent->client, req)); } // continue here and use the nonce.... @@ -435,13 +435,13 @@ static in3_ret_t handle_intern(void* pdata, in3_plugin_act_t action, void* args) swtch (action) { case PLGN_ACT_RPC_HANDLE: { // get method and params - char* method = d_get_stringk(rpc->request, K_METHOD); + char* method = d_get_string(rpc->request, K_METHOD); d_token_t* params = d_get(rpc->request, K_PARAMS); // do we support it? if (strcmp(method, "web3_sha3") == 0) { // check the params - if (!params || d_len(params) != 1) return ctx_set_error(rpc->ctx, "invalid params", IN3_EINVAL); + if (!params || d_len(params) != 1) return req_set_error(rpc->ctx, "invalid params", IN3_EINVAL); bytes32_t hash; // hash the first param keccak(d_to_bytes(d_get_at(params,0)), hash); @@ -471,7 +471,7 @@ This plugin reprresents a verifier. It will be triggered after we have received ```c typedef struct { - in3_ctx_t* ctx; // Request context. + in3_req_t* ctx; // Request context. in3_chain_t* chain; // the chain definition. d_token_t* result; // the result to verify d_token_t* request; // the request sent. @@ -495,11 +495,11 @@ in3_ret_t in3_verify_ipfs(void* pdata, in3_plugin_act_t action, void* args) { in3_vctx_t* vc = args; - char* method = d_get_stringk(vc->request, K_METHOD); + char* method = d_get_string(vc->request, K_METHOD); d_token_t* params = d_get(vc->request, K_PARAMS); // did we ask for proof? - if (in3_ctx_get_proof(vc->ctx, vc->index) == PROOF_NONE) return IN3_OK; + if (in3_req_get_proof(vc->ctx, vc->index) == PROOF_NONE) return IN3_OK; // do we have a result? if not it is a vaslid error-response if (!vc->result) @@ -532,7 +532,7 @@ This action will be triggered whenever there is something worth putting in a cac ```c typedef struct in3_cache_ctx { - in3_ctx_t* ctx; // the request context + in3_req_t* ctx; // the request context char* key; // the key to fetch bytes_t* content; // the content to set } in3_cache_ctx_t; @@ -578,7 +578,7 @@ This action will be triggered whenever we access the cache in order to get value ```c typedef struct in3_cache_ctx { - in3_ctx_t* ctx; // the request context + in3_req_t* ctx; // the request context char* key; // the key to fetch bytes_t* content; // the content to set } in3_cache_ctx_t; @@ -728,7 +728,7 @@ this will be triggered in order to sign a request. It will provide a request_has ```c typedef struct { - in3_ctx_t* ctx; /**< Request context. */ + in3_req_t* ctx; /**< Request context. */ d_token_t* request; /**< the request sent. */ bytes32_t request_hash; /**< the hash to sign */ uint8_t signature[65]; /**< the signature */ diff --git a/c/examples/build.sh b/c/examples/build.sh index 6257b9b91..f2d4b4273 100755 --- a/c/examples/build.sh +++ b/c/examples/build.sh @@ -12,10 +12,19 @@ if [ ! -d /usr/local/include/in3 ]; then cd ../c/examples fi + BUILDARGS="-L../../build/lib/ -I../../c/include/ -lin3 -lm" + + # if you want to staticly link, uncomment the next lines + + # do we need to add zk_crypto? + # if [ -f ../../build/rust/zkcrypto/release/libzk_crypto.a ]; then + # ZKCRYPTO="../../build/rust/zkcrypto/release/libzk_crypto.a -lm -ldl" + # fi + # set the library path to use the local - BUILDARGS="-L../../build/lib/ -I../../c/include/ ../../build/lib/libin3.a -ltransport_curl -lcurl" + # BUILDARGS="-v -L../../build/lib/ -I../../c/include/ ../../build/lib/libin3.a $ZKCRYPTO -ltransport_curl -lcurl -pthread" else - BUILDARGS="-lin3" + BUILDARGS="-lin3 -lm" fi # now build the examples build for f in *.c; diff --git a/c/examples/usn_device.c b/c/examples/usn_device.c index 1fe5e6819..adbefb829 100644 --- a/c/examples/usn_device.c +++ b/c/examples/usn_device.c @@ -23,16 +23,13 @@ static int handle_booking(usn_event_t* ev) { int main(int argc, char* argv[]) { // create new incubed client - in3_t* c = in3_for_chain(CHAIN_ID_MAINNET); - - // switch to goerli - c->chain_id = 0x5; + in3_t* c = in3_for_chain(CHAIN_ID_GOERLI); // setting up a usn-device-config usn_device_conf_t usn; usn.booking_handler = handle_booking; // this is the handler, which is called for each rent/return or start/stop usn.c = c; // the incubed client - usn.chain_id = c->chain_id; // the chain_id + usn.chain_id = c->chain.chain_id; // the chain_id usn.devices = NULL; // this will contain the list of devices supported usn.len_devices = 0; // and length of this list usn.now = 0; // the current timestamp diff --git a/c/include/in3.rs.h b/c/include/in3.rs.h index f9a3ac119..f03fa7636 100644 --- a/c/include/in3.rs.h +++ b/c/include/in3.rs.h @@ -1,12 +1,12 @@ // AUTO-GENERATED FILE // See scripts/build_includeh.sh -#include "../src/core/client/context_internal.h" +#include "../src/core/client/request_internal.h" #include "../src/signer/pk-signer/signer.h" #include "../src/tools/clientdata/client_data.h" #include "../src/api/btc/btc_api.h" #include "in3/bytes.h" #include "in3/client.h" -#include "in3/context.h" +#include "in3/request.h" #include "in3/plugin.h" #include "in3/error.h" #include "in3/eth_api.h" diff --git a/c/include/in3/bytes.h b/c/include/in3/bytes.h index 4bb0ca95f..de07d151f 100644 --- a/c/include/in3/bytes.h +++ b/c/include/in3/bytes.h @@ -122,6 +122,15 @@ NONULL static inline void b_optimize_len(bytes_t* b) { b->len--; } } + +#define b_to_stack(d) \ + { \ + bytes_t o = d; \ + d.data = alloca(d.len); \ + memcpy(d.data, o.data, o.len); \ + _free(o.data); \ + } /**< converts bytes from heap to stack */ + #ifdef __cplusplus } #endif diff --git a/c/include/in3/client.h b/c/include/in3/client.h index 766c2fc03..655063944 100644 --- a/c/include/in3/client.h +++ b/c/include/in3/client.h @@ -70,8 +70,6 @@ extern "C" { */ typedef uint32_t chain_id_t; -struct in3_ctx; - /** the type of the chain. * * for incubed a chain can be any distributed network or database with incubed support. @@ -103,110 +101,21 @@ typedef enum { */ typedef uint64_t in3_node_props_t; -typedef enum { - NODE_PROP_PROOF = 0x1, /**< filter out nodes which are providing no proof */ - NODE_PROP_MULTICHAIN = 0x2, /**< filter out nodes other then which have capability of the same RPC endpoint may also accept requests for different chains */ - NODE_PROP_ARCHIVE = 0x4, /**< filter out non-archive supporting nodes */ - NODE_PROP_HTTP = 0x8, /**< filter out non-http nodes */ - NODE_PROP_BINARY = 0x10, /**< filter out nodes that don't support binary encoding */ - NODE_PROP_ONION = 0x20, /**< filter out non-onion nodes */ - NODE_PROP_SIGNER = 0x40, /**< filter out non-signer nodes */ - NODE_PROP_DATA = 0x80, /**< filter out non-data provider nodes */ - NODE_PROP_STATS = 0x100, /**< filter out nodes that do not provide stats */ - NODE_PROP_MIN_BLOCK_HEIGHT = 0x400, /**< filter out nodes that will sign blocks with lower min block height than specified */ -} in3_node_props_type_t; - /** * a list of flags defining the behavior of the incubed client. They should be used as bitmask for the flags-property. */ typedef enum { - FLAGS_KEEP_IN3 = 0x1, /**< the in3-section with the proof will also returned */ - FLAGS_AUTO_UPDATE_LIST = 0x2, /**< the nodelist will be automatically updated if the last_block is newer */ - FLAGS_INCLUDE_CODE = 0x4, /**< the code is included when sending eth_call-requests */ - FLAGS_BINARY = 0x8, /**< the client will use binary format */ - FLAGS_HTTP = 0x10, /**< the client will try to use http instead of https */ - FLAGS_STATS = 0x20, /**< nodes will keep track of the stats (default=true) */ - FLAGS_NODE_LIST_NO_SIG = 0x40, /**< nodelist update request will not automatically ask for signatures and proof */ - FLAGS_BOOT_WEIGHTS = 0x80 /**< if true the client will initialize the first weights from the nodelist given by the nodelist.*/ + FLAGS_KEEP_IN3 = 0x1, /**< the in3-section with the proof will also returned */ + FLAGS_AUTO_UPDATE_LIST = 0x2, /**< the nodelist will be automatically updated if the last_block is newer */ + FLAGS_INCLUDE_CODE = 0x4, /**< the code is included when sending eth_call-requests */ + FLAGS_BINARY = 0x8, /**< the client will use binary format */ + FLAGS_HTTP = 0x10, /**< the client will try to use http instead of https */ + FLAGS_STATS = 0x20, /**< nodes will keep track of the stats (default=true) */ + FLAGS_NODE_LIST_NO_SIG = 0x40, /**< nodelist update request will not automatically ask for signatures and proof */ + FLAGS_BOOT_WEIGHTS = 0x80, /**< if true the client will initialize the first weights from the nodelist given by the nodelist.*/ + FLAGS_ALLOW_EXPERIMENTAL = 0x100 /**< if true the client will support experimental features.*/ } in3_flags_type_t; -/** - * a list of node attributes (mostly used internally) - */ -typedef enum { - ATTR_WHITELISTED = 1, /**< indicates if node exists in whiteList */ - ATTR_BOOT_NODE = 2, /**< used to avoid filtering manually added nodes before first nodeList update */ -} in3_node_attr_type_t; - -/** incubed node-configuration. - * - * These information are read from the Registry contract and stored in this struct representing a server or node. - */ -typedef struct in3_node { - address_t address; /**< address of the server */ - bool blocked; /**< if true this node has been blocked for sending wrong responses */ - uint_fast16_t index; /**< index within the nodelist, also used in the contract as key */ - uint_fast16_t capacity; /**< the maximal capacity able to handle */ - uint64_t deposit; /**< the deposit stored in the registry contract, which this would lose if it sends a wrong blockhash */ - in3_node_props_t props; /**< used to identify the capabilities of the node. See in3_node_props_type_t in nodelist.h */ - char* url; /**< the url of the node */ - uint_fast8_t attrs; /**< bitmask of internal attributes */ -} in3_node_t; - -/** - * Weight or reputation of a node. - * - * Based on the past performance of the node a weight is calculated given faster nodes a higher weight - * and chance when selecting the next node from the nodelist. - * These weights will also be stored in the cache (if available) - */ -typedef struct in3_node_weight { - uint32_t response_count; /**< counter for responses */ - uint32_t total_response_time; /**< total of all response times */ - uint64_t blacklisted_until; /**< if >0 this node is blacklisted until k. k is a unix timestamp */ -} in3_node_weight_t; - -/** - * Initializer for in3_node_props_t - */ -#define in3_node_props_init(np) *(np) = 0 - -/** - * setter method for interacting with in3_node_props_t. - */ -NONULL void in3_node_props_set(in3_node_props_t* node_props, /**< pointer to the properties to change */ - in3_node_props_type_t type, /**< key or type of the property */ - uint8_t value /**< value to set */ -); - -/** - * returns the value of the specified property-type. - * @return value as a number - */ -static inline uint32_t in3_node_props_get(in3_node_props_t np, /**< property to read from */ - in3_node_props_type_t t) { /**< the value to extract */ - return ((t == NODE_PROP_MIN_BLOCK_HEIGHT) ? ((np >> 32U) & 0xFFU) : !!(np & t)); -} - -/** - * checks if the given type is set in the properties - * @return true if set - */ -static inline bool in3_node_props_matches(in3_node_props_t np, /**< property to read from */ - in3_node_props_type_t t) { /**< the value to extract */ - return !!(np & t); -} - -/** - * defines a whitelist structure used for the nodelist. - */ -typedef struct in3_whitelist { - bool needs_update; /**< if true the nodelist should be updated and will trigger a `in3_nodeList`-request before the next request is send. */ - uint64_t last_block; /**< last blocknumber the whiteList was updated, which is used to detect changed in the whitelist */ - address_t contract; /**< address of whiteList contract. If specified, whiteList is always auto-updated and manual whiteList is overridden */ - bytes_t addresses; /**< serialized list of node addresses that constitute the whiteList */ -} in3_whitelist_t; - /** represents a blockhash which was previously verified */ typedef struct in3_verified_hash { uint64_t block_number; /**< the number of the block */ @@ -225,30 +134,6 @@ typedef struct in3_chain { in3_verified_hash_t* verified_hashes; /**< contains the list of already verified blockhashes */ } in3_chain_t; -/** Incubed Configuration. - * - * This struct holds the configuration and also point to internal resources such as filters or chain configs. - * - */ -typedef struct in3_t_ in3_t; - -/** - * Filter type used internally when managing filters. - */ -typedef enum { - FILTER_EVENT = 0, /**< Event filter */ - FILTER_BLOCK = 1, /**< Block filter */ - FILTER_PENDING = 2, /**< Pending filter (Unsupported) */ -} in3_filter_type_t; - -typedef struct in3_filter_t_ { - bool is_first_usage; /**< if true the filter was not used previously */ - in3_filter_type_t type; /**< filter type: (event, block or pending) */ - uint64_t last_block; /**< block no. when filter was created OR eth_getFilterChanges was called */ - char* options; /**< associated filter options */ - void (*release)(struct in3_filter_t_* f); /**< method to release owned resources */ -} in3_filter_t; - #define PLGN_ACT_LIFECYCLE (PLGN_ACT_INIT | PLGN_ACT_TERM) #define PLGN_ACT_TRANSPORT (PLGN_ACT_TRANSPORT_SEND | PLGN_ACT_TRANSPORT_RECEIVE | PLGN_ACT_TRANSPORT_CLEAN) #define PLGN_ACT_NODELIST (PLGN_ACT_NL_PICK | PLGN_ACT_NL_PICK_FOLLOWUP | PLGN_ACT_NL_BLACKLIST | PLGN_ACT_NL_FAILABLE | PLGN_ACT_NL_OFFLINE) @@ -257,7 +142,7 @@ typedef struct in3_filter_t_ { /** plugin action list */ typedef enum { - PLGN_ACT_INIT = 0x1, /**< initialize plugin - use for allocating/setting-up internal resources */ + PLGN_ACT_INIT = 0x1, /**< initialize plugin - use for allocating/setting-up internal resources . Plugins will be initialized before first used. The plgn_ctx will be the first request ctx in3_req_t */ PLGN_ACT_TERM = 0x2, /**< terminate plugin - use for releasing internal resources and cleanup. */ PLGN_ACT_TRANSPORT_SEND = 0x4, /**< sends out a request - the transport plugin will receive a request_t as plgn_ctx, it may set a cptr which will be passed back when fetching more responses. */ PLGN_ACT_TRANSPORT_RECEIVE = 0x8, /**< fetch next response - the transport plugin will receive a request_t as plgn_ctx, which contains a cptr if set previously*/ @@ -277,10 +162,10 @@ typedef enum { PLGN_ACT_PAY_HANDLE = 0x20000, /**< handles the payment */ PLGN_ACT_PAY_SIGN_REQ = 0x40000, /**< signs a request */ PLGN_ACT_LOG_ERROR = 0x80000, /**< report an error */ - PLGN_ACT_NL_PICK = 0x100000, /**< picks the data nodes, plgn_ctx will be a pointer to in3_ctx_t */ - PLGN_ACT_NL_PICK_FOLLOWUP = 0x200000, /**< called after receiving a response in order to decide whether a update is needed, plgn_ctx will be a pointer to in3_ctx_t */ + PLGN_ACT_NL_PICK = 0x100000, /**< picks the data nodes, plgn_ctx will be a pointer to in3_req_t */ + PLGN_ACT_NL_PICK_FOLLOWUP = 0x200000, /**< called after receiving a response in order to decide whether a update is needed, plgn_ctx will be a pointer to in3_req_t */ PLGN_ACT_NL_BLACKLIST = 0x400000, /**< blacklist a particular node in the nodelist, plgn_ctx will be a pointer to the node's address. */ - PLGN_ACT_NL_FAILABLE = 0x800000, /**< handle fail-able request, plgn_ctx will be a pointer to in3_ctx_t */ + PLGN_ACT_NL_FAILABLE = 0x800000, /**< handle fail-able request, plgn_ctx will be a pointer to in3_req_t */ PLGN_ACT_NL_OFFLINE = 0x1000000, /**< mark a particular node in the nodelist as offline, plgn_ctx will be a pointer to in3_nl_offline_ctx_t. */ PLGN_ACT_CHAIN_CHANGE = 0x2000000, /**< chain id change event, called after setting new chain id */ PLGN_ACT_GET_DATA = 0x4000000, /**< get access to plugin data as a void ptr */ @@ -312,25 +197,15 @@ struct in3_plugin { in3_plugin_t* next; /**< pointer to next plugin in list */ }; -/** - * Handler which is added to client config in order to handle filter. - */ -typedef struct in3_filter_handler_t_ { - in3_filter_t** array; /** array of filters */ - size_t count; /** counter for filters */ -} in3_filter_handler_t; - /** Incubed Configuration. * * This struct holds the configuration and also point to internal resources such as filters or chain configs. * */ -struct in3_t_ { - uint8_t request_count; /**< the number of request send when getting a first answer */ +typedef struct in3_t_ { uint8_t signature_count; /**< the number of signatures used to proof the blockhash. */ uint8_t replace_latest_block; /**< if specified, the blocknumber *latest* will be replaced by blockNumber- specified value */ - uint_fast8_t flags; /**< a bit mask with flags defining the behavior of the incubed client. See the FLAG...-defines*/ - uint16_t node_limit; /**< the limit of nodes to store in the client. */ + uint_fast16_t flags; /**< a bit mask with flags defining the behavior of the incubed client. See the FLAG...-defines*/ uint16_t finality; /**< the number of signatures in percent required for the request*/ uint_fast16_t max_attempts; /**< the max number of attempts before giving up*/ uint_fast16_t max_verified_hashes; /**< max number of verified hashes to cache (actual number may temporarily exceed this value due to pending requests) */ @@ -341,12 +216,9 @@ struct in3_t_ { uint32_t id_count; /**< counter for use as JSON RPC id - incremented for every request */ in3_plugin_supp_acts_t plugin_acts; /**< bitmask of supported actions of all plugins registered with this client */ in3_proof_t proof; /**< the type of proof used */ - uint64_t min_deposit; /**< min stake of the server. Only nodes owning at least this amount will be chosen. */ - in3_node_props_t node_props; /**< used to identify the capabilities of the node. */ in3_chain_t chain; /**< chain spec and nodeList definitions*/ - in3_filter_handler_t* filters; /**< filter handler */ in3_plugin_t* plugins; /**< list of registered plugins */ -}; +} in3_t; /** creates a new Incubed configuration for a specified chain and returns the pointer. * when creating the client only the one chain will be configured. (saves memory). @@ -445,7 +317,6 @@ typedef in3_ret_t (*plgn_register)(in3_t* c); assert(c); \ assert((c)->chain.chain_id); \ assert((c)->plugins); \ - assert((c)->request_count > 0); \ assert((c)->max_attempts > 0); \ assert((c)->proof >= 0 && (c)->proof <= PROOF_FULL); \ assert((c)->proof >= 0 && (c)->proof <= PROOF_FULL); diff --git a/c/include/in3/data.h b/c/include/in3/data.h index a1770b86e..016a41daa 100644 --- a/c/include/in3/data.h +++ b/c/include/in3/data.h @@ -144,7 +144,8 @@ NONULL json_ctx_t* parse_json_indexed(const char* js); /**< parses NONULL void json_free(json_ctx_t* parser_ctx); /**< frees the parse-context after usage */ NONULL str_range_t d_to_json(const d_token_t* item); /**< returns the string for a object or array. This only works for json as string. For binary it will not work! */ char* d_create_json(json_ctx_t* ctx, d_token_t* item); /**< creates a json-string. It does not work for objects if the parsed data were binary!*/ -json_ctx_t* json_create(); + +json_ctx_t* json_create(); NONULL d_token_t* json_create_null(json_ctx_t* jp); NONULL d_token_t* json_create_bool(json_ctx_t* jp, bool value); NONULL d_token_t* json_create_int(json_ctx_t* jp, uint64_t value); @@ -165,21 +166,17 @@ NONULL static inline d_key_t key(const char* c) { return val; } -static inline char* d_get_stringk(d_token_t* r, d_key_t k) { return d_string(d_get(r, k)); } /**< reads token of a property as string. */ -static inline char* d_get_string(d_token_t* r, char* k) { return d_get_stringk(r, key(k)); } /**< reads token of a property as string. */ -static inline char* d_get_string_at(d_token_t* r, uint32_t pos) { return d_string(d_get_at(r, pos)); } /**< reads string at given pos of an array. */ -static inline int32_t d_get_intk(d_token_t* r, d_key_t k) { return d_int(d_get(r, k)); } /**< reads token of a property as int. */ -static inline int32_t d_get_intkd(d_token_t* r, d_key_t k, uint32_t d) { return d_intd(d_get(r, k), d); } /**< reads token of a property as int. */ -static inline int32_t d_get_int(d_token_t* r, char* k) { return d_get_intk(r, key(k)); } /**< reads token of a property as int. */ -static inline int32_t d_get_int_at(d_token_t* r, uint32_t pos) { return d_int(d_get_at(r, pos)); } /**< reads a int at given pos of an array. */ -static inline uint64_t d_get_longk(d_token_t* r, d_key_t k) { return d_long(d_get(r, k)); } /**< reads token of a property as long. */ -static inline uint64_t d_get_longkd(d_token_t* r, d_key_t k, uint64_t d) { return d_longd(d_get(r, k), d); } /**< reads token of a property as long. */ -static inline uint64_t d_get_long(d_token_t* r, char* k) { return d_get_longk(r, key(k)); } /**< reads token of a property as long. */ -static inline uint64_t d_get_long_at(d_token_t* r, uint32_t pos) { return d_long(d_get_at(r, pos)); } /**< reads long at given pos of an array. */ -static inline bytes_t* d_get_bytesk(d_token_t* r, d_key_t k) { return d_bytes(d_get(r, k)); } /**< reads token of a property as bytes. */ -static inline bytes_t* d_get_bytes(d_token_t* r, char* k) { return d_get_bytesk(r, key(k)); } /**< reads token of a property as bytes. */ -static inline bytes_t* d_get_bytes_at(d_token_t* r, uint32_t pos) { return d_bytes(d_get_at(r, pos)); } /**< reads bytes at given pos of an array. */ -static inline bool d_is_binary_ctx(json_ctx_t* ctx) { return ctx->allocated == 0; } /**< check if the parser context was created from binary data. */ +static inline char* d_get_string(d_token_t* r, d_key_t k) { return d_string(d_get(r, k)); } /**< reads token of a property as string. */ +static inline char* d_get_string_at(d_token_t* r, uint32_t pos) { return d_string(d_get_at(r, pos)); } /**< reads string at given pos of an array. */ +static inline int32_t d_get_int(d_token_t* r, d_key_t k) { return d_int(d_get(r, k)); } /**< reads token of a property as int. */ +static inline int32_t d_get_intd(d_token_t* r, d_key_t k, uint32_t d) { return d_intd(d_get(r, k), d); } /**< reads token of a property as int. */ +static inline int32_t d_get_int_at(d_token_t* r, uint32_t pos) { return d_int(d_get_at(r, pos)); } /**< reads a int at given pos of an array. */ +static inline uint64_t d_get_long(d_token_t* r, d_key_t k) { return d_long(d_get(r, k)); } /**< reads token of a property as long. */ +static inline uint64_t d_get_longd(d_token_t* r, d_key_t k, uint64_t d) { return d_longd(d_get(r, k), d); } /**< reads token of a property as long. */ +static inline uint64_t d_get_long_at(d_token_t* r, uint32_t pos) { return d_long(d_get_at(r, pos)); } /**< reads long at given pos of an array. */ +static inline bytes_t* d_get_bytes(d_token_t* r, d_key_t k) { return d_bytes(d_get(r, k)); } /**< reads token of a property as bytes. */ +static inline bytes_t* d_get_bytes_at(d_token_t* r, uint32_t pos) { return d_bytes(d_get_at(r, pos)); } /**< reads bytes at given pos of an array. */ +static inline bool d_is_binary_ctx(json_ctx_t* ctx) { return ctx->allocated == 0; } /**< check if the parser context was created from binary data. */ bytes_t* d_get_byteskl(d_token_t* r, d_key_t k, uint32_t minl); d_token_t* d_getl(d_token_t* item, uint16_t k, uint32_t minl); diff --git a/c/include/in3/error.h b/c/include/in3/error.h index b0c6fbd2f..78d678346 100644 --- a/c/include/in3/error.h +++ b/c/include/in3/error.h @@ -68,7 +68,7 @@ typedef enum { IN3_EVERS = -8, /**< Version mismatch */ IN3_EINVALDT = -9, /**< Data invalid, eg. invalid/incomplete JSON */ IN3_EPASS = -10, /**< Wrong password */ - IN3_ERPC = -11, /**< RPC error (i.e. in3_ctx_t::error set) */ + IN3_ERPC = -11, /**< RPC error (i.e. in3_req_t::error set) */ IN3_ERPCNRES = -12, /**< RPC no response */ IN3_EUSNURL = -13, /**< USN URL parse error */ IN3_ETRANS = -14, /**< Transport error */ @@ -79,6 +79,23 @@ typedef enum { IN3_ENODEVICE = -19, /**< harware wallet device not connected */ IN3_EAPDU = -20, /**< error in hardware wallet communication */ IN3_EPLGN_NONE = -21, /**< no plugin could handle specified action */ + + IN3_HTTP_BAD_REQUEST = -400, /**< Bad Request */ + IN3_HTTP_UNAUTHORIZED = -401, /**< Unauthorized */ + IN3_HTTP_PAYMENT_REQUIRED = -402, /**< Unauthorized */ + IN3_HTTP_FORBIDDEN = -403, /**< Forbidden */ + IN3_HTTP_NOT_FOUND = -404, /**< not found */ + IN3_HTTP_M_NOT_ALLOWED = -405, /**< method not allowed */ + IN3_HTTP_NOT_ACCEPTABLE = -406, /**< Not acceptable */ + IN3_HTTP_PROX_AUTH_REQUIRED = -407, /**< Proxy Authentification required */ + IN3_HTTP_TIMEOUT = -408, /**< Request timeout */ + IN3_HTTP_CONFLICT = -409, /**< conflict */ + IN3_HTTP_GONE = -410, /**< gone */ + IN3_HTTP_INTERNAL_ERROR = -500, /**< Internal Server Error */ + IN3_HTTP_NOT_IMPLEMENTED = -501, /**< not implemented */ + IN3_HTTP_BAD_GATEWAY = -502, /**< Bad Gateway */ + IN3_HTTP_UNAVAILABLE = -503 /**< service unavailable */ + } in3_ret_t; /** Optional type similar to C++ std::optional diff --git a/c/include/in3/mem.h b/c/include/in3/mem.h index 65eedd6fa..9ab43e032 100644 --- a/c/include/in3/mem.h +++ b/c/include/in3/mem.h @@ -92,14 +92,12 @@ #define _calloc(n, s) t_calloc(n, s, __FILE__, __func__, __LINE__) #define _free(p) t_free(p, __FILE__, __func__, __LINE__) #define _realloc(p, s, o) t_realloc(p, s, o, __FILE__, __func__, __LINE__) -size_t mem_get_max_heap(); -void* t_malloc(size_t size, char* file, const char* func, int line); -void* t_realloc(void* ptr, size_t size, size_t oldsize, char* file, const char* func, int line); -void* t_calloc(size_t n, size_t size, char* file, const char* func, int line); -void t_free(void* ptr, char* file, const char* func, int line); -int mem_get_memleak_cnt(); -void mem_reset(int cnt); -void memstack(); +void* t_malloc(size_t size, char* file, const char* func, int line); +void* t_realloc(void* ptr, size_t size, size_t oldsize, char* file, const char* func, int line); +void* t_calloc(size_t n, size_t size, char* file, const char* func, int line); +void t_free(void* ptr, char* file, const char* func, int line); +int mem_get_memleak_cnt(); +void mem_reset(); #else /* TEST */ #ifdef LOGGING #define _malloc(s) _malloc_(s, __FILE__, __func__, __LINE__) diff --git a/c/include/in3/plugin.h b/c/include/in3/plugin.h index 559c22adb..5d8601723 100644 --- a/c/include/in3/plugin.h +++ b/c/include/in3/plugin.h @@ -45,12 +45,12 @@ extern "C" { #endif #include "client.h" -#include "context.h" +#include "request.h" // ---------- plugin management ----------------- /** checks if a plugin for specified action is registered with the client */ -#define in3_plugin_is_registered(client, action) ((client)->plugin_acts & (action)) +#define in3_plugin_is_registered(client, action) (((client)->plugin_acts & (action)) == (action)) /** registers a plugin with the client */ in3_ret_t in3_plugin_register( @@ -72,24 +72,21 @@ in3_ret_t in3_plugin_execute_all(in3_t* c, in3_plugin_act_t action, void* plugin /** * executes all plugin actions one-by-one, stops when a plugin returns anything other than IN3_EIGNORE. * returns IN3_EPLGN_NONE if no plugin was able to handle specified action, otherwise returns IN3_OK - * plugin errors are reported via the in3_ctx_t + * plugin errors are reported via the in3_req_t */ -in3_ret_t in3_plugin_execute_first(in3_ctx_t* ctx, in3_plugin_act_t action, void* plugin_ctx); +in3_ret_t in3_plugin_execute_first(in3_req_t* req, in3_plugin_act_t action, void* plugin_ctx); /** * same as in3_plugin_execute_first(), but returns IN3_OK even if no plugin could handle specified action */ -in3_ret_t in3_plugin_execute_first_or_none(in3_ctx_t* ctx, in3_plugin_act_t action, void* plugin_ctx); +in3_ret_t in3_plugin_execute_first_or_none(in3_req_t* req, in3_plugin_act_t action, void* plugin_ctx); /** * get direct access to plugin data (if registered) based on action function */ static inline void* in3_plugin_get_data(in3_t* c, in3_plugin_act_fn fn) { - in3_plugin_t* p = c->plugins; - while (p) { - if (p->action_fn == fn) - return p->data; - p = p->next; + for (in3_plugin_t* p = c->plugins; p; p = p->next) { + if (p->action_fn == fn) return p->data; } return NULL; } @@ -100,9 +97,11 @@ static inline void* in3_plugin_get_data(in3_t* c, in3_plugin_act_fn fn) { * verification context holding the pointers to all relevant toknes. */ typedef struct { - in3_ctx_t* ctx; /**< Request context. */ + in3_req_t* req; /**< Request context. */ d_token_t* request; /**< request */ in3_response_t** response; /**< the responses which a prehandle-method should set*/ + char* method; /**< the method of the request */ + d_token_t* params; /**< the params */ } in3_rpc_handle_ctx_t; /** @@ -132,45 +131,83 @@ NONULL in3_ret_t in3_rpc_handle_with_int(in3_rpc_handle_ctx_t* hctx, uint64_t va // -------------- TRANSPORT ------------- +/** + * optional request headers + */ +typedef struct in3_req_header { + char* value; /**< the value */ + struct in3_req_header* next; /**< pointer to next header */ +} in3_req_header_t; + /** request-object. * * represents a RPC-request */ -typedef struct in3_request { - char* payload; /**< the payload to send */ - char** urls; /**< array of urls */ - uint_fast16_t urls_len; /**< number of urls */ - struct in3_ctx* ctx; /**< the current context */ - void* cptr; /**< a custom ptr to hold information during */ - uint32_t wait; /**< time in ms to wait before sending out the request */ -} in3_request_t; +typedef struct in3_http_request { + char* method; /**< the http-method to be used */ + char* payload; /**< the payload to send */ + char** urls; /**< array of urls */ + uint_fast16_t urls_len; /**< number of urls */ + uint32_t payload_len; /**< length of the payload in bytes. */ + struct in3_req* req; /**< the current context */ + void* cptr; /**< a custom ptr to hold information during */ + uint32_t wait; /**< time in ms to wait before sending out the request */ + in3_req_header_t* headers; /**< optional additional headers to be send with the request */ +} in3_http_request_t; /** - * getter to retrieve the payload from a in3_request_t struct + * getter to retrieve the payload from a in3_http_request_t struct */ char* in3_get_request_payload( - in3_request_t* request /**< request struct */ + in3_http_request_t* request /**< request struct */ +); +/** + * getter to retrieve the length of the payload from a in3_http_request_t struct + */ +uint32_t in3_get_request_payload_len( + in3_http_request_t* request /**< request struct */ +); + +/** + * getter to retrieve the urls list length from a in3_http_request_t struct + */ +int in3_get_request_headers_len( + in3_http_request_t* request /**< request struct */ +); +/** + * getter to retrieve the urls list length from a in3_http_request_t struct + */ +char* in3_get_request_headers_at( + in3_http_request_t* request, /**< request struct */ + int index /**< the inde xof the header */ +); + +/** + * getter to retrieve the http-method from a in3_http_request_t struct + */ +char* in3_get_request_method( + in3_http_request_t* request /**< request struct */ ); /** - * getter to retrieve the urls list from a in3_request_t struct + * getter to retrieve the urls list from a in3_http_request_t struct */ char** in3_get_request_urls( - in3_request_t* request /**< request struct */ + in3_http_request_t* request /**< request struct */ ); /** - * getter to retrieve the urls list length from a in3_request_t struct + * getter to retrieve the urls list length from a in3_http_request_t struct */ int in3_get_request_urls_len( - in3_request_t* request /**< request struct */ + in3_http_request_t* request /**< request struct */ ); /** - * getter to retrieve the urls list length from a in3_request_t struct + * getter to retrieve the urls list length from a in3_http_request_t struct */ uint32_t in3_get_request_timeout( - in3_request_t* request /**< request struct */ + in3_http_request_t* request /**< request struct */ ); /** @@ -178,12 +215,12 @@ uint32_t in3_get_request_timeout( * This function should be used in the transport-function to set the response. */ NONULL void in3_req_add_response( - in3_request_t* req, /**< [in]the the request */ - int index, /**< [in] the index of the url, since this request could go out to many urls */ - bool is_error, /**< [in] if true this will be reported as error. the message should then be the error-message */ - const char* data, /**< the data or the the string*/ - int data_len, /**< the length of the data or the the string (use -1 if data is a null terminated string)*/ - uint32_t time /**< the time this request took in ms or 0 if not possible (it will be used to calculate the weights)*/ + in3_http_request_t* req, /**< [in]the the request */ + int index, /**< [in] the index of the url, since this request could go out to many urls */ + int error, /**< [in] if <0 this will be reported as error. the message should then be the error-message */ + const char* data, /**< the data or the the string*/ + int data_len, /**< the length of the data or the the string (use -1 if data is a null terminated string)*/ + uint32_t time /**< the time this request took in ms or 0 if not possible (it will be used to calculate the weights)*/ ); /** @@ -191,15 +228,15 @@ NONULL void in3_req_add_response( * This function should be used in the transport-function to set the response. */ NONULL void in3_ctx_add_response( - in3_ctx_t* ctx, /**< [in]the current context */ + in3_req_t* req, /**< [in]the current context */ int index, /**< [in] the index of the url, since this request could go out to many urls */ - bool is_error, /**< [in] if true this will be reported as error. the message should then be the error-message */ + int error, /**< [in] if <0 this will be reported as error. the message should then be the error-message */ const char* data, /**< the data or the the string*/ int data_len, /**< the length of the data or the the string (use -1 if data is a null terminated string)*/ uint32_t time /**< the time this request took in ms or 0 if not possible (it will be used to calculate the weights)*/ ); -typedef in3_ret_t (*in3_transport_legacy)(in3_request_t* request); +typedef in3_ret_t (*in3_transport_legacy)(in3_http_request_t* request); /** * defines a default transport which is used when creating a new client. */ @@ -219,7 +256,7 @@ typedef enum { * action context when retrieving the account of a signer. */ typedef struct sign_account_ctx { - struct in3_ctx* ctx; /**< the context of the request in order report errors */ + struct in3_req* req; /**< the context of the request in order report errors */ uint8_t* accounts; /**< the account to use for the signature */ int accounts_len; /**< number of accounts */ in3_signer_type_t signer_type; /**< the type of the signer used for this account.*/ @@ -231,7 +268,7 @@ typedef struct sign_account_ctx { * action context when retrieving the account of a signer. */ typedef struct sign_prepare_ctx { - struct in3_ctx* ctx; /**< the context of the request in order report errors */ + struct in3_req* req; /**< the context of the request in order report errors */ address_t account; /**< the account to use for the signature */ bytes_t old_tx; bytes_t new_tx; @@ -252,7 +289,7 @@ typedef enum { typedef struct sign_ctx { bytes_t signature; /**< the resulting signature */ d_signature_type_t type; /**< the type of signature*/ - struct in3_ctx* ctx; /**< the context of the request in order report errors */ + struct in3_req* req; /**< the context of the request in order report errors */ bytes_t message; /**< the message to sign*/ bytes_t account; /**< the account to use for the signature */ } in3_sign_ctx_t; @@ -283,7 +320,7 @@ void in3_sign_ctx_set_signature_hex( * creates a signer ctx to be used for async signing. */ NONULL in3_sign_ctx_t* create_sign_ctx( - in3_ctx_t* ctx /**< [in] the rpc context */ + in3_req_t* req /**< [in] the rpc context */ ); // -------- SET_CONFIG --------- @@ -337,7 +374,7 @@ typedef void (*in3_storage_clear)( * context used during get config */ typedef struct in3_cache_ctx { - in3_ctx_t* ctx; /**< the request context */ + in3_req_t* req; /**< the request context */ char* key; /**< the key to fetch */ bytes_t* content; /**< the content to set */ } in3_cache_ctx_t; @@ -367,7 +404,7 @@ void in3_set_storage_handler( * verification context holding the pointers to all relevant toknes. */ typedef struct { - in3_ctx_t* ctx; /**< Request context. */ + in3_req_t* req; /**< Request context. */ in3_chain_t* chain; /**< the chain definition. */ d_token_t* result; /**< the result to verify */ d_token_t* request; /**< the request sent. */ @@ -378,6 +415,7 @@ typedef struct { int index; /**< the index of the request within the bulk */ node_match_t* node; /**< the node who delivered this response */ bool dont_blacklist; /**< indicates whether the plugin would like the node to be blacklisted */ + char* method; /**< the rpc-method to verify agains */ } in3_vctx_t; #ifdef LOGGING @@ -395,7 +433,7 @@ in3_ret_t vc_set_error( // ---- PLGN_ACT_PAY_FOLLOWUP ----------- typedef struct { - in3_ctx_t* ctx; /**< Request context. */ + in3_req_t* req; /**< Request context. */ node_match_t* node; /**< the responding node. */ d_token_t* resp_in3; /**< the response's in3 section */ d_token_t* resp_error; /**< the response's error section */ @@ -404,7 +442,7 @@ typedef struct { // ---- PLGN_ACT_PAY_HANDLE ----------- typedef struct { - in3_ctx_t* ctx; /**< Request context. */ + in3_req_t* req; /**< Request context. */ sb_t* payload; /**< the request payload */ bytes32_t pk; /**< the private-key to sign with */ } in3_pay_handle_ctx_t; @@ -412,18 +450,26 @@ typedef struct { // ---- PAY_SIGN_REQ ----------- typedef struct { - in3_ctx_t* ctx; /**< Request context. */ + in3_req_t* req; /**< Request context. */ d_token_t* request; /**< the request sent. */ bytes32_t request_hash; /**< the hash to sign */ uint8_t signature[65]; /**< the signature */ } in3_pay_sign_req_ctx_t; +// ---- PLGN_ACT_ADD_PAYLOAD ----------- + +typedef struct { + in3_req_t* req; /**< Request context. */ + d_token_t* request; /**< the request sent. */ + sb_t* sb; /**< the string builder in the in3-section */ +} in3_pay_payload_ctx_t; + // ---- LOG_ERROR ----------- typedef struct { char* msg; /**< the error message. */ uint16_t error; /**< error code. */ - in3_ctx_t* ctx; /**< ctx . */ + in3_req_t* req; /**< ctx . */ } error_log_ctx_t; // -------- NL_PICK --------- @@ -434,12 +480,12 @@ typedef enum { typedef struct { in3_nl_pick_type_t type; /**< type of node to pick. */ - in3_ctx_t* ctx; /**< Request context. */ + in3_req_t* req; /**< Request context. */ } in3_nl_pick_ctx_t; // -------- NL_FOLLOWUP --------- typedef struct { - in3_ctx_t* ctx; /**< Request context. */ + in3_req_t* req; /**< Request context. */ node_match_t* node; /**< Node that gave us a valid response */ } in3_nl_followup_ctx_t; diff --git a/c/include/in3/context.h b/c/include/in3/request.h similarity index 76% rename from c/include/in3/context.h rename to c/include/in3/request.h index 3be0e625c..114de40b9 100644 --- a/c/include/in3/context.h +++ b/c/include/in3/request.h @@ -56,9 +56,9 @@ extern "C" { * type of the request context, */ typedef enum ctx_type { - CT_RPC = 0, /**< a json-rpc request, which needs to be send to a incubed node */ - CT_SIGN = 1 /**< a sign request */ -} ctx_type_t; + RT_RPC = 0, /**< a json-rpc request, which needs to be send to a incubed node */ + RT_SIGN = 1 /**< a sign request */ +} req_type_t; /** * the weight of a certain node as linked list. @@ -89,12 +89,12 @@ typedef struct in3_response { * * This is generated for each request and represents the current state. it holds the state until the request is finished and must be freed afterwards. * */ -typedef struct in3_ctx { +typedef struct in3_req { uint_fast8_t signers_length; /**< number or addresses */ - uint16_t len; /**< the number of requests */ + uint_fast16_t len; /**< the number of requests */ uint_fast16_t attempt; /**< the number of attempts */ uint32_t id; /**< JSON RPC id of request at index 0 */ - ctx_type_t type; /**< the type of the request */ + req_type_t type; /**< the type of the request */ in3_ret_t verification_state; /**< state of the verification */ char* error; /**< in case of an error this will hold the message, if not it points to `NULL` */ json_ctx_t* request_context; /**< the result of the json-parser for the request.*/ @@ -105,9 +105,9 @@ typedef struct in3_ctx { uint8_t* signers; /**< the addresses of servers requested to sign the blockhash */ node_match_t* nodes; /**< selected nodes to process the request, which are stored as linked list.*/ cache_entry_t* cache; /** CTX [label="ctx_new()"] + RPC -> CTX [label="req_new()"] CTX -> exec @@ -192,8 +192,8 @@ NONULL in3_ctx_state_t in3_ctx_exec_state( exec -> response[label="IN3_OK"] exec -> waiting[label="IN3_WAITING"] - waiting -> sign[label=CT_SIGN] - waiting -> request[label=CT_RPC] + waiting -> sign[label=RT_SIGN] + waiting -> request[label=RT_RPC] sign -> exec [label="in3_ctx_add_response()"] request -> exec[label="in3_ctx_add_response()"] @@ -213,23 +213,23 @@ NONULL in3_ctx_state_t in3_ctx_exec_state( * * ```c * - in3_ret_t in3_send_ctx(in3_ctx_t* ctx) { + in3_ret_t in3_send_req(in3_req_t* req) { in3_ret_t ret; // execute the context and store the return value. // if the return value is 0 == IN3_OK, it was successful and we return, // if not, we keep on executing - while ((ret = in3_ctx_execute(ctx))) { + while ((ret = in3_req_execute(ctx))) { // error we stop here, because this means we got an error if (ret != IN3_WAITING) return ret; // handle subcontexts first, if they have not been finished - while (ctx->required && in3_ctx_state(ctx->required) != CTX_SUCCESS) { + while (ctx->required && in3_req_state(ctx->required) != REQ_SUCCESS) { // exxecute them, and return the status if still waiting or error - if ((ret = in3_send_ctx(ctx->required))) return ret; + if ((ret = in3_send_req(ctx->required))) return ret; // recheck in order to prepare the request. // if it is not waiting, then it we cannot do much, becaus it will an error or successfull. - if ((ret = in3_ctx_execute(ctx)) != IN3_WAITING) return ret; + if ((ret = in3_req_execute(ctx)) != IN3_WAITING) return ret; } // only if there is no response yet... @@ -239,10 +239,10 @@ NONULL in3_ctx_state_t in3_ctx_exec_state( switch (ctx->type) { // RPC-request to send to the nodes - case CT_RPC: { + case RT_RPC: { // build the request - in3_request_t* request = in3_create_request(ctx); + in3_http_request_t* request = in3_create_request(ctx); // here we use the transport, but you can also try to fetch the data in any other way. ctx->client->transport(request); @@ -253,7 +253,7 @@ NONULL in3_ctx_state_t in3_ctx_exec_state( } // this is a request to sign a transaction - case CT_SIGN: { + case RT_SIGN: { // read the data to sign from the request d_token_t* params = d_get(ctx->requests[0], K_PARAMS); // the data to sign @@ -271,7 +271,7 @@ NONULL in3_ctx_state_t in3_ctx_exec_state( // use the signer to create the signature ret = ctx->client->signer->sign(ctx, SIGN_EC_HASH, data, from, sig); // if it fails we report this as error - if (ret < 0) return ctx_set_error(ctx, ctx->raw_response->error.data, ret); + if (ret < 0) return req_set_error(ctx, ctx->raw_response->error.data, ret); // otherwise we simply add the raw 65 bytes to the response. sb_add_range(&ctx->raw_response->result, (char*) sig, 0, 65); } @@ -287,36 +287,36 @@ NONULL in3_ctx_state_t in3_ctx_exec_state( * * */ -NONULL in3_ret_t in3_ctx_execute( - in3_ctx_t* ctx /**< [in] the request context. */ +NONULL in3_ret_t in3_req_execute( + in3_req_t* req /**< [in] the request context. */ ); /** * returns the current state of the context. */ -NONULL in3_ctx_state_t in3_ctx_state( - in3_ctx_t* ctx /**< [in] the request context. */ +NONULL in3_req_state_t in3_req_state( + in3_req_t* req /**< [in] the request context. */ ); /** * returns the error of the context. */ -char* ctx_get_error_data( - in3_ctx_t* ctx /**< [in] the request context. */ +char* req_get_error_data( + in3_req_t* req /**< [in] the request context. */ ); /** * returns json response for that context */ -char* ctx_get_response_data( - in3_ctx_t* ctx /**< [in] the request context. */ +char* req_get_response_data( + in3_req_t* req /**< [in] the request context. */ ); /** * returns the type of the request */ -NONULL ctx_type_t ctx_get_type( - in3_ctx_t* ctx /**< [in] the request context. */ +NONULL req_type_t req_get_type( + in3_req_t* req /**< [in] the request context. */ ); /** @@ -324,8 +324,8 @@ NONULL ctx_type_t ctx_get_type( * * But this will not free the request string passed when creating the context! */ -NONULL void ctx_free( - in3_ctx_t* ctx /**< [in] the request context. */ +NONULL void req_free( + in3_req_t* req /**< [in] the request context. */ ); /** * adds a new context as a requirment. @@ -337,22 +337,22 @@ NONULL void ctx_free( * Here is an example of how to use it: * * ```c -in3_ret_t get_from_nodes(in3_ctx_t* parent, char* method, char* params, bytes_t* dst) { +in3_ret_t get_from_nodes(in3_req_t* parent, char* method, char* params, bytes_t* dst) { // check if the method is already existing - in3_ctx_t* ctx = ctx_find_required(parent, method); + in3_req_t* req = req_find_required(parent, method); if (ctx) { // found one - so we check if it is useable. - switch (in3_ctx_state(ctx)) { + switch (in3_req_state(ctx)) { // in case of an error, we report it back to the parent context - case CTX_ERROR: - return ctx_set_error(parent, ctx->error, IN3_EUNKNOWN); + case REQ_ERROR: + return req_set_error(parent, ctx->error, IN3_EUNKNOWN); // if we are still waiting, we stop here and report it. case CTX_WAITING_FOR_REQUIRED_CTX: - case CTX_WAITING_FOR_RESPONSE: + case REQ_WAITING_FOR_RESPONSE: return IN3_WAITING; // if it is useable, we can now handle the result. - case CTX_SUCCESS: { + case REQ_SUCCESS: { d_token_t* r = d_get(ctx->responses[0], K_RESULT); if (r) { // we have a result, so write it back to the dst @@ -360,7 +360,7 @@ in3_ret_t get_from_nodes(in3_ctx_t* parent, char* method, char* params, bytes_t* return IN3_OK; } else // or check the error and report it - return ctx_check_response_error(parent, 0); + return req_check_response_error(parent, 0); } } } @@ -373,54 +373,54 @@ in3_ret_t get_from_nodes(in3_ctx_t* parent, char* method, char* params, bytes_t* // create it sprintf(req, "{\"method\":\"%s\",\"jsonrpc\":\"2.0\",\"id\":1,\"params\":%s}", method, params); // and add the request context to the parent. - return ctx_add_required(parent, ctx_new(parent->client, req)); + return req_add_required(parent, req_new(parent->client, req)); } * ``` */ -NONULL in3_ret_t ctx_add_required( - in3_ctx_t* parent, /**< [in] the current request context. */ - in3_ctx_t* ctx /**< [in] the new request context to add. */ +NONULL in3_ret_t req_add_required( + in3_req_t* parent, /**< [in] the current request context. */ + in3_req_t* req /**< [in] the new request context to add. */ ); /** * searches within the required request contextes for one with the given method. * * This method is used internaly to find a previously added context. */ -NONULL in3_ctx_t* ctx_find_required( - const in3_ctx_t* parent, /**< [in] the current request context. */ +NONULL in3_req_t* req_find_required( + const in3_req_t* parent, /**< [in] the current request context. */ const char* method /**< [in] the method of the rpc-request. */ ); /** * removes a required context after usage. * removing will also call free_ctx to free resources. */ -NONULL in3_ret_t ctx_remove_required( - in3_ctx_t* parent, /**< [in] the current request context. */ - in3_ctx_t* ctx, /**< [in] the request context to remove. */ +NONULL in3_ret_t req_remove_required( + in3_req_t* parent, /**< [in] the current request context. */ + in3_req_t* req, /**< [in] the request context to remove. */ bool rec /**< [in] if true all sub contexts will aösp be removed*/ ); /** * check if the response contains a error-property and reports this as error in the context. */ -NONULL in3_ret_t ctx_check_response_error( - in3_ctx_t* c, /**< [in] the current request context. */ +NONULL in3_ret_t req_check_response_error( + in3_req_t* c, /**< [in] the current request context. */ int i /**< [in] the index of the request to check (if this is a batch-request, otherwise 0). */ ); /** * determins the errorcode for the given request. */ -NONULL in3_ret_t ctx_get_error( - in3_ctx_t* ctx, /**< [in] the current request context. */ +NONULL in3_ret_t req_get_error( + in3_req_t* req, /**< [in] the current request context. */ int id /**< [in] the index of the request to check (if this is a batch-request, otherwise 0). */ ); /** * sends a request and returns a context used to access the result or errors. * - * This context *MUST* be freed with ctx_free(ctx) after usage to release the resources. + * This context *MUST* be freed with req_free(ctx) after usage to release the resources. */ -NONULL in3_ctx_t* in3_client_rpc_ctx_raw( +NONULL in3_req_t* in3_client_rpc_ctx_raw( in3_t* c, /**< [in] the client config. */ const char* request /**< [in] rpc request. */ ); @@ -428,9 +428,9 @@ NONULL in3_ctx_t* in3_client_rpc_ctx_raw( /** * sends a request and returns a context used to access the result or errors. * - * This context *MUST* be freed with ctx_free(ctx) after usage to release the resources. + * This context *MUST* be freed with req_free(ctx) after usage to release the resources. */ -NONULL in3_ctx_t* in3_client_rpc_ctx( +NONULL in3_req_t* in3_client_rpc_ctx( in3_t* c, /**< [in] the clientt config. */ const char* method, /**< [in] rpc method. */ const char* params /**< [in] params as string. */ @@ -439,10 +439,11 @@ NONULL in3_ctx_t* in3_client_rpc_ctx( /** * determines the proof as set in the request. */ -NONULL in3_proof_t in3_ctx_get_proof( - in3_ctx_t* ctx, /**< [in] the current request. */ +NONULL in3_proof_t in3_req_get_proof( + in3_req_t* req, /**< [in] the current request. */ int i /**< [in] the index within the request. */ ); + #ifdef __cplusplus } #endif diff --git a/c/include/in3/scache.h b/c/include/in3/scache.h index e486eca95..4f3970b64 100644 --- a/c/include/in3/scache.h +++ b/c/include/in3/scache.h @@ -52,7 +52,8 @@ extern "C" { typedef enum cache_props { CACHE_PROP_MUST_FREE = 0x1, /**< indicates the content must be freed*/ CACHE_PROP_SRC_REQ = 0x2, /**< the value holds the src-request */ - CACHE_PROP_ONLY_EXTERNAL = 0x4 /**< should only be freed if the context is external */ + CACHE_PROP_ONLY_EXTERNAL = 0x4, /**< should only be freed if the context is external */ + CACHE_PROP_PAYMENT = 0x80 /**< This cache-entry is a payment.data */ } cache_props_t; /** * represents a single cache entry in a linked list. diff --git a/c/include/in3/utils.h b/c/include/in3/utils.h index c02ced227..64acd9d1c 100644 --- a/c/include/in3/utils.h +++ b/c/include/in3/utils.h @@ -45,6 +45,7 @@ extern "C" { #endif #include "bytes.h" +#include #include #ifdef __ZEPHYR__ @@ -53,6 +54,7 @@ extern "C" { #else #define _strtoull(str, endptr, base) strtoull(str, endptr, base) #endif + /** simple swap macro for integral types */ #define SWAP(a, b) \ { \ @@ -85,7 +87,7 @@ extern "C" { #define STR_IMPL_(x) #x #define STR(x) STR_IMPL_(x) -/** converts the bytes to a unsigned long (at least the last max len bytes) */ +/** converts the bytes to a unsigned long (at least the last max len bytes). */ uint64_t bytes_to_long(const uint8_t* data, int len); /** converts the bytes to a unsigned int (at least the last max len bytes) */ @@ -105,12 +107,17 @@ static inline uint32_t bytes_to_int(const uint8_t* data, int len) { /** converts a character into a uint64_t*/ uint64_t char_to_long(const char* a, int l); -/** converts a hexchar to byte (4bit) */ +/** converts a hexchar to byte (4bit). In case of a nonhex char 0xff will be returned. */ uint8_t hexchar_to_int(char c); +#ifdef __ZEPHYR__ +// this function is only used in zephyr, because there it does not support printf("%ull",u64); + /** converts a uint64_t to string (char*); buffer-size min. 21 bytes */ const char* u64_to_str(uint64_t value, char* pBuf, int szBuf); +#endif + /** * convert a c hex string to a byte array storing it into an existing buffer. * @@ -128,19 +135,16 @@ bytes_t* hex_to_new_bytes(const char* buf, int len); /** convefrts a bytes into hex */ int bytes_to_hex(const uint8_t* buffer, int len, char* out); -/** hashes the bytes and creates a new bytes_t */ -bytes_t* sha3(const bytes_t* data); - /** writes 32 bytes to the pointer. */ int keccak(bytes_t data, void* dst); -/** converts a long to 8 bytes */ +/** converts a a uin64_t to 8 bytes written to dst using big endian*/ void long_to_bytes(uint64_t val, uint8_t* dst); -/** converts a int to 4 bytes */ +/** converts a unsigned int to 4 bytes written to dst using big endian*/ void int_to_bytes(uint32_t val, uint8_t* dst); -/** duplicate the string */ +/** duplicate the string. A len=-1 will determine the len with strlen. */ char* _strdupn(const char* src, int len); /** calculate the min number of byte to represents the len */ @@ -148,6 +152,9 @@ int min_bytes_len(uint64_t val); /** * sets a variable value to 32byte word. + * @param src The src data + * @param src_len the number of bytes + * @param dst target pointer */ void uint256_set(const uint8_t* src, wlen_t src_len, bytes32_t dst); @@ -168,7 +175,7 @@ char* str_replace_pos(char* orig, size_t pos, size_t len, const char* rep); char* str_find(char* haystack, const char* needle); /** - * remove all html-tags in the text. + * remove all html-tags in the text. This function will modify the orifinal data and return the same pointer as the input. */ char* str_remove_html(char* data); @@ -177,7 +184,7 @@ char* str_remove_html(char* data); */ uint64_t current_ms(); -/** changes to pointer (a) and it length (l) to remove leading 0 bytes.*/ +/** changes to pointer (a) and it length (l) to remove leading 0 bytes. it will reduce it to max len=1*/ #define optimize_len(a, l) \ while (l > 1 && *a == 0) { \ l--; \ @@ -205,6 +212,19 @@ uint64_t current_ms(); if (_r < 0) return _r; \ } +/** + * executes the expression and expects the return value to be a int indicating the error. + * if the return value is negative it will stop and return this value otherwise continue. + */ +#define TRY_CATCH(exp, catch) \ + { \ + int _r = (exp); \ + if (_r < 0) { \ + catch; \ + return _r; \ + } \ + } + /** * executes the expression and expects value to equal val. * if not it will return IN3_EINVAL @@ -234,12 +254,17 @@ uint64_t current_ms(); if (res < 0) goto clean; \ } +/** + * returns true if all pytes (specified by l) of pts have a value of zero. + */ static inline bool memiszero(uint8_t* ptr, size_t l) { - while (l > 0 && *ptr == 0) { + assert(l > 0); + while (l) { + if (*ptr) return false; l--; ptr++; } - return !l; + return true; } /** @@ -294,6 +319,47 @@ int64_t parse_float_val(const char* data, /**< the data string*/ int32_t expo /**< the exponent */ ); +#ifdef THREADSAFE +#define _NAME(x, y) x##y +#if defined(_MSC_VER) || defined(__MINGW32__) + +#include + +#define INIT_LOCK(NAME) \ + static HANDLE _NAME(_lock_handle_, NAME) = NULL; \ + static void _NAME(_lock, NAME)() { \ + if (!_NAME(_lock_handle_, NAME)) { \ + HANDLE p = CreateMutex(NULL, FALSE, NULL); \ + if (InterlockedCompareExchangePointer((PVOID*) &_NAME(_lock_handle_, NAME), (PVOID) p, NULL)) CloseHandle(p); \ + } \ + WaitForSingleObject(_NAME(_lock_handle_, NAME), INFINITE); \ + } + +#define LOCK(NAME, code) \ + { \ + _NAME(_lock, NAME) \ + (); \ + code \ + ReleaseMutex(_NAME(_lock_handle_, NAME)); \ + } + +#else +#include +#define INIT_LOCK(NAME) static pthread_mutex_t _NAME(_lock_handle_, NAME) = PTHREAD_MUTEX_INITIALIZER; +#define LOCK(NAME, code) \ + { \ + pthread_mutex_lock(&(_NAME(_lock_handle_, NAME))); \ + code \ + pthread_mutex_unlock(&(_NAME(_lock_handle_, NAME))); \ + } +#endif +#else +#define INIT_LOCK(NAME) \ + {} +#define LOCK(NAME, code) \ + { code } +#endif + #ifdef __cplusplus } #endif diff --git a/c/include/in3/zksync.h b/c/include/in3/zksync.h index 700fbd370..7b77f1be6 100644 --- a/c/include/in3/zksync.h +++ b/c/include/in3/zksync.h @@ -97,31 +97,44 @@ typedef struct zk_musig_session { bytes_t commitments; /**< all commits */ bytes_t signature_shares; /**< all signatures shares */ void* signer; /**< handle for the signer */ + char* proof_data; /**< the proof needed by the server to verify. This is created by the client and checked in the server. */ struct zk_musig_session* next; /**< next session */ } zk_musig_session_t; +struct pay_criteria; + /** internal configuration-object */ -typedef struct { - char* provider_url; /**< url of the zksync-server */ - uint8_t* account; /**< address of the account */ - uint8_t* main_contract; /**< address of the main zksync contract*/ - uint8_t* gov_contract; /**< address of the government contract */ - uint64_t account_id; /**< the id of the account as used in the messages */ - uint64_t nonce; /**< the current nonce */ - address_t pub_key_hash_set; /**< the pub_key_hash as set in the account*/ - address_t pub_key_hash_pk; /**< the pub_key_hash based on the sync_key*/ - bytes32_t pub_key; /**< the pub_key */ - uint16_t token_len; /**< number of tokens in the tokenlist */ - bytes32_t sync_key; /**< the raw key to sign with*/ - zksync_token_t* tokens; /**< the token-list */ - zk_sign_type_t sign_type; /**< the signature-type to use*/ - uint32_t version; /**< zksync version */ - zk_create2_t* create2; /**< create2 args */ - bytes_t musig_pub_keys; /**< the public keys of all participants of a schnorr musig signature */ - zk_musig_session_t* musig_sessions; /**< linked list of open musig sessions */ - char** musig_urls; /**< urls to get signatureshares, the order must be in the same order as the pub_keys */ +typedef struct zksync_config { + char* provider_url; /**< url of the zksync-server */ + uint8_t* account; /**< address of the account */ + uint8_t* main_contract; /**< address of the main zksync contract*/ + uint8_t* gov_contract; /**< address of the government contract */ + uint64_t account_id; /**< the id of the account as used in the messages */ + uint64_t nonce; /**< the current nonce */ + address_t pub_key_hash_set; /**< the pub_key_hash as set in the account*/ + address_t pub_key_hash_pk; /**< the pub_key_hash based on the sync_key*/ + bytes32_t pub_key; /**< the pub_key */ + uint16_t token_len; /**< number of tokens in the tokenlist */ + bytes32_t sync_key; /**< the raw key to sign with*/ + zksync_token_t* tokens; /**< the token-list */ + zk_sign_type_t sign_type; /**< the signature-type to use*/ + uint32_t version; /**< zksync version */ + zk_create2_t* create2; /**< create2 args */ + bytes_t musig_pub_keys; /**< the public keys of all participants of a schnorr musig signature */ + zk_musig_session_t* musig_sessions; /**< linked list of open musig sessions */ + char** musig_urls; /**< urls to get signatureshares, the order must be in the same order as the pub_keys */ + struct pay_criteria* incentive; /**< incentive payment configuration */ + char* proof_verify_method; /**< the rpc-method used to verify the proof before creating a signature */ + char* proof_create_method; /**< the rpc-method used to create the proof before creating a signature */ } zksync_config_t; +typedef struct pay_criteria { + uint_fast32_t payed_nodes; /**< max number of nodes payed at the same time*/ + uint64_t max_price_per_hundred_igas; /**< the max price per 100 gas units to accept a payment offer */ + char* token; /**< token-name */ + zksync_config_t config; /**< the account configuration */ +} pay_criteria_t; + /** a transaction */ typedef struct { zksync_config_t* conf; /**< the configuration of the zksync-account */ @@ -139,27 +152,30 @@ typedef struct { NONULL in3_ret_t in3_register_zksync(in3_t* c); /** sets a PubKeyHash for the current Account */ -NONULL in3_ret_t zksync_set_key(zksync_config_t* conf, in3_rpc_handle_ctx_t* ctx, d_token_t* params); +NONULL in3_ret_t zksync_set_key(zksync_config_t* conf, in3_rpc_handle_ctx_t* ctx); /** sends a transfer transaction in Layer 2*/ -NONULL in3_ret_t zksync_transfer(zksync_config_t* conf, in3_rpc_handle_ctx_t* ctx, d_token_t* params, zk_msg_type_t type); +NONULL in3_ret_t zksync_transfer(zksync_config_t* conf, in3_rpc_handle_ctx_t* ctx, zk_msg_type_t type); /** sends a deposit transaction in Layer 1*/ -NONULL in3_ret_t zksync_deposit(zksync_config_t* conf, in3_rpc_handle_ctx_t* ctx, d_token_t* params); +NONULL in3_ret_t zksync_deposit(zksync_config_t* conf, in3_rpc_handle_ctx_t* ctx); /** sends a emergency withdraw transaction in Layer 1*/ -NONULL in3_ret_t zksync_emergency_withdraw(zksync_config_t* conf, in3_rpc_handle_ctx_t* ctx, d_token_t* params); +NONULL in3_ret_t zksync_emergency_withdraw(zksync_config_t* conf, in3_rpc_handle_ctx_t* ctx); /** creates message data and signs a transfer-message */ -NONULL in3_ret_t zksync_sign_transfer(sb_t* sb, zksync_tx_data_t* data, in3_ctx_t* ctx, zksync_config_t* conf); +NONULL in3_ret_t zksync_sign_transfer(sb_t* sb, zksync_tx_data_t* data, in3_req_t* req, zksync_config_t* conf); /** creates message data and signs a change_pub_key-message */ -NONULL in3_ret_t zksync_sign_change_pub_key(sb_t* sb, in3_ctx_t* ctx, uint8_t* sync_pub_key, uint32_t nonce, zksync_config_t* conf, zk_fee_t fee, zksync_token_t* token); +NONULL in3_ret_t zksync_sign_change_pub_key(sb_t* sb, in3_req_t* req, uint8_t* sync_pub_key, uint32_t nonce, zksync_config_t* conf, zk_fee_t fee, zksync_token_t* token); -in3_ret_t zksync_musig_sign(zksync_config_t* conf, in3_rpc_handle_ctx_t* ctx, d_token_t* params); +in3_ret_t zksync_musig_sign(zksync_config_t* conf, in3_rpc_handle_ctx_t* ctx); zk_musig_session_t* zk_musig_session_free(zk_musig_session_t* s); -in3_ret_t zksync_sign(zksync_config_t* conf, bytes_t msg, in3_ctx_t* ctx, uint8_t* sig); - +in3_ret_t zksync_sign(zksync_config_t* conf, bytes_t msg, in3_req_t* req, uint8_t* sig); +in3_ret_t zksync_check_payment(zksync_config_t* conf, in3_pay_followup_ctx_t* ctx); +in3_ret_t zksync_add_payload(in3_pay_payload_ctx_t* ctx); +in3_ret_t update_nodelist_from_cache(in3_req_t* req, unsigned int nodelen); +in3_ret_t handle_zksync(void* conf, in3_plugin_act_t action, void* arg); #ifdef __cplusplus } #endif diff --git a/c/src/api/btc/btc_api.c b/c/src/api/btc/btc_api.c index 1b658b55b..45ad75050 100644 --- a/c/src/api/btc/btc_api.c +++ b/c/src/api/btc/btc_api.c @@ -89,30 +89,30 @@ static in3_ret_t fill_tx(d_token_t* t, btc_transaction_t* res, void* data, bytes d_token_t* t_vout = d_get(t, key("vout")); if (!t_hex || !t_vin || !t_vout) return IN3_EFIND; - res->in_active_chain = !!d_get_intkd(t, key("in_active_chain"), 1); + res->in_active_chain = !!d_get_intd(t, key("in_active_chain"), 1); res->vin = data; res->vout = ((void*) res->vin) + d_len(t_vin) * sizeof(btc_transaction_in_t); res->data = bytes(((void*) res->vout) + d_len(t_vout) * sizeof(btc_transaction_out_t), d_len(t_hex) / 2); res->vin_len = d_len(t_vin), res->vout_len = d_len(t_vout); - res->size = d_get_intk(t, key("size")); - res->vsize = d_get_intk(t, key("vsize")); - res->weight = d_get_intk(t, key("weight")); - res->version = d_get_intk(t, key("version")); - res->locktime = d_get_intk(t, key("locktime")); - res->time = d_get_intk(t, key("time")); - res->blocktime = d_get_intk(t, key("blocktime")); - res->confirmations = d_get_intk(t, key("confirmations")); + res->size = d_get_int(t, key("size")); + res->vsize = d_get_int(t, key("vsize")); + res->weight = d_get_int(t, key("weight")); + res->version = d_get_int(t, key("version")); + res->locktime = d_get_int(t, key("locktime")); + res->time = d_get_int(t, key("time")); + res->blocktime = d_get_int(t, key("blocktime")); + res->confirmations = d_get_int(t, key("confirmations")); TRY(hex_to_bytes(d_string(t_hex), -1, res->data.data, res->data.len)) TRY(btc_parse_tx(res->data, &txdata)); - EXPECT_EQ(hex_to_bytes(d_get_stringk(t, key("txid")), -1, res->txid, 32), 32) - EXPECT_EQ(hex_to_bytes(d_get_stringk(t, key("hash")), -1, res->hash, 32), 32) + EXPECT_EQ(hex_to_bytes(d_get_string(t, key("txid")), -1, res->txid, 32), 32) + EXPECT_EQ(hex_to_bytes(d_get_string(t, key("hash")), -1, res->hash, 32), 32) if (block_hash) memcpy(res->blockhash, block_hash, 32); else - EXPECT_EQ(hex_to_bytes(d_get_stringk(t, key("blockhash")), -1, res->blockhash, 32), 32) + EXPECT_EQ(hex_to_bytes(d_get_string(t, key("blockhash")), -1, res->blockhash, 32), 32) // handle vin uint8_t* p = txdata.input.data; @@ -156,21 +156,21 @@ btc_transaction_t* btc_d_to_tx(d_token_t* t) { static in3_ret_t fill_blockheader(d_token_t* t, btc_blockheader_t* res) { EXPECT_EQ(d_type(t), T_OBJECT) - EXPECT_EQ(hex_to_bytes(d_get_string(t, "hash"), 64, res->hash, 32), 32); - EXPECT_EQ(hex_to_bytes(d_get_string(t, "merkleroot"), 64, res->merkleroot, 32), 32); - EXPECT_EQ(hex_to_bytes(d_get_string(t, "bits"), 8, res->bits, 4), 4); - EXPECT_EQ(hex_to_bytes(d_get_string(t, "chainwork"), 64, res->chainwork, 32), 32); - EXPECT_EQ(hex_to_bytes(d_get_string(t, "previousblockhash"), 64, res->previous_hash, 32), 32); - EXPECT_EQ(hex_to_bytes(d_get_string(t, "nextblockhash"), 64, res->next_hash, 32), 32); + EXPECT_EQ(hex_to_bytes(d_get_string(t, K_HASH), 64, res->hash, 32), 32); + EXPECT_EQ(hex_to_bytes(d_get_string(t, key("merkleroot")), 64, res->merkleroot, 32), 32); + EXPECT_EQ(hex_to_bytes(d_get_string(t, key("bits")), 8, res->bits, 4), 4); + EXPECT_EQ(hex_to_bytes(d_get_string(t, key("chainwork")), 64, res->chainwork, 32), 32); + EXPECT_EQ(hex_to_bytes(d_get_string(t, key("previousblockhash")), 64, res->previous_hash, 32), 32); + EXPECT_EQ(hex_to_bytes(d_get_string(t, key("nextblockhash")), 64, res->next_hash, 32), 32); TRY(btc_serialize_block_header(t, res->data)) - res->confirmations = d_get_int(t, "confirmations"); - res->height = d_get_int(t, "height"); - res->version = d_get_int(t, "version"); - res->time = d_get_int(t, "time"); - res->nonce = d_get_int(t, "nonce"); - res->n_tx = d_get_int(t, "nTx"); + res->confirmations = d_get_int(t, key("confirmations")); + res->height = d_get_int(t, key("height")); + res->version = d_get_int(t, key("version")); + res->time = d_get_int(t, key("time")); + res->nonce = d_get_int(t, key("nonce")); + res->n_tx = d_get_int(t, key("nTx")); return IN3_OK; } diff --git a/c/src/api/eth1/ens.c b/c/src/api/eth1/ens.c index 93d9bc31e..7ddd05278 100644 --- a/c/src/api/eth1/ens.c +++ b/c/src/api/eth1/ens.c @@ -1,7 +1,7 @@ #include "ens.h" -#include "../../core/client/context_internal.h" #include "../../core/client/keys.h" #include "../../core/client/plugin.h" +#include "../../core/client/request_internal.h" #include "../../core/util/bytes.h" #include "../../core/util/data.h" #include "../../core/util/mem.h" @@ -15,35 +15,33 @@ static int next_token(const char* c, int p) { return -1; } -static in3_ctx_t* find_pending_ctx(in3_ctx_t* ctx, bytes_t data) { +static in3_req_t* find_pending_ctx(in3_req_t* ctx, bytes_t data) { // ok, we need a request, do we have a useable? - ctx = ctx->required; - while (ctx) { - if (strcmp(d_get_stringk(ctx->requests[0], K_METHOD), "eth_call") == 0) { - bytes_t* ctx_data = d_get_bytesk(d_get_at(d_get(ctx->requests[0], K_PARAMS), 0), K_DATA); + for (ctx = ctx->required; ctx; ctx = ctx->required) { + if (strcmp(d_get_string(ctx->requests[0], K_METHOD), "eth_call") == 0) { + bytes_t* ctx_data = d_get_bytes(d_get_at(d_get(ctx->requests[0], K_PARAMS), 0), K_DATA); if (ctx_data && b_cmp(ctx_data, &data)) return ctx; } - ctx = ctx->required; } return NULL; } -static in3_ret_t exec_call(bytes_t calldata, char* to, in3_ctx_t* parent, bytes_t** result) { - in3_ctx_t* ctx = find_pending_ctx(parent, calldata); +static in3_ret_t exec_call(bytes_t calldata, char* to, in3_req_t* parent, bytes_t** result) { + in3_req_t* ctx = find_pending_ctx(parent, calldata); if (ctx) { - switch (in3_ctx_state(ctx)) { - case CTX_SUCCESS: { + switch (in3_req_state(ctx)) { + case REQ_SUCCESS: { d_token_t* rpc_result = d_get(ctx->responses[0], K_RESULT); if (!ctx->error && rpc_result && d_type(rpc_result) == T_BYTES && d_len(rpc_result) >= 20) { *result = d_bytes(rpc_result); - // ctx_remove_required(parent, ctx); + // req_remove_required(parent, ctx); return IN3_OK; } else - return ctx_set_error(parent, "could not get the resolver", IN3_EFIND); + return req_set_error(parent, "could not get the resolver", IN3_EFIND); } - case CTX_ERROR: + case REQ_ERROR: return IN3_ERPC; default: return IN3_WAITING; @@ -55,7 +53,7 @@ static in3_ret_t exec_call(bytes_t calldata, char* to, in3_ctx_t* parent, bytes_ char data[73]; bytes_to_hex(calldata.data, 36, data); sprintf(req, "{\"method\":\"eth_call\",\"jsonrpc\":\"2.0\",\"params\":[{\"to\":\"%s\",\"data\":\"0x%s\"},\"latest\"]}", to, data); - return ctx_add_required(parent, ctx_new(parent->client, req)); + return req_add_required(parent, req_new(parent->client, req)); } } @@ -71,7 +69,7 @@ static void ens_hash(const char* domain, bytes32_t dst) { memcpy(dst, hash, 32); // we only the first 32 bytes - the root } -in3_ret_t ens_resolve(in3_ctx_t* parent, char* name, const address_t registry, in3_ens_type type, uint8_t* dst, int* res_len) { +in3_ret_t ens_resolve(in3_req_t* parent, char* name, const address_t registry, in3_ens_type type, uint8_t* dst, int* res_len) { const int len = strlen(name); if (*name == '0' && name[1] == 'x' && len == 42) { hex_to_bytes(name, 40, dst, 20); @@ -87,7 +85,7 @@ in3_ret_t ens_resolve(in3_ctx_t* parent, char* name, const address_t registry, i if (in3_plugin_is_registered(parent->client, PLGN_ACT_CACHE)) { cachekey = alloca(strlen(name) + 5); sprintf(cachekey, "ens:%s:%i:%d", name, type, (int) parent->client->chain.chain_id); - in3_cache_ctx_t cctx = {.ctx = parent, .key = cachekey, .content = NULL}; + in3_cache_ctx_t cctx = {.req = parent, .key = cachekey, .content = NULL}; TRY(in3_plugin_execute_first_or_none(parent, PLGN_ACT_CACHE_GET, &cctx)) if (cctx.content) { memcpy(dst, cctx.content->data, 20); @@ -137,18 +135,18 @@ in3_ret_t ens_resolve(in3_ctx_t* parent, char* name, const address_t registry, i registry_address = "0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e"; break; default: - return ctx_set_error(parent, "There is no ENS-contract for the current chain", IN3_ENOTSUP); + return req_set_error(parent, "There is no ENS-contract for the current chain", IN3_ENOTSUP); } in3_ret_t res = exec_call(callbytes, registry_address, parent, &last_result); if (res < 0) return res; if (last_result && last_result->data) memcpy(resolver, last_result->data + last_result->len - 20, 20); - if (memiszero(resolver, 20)) return ctx_set_error(parent, "resolver not registered", IN3_EFIND); + if (memiszero(resolver, 20)) return req_set_error(parent, "resolver not registered", IN3_EFIND); if (type == ENS_RESOLVER || type == ENS_OWNER) { memcpy(dst, resolver, 20); - in3_cache_ctx_t cctx = {.ctx = parent, .key = cachekey, .content = &dst_bytes}; + in3_cache_ctx_t cctx = {.req = parent, .key = cachekey, .content = &dst_bytes}; in3_plugin_execute_all(parent->client, PLGN_ACT_CACHE_SET, &cctx); return IN3_OK; } @@ -177,14 +175,14 @@ in3_ret_t ens_resolve(in3_ctx_t* parent, char* name, const address_t registry, i if (res < 0) return res; if (!last_result || !last_result->data) return IN3_ENOMEM; - if (last_result->len < 20 || memiszero(last_result->data, 20)) return ctx_set_error(parent, "address not registered", IN3_EFIND); + if (last_result->len < 20 || memiszero(last_result->data, 20)) return req_set_error(parent, "address not registered", IN3_EFIND); if (type == ENS_ADDR) memcpy(dst, last_result->data + last_result->len - 20, 20); else if (type == ENS_NAME) { } - in3_cache_ctx_t cctx = {.ctx = parent, .key = cachekey, .content = &dst_bytes}; + in3_cache_ctx_t cctx = {.req = parent, .key = cachekey, .content = &dst_bytes}; in3_plugin_execute_first_or_none(parent, PLGN_ACT_CACHE_SET, &cctx); return IN3_OK; } \ No newline at end of file diff --git a/c/src/api/eth1/ens.h b/c/src/api/eth1/ens.h index 69ae2118c..4b631fc1b 100644 --- a/c/src/api/eth1/ens.h +++ b/c/src/api/eth1/ens.h @@ -32,7 +32,7 @@ * with this program. If not, see . *******************************************************************************/ -#include "../../core/client/context.h" +#include "../../core/client/request.h" #ifndef _ETH_API_ENS_H_ #define _ETH_API_ENS_H_ @@ -45,6 +45,6 @@ typedef enum { ENS_HASH = 4 /**< hash */ } in3_ens_type; -in3_ret_t ens_resolve(in3_ctx_t* parent, char* name, const address_t registry, in3_ens_type type, uint8_t* dst, int* len); +in3_ret_t ens_resolve(in3_req_t* parent, char* name, const address_t registry, in3_ens_type type, uint8_t* dst, int* len); #endif // _ETH_API_ENS_H_ diff --git a/c/src/api/eth1/eth_api.c b/c/src/api/eth1/eth_api.c index 57aeafc68..fd308d67f 100644 --- a/c/src/api/eth1/eth_api.c +++ b/c/src/api/eth1/eth_api.c @@ -33,10 +33,11 @@ *******************************************************************************/ #include "eth_api.h" -#include "../../core/client/context.h" #include "../../core/client/keys.h" +#include "../../core/client/request.h" #include "../../core/util/log.h" #include "../../core/util/mem.h" +#include "../../verifier/eth1/basic/eth_basic.h" #include "../../verifier/eth1/basic/filter.h" #include "../../verifier/eth1/nano/rlp.h" #include "../utils/api_utils_priv.h" @@ -112,13 +113,13 @@ static size_t align(size_t val) { static uint32_t write_tx(d_token_t* t, eth_tx_t* tx) { bytes_t b = d_to_bytes(d_get(t, K_INPUT)); - tx->signature[64] = d_get_intk(t, K_V); - tx->block_number = d_get_longk(t, K_BLOCK_NUMBER); - tx->gas = d_get_longk(t, K_GAS); - tx->gas_price = d_get_longk(t, K_GAS_PRICE); - tx->nonce = d_get_longk(t, K_NONCE); + tx->signature[64] = d_get_int(t, K_V); + tx->block_number = d_get_long(t, K_BLOCK_NUMBER); + tx->gas = d_get_long(t, K_GAS); + tx->gas_price = d_get_long(t, K_GAS_PRICE); + tx->nonce = d_get_long(t, K_NONCE); tx->data = bytes((uint8_t*) tx + sizeof(eth_tx_t), b.len); - tx->transaction_index = d_get_intk(t, K_TRANSACTION_INDEX); + tx->transaction_index = d_get_int(t, K_TRANSACTION_INDEX); memcpy((uint8_t*) tx + sizeof(eth_tx_t), b.data, b.len); // copy the data right after the tx-struct. copy_fixed(tx->block_hash, 32, d_to_bytes(d_getl(t, K_BLOCK_HASH, 32))); copy_fixed(tx->from, 20, d_to_bytes(d_getl(t, K_FROM, 20))); @@ -191,10 +192,10 @@ static eth_block_t* eth_getBlock(d_token_t* result, bool include_tx) { copy_fixed(b->sha3_uncles, 32, d_to_bytes(d_getl(result, K_SHA3_UNCLES, 32))); copy_fixed(b->state_root, 32, d_to_bytes(d_getl(result, K_STATE_ROOT, 32))); - b->gasLimit = d_get_longk(result, K_GAS_LIMIT); - b->gasUsed = d_get_longk(result, K_GAS_USED); - b->number = d_get_longk(result, K_NUMBER); - b->timestamp = d_get_longk(result, K_TIMESTAMP); + b->gasLimit = d_get_long(result, K_GAS_LIMIT); + b->gasUsed = d_get_long(result, K_GAS_USED); + b->number = d_get_long(result, K_NUMBER); + b->timestamp = d_get_long(result, K_TIMESTAMP); b->tx_count = d_len(txs); b->seal_fields_count = d_len(sealed); b->extra_data = bytes(p, extra.len); @@ -278,10 +279,10 @@ static eth_log_t* parse_logs(d_token_t* result) { prev = first = NULL; for (d_iterator_t it = d_iter(result); it.left; d_iter_next(&it)) { eth_log_t* log = _calloc(1, sizeof(*log)); - log->removed = d_get_intk(it.token, K_REMOVED); - log->log_index = d_get_intk(it.token, K_LOG_INDEX); - log->transaction_index = d_get_intk(it.token, K_TRANSACTION_INDEX); - log->block_number = d_get_longk(it.token, K_BLOCK_NUMBER); + log->removed = d_get_int(it.token, K_REMOVED); + log->log_index = d_get_int(it.token, K_LOG_INDEX); + log->transaction_index = d_get_int(it.token, K_TRANSACTION_INDEX); + log->block_number = d_get_long(it.token, K_BLOCK_NUMBER); log->data.len = d_len(d_get(it.token, K_DATA)); log->data.data = _malloc(sizeof(uint8_t) * log->data.len); log->topics = _malloc(sizeof(bytes32_t) * d_len(d_get(it.token, K_TOPICS))); @@ -398,11 +399,11 @@ static void* eth_call_fn_intern(in3_t* in3, address_t contract, eth_blknum_t blo static char* wait_for_receipt(in3_t* in3, char* params, int timeout, int count) { errno = 0; - in3_ctx_t* ctx = in3_client_rpc_ctx(in3, "eth_getTransactionReceipt", params); + in3_req_t* ctx = in3_client_rpc_ctx(in3, "eth_getTransactionReceipt", params); d_token_t* result = get_result(ctx); if (result) { if (d_type(result) == T_NULL) { - ctx_free(ctx); + req_free(ctx); if (count) { #if defined(_WIN32) || defined(WIN32) Sleep(timeout); @@ -421,12 +422,12 @@ static char* wait_for_receipt(in3_t* in3, char* params, int timeout, int count) else { // char* c = d_create_json(ctx->response_context, result); - ctx_free(ctx); + req_free(ctx); return c; } } api_set_error(3, ctx->error ? ctx->error : "Error getting the Receipt!"); - ctx_free(ctx); + req_free(ctx); return NULL; } @@ -461,16 +462,16 @@ in3_ret_t eth_newPendingTransactionFilter(in3_t* in3) { } bool eth_uninstallFilter(in3_t* in3, size_t id) { - return filter_remove(in3, id); + return filter_remove(eth_basic_get_filters(in3), id); } in3_ret_t eth_getFilterChanges(in3_t* in3, size_t id, bytes32_t** block_hashes, eth_log_t** logs) { - if (in3->filters == NULL) + in3_filter_handler_t* filters = eth_basic_get_filters(in3); + if (filters == NULL) return IN3_EFIND; + if (id == 0 || id > filters->count) return IN3_EFIND; - if (id == 0 || id > in3->filters->count) - return IN3_EINVAL; - in3_filter_t* f = in3->filters->array[id - 1]; + in3_filter_t* f = filters->array[id - 1]; if (!f) return IN3_EFIND; @@ -510,12 +511,12 @@ in3_ret_t eth_getFilterChanges(in3_t* in3, size_t id, bytes32_t** block_hashes, } in3_ret_t eth_getFilterLogs(in3_t* in3, size_t id, eth_log_t** logs) { - if (in3->filters == NULL) + in3_filter_handler_t* filters = eth_basic_get_filters(in3); + if (filters == NULL) return IN3_EFIND; + if (id == 0 || id > filters->count) return IN3_EFIND; - if (id == 0 || id > in3->filters->count) - return IN3_EINVAL; - in3_filter_t* f = in3->filters->array[id - 1]; + in3_filter_t* f = filters->array[id - 1]; if (!f) return IN3_EFIND; @@ -623,11 +624,11 @@ static eth_tx_receipt_t* parse_tx_receipt(d_token_t* result) { api_set_error(EAGAIN, "Error getting the Receipt!"); else { eth_tx_receipt_t* txr = _malloc(sizeof(*txr)); - txr->transaction_index = d_get_intk(result, K_TRANSACTION_INDEX); - txr->block_number = d_get_longk(result, K_BLOCK_NUMBER); - txr->cumulative_gas_used = d_get_longk(result, K_CUMULATIVE_GAS_USED); - txr->gas_used = d_get_longk(result, K_GAS_USED); - txr->status = (d_get_intk(result, K_STATUS) == 1); + txr->transaction_index = d_get_int(result, K_TRANSACTION_INDEX); + txr->block_number = d_get_long(result, K_BLOCK_NUMBER); + txr->cumulative_gas_used = d_get_long(result, K_CUMULATIVE_GAS_USED); + txr->gas_used = d_get_long(result, K_GAS_USED); + txr->status = (d_get_int(result, K_STATUS) == 1); txr->contract_address = b_dup(d_get_byteskl(result, K_CONTRACT_ADDRESS, 20)); txr->logs = parse_logs(d_get(result, K_LOGS)); copy_fixed(txr->transaction_hash, 32, d_to_bytes(d_getl(result, K_TRANSACTION_HASH, 32))); diff --git a/c/src/api/eth1/key.c b/c/src/api/eth1/key.c index d9669c68d..c86cbd720 100644 --- a/c/src/api/eth1/key.c +++ b/c/src/api/eth1/key.c @@ -33,6 +33,7 @@ *******************************************************************************/ #include "../../core/client/client.h" +#include "../../core/client/keys.h" #include "../../core/util/data.h" #include "../../core/util/mem.h" #include "../../core/util/utils.h" @@ -45,48 +46,49 @@ #endif in3_ret_t decrypt_key(d_token_t* key_data, char* password, bytes32_t dst) { - if (d_get_int(key_data, "version") != 3) return IN3_EVERS; + if (d_get_int(key_data, K_VERSION) != 3) return IN3_EVERS; d_token_t* crypto = d_get(key_data, key("crypto")); - char* kdf = d_get_string(crypto, "kdf"); + char* kdf = d_get_string(crypto, key("kdf")); d_token_t* kdf_params = d_get(crypto, key("kdfparams")); if (!crypto || !kdf || !kdf_params) return IN3_EINVALDT; - int klen = d_get_int(kdf_params, "dklen"); - char* salt_hex = d_get_string(kdf_params, "salt"); + int klen = d_get_int(kdf_params, key("dklen")); + char* salt_hex = d_get_string(kdf_params, key("salt")); uint8_t *salt_data = alloca(strlen(salt_hex) >> 1), *aeskey = alloca(klen), cipher_data[64]; bytes_t salt = bytes(salt_data, hex_to_bytes(salt_hex, -1, salt_data, 0xFF)); if (strcmp(kdf, "scrypt") == 0) { #ifdef SCRYPT if (libscrypt_scrypt((const uint8_t*) password, strlen(password), salt.data, salt.len, - d_get_long(kdf_params, "n"), d_get_int(kdf_params, "r"), d_get_long(kdf_params, "p"), aeskey, klen)) + d_get_long(kdf_params, key("n")), d_get_int(kdf_params, key("r")), d_get_long(kdf_params, key("p")), aeskey, klen)) return IN3_EPASS; #else return IN3_ENOTSUP; #endif } else if (strcmp(kdf, "pbkdf2") == 0) { - if (!kdf_params || strcmp(d_get_string(kdf_params, "prf"), "hmac-sha256")) return IN3_ENOTSUP; - if (strcmp(d_get_string(crypto, "cipher"), "aes-128-ctr")) return IN3_ENOTSUP; - pbkdf2_hmac_sha256((const uint8_t*) password, strlen(password), salt.data, salt.len, d_get_int(kdf_params, "c"), aeskey, klen); + if (!kdf_params || strcmp(d_get_string(kdf_params, key("prf")), "hmac-sha256")) return IN3_ENOTSUP; + if (strcmp(d_get_string(crypto, key("cipher")), "aes-128-ctr")) return IN3_ENOTSUP; + pbkdf2_hmac_sha256((const uint8_t*) password, strlen(password), salt.data, salt.len, d_get_int(kdf_params, key("c")), aeskey, klen); } else return IN3_ENOTSUP; - bytes_t cipher = bytes(cipher_data, hex_to_bytes(d_get_string(crypto, "ciphertext"), -1, cipher_data, 64)); + bytes_t cipher = bytes(cipher_data, hex_to_bytes(d_get_string(crypto, key("ciphertext")), -1, cipher_data, 64)); uint8_t *msg = alloca(cipher.len + 16), mac[32]; memcpy(msg, aeskey + 16, 16); memcpy(msg + 16, cipher.data, cipher.len); keccak(bytes(msg, cipher.len + 16), mac); bytes32_t mac_verify; - hex_to_bytes(d_get_string(crypto, "mac"), -1, mac_verify, 32); + hex_to_bytes(d_get_string(crypto, key("mac")), -1, mac_verify, 32); if (memcmp(mac, mac_verify, 32)) return IN3_EPASS; // aes-128-ctr aes_init(); aes_encrypt_ctx cx[1]; - char* iv_hex = d_get_string(d_get(crypto, key("cipherparams")), "iv"); - int iv_len = strlen(iv_hex) / 2; - uint8_t* iv_data = alloca(iv_len); + d_token_t* cipherparams = d_get(crypto, key("cipherparams")); + char* iv_hex = d_get_string(cipherparams, key("iv")); + int iv_len = strlen(iv_hex) / 2; + uint8_t* iv_data = alloca(iv_len); hex_to_bytes(iv_hex, -1, iv_data, iv_len); aes_encrypt_key128(aeskey, cx); diff --git a/c/src/api/eth1/rpc_api.c b/c/src/api/eth1/rpc_api.c index 32131c085..bd0d1a162 100644 --- a/c/src/api/eth1/rpc_api.c +++ b/c/src/api/eth1/rpc_api.c @@ -32,9 +32,9 @@ * with this program. If not, see . *******************************************************************************/ -#include "../../core/client/context_internal.h" #include "../../core/client/keys.h" #include "../../core/client/plugin.h" +#include "../../core/client/request_internal.h" #include "../../core/util/debug.h" #include "../../core/util/log.h" #include "../../core/util/mem.h" @@ -56,15 +56,15 @@ #define ETH_SIGN_PREFIX "\x19" \ "Ethereum Signed Message:\n%u" -static in3_ret_t in3_abiEncode(in3_rpc_handle_ctx_t* ctx, d_token_t* params) { - CHECK_PARAM_TYPE(ctx->ctx, params, 0, T_STRING) +static in3_ret_t in3_abiEncode(in3_rpc_handle_ctx_t* ctx) { + CHECK_PARAM_TYPE(ctx->req, ctx->params, 0, T_STRING) in3_ret_t ret = IN3_OK; bytes_t data = {0}; char* error = NULL; - char* sig = d_get_string_at(params, 0); - d_token_t* para = d_get_at(params, 1); - if (!sig) return ctx_set_error(ctx->ctx, "missing signature", IN3_EINVAL); - if (!para) return ctx_set_error(ctx->ctx, "missing values", IN3_EINVAL); + char* sig = d_get_string_at(ctx->params, 0); + d_token_t* para = d_get_at(ctx->params, 1); + if (!sig) return req_set_error(ctx->req, "missing signature", IN3_EINVAL); + if (!para) return req_set_error(ctx->req, "missing values", IN3_EINVAL); abi_sig_t* s = abi_sig_create(sig, &error); if (!error) data = abi_encode(s, para, &error); @@ -72,23 +72,23 @@ static in3_ret_t in3_abiEncode(in3_rpc_handle_ctx_t* ctx, d_token_t* params) { ret = in3_rpc_handle_with_bytes(ctx, data); if (s) abi_sig_free(s); if (data.data) _free(data.data); - return error ? ctx_set_error(ctx->ctx, error, IN3_EINVAL) : ret; + return error ? req_set_error(ctx->req, error, IN3_EINVAL) : ret; } -static in3_ret_t in3_abiDecode(in3_rpc_handle_ctx_t* ctx, d_token_t* params) { - CHECK_PARAM_TYPE(ctx->ctx, params, 0, T_STRING) - CHECK_PARAM_TYPE(ctx->ctx, params, 1, T_BYTES) - CHECK_PARAM(ctx->ctx, params, 1, val->len % 32 == 0) +static in3_ret_t in3_abiDecode(in3_rpc_handle_ctx_t* ctx) { + CHECK_PARAM_TYPE(ctx->req, ctx->params, 0, T_STRING) + CHECK_PARAM_TYPE(ctx->req, ctx->params, 1, T_BYTES) + CHECK_PARAM(ctx->req, ctx->params, 1, val->len % 32 == 0) char* error = NULL; json_ctx_t* res = NULL; - char* sig = d_get_string_at(params, 0); - bytes_t data = d_to_bytes(d_get_at(params, 1)); - if (d_len(params) > 2) return ctx_set_error(ctx->ctx, "too many arguments (only 2 alllowed)", IN3_EINVAL); + char* sig = d_get_string_at(ctx->params, 0); + bytes_t data = d_to_bytes(d_get_at(ctx->params, 1)); + if (d_len(ctx->params) > 2) return req_set_error(ctx->req, "too many arguments (only 2 alllowed)", IN3_EINVAL); abi_sig_t* req = abi_sig_create(sig, &error); if (!error) res = abi_decode(req, data, &error); if (req) abi_sig_free(req); - if (error) return ctx_set_error(ctx->ctx, error, IN3_EINVAL); + if (error) return req_set_error(ctx->req, error, IN3_EINVAL); char* result = d_create_json(res, res->result); in3_rpc_handle_with_string(ctx, result); _free(result); @@ -96,14 +96,14 @@ static in3_ret_t in3_abiDecode(in3_rpc_handle_ctx_t* ctx, d_token_t* params) { return IN3_OK; } -static in3_ret_t in3_checkSumAddress(in3_rpc_handle_ctx_t* ctx, d_token_t* params) { - CHECK_PARAM_ADDRESS(ctx->ctx, params, 0) - if (d_len(params) > 2) return ctx_set_error(ctx->ctx, "must be max 2 arguments", IN3_EINVAL); +static in3_ret_t in3_checkSumAddress(in3_rpc_handle_ctx_t* ctx) { + CHECK_PARAM_ADDRESS(ctx->req, ctx->params, 0) + if (d_len(ctx->params) > 2) return req_set_error(ctx->req, "must be max 2 arguments", IN3_EINVAL); char result[45]; - bytes_t* adr = d_get_bytes_at(params, 0); - if (!adr || adr->len != 20) return ctx_set_error(ctx->ctx, "the address must have 20 bytes", IN3_EINVAL); - in3_ret_t res = to_checksum(adr->data, d_get_int_at(params, 1) ? ctx->ctx->client->chain.chain_id : 0, result + 1); - if (res) return ctx_set_error(ctx->ctx, "Could not create the checksum address", res); + bytes_t* adr = d_get_bytes_at(ctx->params, 0); + if (!adr || adr->len != 20) return req_set_error(ctx->req, "the address must have 20 bytes", IN3_EINVAL); + in3_ret_t res = to_checksum(adr->data, d_get_int_at(ctx->params, 1) ? ctx->req->client->chain.chain_id : 0, result + 1); + if (res) return req_set_error(ctx->req, "Could not create the checksum address", res); result[0] = '\''; result[43] = '\''; result[44] = 0; @@ -111,17 +111,17 @@ static in3_ret_t in3_checkSumAddress(in3_rpc_handle_ctx_t* ctx, d_token_t* param return in3_rpc_handle_with_string(ctx, result); } -static in3_ret_t in3_ens(in3_rpc_handle_ctx_t* ctx, d_token_t* params) { - char* name = d_get_string_at(params, 0); - char* type = d_get_string_at(params, 1); - bytes_t registry = d_to_bytes(d_get_at(params, 2)); +static in3_ret_t in3_ens(in3_rpc_handle_ctx_t* ctx) { + char* name = d_get_string_at(ctx->params, 0); + char* type = d_get_string_at(ctx->params, 1); + bytes_t registry = d_to_bytes(d_get_at(ctx->params, 2)); int res_len = 20; in3_ens_type ens_type = ENS_ADDR; bytes32_t result; // verify input if (!type) type = "addr"; - if (!name || !strchr(name, '.')) return ctx_set_error(ctx->ctx, "the first param msut be a valid domain name", IN3_EINVAL); + if (!name || !strchr(name, '.')) return req_set_error(ctx->req, "the first param msut be a valid domain name", IN3_EINVAL); if (strcmp(type, "addr") == 0) ens_type = ENS_ADDR; else if (strcmp(type, "resolver") == 0) @@ -131,18 +131,28 @@ static in3_ret_t in3_ens(in3_rpc_handle_ctx_t* ctx, d_token_t* params) { else if (strcmp(type, "hash") == 0) ens_type = ENS_HASH; else - return ctx_set_error(ctx->ctx, "currently only 'hash','addr','owner' or 'resolver' are allowed as type", IN3_EINVAL); - if (registry.data && registry.len != 20) return ctx_set_error(ctx->ctx, "the registry must be a 20 bytes address", IN3_EINVAL); + return req_set_error(ctx->req, "currently only 'hash','addr','owner' or 'resolver' are allowed as type", IN3_EINVAL); + if (registry.data && registry.len != 20) return req_set_error(ctx->req, "the registry must be a 20 bytes address", IN3_EINVAL); - TRY(ens_resolve(ctx->ctx, name, registry.data, ens_type, result, &res_len)) + TRY(ens_resolve(ctx->req, name, registry.data, ens_type, result, &res_len)) return in3_rpc_handle_with_bytes(ctx, bytes(result, res_len)); } -static in3_ret_t in3_sha3(in3_rpc_handle_ctx_t* ctx, d_token_t* params) { - if (!params || d_len(params) != 1) return ctx_set_error(ctx->ctx, "no data", IN3_EINVAL); +static in3_ret_t in3_sha3(in3_rpc_handle_ctx_t* ctx) { + if (!ctx->params || d_len(ctx->params) != 1) return req_set_error(ctx->req, "no data", IN3_EINVAL); bytes32_t hash; - keccak(d_to_bytes(params + 1), hash); + keccak(d_to_bytes(ctx->params + 1), hash); + return in3_rpc_handle_with_bytes(ctx, bytes(hash, 32)); +} +static in3_ret_t in3_sha256(in3_rpc_handle_ctx_t* ctx) { + if (!ctx->params || d_len(ctx->params) != 1) return req_set_error(ctx->req, "no data", IN3_EINVAL); + bytes32_t hash; + bytes_t data = d_to_bytes(ctx->params + 1); + SHA256_CTX c; + sha256_Init(&c); + sha256_Update(&c, data.data, data.len); + sha256_Final(&c, hash); return in3_rpc_handle_with_bytes(ctx, bytes(hash, 32)); } static const char* UNITS[] = { @@ -247,37 +257,37 @@ int string_val_to_bytes(char* val, char* unit, bytes32_t target) { #endif } -static in3_ret_t in3_toWei(in3_rpc_handle_ctx_t* ctx, d_token_t* params) { - if (!params || d_len(params) != 2 || d_type(params + 2) != T_STRING) return ctx_set_error(ctx->ctx, "must have 2 params as strings", IN3_EINVAL); - char* val = d_get_string_at(params, 0); +static in3_ret_t in3_toWei(in3_rpc_handle_ctx_t* ctx) { + if (!ctx->params || d_len(ctx->params) != 2 || d_type(ctx->params + 2) != T_STRING) return req_set_error(ctx->req, "must have 2 params as strings", IN3_EINVAL); + char* val = d_get_string_at(ctx->params, 0); if (!val) { - if (d_type(params + 1) == T_INTEGER) { + if (d_type(ctx->params + 1) == T_INTEGER) { val = alloca(20); - sprintf(val, "%i", d_int(params + 1)); + sprintf(val, "%i", d_int(ctx->params + 1)); } else - return ctx_set_error(ctx->ctx, "the value must be a string", IN3_EINVAL); + return req_set_error(ctx->req, "the value must be a string", IN3_EINVAL); } bytes32_t tmp; - int s = string_val_to_bytes(val, d_get_string_at(params, 1), tmp); + int s = string_val_to_bytes(val, d_get_string_at(ctx->params, 1), tmp); return s < 0 - ? ctx_set_error(ctx->ctx, "invalid number string", IN3_EINVAL) + ? req_set_error(ctx->req, "invalid number string", IN3_EINVAL) : in3_rpc_handle_with_bytes(ctx, bytes(tmp, (uint32_t) s)); } -static in3_ret_t in3_config(in3_rpc_handle_ctx_t* ctx, d_token_t* params) { - if (!params || d_len(params) != 1 || d_type(params + 1) != T_OBJECT) return ctx_set_error(ctx->ctx, "no valid config-object as argument", IN3_EINVAL); +static in3_ret_t in3_config(in3_rpc_handle_ctx_t* ctx) { + if (!ctx->params || d_len(ctx->params) != 1 || d_type(ctx->params + 1) != T_OBJECT) return req_set_error(ctx->req, "no valid config-object as argument", IN3_EINVAL); - ctx->ctx->client->pending--; // we need to to temporarly decrees it in order to allow configuring - str_range_t r = d_to_json(params + 1); + ctx->req->client->pending--; // we need to to temporarly decrees it in order to allow configuring + str_range_t r = d_to_json(ctx->params + 1); char old = r.data[r.len]; r.data[r.len] = 0; - char* ret = in3_configure(ctx->ctx->client, r.data); + char* ret = in3_configure(ctx->req->client, r.data); r.data[r.len] = old; - ctx->ctx->client->pending++; + ctx->req->client->pending++; if (ret) { - ctx_set_error(ctx->ctx, ret, IN3_ECONFIG); + req_set_error(ctx->req, ret, IN3_ECONFIG); free(ret); return IN3_ECONFIG; } @@ -286,20 +296,20 @@ static in3_ret_t in3_config(in3_rpc_handle_ctx_t* ctx, d_token_t* params) { } static in3_ret_t in3_getConfig(in3_rpc_handle_ctx_t* ctx) { - char* ret = in3_get_config(ctx->ctx->client); + char* ret = in3_get_config(ctx->req->client); in3_rpc_handle_with_string(ctx, ret); _free(ret); return IN3_OK; } -static in3_ret_t in3_pk2address(in3_rpc_handle_ctx_t* ctx, d_token_t* params) { - bytes_t* pk = d_get_bytes_at(params, 0); - if (!pk || pk->len != 32 || d_len(params) != 1) return ctx_set_error(ctx->ctx, "Invalid private key! must be 32 bytes long", IN3_EINVAL); +static in3_ret_t in3_pk2address(in3_rpc_handle_ctx_t* ctx) { + bytes_t* pk = d_get_bytes_at(ctx->params, 0); + if (!pk || pk->len != 32 || d_len(ctx->params) != 1) return req_set_error(ctx->req, "Invalid private key! must be 32 bytes long", IN3_EINVAL); uint8_t public_key[65], sdata[32]; ecdsa_get_public_key65(&secp256k1, pk->data, public_key); - if (strcmp(d_get_stringk(ctx->ctx->requests[0], K_METHOD), "in3_pk2address") == 0) { + if (strcmp(ctx->method, "in3_pk2address") == 0) { keccak(bytes(public_key + 1, 64), sdata); return in3_rpc_handle_with_bytes(ctx, bytes(sdata + 12, 20)); } @@ -307,13 +317,13 @@ static in3_ret_t in3_pk2address(in3_rpc_handle_ctx_t* ctx, d_token_t* params) { return in3_rpc_handle_with_bytes(ctx, bytes(public_key + 1, 64)); } -static in3_ret_t in3_ecrecover(in3_rpc_handle_ctx_t* ctx, d_token_t* params) { - bytes_t msg = d_to_bytes(d_get_at(params, 0)); - bytes_t* sig = d_get_bytes_at(params, 1); - char* sig_type = d_get_string_at(params, 2); +static in3_ret_t in3_ecrecover(in3_rpc_handle_ctx_t* ctx) { + bytes_t msg = d_to_bytes(d_get_at(ctx->params, 0)); + bytes_t* sig = d_get_bytes_at(ctx->params, 1); + char* sig_type = d_get_string_at(ctx->params, 2); if (!sig_type) sig_type = "raw"; - if (!sig || sig->len != 65) return ctx_set_error(ctx->ctx, "Invalid signature! must be 65 bytes long", IN3_EINVAL); - if (!msg.data) return ctx_set_error(ctx->ctx, "Missing message", IN3_EINVAL); + if (!sig || sig->len != 65) return req_set_error(ctx->req, "Invalid signature! must be 65 bytes long", IN3_EINVAL); + if (!msg.data) return req_set_error(ctx->req, "Missing message", IN3_EINVAL); bytes32_t hash; uint8_t pub[65]; @@ -326,14 +336,14 @@ static in3_ret_t in3_ecrecover(in3_rpc_handle_ctx_t* ctx, d_token_t* params) { msg.len += l; } if (strcmp(sig_type, "hash") == 0) { - if (msg.len != 32) return ctx_set_error(ctx->ctx, "The message hash must be 32 byte", IN3_EINVAL); + if (msg.len != 32) return req_set_error(ctx->req, "The message hash must be 32 byte", IN3_EINVAL); memcpy(hash, msg.data, 32); } else keccak(msg, hash); if (ecdsa_recover_pub_from_sig(&secp256k1, pub, sig->data, hash, sig->data[64] >= 27 ? sig->data[64] - 27 : sig->data[64])) - return ctx_set_error(ctx->ctx, "Invalid Signature", IN3_EINVAL); + return req_set_error(ctx->req, "Invalid Signature", IN3_EINVAL); sb_t* sb = in3_rpc_handle_start(ctx); @@ -348,14 +358,14 @@ static in3_ret_t in3_ecrecover(in3_rpc_handle_ctx_t* ctx, d_token_t* params) { return in3_rpc_handle_finish(ctx); } -static in3_ret_t in3_sign_data(in3_rpc_handle_ctx_t* ctx, d_token_t* params) { - bytes_t data = d_to_bytes(d_get_at(params, 0)); - const bytes_t* pk = d_get_bytes_at(params, 1); - char* sig_type = d_get_string_at(params, 2); +static in3_ret_t in3_sign_data(in3_rpc_handle_ctx_t* ctx) { + bytes_t data = d_to_bytes(d_get_at(ctx->params, 0)); + const bytes_t* pk = d_get_bytes_at(ctx->params, 1); + char* sig_type = d_get_string_at(ctx->params, 2); if (!sig_type) sig_type = "raw"; - // if (!pk) return ctx_set_error(ctx, "Invalid sprivate key! must be 32 bytes long", IN3_EINVAL); - if (!data.data) return ctx_set_error(ctx->ctx, "Missing message", IN3_EINVAL); + // if (!pk) return req_set_error(ctx, "Invalid sprivate key! must be 32 bytes long", IN3_EINVAL); + if (!data.data) return req_set_error(ctx->req, "Missing message", IN3_EINVAL); if (strcmp(sig_type, "eth_sign") == 0) { char* tmp = alloca(data.len + 30); @@ -367,13 +377,13 @@ static in3_ret_t in3_sign_data(in3_rpc_handle_ctx_t* ctx, d_token_t* params) { } in3_sign_ctx_t sc = {0}; - sc.ctx = ctx->ctx; + sc.req = ctx->req; sc.message = data; sc.account = pk ? *pk : bytes(NULL, 0); sc.type = strcmp(sig_type, "hash") == 0 ? SIGN_EC_RAW : SIGN_EC_HASH; - if ((sc.account.len == 20 || sc.account.len == 0) && in3_plugin_is_registered(ctx->ctx->client, PLGN_ACT_SIGN)) { - TRY(in3_plugin_execute_first(ctx->ctx, PLGN_ACT_SIGN, &sc)); + if ((sc.account.len == 20 || sc.account.len == 0) && in3_plugin_is_registered(ctx->req->client, PLGN_ACT_SIGN)) { + TRY(in3_plugin_execute_first(ctx->req, PLGN_ACT_SIGN, &sc)); } else if (sc.account.len == 32) { sc.signature = bytes(_malloc(65), 65); @@ -383,11 +393,11 @@ static in3_ret_t in3_sign_data(in3_rpc_handle_ctx_t* ctx, d_token_t* params) { ecdsa_sign(&secp256k1, HASHER_SHA3K, pk->data, data.data, data.len, sc.signature.data, sc.signature.data + 64, NULL); else { _free(sc.signature.data); - return ctx_set_error(ctx->ctx, "unsupported sigType", IN3_EINVAL); + return req_set_error(ctx->req, "unsupported sigType", IN3_EINVAL); } } else - return ctx_set_error(ctx->ctx, "Invalid private key! Must be either an address(20 byte) or an raw private key (32 byte)", IN3_EINVAL); + return req_set_error(ctx->req, "Invalid private key! Must be either an address(20 byte) or an raw private key (32 byte)", IN3_EINVAL); bytes_t sig_bytes = sc.signature; if (sc.signature.len == 65 && sc.signature.data[64] < 2) @@ -421,49 +431,49 @@ static in3_ret_t in3_sign_data(in3_rpc_handle_ctx_t* ctx, d_token_t* params) { } static in3_ret_t in3_cacheClear(in3_rpc_handle_ctx_t* ctx) { - TRY(in3_plugin_execute_first(ctx->ctx, PLGN_ACT_CACHE_CLEAR, NULL)); + TRY(in3_plugin_execute_first(ctx->req, PLGN_ACT_CACHE_CLEAR, NULL)); return in3_rpc_handle_with_string(ctx, "true"); } -static in3_ret_t in3_decryptKey(in3_rpc_handle_ctx_t* ctx, d_token_t* params) { - d_token_t* keyfile = d_get_at(params, 0); - bytes_t password_bytes = d_to_bytes(d_get_at(params, 1)); +static in3_ret_t in3_decryptKey(in3_rpc_handle_ctx_t* ctx) { + d_token_t* keyfile = d_get_at(ctx->params, 0); + bytes_t password_bytes = d_to_bytes(d_get_at(ctx->params, 1)); bytes32_t dst; - if (!password_bytes.data) return ctx_set_error(ctx->ctx, "you need to specify a passphrase", IN3_EINVAL); - if (!keyfile || d_type(keyfile) != T_OBJECT) return ctx_set_error(ctx->ctx, "no valid key given", IN3_EINVAL); + if (!password_bytes.data) return req_set_error(ctx->req, "you need to specify a passphrase", IN3_EINVAL); + if (!keyfile || d_type(keyfile) != T_OBJECT) return req_set_error(ctx->req, "no valid key given", IN3_EINVAL); char* passphrase = alloca(password_bytes.len + 1); memcpy(passphrase, password_bytes.data, password_bytes.len); passphrase[password_bytes.len] = 0; in3_ret_t res = decrypt_key(keyfile, passphrase, dst); - if (res) return ctx_set_error(ctx->ctx, "Invalid key", res); + if (res) return req_set_error(ctx->req, "Invalid key", res); return in3_rpc_handle_with_bytes(ctx, bytes(dst, 32)); } -static in3_ret_t in3_prepareTx(in3_rpc_handle_ctx_t* ctx, d_token_t* params) { - d_token_t* tx = d_get_at(params, 0); +static in3_ret_t in3_prepareTx(in3_rpc_handle_ctx_t* ctx) { + d_token_t* tx = d_get_at(ctx->params, 0); bytes_t dst = {0}; #if defined(ETH_BASIC) || defined(ETH_FULL) - TRY(eth_prepare_unsigned_tx(tx, ctx->ctx, &dst)) + TRY(eth_prepare_unsigned_tx(tx, ctx->req, &dst)) #else - if (params || tx || ctx) return ctx_set_error(ctx->ctx, "eth_basic is needed in order to use eth_prepareTx", IN3_EINVAL); + if (ctx->params || tx || ctx) return req_set_error(ctx->req, "eth_basic is needed in order to use eth_prepareTx", IN3_EINVAL); #endif in3_rpc_handle_with_bytes(ctx, dst); _free(dst.data); return IN3_OK; } -static in3_ret_t in3_signTx(in3_rpc_handle_ctx_t* ctx, d_token_t* params) { - bytes_t* data = d_get_bytes_at(params, 0); - bytes_t* from_b = d_get_bytes_at(params, 1); +static in3_ret_t in3_signTx(in3_rpc_handle_ctx_t* ctx) { + bytes_t* data = d_get_bytes_at(ctx->params, 0); + bytes_t* from_b = d_get_bytes_at(ctx->params, 1); address_t from; memset(from, 0, 20); if (from_b && from_b->data && from_b->len == 20) memcpy(from, from_b->data, 20); bytes_t dst = {0}; #if defined(ETH_BASIC) || defined(ETH_FULL) - TRY(eth_sign_raw_tx(*data, ctx->ctx, from, &dst)) + TRY(eth_sign_raw_tx(*data, ctx->req, from, &dst)) #else - if (data || ctx || from[0] || params) return ctx_set_error(ctx->ctx, "eth_basic is needed in order to use eth_prepareTx", IN3_EINVAL); + if (data || ctx || from[0] || ctx->params) return req_set_error(ctx->req, "eth_basic is needed in order to use eth_prepareTx", IN3_EINVAL); #endif in3_rpc_handle_with_bytes(ctx, dst); _free(dst.data); @@ -474,27 +484,26 @@ static in3_ret_t handle_intern(void* pdata, in3_plugin_act_t action, void* plugi UNUSED_VAR(pdata); UNUSED_VAR(action); - in3_rpc_handle_ctx_t* rpc_ctx = plugin_ctx; - char* method = d_get_stringk(rpc_ctx->request, K_METHOD); - d_token_t* params = d_get(rpc_ctx->request, K_PARAMS); - - TRY_RPC("in3_abiEncode", in3_abiEncode(rpc_ctx, params)) - TRY_RPC("in3_abiDecode", in3_abiDecode(rpc_ctx, params)) - TRY_RPC("in3_checksumAddress", in3_checkSumAddress(rpc_ctx, params)) - TRY_RPC("in3_ens", in3_ens(rpc_ctx, params)) - TRY_RPC("web3_sha3", in3_sha3(rpc_ctx, params)) - TRY_RPC("keccak", in3_sha3(rpc_ctx, params)) - TRY_RPC("in3_toWei", in3_toWei(rpc_ctx, params)) - TRY_RPC("in3_config", in3_config(rpc_ctx, params)) - TRY_RPC("in3_getConfig", in3_getConfig(rpc_ctx)) - TRY_RPC("in3_pk2address", in3_pk2address(rpc_ctx, params)) - TRY_RPC("in3_pk2public", in3_pk2address(rpc_ctx, params)) - TRY_RPC("in3_ecrecover", in3_ecrecover(rpc_ctx, params)) - TRY_RPC("in3_signData", in3_sign_data(rpc_ctx, params)) - TRY_RPC("in3_cacheClear", in3_cacheClear(rpc_ctx)) - TRY_RPC("in3_decryptKey", in3_decryptKey(rpc_ctx, params)) - TRY_RPC("in3_prepareTx", in3_prepareTx(rpc_ctx, params)) - TRY_RPC("in3_signTx", in3_signTx(rpc_ctx, params)) + in3_rpc_handle_ctx_t* ctx = plugin_ctx; + + TRY_RPC("in3_abiEncode", in3_abiEncode(ctx)) + TRY_RPC("in3_abiDecode", in3_abiDecode(ctx)) + TRY_RPC("in3_checksumAddress", in3_checkSumAddress(ctx)) + TRY_RPC("in3_ens", in3_ens(ctx)) + TRY_RPC("web3_sha3", in3_sha3(ctx)) + TRY_RPC("keccak", in3_sha3(ctx)) + TRY_RPC("sha256", in3_sha256(ctx)) + TRY_RPC("in3_toWei", in3_toWei(ctx)) + TRY_RPC("in3_config", in3_config(ctx)) + TRY_RPC("in3_getConfig", in3_getConfig(ctx)) + TRY_RPC("in3_pk2address", in3_pk2address(ctx)) + TRY_RPC("in3_pk2public", in3_pk2address(ctx)) + TRY_RPC("in3_ecrecover", in3_ecrecover(ctx)) + TRY_RPC("in3_signData", in3_sign_data(ctx)) + TRY_RPC("in3_cacheClear", in3_cacheClear(ctx)) + TRY_RPC("in3_decryptKey", in3_decryptKey(ctx)) + TRY_RPC("in3_prepareTx", in3_prepareTx(ctx)) + TRY_RPC("in3_signTx", in3_signTx(ctx)) return IN3_EIGNORE; } diff --git a/c/src/api/usn/usn_api.c b/c/src/api/usn/usn_api.c index 1c01a0ed4..6e16d4218 100644 --- a/c/src/api/usn/usn_api.c +++ b/c/src/api/usn/usn_api.c @@ -32,8 +32,8 @@ * with this program. If not, see . *******************************************************************************/ #include "usn_api.h" -#include "../../core/client/context.h" #include "../../core/client/keys.h" +#include "../../core/client/request.h" #include "../../core/util/debug.h" #include "../../core/util/mem.h" #include "../../verifier/eth1/nano/eth_nano.h" @@ -118,16 +118,16 @@ static in3_ret_t exec_eth_call(usn_device_conf_t* conf, char* fn_hash, bytes32_t sprintf(p, "\"},\"latest\"]"); // send the request - in3_ctx_t* ctx = in3_client_rpc_ctx(conf->c, "eth_call", op); + in3_req_t* ctx = in3_client_rpc_ctx(conf->c, "eth_call", op); // do we have a valid result? - in3_ret_t res = ctx_get_error(ctx, 0); + in3_ret_t res = req_get_error(ctx, 0); if (res != IN3_OK) { - ctx_free(ctx); + req_free(ctx); return res; } l = d_bytes_to(d_get(ctx->responses[0], K_RESULT), result, max); - ctx_free(ctx); + req_free(ctx); return l == max ? l : IN3_EINVALDT; } @@ -148,17 +148,17 @@ static in3_ret_t exec_eth_send(usn_device_conf_t* conf, bytes_t data, bytes32_t sprintf(p, "\"}]"); // send the request - in3_ctx_t* ctx = in3_client_rpc_ctx(conf->c, "eth_sendTransaction", op); + in3_req_t* ctx = in3_client_rpc_ctx(conf->c, "eth_sendTransaction", op); // do we have a valid result? - in3_ret_t res = ctx_get_error(ctx, 0); + in3_ret_t res = req_get_error(ctx, 0); if (res != IN3_OK) { - ctx_free(ctx); + req_free(ctx); return res; } int l = d_bytes_to(d_get(ctx->responses[0], K_RESULT), tx_hash, 32); - ctx_free(ctx); + req_free(ctx); return l; } @@ -166,13 +166,13 @@ static void verify_action_message(usn_device_conf_t* conf, d_token_t* msg, usn_m bytes32_t hash; address_t sender; char tmp[400], mhash[500]; - in3_ctx_t* ctx = NULL; - result->device = find_device(conf, d_get_stringk(msg, K_URL)); + in3_req_t* ctx = NULL; + result->device = find_device(conf, d_get_string(msg, K_URL)); rejectp_if(!result->device, "the device with this url does not exist"); // prepare message hash // the timestamp would run out space around 2106, so please make sure we update by then. ! - sprintf(tmp, "%s%u%s{}", result->device->url, d_get_intk(msg, K_TIMESTAMP), d_get_stringk(msg, K_ACTION)); + sprintf(tmp, "%s%u%s{}", result->device->url, d_get_int(msg, K_TIMESTAMP), d_get_string(msg, K_ACTION)); sprintf(mhash, "\031Ethereum Signed Message:\n%u%s", (int) strlen(tmp), tmp); bytes_t msg_data = {.data = (uint8_t*) mhash, .len = strlen(mhash)}; keccak(msg_data, hash); @@ -189,7 +189,7 @@ static void verify_action_message(usn_device_conf_t* conf, d_token_t* msg, usn_m b_free(signer); // look for a transaction hash - bytes_t* tx_hash = d_get_bytesk(msg, K_TRANSACTIONHASH); + bytes_t* tx_hash = d_get_bytes(msg, K_TRANSACTIONHASH); rejectp_if(tx_hash && tx_hash->len != 32, "incorrect transactionhash"); if (!tx_hash) { @@ -242,7 +242,7 @@ static void verify_action_message(usn_device_conf_t* conf, d_token_t* msg, usn_m rejectp_if(!event || d_type(event) != T_OBJECT, "the tx receipt or the event could not be found"); // extract the values - bytes_t* data = d_get_bytesk(event, K_DATA); + bytes_t* data = d_get_bytes(event, K_DATA); bytes_t* address = d_get_byteskl(event, K_ADDRESS, 20); bytes_t* device_id = d_bytesl(d_get_at(d_get(event, K_TOPICS), 2), 32); r.rented_from = bytes_to_long(data->data + 32, 32); @@ -260,7 +260,7 @@ static void verify_action_message(usn_device_conf_t* conf, d_token_t* msg, usn_m } // check if the time and sender is correct - uint64_t now = conf->now ? conf->now : d_get_longk(msg, K_TIMESTAMP); + uint64_t now = conf->now ? conf->now : d_get_long(msg, K_TIMESTAMP); rejectp_if(r.rented_from >= r.rented_until || r.rented_from > now || r.rented_until < now, "Invalid Time"); dbg_log("sender : 0x%02x%02x%02x%02x\n", sender[0], sender[1], sender[2], sender[3]); dbg_log("controller : 0x%02x%02x%02x%02x\n", r.controller[0], r.controller[1], r.controller[2], r.controller[3]); @@ -268,10 +268,10 @@ static void verify_action_message(usn_device_conf_t* conf, d_token_t* msg, usn_m } result->accepted = true; - strcpy(result->action, d_get_stringk(msg, K_ACTION)); // this is not nice to overwrite the original payload, but this way we don't need to free it. + strcpy(result->action, d_get_string(msg, K_ACTION)); // this is not nice to overwrite the original payload, but this way we don't need to free it. clean: - if (ctx) ctx_free(ctx); + if (ctx) req_free(ctx); } usn_msg_result_t usn_verify_message(usn_device_conf_t* conf, char* message) { @@ -285,8 +285,8 @@ usn_msg_result_t usn_verify_message(usn_device_conf_t* conf, char* message) { reject_if(!conf->chain_id, "chain_id missing in config"); // check message type - char* msgType = d_get_stringk(parsed->result, K_MSG_TYPE); - result.id = d_get_intk(parsed->result, K_ID); + char* msgType = d_get_string(parsed->result, K_MSG_TYPE); + result.id = d_get_int(parsed->result, K_ID); reject_if(!parsed->result || d_type(parsed->result) != T_OBJECT, "no message-object passed"); reject_if(!msgType || strlen(msgType) == 0, "the messageType is missing"); @@ -372,14 +372,14 @@ static int usn_add_booking(usn_device_t* device, address_t controller, uint64_t in3_ret_t usn_update_bookings(usn_device_conf_t* conf) { // first we get the current BlockNumber - in3_ctx_t* ctx = in3_client_rpc_ctx(conf->c, "eth_blockNumber", "[]"); - in3_ret_t res = ctx_get_error(ctx, 0); + in3_req_t* ctx = in3_client_rpc_ctx(conf->c, "eth_blockNumber", "[]"); + in3_ret_t res = req_get_error(ctx, 0); if (res != IN3_OK) { - ctx_free(ctx); + req_free(ctx); return res; } - uint64_t current_block = d_get_longk(ctx->responses[0], K_RESULT); - ctx_free(ctx); + uint64_t current_block = d_get_long(ctx->responses[0], K_RESULT); + req_free(ctx); if (conf->last_checked_block == current_block) return IN3_OK; if (!conf->last_checked_block) { @@ -444,8 +444,8 @@ in3_ret_t usn_update_bookings(usn_device_conf_t* conf) { ctx = in3_client_rpc_ctx(conf->c, "eth_getLogs", params); // do we have a valid result? - if ((res = ctx_get_error(ctx, 0))) { - ctx_free(ctx); + if ((res = req_get_error(ctx, 0))) { + req_free(ctx); return res; } @@ -454,16 +454,16 @@ in3_ret_t usn_update_bookings(usn_device_conf_t* conf) { d_token_t* topics = d_get(iter.token, K_TOPICS); bytes_t* t0 = d_bytesl(d_get_at(topics, 0), 32); usn_device_t* device = find_device_by_id(conf, d_to_bytes(d_get_at(topics, 2)).data); - bytes_t* data = d_get_bytesk(iter.token, K_DATA); + bytes_t* data = d_get_bytes(iter.token, K_DATA); if (t0->len != 32 || !device || !data) continue; usn_add_booking(device, data->data + 12, bytes_to_long(data->data + 32 + 24, 8), bytes_to_long(data->data + 64 + 24, 8), *(t0->data) == 0x63 ? NULL : data->data + 6 + 32 + 16, - d_get_bytesk(iter.token, K_TRANSACTION_HASH)->data); + d_get_bytes(iter.token, K_TRANSACTION_HASH)->data); } - ctx_free(ctx); + req_free(ctx); } // update the last_block diff --git a/c/src/api/utils/api_utils.c b/c/src/api/utils/api_utils.c index a7c495c60..3b1e1e85f 100644 --- a/c/src/api/utils/api_utils.c +++ b/c/src/api/utils/api_utils.c @@ -96,7 +96,7 @@ void api_set_error(int err, const char* msg) { return set_error_impl(err, msg ? msg : "unknown error"); } -d_token_t* get_result(in3_ctx_t* ctx) { +d_token_t* get_result(in3_req_t* ctx) { if (ctx->error) { // error means something went wrong during verification or a timeout occured. api_set_error(ETIMEDOUT, ctx->error); // so we copy the error as last_error return NULL; @@ -113,7 +113,7 @@ d_token_t* get_result(in3_ctx_t* ctx) { t = d_get(ctx->responses[0], K_ERROR); // we we have an error... api_set_error(ETIMEDOUT, !t ? "No result or error in response" - : (d_type(t) != T_OBJECT ? d_string(t) : d_get_stringk(t, K_MESSAGE))); + : (d_type(t) != T_OBJECT ? d_string(t) : d_get_string(t, K_MESSAGE))); return NULL; } diff --git a/c/src/api/utils/api_utils_priv.h b/c/src/api/utils/api_utils_priv.h index 7c0545272..e2c81df8d 100644 --- a/c/src/api/utils/api_utils_priv.h +++ b/c/src/api/utils/api_utils_priv.h @@ -35,8 +35,8 @@ #ifndef IN3_API_UTILS_PRIV_H #define IN3_API_UTILS_PRIV_H -#include "../../core/client/context.h" #include "../../core/client/keys.h" +#include "../../core/client/request.h" #include "../../core/util/data.h" #include "../../core/util/error.h" #include "../../core/util/log.h" @@ -61,14 +61,14 @@ // execute the request after the params have been set. #define rpc_exec(METHOD, RETURN_TYPE, HANDLE_RESULT) \ errno = 0; \ - in3_ctx_t* _ctx_ = in3_client_rpc_ctx(in3, (METHOD), sb_add_char(params, ']')->data); \ + in3_req_t* _ctx_ = in3_client_rpc_ctx(in3, (METHOD), sb_add_char(params, ']')->data); \ d_token_t* result = get_result(_ctx_); \ RETURN_TYPE _res_; \ if (result) \ _res_ = (HANDLE_RESULT); \ else \ memset(&_res_, 0, sizeof(RETURN_TYPE)); \ - ctx_free(_ctx_); \ + req_free(_ctx_); \ sb_free(params); \ return _res_; @@ -89,6 +89,6 @@ void api_set_error(int err, const char* msg); /** returns the result from a previously executed ctx */ -d_token_t* get_result(in3_ctx_t* ctx); +d_token_t* get_result(in3_req_t* req); #endif //IN3_API_UTILS_PRIV_H diff --git a/c/src/cmd/http-server/http_server.c b/c/src/cmd/http-server/http_server.c index 57d02d35e..9f17e89a4 100644 --- a/c/src/cmd/http-server/http_server.c +++ b/c/src/cmd/http-server/http_server.c @@ -33,7 +33,8 @@ *******************************************************************************/ #include "http_server.h" -#include "../../core/client/context.h" +#include "../../core/client/keys.h" +#include "../../core/client/request.h" #include "../../core/util/colors.h" #include "../../core/util/mem.h" #include @@ -48,14 +49,110 @@ #include #include -#define MAX_CON 100 +void term(int signum) { + printf("Finishing..!(caught signal %i)\n", signum); + exit(EXIT_SUCCESS); +} + +static int listenfd; +void* respond(void* arg); +typedef struct m { + char* method; + struct m* next; +} method_t; + +method_t* allowed_methods = NULL; +void set_allowed_methods(char* allowed) { + if (!allowed) return; + allowed = _strdupn(allowed, -1); + for (char* m = strtok(allowed, ","); m; m = strtok(NULL, ",")) { + method_t* method = _malloc(sizeof(method_t)); + method->method = m; + method->next = allowed_methods; + allowed_methods = method; + } +} + +static bool is_allowed(char* method) { + if (allowed_methods == NULL) return true; + for (method_t* m = allowed_methods; m; m = m->next) { + if (strcmp(m->method, method) == 0) return true; + } + return false; +} +typedef struct { + int con; + int s; + in3_t* in3; +} req_t; + +#ifdef THREADSAFE +#include + +#define POOL_SIZE 10 + +pthread_t thread_pool[POOL_SIZE]; +pthread_mutex_t queue_mutex = PTHREAD_MUTEX_INITIALIZER; +pthread_cond_t queue_cond = PTHREAD_COND_INITIALIZER; + +typedef struct queue { + struct queue* next; + req_t* r; +} queue_t; + +queue_t * q_head = NULL, *q_tail = NULL; +static void error_response(char* message, int error_code) { + char* payload = alloca(strlen(message) + 100); + sprintf(payload, "{\"id\":1,\"jsonrpc\":\"2.0\",\"error\":{\"message\":\"%s\",\"code\":%i}}", message, error_code); + printf("HTTP/1.1 200\r\nContent-Type: application/json; charset=utf-8\r\nContent-Length: %lu\r\n\r\n%s\r\n", strlen(payload), payload); +} +static void queue_add(req_t* r) { + pthread_mutex_lock(&queue_mutex); + queue_t* q = _malloc(sizeof(queue_t)); + q->next = NULL; + q->r = r; + if (q_tail) + q_tail->next = q; + else + q_head = q_tail = q; + pthread_cond_signal(&queue_cond); + pthread_mutex_unlock(&queue_mutex); +} -static int listenfd, clients[MAX_CON]; +static req_t* queue_next() { + pthread_mutex_lock(&queue_mutex); + if (!q_head) pthread_cond_wait(&queue_cond, &queue_mutex); + + req_t* r = NULL; + if (q_head) { + queue_t* q = q_head; + q_head = q_head->next; + r = q->r; + _free(q); + if (!q_head) q_tail = NULL; + } + pthread_mutex_unlock(&queue_mutex); + return r; +} +static void* thread_run(void* p) { + UNUSED_VAR(p); + while (true) { + req_t* r = queue_next(); + if (r) respond(r); + } + return NULL; +} + +#else +#define MAX_CON 100 +static int clients[MAX_CON]; +#endif //client connection -static void respond(int s, in3_t* in3) { - char* buf = malloc(65535); - int rcvd = recv(clients[s], buf, 65535, 0); +void* respond(void* arg) { + req_t* r = arg; + char* buf = malloc(65535); + int rcvd = recv(r->con, buf, 65535, 0); if (rcvd < 0) // receive error fprintf(stderr, ("recv() error\n")); @@ -70,25 +167,33 @@ static void respond(int s, in3_t* in3) { char* prot = uri ? strtok(NULL, " \t\r\n") : NULL; char* rest = prot ? strstr(prot + strlen(prot) + 1, "\n\r\n") : NULL; - dup2(clients[s], STDOUT_FILENO); - close(clients[s]); + dup2(r->con, STDOUT_FILENO); + // close(r->con); if (rest) { rest += 3; if (strlen(rest) > 2 && (rest[0] == '{' || rest[0] == '[')) { // execute in3 - in3_ctx_t* ctx = ctx_new(in3, rest); - if (ctx == NULL) - printf("HTTP/1.1 500 Not Handled\r\n\r\nInvalid request.\r\n"); - else if (ctx->error) - printf("HTTP/1.1 500 Not Handled\r\n\r\n%s\r\n", ctx->error); + in3_req_t* req = req_new(r->in3, rest); + if (req == NULL) + error_response("Request can not be parsed", -32700); + else if (req->error) + error_response(req->error, -32603); + else if (!is_allowed(d_get_string(req->requests[0], K_METHOD))) + error_response("Method not allowed", -32601); else { // execute it - fprintf(stderr, "RPC %s\n", d_get_string(ctx->request_context->result, "method")); //conceal typing and save position - if (in3_send_ctx(ctx) == IN3_OK) { + str_range_t range = d_to_json(d_get(req->requests[0], key("params"))); + char* params = range.data ? alloca(range.len) : NULL; + if (params) { + memcpy(params, range.data + 1, range.len - 2); + params[range.len - 2] = 0; + } + fprintf(stderr, "RPC %s %s\n", d_get_string(req->requests[0], K_METHOD), params); //conceal typing and save position + if (in3_send_req(req) == IN3_OK) { // the request was succesfull, so we delete interim errors (which can happen in case in3 had to retry) - if (ctx->error) _free(ctx->error); - ctx->error = NULL; - str_range_t range = d_to_json(ctx->responses[0]); + if (req->error) _free(req->error); + req->error = NULL; + str_range_t range = d_to_json(req->responses[0]); range.data[range.len] = 0; // remove in3 @@ -100,20 +205,20 @@ static void respond(int s, in3_t* in3) { range.len = strlen(range.data); printf("HTTP/1.1 200\r\nContent-Type: application/json; charset=utf-8\r\nContent-Length: %i\r\n\r\n%s\r\n", (int) range.len, range.data); } - else if (ctx->error) - printf("HTTP/1.1 500 Not Handled\r\n\r\n%s\r\n", ctx->error); + else if (req->error) + error_response(req->error, req->verification_state); else - printf("HTTP/1.1 500 Not Handled\r\n\r\nCould not execute\r\n"); + error_response("Could not execute the request", req->verification_state); } - if (ctx) - ctx_free(ctx); + if (req) + req_free(req); } else rest = NULL; } if (!rest) - printf("HTTP/1.1 500 Not Handled\r\n\r\nThe server has no handler to the request.\r\n"); + error_response("The server has no handler to the request", -32603); // tidy up fflush(stdout); @@ -122,21 +227,36 @@ static void respond(int s, in3_t* in3) { } //Closing SOCKET - shutdown(clients[s], SHUT_RDWR); //All further send and recieve operations are DISABLED... - close(clients[s]); - clients[s] = -1; + shutdown(r->con, SHUT_RDWR); //All further send and recieve operations are DISABLED... + close(r->con); +#ifdef THREADSAFE + _free(r); +#endif + return NULL; } -void http_run_server(const char* port, in3_t* in3) { +void http_run_server(const char* port, in3_t* in3, char* allowed_methods) { + struct sigaction action; + memset(&action, 0, sizeof(action)); + action.sa_handler = term; + sigaction(SIGTERM, &action, NULL); + sigaction(SIGKILL, &action, NULL); + sigaction(SIGINT, &action, NULL); + + set_allowed_methods(allowed_methods); struct sockaddr_in clientaddr; socklen_t addrlen; - int s = 0; printf( - "Server started %shttp://127.0.0.1:%s%s\n", - COLORT_LIGHTGREEN, port, COLORT_RESET); + "Server started %shttp://127.0.0.1:%s%s [%s]\n", + COLORT_LIGHTGREEN, port, COLORT_RESET, allowed_methods ? allowed_methods : "all methods"); +#ifdef THREADSAFE + for (int i = 0; i < POOL_SIZE; i++) pthread_create(&thread_pool[i], NULL, thread_run, NULL); +#else + int s = 0; for (int i = 0; i < MAX_CON; i++) clients[i] = -1; +#endif // start the serevr struct addrinfo hints, *res, *p; @@ -174,19 +294,35 @@ void http_run_server(const char* port, in3_t* in3) { // ACCEPT connections while (1) { - addrlen = sizeof(clientaddr); + addrlen = sizeof(clientaddr); + +#ifdef THREADSAFE + int con = accept(listenfd, (struct sockaddr*) &clientaddr, &addrlen); + if (con < 0) + perror("accept() error"); + else { + req_t* r = _malloc(sizeof(req_t)); + r->con = con; + r->s = 0; + r->in3 = in3; + queue_add(r); + } + +#else clients[s] = accept(listenfd, (struct sockaddr*) &clientaddr, &addrlen); if (clients[s] < 0) { perror("accept() error"); } else { + req_t r = {.con = clients[s], .s = s, .in3 = in3}; if (fork() == 0) { - respond(s, in3); + respond(&r); + clients[s] = -1; exit(0); } } - while (clients[s] != -1) s = (s + 1) % MAX_CON; +#endif } } diff --git a/c/src/cmd/http-server/http_server.h b/c/src/cmd/http-server/http_server.h index 33b0438e5..906ea9a0b 100644 --- a/c/src/cmd/http-server/http_server.h +++ b/c/src/cmd/http-server/http_server.h @@ -35,10 +35,10 @@ #ifndef _http_server_h___ #define _http_server_h___ -#include "../../core/client/context.h" +#include "../../core/client/request.h" #include #include -void http_run_server(const char* port, in3_t* in3); +void http_run_server(const char* port, in3_t* in3, char* allowed_methods); #endif diff --git a/c/src/cmd/in3/main.c b/c/src/cmd/in3/main.c index c6ad97349..ea0784ce8 100644 --- a/c/src/cmd/in3/main.c +++ b/c/src/cmd/in3/main.c @@ -60,8 +60,8 @@ #include "../../core/client/plugin.h" #include "../../core/client/version.h" #include "../../core/util/colors.h" -#include "../../nodeselect/cache.h" -#include "../../nodeselect/nodelist.h" +#include "../../nodeselect/full/cache.h" +#include "../../nodeselect/full/nodelist.h" #if defined(LEDGER_NANO) #include "../../signer/ledger-nano/signer/ethereum_apdu_client.h" @@ -69,12 +69,12 @@ #include "../../signer/ledger-nano/signer/ledger_signer.h" #endif -#include "../../nodeselect/nodeselect_def.h" +#include "../../init/in3_init.h" +#include "../../nodeselect/full/nodeselect_def.h" #include "../../signer/multisig/multisig.h" #include "../../signer/pk-signer/signer.h" #include "../../tools/recorder/recorder.h" #include "../../verifier/eth1/nano/chainspec.h" -#include "../../verifier/in3_init.h" #include "in3_storage.h" #include #include @@ -103,6 +103,7 @@ void show_help(char* name) { -s, -signs number of signatures to use when verifying.\n\ -f finality : number of blocks on top of the current one.\n\ -port if specified it will run as http-server listening to the given port.\n\ +-am only works if port is specified and declares a comma-seperated list of rpc-methods which are allowed. All other will be rejected.\n\ -b, -block the blocknumber to use when making calls. could be either latest (default),earliest or a hexnumbner\n\ -to the target address of the call\n\ -d, -data the data for a transaction. This can be a filepath, a 0x-hexvalue or - for stdin.\n\ @@ -139,7 +140,10 @@ void show_help(char* name) { -zc2 zksync create2 arguments in the form ::. if set the account type is also changed to create2\n\ -zms public keys of a musig schnorr signatures to sign with\n\ -zmu url for signing service matching the first remote public key\n\ +-zvpm method for calling to verify the proof\n\ +-zcpm method for calling to create the proof\n\ -os only sign, don't send the raw Transaction \n\ +-x support experimental features \n\ -version displays the version \n\ -help displays this help message \n\ \n\ @@ -196,11 +200,33 @@ in3_ens \n\ \n", name); } - _Noreturn static void die(char* msg) { recorder_print(1, COLORT_RED "Error: %s" COLORT_RESET "\n", msg); recorder_exit(EXIT_FAILURE); } +static void _configure(in3_t* c, char* k, const char* p, char* val) { + char* pattern = alloca(strlen(val) + strlen(k) + strlen(p) + 8); + char* data = alloca(strlen(val) + strlen(k) + 8); + sprintf(pattern, "{\"%s\": %s}", "%s", p); + sprintf(data, pattern, k, val); + char* e = in3_configure(c, data); + if (e) { + char* tmp = alloca(strlen(data) + strlen(e) + 60); + sprintf(tmp, "Error configuring the client with config (%s): %s", data, e); + die(tmp); + } +} +static void _configure2(in3_t* c, char* k1, char* k2, const char* p, char* val) { + char* pattern = alloca(strlen(val) + strlen(k1) + strlen(k2) + 16); + char* data = alloca(strlen(val) + strlen(k1) + strlen(k2) + 16); + sprintf(pattern, "{\"%s\":{\"%s\" : %s}}", "%s", "%s", p); + sprintf(data, pattern, k1, k2, val); + char* e = in3_configure(c, data); + if (e) die(e); +} + +#define configure(s, p) _configure(c, s, "\"%s\"", p) +#define configure_2(s1, s2, p) _configure2(c, s1, s2, "\"%s\"", p) static bool debug_mode = false; static void print_hex(uint8_t* data, int len) { @@ -268,12 +294,12 @@ static void execute(in3_t* c, FILE* f) { if (d == stop) level--; if (level == 0) { // time to execute - in3_ctx_t* ctx = ctx_new(c, sb->data); + in3_req_t* ctx = req_new(c, sb->data); if (ctx->error) recorder_print(0, "{\"jsonrpc\":\"2.0\",\"id\":%i,\"error\":{\"code\":%i,\"message\":\"%s\"}\n", 1, ctx->verification_state, ctx->error); else { - in3_ret_t ret = in3_send_ctx(ctx); - uint32_t id = d_get_intk(ctx->requests[0], K_ID); + in3_ret_t ret = in3_send_req(ctx); + uint32_t id = d_get_int(ctx->requests[0], K_ID); if (ctx->error) { for (char* x = ctx->error; *x; x++) { if (*x == '\n') *x = ' '; @@ -300,7 +326,7 @@ static void execute(in3_t* c, FILE* f) { else recorder_print(0, "{\"jsonrpc\":\"2.0\",\"id\":%i,\"error\":{\"code\":%i,\"message\":\"%s\"}}\n", id, ctx->verification_state, ctx->error == NULL ? "Unknown error" : ctx->error); } - ctx_free(ctx); + req_free(ctx); first = 0; sb->len = 0; } @@ -389,15 +415,12 @@ void set_chain_id(in3_t* c, char* id) { c->chain.chain_id = strstr(id, "://") ? CHAIN_ID_LOCAL : getchain_id(id); if (c->chain.chain_id == CHAIN_ID_LOCAL) { sb_t* sb = sb_new("{\"autoUpdateList\":false,\"proof\":\"none\""); - if (strstr(id, "://")) { // its a url - sb_add_chars(sb, ",\"nodeRegistry\":{\"needsUpdate\":false,\"nodeList\":["); - sb_add_chars(sb, "{\"address\":\"0x0000000000000000000000000000000000000000\""); - sb_add_chars(sb, ",\"url\":\""); - sb_add_chars(sb, id); - sb_add_chars(sb, "\",\"props\":\"0xffff\"}"); - sb_add_chars(sb, "]}}"); - } - sb_add_chars(sb, "}"); + sb_add_chars(sb, ",\"nodeRegistry\":{\"needsUpdate\":false,\"nodeList\":["); + sb_add_chars(sb, "{\"address\":\"0x0000000000000000000000000000000000000000\""); + sb_add_chars(sb, ",\"url\":\""); + sb_add_chars(sb, strstr(id, "://") ? id : "http://localhost:8545"); + sb_add_chars(sb, "\",\"props\":\"0xffff\"}"); + sb_add_chars(sb, "]}}}"); char* err = in3_configure(c, sb->data); if (err) die(err); @@ -533,9 +556,9 @@ void read_pk(char* pk_file, char* pwd, in3_t* c, char* method) { eth_set_pk_signer(c, pk_seed); } } - +#ifdef NODESELECT_DEF static void set_nodelist(in3_t* c, char* nodes, bool update) { - if (!update) c->flags = FLAGS_STATS | FLAGS_BOOT_WEIGHTS; + if (!update) c->flags = FLAGS_STATS | FLAGS_BOOT_WEIGHTS | (c->flags & FLAGS_ALLOW_EXPERIMENTAL); char* cpy = alloca(strlen(nodes) + 1); in3_nodeselect_def_t* nl = in3_nodeselect_def_data(c); if (!update && nl->nodelist_upd8_params) { @@ -544,7 +567,7 @@ static void set_nodelist(in3_t* c, char* nodes, bool update) { } memcpy(cpy, nodes, strlen(nodes) + 1); char* s = NULL; - sb_t* sb = sb_new("{\"nodeRegistry\":{\"nodeList\":["); + sb_t* sb = sb_new("{\"nodeRegistry\":{\"needsUpdate\":false,\"nodeList\":["); for (char* next = strtok(cpy, ","); next; next = strtok(NULL, ",")) { if (next != cpy) sb_add_char(sb, ','); str_range_t address, url; @@ -569,14 +592,14 @@ static void set_nodelist(in3_t* c, char* nodes, bool update) { die(err); sb_free(sb); } - +#endif static bytes_t* last_response; static bytes_t in_response = {.data = NULL, .len = 0}; static bool only_show_raw_tx = false; static in3_ret_t debug_transport(void* plugin_data, in3_plugin_act_t action, void* plugin_ctx) { UNUSED_VAR(plugin_data); - in3_request_t* req = plugin_ctx; + in3_http_request_t* req = plugin_ctx; if (action == PLGN_ACT_TRANSPORT_SEND) { #ifndef DEBUG if (debug_mode) @@ -584,9 +607,9 @@ static in3_ret_t debug_transport(void* plugin_data, in3_plugin_act_t action, voi #endif if (in_response.len) { for (unsigned int i = 0; i < req->urls_len; i++) { - req->ctx->raw_response[i].state = IN3_OK; - sb_add_range(&req->ctx->raw_response[i].data, (char*) in_response.data, 0, in_response.len); - req->ctx->raw_response[i].state = IN3_OK; + req->req->raw_response[i].state = IN3_OK; + sb_add_range(&req->req->raw_response[i].data, (char*) in_response.data, 0, in_response.len); + req->req->raw_response[i].state = IN3_OK; } return 0; } @@ -607,13 +630,13 @@ static in3_ret_t debug_transport(void* plugin_data, in3_plugin_act_t action, voi in3_ret_t r = plugin_ctx != NULL ? IN3_OK : IN3_ECONFIG; #endif if (action != PLGN_ACT_TRANSPORT_CLEAN) { - last_response = b_new((uint8_t*) req->ctx->raw_response[0].data.data, req->ctx->raw_response[0].data.len); + last_response = b_new((uint8_t*) req->req->raw_response[0].data.data, req->req->raw_response[0].data.len); #ifndef DEBUG if (debug_mode) { - if (req->ctx->raw_response[0].state == IN3_OK) - fprintf(stderr, "success response \n" COLORT_RGREEN "%s" COLORT_RESET "\n", req->ctx->raw_response[0].data.data); + if (req->req->raw_response[0].state == IN3_OK) + fprintf(stderr, "success response \n" COLORT_RGREEN "%s" COLORT_RESET "\n", req->req->raw_response[0].data.data); else - fprintf(stderr, "error response \n" COLORT_RRED "%s" COLORT_RESET "\n", req->ctx->raw_response[0].data.data); + fprintf(stderr, "error response \n" COLORT_RRED "%s" COLORT_RESET "\n", req->req->raw_response[0].data.data); } #endif } @@ -622,7 +645,7 @@ static in3_ret_t debug_transport(void* plugin_data, in3_plugin_act_t action, voi static char* test_name = NULL; static in3_ret_t test_transport(void* plugin_data, in3_plugin_act_t action, void* plugin_ctx) { UNUSED_VAR(plugin_data); - in3_request_t* req = plugin_ctx; + in3_http_request_t* req = plugin_ctx; #ifdef USE_CURL in3_ret_t r = send_curl(NULL, action, plugin_ctx); #elif USE_WINHTTP @@ -634,7 +657,7 @@ static in3_ret_t test_transport(void* plugin_data, in3_plugin_act_t action, void #endif if (r == IN3_OK) { req->payload[strlen(req->payload) - 1] = 0; - recorder_print(0, "[{ \"descr\": \"%s\",\"chainId\": \"0x1\", \"verification\": \"proof\",\"binaryFormat\": false, \"request\": %s, \"response\": %s }]", test_name, req->payload + 1, req->ctx->raw_response->data.data); + recorder_print(0, "[{ \"descr\": \"%s\",\"chainId\": \"0x1\", \"verification\": \"proof\",\"binaryFormat\": false, \"request\": %s, \"response\": %s }]", test_name, req->payload + 1, req->req->raw_response->data.data); recorder_exit(0); } @@ -676,10 +699,9 @@ int main(int argc, char* argv[]) { } // define vars - char* method = NULL; - sb_t* args = sb_new("["); - int i; - bytes32_t pk; + char* method = NULL; + sb_t* args = sb_new("["); + int i; #ifdef LEDGER_NANO uint8_t path[5]; #endif @@ -688,8 +710,7 @@ int main(int argc, char* argv[]) { in3_log_set_level(LOG_INFO); // create the client - in3_t* c = in3_for_chain(CHAIN_ID_MAINNET); - c->request_count = 2; + in3_t* c = in3_for_chain(CHAIN_ID_MAINNET); bool out_response = false; int run_test_request = 0; bool force_hex = false; @@ -700,6 +721,7 @@ int main(int argc, char* argv[]) { abi_sig_t* req = NULL; bool json = false; char* ms_sigs = NULL; + char* allowed_methods = NULL; uint64_t gas_limit = 100000; uint64_t gas_price = 0; char* value = NULL; @@ -711,12 +733,18 @@ int main(int argc, char* argv[]) { char* port = NULL; char* sig_type = "raw"; bool to_eth = false; + char* rc = "2"; in3_plugin_register(c, PLGN_ACT_TRANSPORT, debug_transport, NULL, true); #ifndef USE_WINHTTP - c->request_count = 1; + rc = "1"; +#endif + +#ifdef NODESELECT_DEF + _configure(c, "requestCount", "%s", rc); #endif + // handle clear cache opt before initializing cache for (i = 1; i < argc; i++) { if (strcmp(argv[i], "-fi") == 0) { @@ -736,17 +764,16 @@ int main(int argc, char* argv[]) { // check env if (getenv("IN3_PK") && !use_pk) { - hex_to_bytes(getenv("IN3_PK"), -1, pk, 32); - eth_set_pk_signer(c, pk); + char* pks = _strdupn(getenv("IN3_PK"), -1); + bytes32_t pk; + for (char* cc = strtok(pks, ","); cc; cc = strtok(NULL, ",")) { + hex_to_bytes(cc, -1, pk, 32); + eth_set_pk_signer(c, pk); + } } #ifdef ZKSYNC - if (getenv("IN3_ZKS")) { - char tmp[500]; - sprintf(tmp, "{\"zksync\":{\"provider_url\":\"%s\"}}", getenv("IN3_ZKS")); - char* err = in3_configure(c, tmp); - if (err) die(err); - } + if (getenv("IN3_ZKS")) configure_2("zksync", "provider_url", getenv("IN3_ZKS")); #endif if (getenv("IN3_CHAIN")) @@ -756,8 +783,8 @@ int main(int argc, char* argv[]) { for (i = 1; i < argc; i++) { if (strcmp(argv[i], "-pk") == 0) { // private key? if (argv[i + 1][0] == '0' && argv[i + 1][1] == 'x') { + bytes32_t pk; hex_to_bytes(argv[++i], -1, pk, 32); - eth_set_pk_signer(c, pk); } else @@ -795,42 +822,22 @@ int main(int argc, char* argv[]) { else if (strcmp(argv[i], "-latest") == 0 || strcmp(argv[i], "-l") == 0) c->replace_latest_block = atoll(argv[++i]); #ifdef ZKSYNC - else if (strcmp(argv[i], "-zks") == 0) { - char tmp[500]; - sprintf(tmp, "{\"zksync\":{\"provider_url\":\"%s\"}}", argv[++i]); - char* err = in3_configure(c, tmp); - if (err) die(err); - } - else if (strcmp(argv[i], "-zka") == 0) { - char tmp[500]; - sprintf(tmp, "{\"zksync\":{\"account\":\"%s\"}}", argv[++i]); - char* err = in3_configure(c, tmp); - if (err) die(err); - } - else if (strcmp(argv[i], "-zkat") == 0) { - char tmp[500]; - sprintf(tmp, "{\"zksync\":{\"signer_type\":\"%s\"}}", argv[++i]); - char* err = in3_configure(c, tmp); - if (err) die(err); - } - else if (strcmp(argv[i], "-zms") == 0) { - char tmp[1000]; - sprintf(tmp, "{\"zksync\":{\"musig_pub_keys\":\"%s\"}}", argv[++i]); - char* err = in3_configure(c, tmp); - if (err) die(err); - } - else if (strcmp(argv[i], "-zmu") == 0) { - char tmp[1000]; - sprintf(tmp, "{\"zksync\":{\"musig_urls\":[null,\"%s\"]}}", argv[++i]); - char* err = in3_configure(c, tmp); - if (err) die(err); - } - else if (strcmp(argv[i], "-zsk") == 0) { - char tmp[500]; - sprintf(tmp, "{\"zksync\":{\"sync_key\":\"%s\"}}", argv[++i]); - char* err = in3_configure(c, tmp); - if (err) die(err); - } + else if (strcmp(argv[i], "-zks") == 0) + configure_2("zksync", "provider_url", argv[++i]); + else if (strcmp(argv[i], "-zka") == 0) + configure_2("zksync", "account", argv[++i]); + else if (strcmp(argv[i], "-zcpm") == 0) + configure_2("zksync", "create_proof_method", argv[++i]); + else if (strcmp(argv[i], "-zvpm") == 0) + configure_2("zksync", "verify_proof_method", argv[++i]); + else if (strcmp(argv[i], "-zkat") == 0) + configure_2("zksync", "signer_type", argv[++i]); + else if (strcmp(argv[i], "-zms") == 0) + configure_2("zksync", "musig_pub_keys", argv[++i]); + else if (strcmp(argv[i], "-zmu") == 0) + _configure2(c, "zksync", "musig_urls", "[null,\"%s\"]", argv[++i]); + else if (strcmp(argv[i], "-zsk") == 0) + configure_2("zksync", "sync_key", argv[++i]); else if (strcmp(argv[i], "-zc2") == 0) { char* c2val = argv[++i]; if (strlen(c2val) != 176) die("create2-arguments must have the form -zc2 ::"); @@ -846,14 +853,18 @@ int main(int argc, char* argv[]) { run_test_request = 1; else if (strcmp(argv[i], "-thr") == 0) run_test_request = 2; + else if (strcmp(argv[i], "-x") == 0) + c->flags |= FLAGS_ALLOW_EXPERIMENTAL; else if (strcmp(argv[i], "-fo") == 0) recorder_write_start(c, argv[++i], argc, argv); else if (strcmp(argv[i], "-fi") == 0) recorder_read_start(c, argv[++i]); +#ifdef NODESELECT_DEF else if (strcmp(argv[i], "-nl") == 0) set_nodelist(c, argv[++i], false); else if (strcmp(argv[i], "-bn") == 0) set_nodelist(c, argv[++i], true); +#endif else if (strcmp(argv[i], "-mss") == 0 || strcmp(argv[i], "-sigs") == 0) ms_sigs = argv[++i]; else if (strcmp(argv[i], "-ms") == 0) { @@ -868,7 +879,7 @@ int main(int argc, char* argv[]) { else if (strcmp(argv[i], "-eth") == 0) to_eth = true; else if (strcmp(argv[i], "-md") == 0) - c->min_deposit = atoll(argv[++i]); + _configure(c, "minDeposit", "%s", argv[++i]); else if (strcmp(argv[i], "-kin3") == 0) c->flags |= FLAGS_KEEP_IN3; else if (strcmp(argv[i], "-bw") == 0) @@ -891,10 +902,12 @@ int main(int argc, char* argv[]) { value = get_wei(argv[++i]); else if (strcmp(argv[i], "-port") == 0) port = argv[++i]; + else if (strcmp(argv[i], "-am") == 0) + allowed_methods = argv[++i]; else if (strcmp(argv[i], "-os") == 0) only_show_raw_tx = true; else if (strcmp(argv[i], "-rc") == 0) - c->request_count = atoi(argv[++i]); + _configure(c, "requestCount", "%s", argv[++i]); else if (strcmp(argv[i], "-a") == 0) c->max_attempts = atoi(argv[++i]); else if (strcmp(argv[i], "-name") == 0) @@ -975,11 +988,12 @@ int main(int argc, char* argv[]) { #ifdef IN3_SERVER // start server if (!method && port) { - http_run_server(port, c); + http_run_server(port, c, allowed_methods); recorder_exit(0); } #else (void) (port); + (void) (allowed_methods); #endif // handle private key @@ -1060,26 +1074,28 @@ int main(int argc, char* argv[]) { #endif } +#ifdef NODESELECT_DEF else if (strcmp(method, "in3_weights") == 0) { c->max_attempts = 1; uint32_t block = 0, b = 0; BIT_CLEAR(c->flags, FLAGS_AUTO_UPDATE_LIST); - uint64_t now = in3_time(NULL); - char* more = "WEIGHT"; - in3_nodeselect_def_t* nl = in3_nodeselect_def_data(c); + uint64_t now = in3_time(NULL); + char* more = "WEIGHT"; + in3_plugin_execute_all(c, PLGN_ACT_CHAIN_CHANGE, c); + in3_nodeselect_def_t* nl = in3_nodeselect_def_data(c); if (run_test_request == 1) more = "WEIGHT : LAST_BLOCK"; if (run_test_request == 2) more = "WEIGHT : NAME VERSION : RUNNING : HEALTH : LAST_BLOCK"; recorder_print(0, " : %-45s : %7s : %5s : %5s: %s\n------------------------------------------------------------------------------------------------\n", "URL", "BL", "CNT", "AVG", more); for (unsigned int i = 0; i < nl->nodelist_length; i++) { - in3_ctx_t* ctx = NULL; + in3_req_t* ctx = NULL; char* health_s = NULL; if (run_test_request) { char req[300]; char adr[41]; bytes_to_hex((nl->nodelist + i)->address, 20, adr); sprintf(req, "{\"id\":1,\"jsonrpc\":\"2.0\",\"method\":\"eth_blockNumber\",\"params\":[],\"in3\":{\"dataNodes\":[\"0x%s\"]}}", adr); - ctx = ctx_new(c, req); - if (ctx) in3_send_ctx(ctx); + ctx = req_new(c, req); + if (ctx) in3_send_req(ctx); if (run_test_request == 2) { int health = 1; char* version = ""; @@ -1090,12 +1106,12 @@ int main(int argc, char* argv[]) { char* urls[1]; urls[0] = health_url; sprintf(health_url, "%s/health", nl->nodelist[i].url); - in3_request_t r; - in3_ctx_t ctx = {0}; + in3_http_request_t r = {0}; + in3_req_t ctx = {0}; ctx.raw_response = _calloc(sizeof(in3_response_t), 1); ctx.raw_response->state = IN3_WAITING; ctx.client = c; - r.ctx = &ctx; + r.req = &ctx; r.urls = urls; r.urls_len = 1; r.payload = ""; @@ -1113,10 +1129,10 @@ int main(int argc, char* argv[]) { if (!health_res) health = 0; else { - node_name = d_get_string(health_res->result, "name"); - version = d_get_string(health_res->result, "version"); - running = d_get_int(health_res->result, "running"); - char* status = d_get_string(health_res->result, "status"); + node_name = d_get_string(health_res->result, key("name")); + version = d_get_string(health_res->result, key("version")); + running = d_get_int(health_res->result, key("running")); + char* status = d_get_string(health_res->result, key("status")); if (!status || strcmp(status, "healthy")) health = 0; } } @@ -1146,16 +1162,16 @@ int main(int argc, char* argv[]) { sprintf((warning = tr), "%s", msg ? d_string(msg) : "Error-Response!"); } else if (!ctx->error) { - b = d_get_intk(ctx->responses[0], K_RESULT); + b = d_get_int(ctx->responses[0], K_RESULT); if (block < b) block = b; if (b < block - 1) sprintf((warning = tr), "#%i ( out of sync : %i blocks behind latest )", b, block - b); else if (strncmp(node->url, "https://", 8)) sprintf((warning = tr), "#%i (missing https, which is required in a browser )", b); - else if (!IS_APPROX(d_get_intk(ctx->responses[0], K_RESULT), d_get_intk(d_get(ctx->responses[0], K_IN3), K_CURRENT_BLOCK), 1)) + else if (!IS_APPROX(d_get_int(ctx->responses[0], K_RESULT), d_get_int(d_get(ctx->responses[0], K_IN3), K_CURRENT_BLOCK), 1)) sprintf((warning = tr), "#%i ( current block mismatch: %i blocks apart )", b, - d_get_intk(ctx->responses[0], K_RESULT) - d_get_intk(d_get(ctx->responses[0], K_IN3), K_CURRENT_BLOCK)); + d_get_int(ctx->responses[0], K_RESULT) - d_get_int(d_get(ctx->responses[0], K_IN3), K_CURRENT_BLOCK)); else sprintf(tr, "#%i", b); } @@ -1183,11 +1199,12 @@ int main(int argc, char* argv[]) { recorder_print(0, COLORT_RESET "\n"); if (tr && tr != ctx->error) _free(tr); if (health_s) _free(health_s); - if (ctx) ctx_free(ctx); + if (ctx) req_free(ctx); } recorder_exit(0); } +#endif else if (strcmp(method, "send") == 0) { prepare_tx(sig, resolve(c, to), args, NULL, gas_limit, gas_price, value, data); method = wait ? "eth_sendTransactionAndWait" : "eth_sendTransaction"; @@ -1207,10 +1224,10 @@ int main(int argc, char* argv[]) { } if (!in3_plugin_is_registered(c, PLGN_ACT_SIGN)) die("No private key/path given"); - in3_ctx_t ctx; + in3_req_t ctx; ctx.client = c; in3_sign_ctx_t sc = {0}; - sc.ctx = &ctx; + sc.req = &ctx; sc.account = bytes(NULL, 0); sc.message = *data; sc.type = strcmp(sig_type, "hash") == 0 ? SIGN_EC_RAW : SIGN_EC_HASH; @@ -1344,7 +1361,9 @@ int main(int argc, char* argv[]) { } in3_log_debug("..sending request %s %s\n", method, args->data); +#ifdef NODESELECT_DEF in3_chain_t* chain = &c->chain; +#endif if (wait && strcmp(method, "eth_sendTransaction") == 0) method = "eth_sendTransactionAndWait"; @@ -1363,6 +1382,7 @@ int main(int argc, char* argv[]) { in3_client_rpc_raw(c, sb->data, &result, &error); +#ifdef NODESELECT_DEF in3_nodeselect_def_t* nl = in3_nodeselect_def_data(c); // Update nodelist if a newer latest block was reported if (chain && nl->nodelist_upd8_params && nl->nodelist_upd8_params->exp_last_block) { @@ -1372,6 +1392,7 @@ int main(int argc, char* argv[]) { // else if (chain->type == CHAIN_BTC) // in3_client_rpc(c, "getblockcount", "[]", &r, &e); } +#endif if (error) die(error); diff --git a/c/src/cmd/tools/data.c b/c/src/cmd/tools/data.c index 8eca4bef8..768c9d9fa 100644 --- a/c/src/cmd/tools/data.c +++ b/c/src/cmd/tools/data.c @@ -247,9 +247,10 @@ int main(int argc, char* argv[]) { if (!input.len) return 0; if (!strcmp(format, "auto")) { - if (input.data[0] == '0' && input.data[1] == 'x') { - input.data = malloc(strlen(argv[i]) / 2); - input.len = hex_to_bytes(argv[i], -1, input.data, strlen(argv[i]) / 2); + if ((input.data[0] == '0' && input.data[1] == 'x') || hexchar_to_int(*input.data) >> 1 == T_BOOLEAN) { + char* hex = (char*) input.data; + input.data = malloc(strlen(hex) / 2); + input.len = hex_to_bytes(hex, -1, input.data, strlen(hex) / 2); format = "json"; } else diff --git a/c/src/cmd/tools/rlp.c b/c/src/cmd/tools/rlp.c index 86e8f27b9..d4519ec81 100644 --- a/c/src/cmd/tools/rlp.c +++ b/c/src/cmd/tools/rlp.c @@ -318,14 +318,11 @@ void write(bytes_t* data, char* l, char** tt) { printf("[ %s", t2 ? t2[0] : ""); if (first) { - bytes_t* hash = sha3(data); + bytes32_t hash; + keccak(*data, hash); printf(" Hash : 0x"); first = 0; - - for (int j = 0; j < 32; j++) - printf("%02x", hash->data[j]); - - b_free(hash); + for (int j = 0; j < 32; j++) printf("%02x", hash[j]); } printf("\n"); diff --git a/c/src/core/CMakeLists.txt b/c/src/core/CMakeLists.txt index af4f75634..e557ab6d9 100644 --- a/c/src/core/CMakeLists.txt +++ b/c/src/core/CMakeLists.txt @@ -44,9 +44,8 @@ add_static_library( NAME core SOURCES - client/context.c + client/request.c client/client.c - client/verifier.c client/execute.c client/client_init.c util/debug.c @@ -62,17 +61,3 @@ add_static_library( DEPENDS crypto ) - - -add_static_library( - NAME init - - SOURCES - ../verifier/in3_init.c - - DEPENDS - ${IN3_VERIFIER} - ${IN3_API} - ${IN3_TRANSPORT} - ${IN3_NODESELECT} -) diff --git a/c/src/core/client/client.c b/c/src/core/client/client.c index d9c7ddf87..73c00f0e0 100644 --- a/c/src/core/client/client.c +++ b/c/src/core/client/client.c @@ -34,20 +34,20 @@ #include "../util/data.h" #include "../util/mem.h" -#include "context.h" #include "keys.h" #include "plugin.h" +#include "request.h" #include #include #include #include #include -in3_ctx_t* in3_client_rpc_ctx_raw(in3_t* c, const char* req) { +in3_req_t* in3_client_rpc_ctx_raw(in3_t* c, const char* req) { assert_in3(c); assert(req); // create a new context by parsing the request - in3_ctx_t* ctx = ctx_new(c, req); + in3_req_t* ctx = req_new(c, req); // this happens if the request is not parseable (JSON-error in params) if (ctx->error) { @@ -56,7 +56,7 @@ in3_ctx_t* in3_client_rpc_ctx_raw(in3_t* c, const char* req) { } // execute it - in3_ret_t ret = in3_send_ctx(ctx); + in3_ret_t ret = in3_send_req(ctx); if (ret == IN3_OK) { // the request was succesfull, so we delete interim errors (which can happen in case in3 had to retry) if (ctx->error) _free(ctx->error); @@ -68,7 +68,7 @@ in3_ctx_t* in3_client_rpc_ctx_raw(in3_t* c, const char* req) { return ctx; // return context and hope the calle will clean it. } -in3_ctx_t* in3_client_rpc_ctx(in3_t* c, const char* method, const char* params) { +in3_req_t* in3_client_rpc_ctx(in3_t* c, const char* method, const char* params) { assert_in3(c); assert(method); assert(params); @@ -79,13 +79,13 @@ in3_ctx_t* in3_client_rpc_ctx(in3_t* c, const char* method, const char* params) char* req = heap ? _malloc(max) : alloca(max); // allocate memory in heap or stack snprintX(req, max, "{\"method\":\"%s\",\"jsonrpc\":\"2.0\",\"params\":%s}", method, params); // create request - in3_ctx_t* ctx = in3_client_rpc_ctx_raw(c, req); + in3_req_t* ctx = in3_client_rpc_ctx_raw(c, req); if (heap) _free(req); // free request string if we created it in heap return ctx; // return context and hope the calle will clean it. } -static in3_ret_t ctx_rpc(in3_ctx_t* ctx, char** result, char** error) { +static in3_ret_t ctx_rpc(in3_req_t* ctx, char** result, char** error) { assert(ctx); assert_in3(ctx->client); if (result) result[0] = 0; @@ -110,12 +110,13 @@ static in3_ret_t ctx_rpc(in3_ctx_t* ctx, char** result, char** error) { } // do we have an error-property in the response? - d_token_t* r = d_get(ctx->responses[0], K_ERROR); + bool is_obj = d_type(ctx->responses[0]) == T_OBJECT; + d_token_t* r = is_obj ? d_get(ctx->responses[0], K_ERROR) : NULL; if (d_type(r) != T_NULL) { if (d_type(r) == T_STRING) *error = _strdupn(d_string(r), -1); else if (d_type(r) == T_OBJECT) { - char* msg = d_get_stringk(r, K_MESSAGE); + char* msg = d_get_string(r, K_MESSAGE); *error = msg ? _strdupn(msg, -1) : d_create_json(ctx->response_context, r); } else @@ -124,10 +125,18 @@ static in3_ret_t ctx_rpc(in3_ctx_t* ctx, char** result, char** error) { goto clean; } - if ((r = d_get(ctx->responses[0], K_RESULT)) == NULL) { - // we have no result - *error = _strdupn("no result or error in rpc-response", -1); - res = IN3_ERPC; + if ((r = (is_obj ? d_get(ctx->responses[0], K_RESULT) : NULL)) == NULL) { + if (strcmp(d_get_string(ctx->requests[0], K_METHOD), "in3_http") == 0) { + *result = d_type(ctx->responses[0]) == T_BYTES + ? _strdupn((void*) ctx->responses[0]->data, ctx->responses[0]->len + 1) + : d_create_json(ctx->response_context, r); + res = IN3_OK; + } + else { + // we have no result + *error = _strdupn("no result or error in rpc-response", -1); + res = IN3_ERPC; + } goto clean; } @@ -135,7 +144,7 @@ static in3_ret_t ctx_rpc(in3_ctx_t* ctx, char** result, char** error) { if (result) *result = d_create_json(ctx->response_context, r); clean: - ctx_free(ctx); + req_free(ctx); // if we have an error, we always return IN3_EUNKNOWN return res; @@ -151,7 +160,7 @@ in3_ret_t in3_client_rpc_raw(in3_t* c, const char* request, char** result, char* return ctx_rpc(in3_client_rpc_ctx_raw(c, request), result, error); } -static char* create_rpc_error(in3_ctx_t* ctx, int code, char* error) { +static char* create_rpc_error(in3_req_t* ctx, int code, char* error) { sb_t sb = {0}; bool is_array = ctx && ctx->request_context && d_type(ctx->request_context->result) == T_ARRAY; uint_fast16_t len = (ctx && ctx->len) ? ctx->len : 1; @@ -159,7 +168,7 @@ static char* create_rpc_error(in3_ctx_t* ctx, int code, char* error) { for (uint_fast16_t i = 0; i < len; i++) { if (i) sb_add_char(&sb, ','); sb_add_chars(&sb, "{\"id\":"); - sb_add_int(&sb, (ctx && ctx->requests && i < ctx->len) ? d_get_intk(ctx->requests[i], K_ID) : 0); + sb_add_int(&sb, (ctx && ctx->requests && i < ctx->len) ? d_get_int(ctx->requests[i], K_ID) : 0); sb_add_chars(&sb, ",\"jsonrpc\":\"2.0\",\"error\":{\"code\":"); sb_add_int(&sb, code); sb_add_chars(&sb, ",\"message\":\""); @@ -170,7 +179,7 @@ static char* create_rpc_error(in3_ctx_t* ctx, int code, char* error) { return sb.data; } -char* ctx_get_error_rpc(in3_ctx_t* ctx, in3_ret_t ret) { +char* req_get_error_rpc(in3_req_t* ctx, in3_ret_t ret) { return create_rpc_error(ctx, ret ? ret : ctx->verification_state, ctx->error); } @@ -180,8 +189,7 @@ char* in3_client_exec_req( ) { // parse it char* res = NULL; - in3_ctx_t* ctx = ctx_new(c, req); - in3_ret_t ret; + in3_req_t* ctx = req_new(c, req); // not enough memory if (!ctx) return NULL; @@ -193,11 +201,12 @@ char* in3_client_exec_req( goto clean; } - ret = in3_send_ctx(ctx); + // execute the request + in3_ret_t ret = in3_send_req(ctx); // do we have an error? if (ctx->error) { - res = ctx_get_error_rpc(ctx, ret); + res = req_get_error_rpc(ctx, ret); goto clean; } @@ -208,11 +217,11 @@ char* in3_client_exec_req( } // looks good, so we use the resonse and return it - res = ctx_get_response_data(ctx); + res = req_get_response_data(ctx); clean: - ctx_free(ctx); + req_free(ctx); return res; } @@ -248,39 +257,80 @@ void in3_sign_ctx_set_signature_hex( } /** - * getter to retrieve the payload from a in3_request_t struct + * getter to retrieve the payload from a in3_http_request_t struct */ char* in3_get_request_payload( - in3_request_t* request /**< request struct */ + in3_http_request_t* request /**< request struct */ ) { return request->payload; } /** - * getter to retrieve the urls list from a in3_request_t struct + * getter to retrieve the length of the payload from a in3_http_request_t struct + */ +uint32_t in3_get_request_payload_len( + in3_http_request_t* request /**< request struct */ +) { + return request->payload_len; +} + +/** + * getter to retrieve the http-method from a in3_http_request_t struct + */ +char* in3_get_request_method( + in3_http_request_t* request /**< request struct */ +) { + return request->method; +} +/** + * getter to retrieve the urls list from a in3_http_request_t struct */ char** in3_get_request_urls( - in3_request_t* request /**< request struct */ + in3_http_request_t* request /**< request struct */ ) { return request->urls; } /** - * getter to retrieve the urls list length from a in3_request_t struct + * getter to retrieve the urls list length from a in3_http_request_t struct */ int in3_get_request_urls_len( - in3_request_t* request /**< request struct */ + in3_http_request_t* request /**< request struct */ ) { return request->urls_len; } /** - * getter to retrieve the urls list length from a in3_request_t struct + * getter to retrieve the urls list length from a in3_http_request_t struct + */ +int in3_get_request_headers_len( + in3_http_request_t* request /**< request struct */ +) { + int n = 0; + for (in3_req_header_t* h = request->headers; h; h = h->next) n++; + return n; +} +/** + * getter to retrieve the urls list length from a in3_http_request_t struct + */ +char* in3_get_request_headers_at( + in3_http_request_t* request, /**< request struct */ + int index /**< the inde xof the header */ +) { + int n = 0; + for (in3_req_header_t* h = request->headers; h; h = h->next, n++) { + if (n == index) return h->value; + } + return NULL; +} + +/** + * getter to retrieve the urls list length from a in3_http_request_t struct */ uint32_t in3_get_request_timeout( - in3_request_t* request /**< request struct */ + in3_http_request_t* request /**< request struct */ ) { - return request->ctx->client->timeout; + return request->req->client->timeout; } /** diff --git a/c/src/core/client/client.h b/c/src/core/client/client.h index 6f9978785..9bd06d68c 100644 --- a/c/src/core/client/client.h +++ b/c/src/core/client/client.h @@ -70,8 +70,6 @@ extern "C" { */ typedef uint32_t chain_id_t; -struct in3_ctx; - /** the type of the chain. * * for incubed a chain can be any distributed network or database with incubed support. @@ -103,110 +101,21 @@ typedef enum { */ typedef uint64_t in3_node_props_t; -typedef enum { - NODE_PROP_PROOF = 0x1, /**< filter out nodes which are providing no proof */ - NODE_PROP_MULTICHAIN = 0x2, /**< filter out nodes other then which have capability of the same RPC endpoint may also accept requests for different chains */ - NODE_PROP_ARCHIVE = 0x4, /**< filter out non-archive supporting nodes */ - NODE_PROP_HTTP = 0x8, /**< filter out non-http nodes */ - NODE_PROP_BINARY = 0x10, /**< filter out nodes that don't support binary encoding */ - NODE_PROP_ONION = 0x20, /**< filter out non-onion nodes */ - NODE_PROP_SIGNER = 0x40, /**< filter out non-signer nodes */ - NODE_PROP_DATA = 0x80, /**< filter out non-data provider nodes */ - NODE_PROP_STATS = 0x100, /**< filter out nodes that do not provide stats */ - NODE_PROP_MIN_BLOCK_HEIGHT = 0x400, /**< filter out nodes that will sign blocks with lower min block height than specified */ -} in3_node_props_type_t; - /** * a list of flags defining the behavior of the incubed client. They should be used as bitmask for the flags-property. */ typedef enum { - FLAGS_KEEP_IN3 = 0x1, /**< the in3-section with the proof will also returned */ - FLAGS_AUTO_UPDATE_LIST = 0x2, /**< the nodelist will be automatically updated if the last_block is newer */ - FLAGS_INCLUDE_CODE = 0x4, /**< the code is included when sending eth_call-requests */ - FLAGS_BINARY = 0x8, /**< the client will use binary format */ - FLAGS_HTTP = 0x10, /**< the client will try to use http instead of https */ - FLAGS_STATS = 0x20, /**< nodes will keep track of the stats (default=true) */ - FLAGS_NODE_LIST_NO_SIG = 0x40, /**< nodelist update request will not automatically ask for signatures and proof */ - FLAGS_BOOT_WEIGHTS = 0x80 /**< if true the client will initialize the first weights from the nodelist given by the nodelist.*/ + FLAGS_KEEP_IN3 = 0x1, /**< the in3-section with the proof will also returned */ + FLAGS_AUTO_UPDATE_LIST = 0x2, /**< the nodelist will be automatically updated if the last_block is newer */ + FLAGS_INCLUDE_CODE = 0x4, /**< the code is included when sending eth_call-requests */ + FLAGS_BINARY = 0x8, /**< the client will use binary format */ + FLAGS_HTTP = 0x10, /**< the client will try to use http instead of https */ + FLAGS_STATS = 0x20, /**< nodes will keep track of the stats (default=true) */ + FLAGS_NODE_LIST_NO_SIG = 0x40, /**< nodelist update request will not automatically ask for signatures and proof */ + FLAGS_BOOT_WEIGHTS = 0x80, /**< if true the client will initialize the first weights from the nodelist given by the nodelist.*/ + FLAGS_ALLOW_EXPERIMENTAL = 0x100 /**< if true the client will support experimental features.*/ } in3_flags_type_t; -/** - * a list of node attributes (mostly used internally) - */ -typedef enum { - ATTR_WHITELISTED = 1, /**< indicates if node exists in whiteList */ - ATTR_BOOT_NODE = 2, /**< used to avoid filtering manually added nodes before first nodeList update */ -} in3_node_attr_type_t; - -/** incubed node-configuration. - * - * These information are read from the Registry contract and stored in this struct representing a server or node. - */ -typedef struct in3_node { - address_t address; /**< address of the server */ - bool blocked; /**< if true this node has been blocked for sending wrong responses */ - uint_fast16_t index; /**< index within the nodelist, also used in the contract as key */ - uint_fast16_t capacity; /**< the maximal capacity able to handle */ - uint64_t deposit; /**< the deposit stored in the registry contract, which this would lose if it sends a wrong blockhash */ - in3_node_props_t props; /**< used to identify the capabilities of the node. See in3_node_props_type_t in nodelist.h */ - char* url; /**< the url of the node */ - uint_fast8_t attrs; /**< bitmask of internal attributes */ -} in3_node_t; - -/** - * Weight or reputation of a node. - * - * Based on the past performance of the node a weight is calculated given faster nodes a higher weight - * and chance when selecting the next node from the nodelist. - * These weights will also be stored in the cache (if available) - */ -typedef struct in3_node_weight { - uint32_t response_count; /**< counter for responses */ - uint32_t total_response_time; /**< total of all response times */ - uint64_t blacklisted_until; /**< if >0 this node is blacklisted until k. k is a unix timestamp */ -} in3_node_weight_t; - -/** - * Initializer for in3_node_props_t - */ -#define in3_node_props_init(np) *(np) = 0 - -/** - * setter method for interacting with in3_node_props_t. - */ -NONULL void in3_node_props_set(in3_node_props_t* node_props, /**< pointer to the properties to change */ - in3_node_props_type_t type, /**< key or type of the property */ - uint8_t value /**< value to set */ -); - -/** - * returns the value of the specified property-type. - * @return value as a number - */ -static inline uint32_t in3_node_props_get(in3_node_props_t np, /**< property to read from */ - in3_node_props_type_t t) { /**< the value to extract */ - return ((t == NODE_PROP_MIN_BLOCK_HEIGHT) ? ((np >> 32U) & 0xFFU) : !!(np & t)); -} - -/** - * checks if the given type is set in the properties - * @return true if set - */ -static inline bool in3_node_props_matches(in3_node_props_t np, /**< property to read from */ - in3_node_props_type_t t) { /**< the value to extract */ - return !!(np & t); -} - -/** - * defines a whitelist structure used for the nodelist. - */ -typedef struct in3_whitelist { - bool needs_update; /**< if true the nodelist should be updated and will trigger a `in3_nodeList`-request before the next request is send. */ - uint64_t last_block; /**< last blocknumber the whiteList was updated, which is used to detect changed in the whitelist */ - address_t contract; /**< address of whiteList contract. If specified, whiteList is always auto-updated and manual whiteList is overridden */ - bytes_t addresses; /**< serialized list of node addresses that constitute the whiteList */ -} in3_whitelist_t; - /** represents a blockhash which was previously verified */ typedef struct in3_verified_hash { uint64_t block_number; /**< the number of the block */ @@ -225,30 +134,6 @@ typedef struct in3_chain { in3_verified_hash_t* verified_hashes; /**< contains the list of already verified blockhashes */ } in3_chain_t; -/** Incubed Configuration. - * - * This struct holds the configuration and also point to internal resources such as filters or chain configs. - * - */ -typedef struct in3_t_ in3_t; - -/** - * Filter type used internally when managing filters. - */ -typedef enum { - FILTER_EVENT = 0, /**< Event filter */ - FILTER_BLOCK = 1, /**< Block filter */ - FILTER_PENDING = 2, /**< Pending filter (Unsupported) */ -} in3_filter_type_t; - -typedef struct in3_filter_t_ { - bool is_first_usage; /**< if true the filter was not used previously */ - in3_filter_type_t type; /**< filter type: (event, block or pending) */ - uint64_t last_block; /**< block no. when filter was created OR eth_getFilterChanges was called */ - char* options; /**< associated filter options */ - void (*release)(struct in3_filter_t_* f); /**< method to release owned resources */ -} in3_filter_t; - #define PLGN_ACT_LIFECYCLE (PLGN_ACT_INIT | PLGN_ACT_TERM) #define PLGN_ACT_TRANSPORT (PLGN_ACT_TRANSPORT_SEND | PLGN_ACT_TRANSPORT_RECEIVE | PLGN_ACT_TRANSPORT_CLEAN) #define PLGN_ACT_NODELIST (PLGN_ACT_NL_PICK | PLGN_ACT_NL_PICK_FOLLOWUP | PLGN_ACT_NL_BLACKLIST | PLGN_ACT_NL_FAILABLE | PLGN_ACT_NL_OFFLINE) @@ -257,7 +142,7 @@ typedef struct in3_filter_t_ { /** plugin action list */ typedef enum { - PLGN_ACT_INIT = 0x1, /**< initialize plugin - use for allocating/setting-up internal resources */ + PLGN_ACT_INIT = 0x1, /**< initialize plugin - use for allocating/setting-up internal resources . Plugins will be initialized before first used. The plgn_ctx will be the first request ctx in3_req_t */ PLGN_ACT_TERM = 0x2, /**< terminate plugin - use for releasing internal resources and cleanup. */ PLGN_ACT_TRANSPORT_SEND = 0x4, /**< sends out a request - the transport plugin will receive a request_t as plgn_ctx, it may set a cptr which will be passed back when fetching more responses. */ PLGN_ACT_TRANSPORT_RECEIVE = 0x8, /**< fetch next response - the transport plugin will receive a request_t as plgn_ctx, which contains a cptr if set previously*/ @@ -277,10 +162,10 @@ typedef enum { PLGN_ACT_PAY_HANDLE = 0x20000, /**< handles the payment */ PLGN_ACT_PAY_SIGN_REQ = 0x40000, /**< signs a request */ PLGN_ACT_LOG_ERROR = 0x80000, /**< report an error */ - PLGN_ACT_NL_PICK = 0x100000, /**< picks the data nodes, plgn_ctx will be a pointer to in3_ctx_t */ - PLGN_ACT_NL_PICK_FOLLOWUP = 0x200000, /**< called after receiving a response in order to decide whether a update is needed, plgn_ctx will be a pointer to in3_ctx_t */ + PLGN_ACT_NL_PICK = 0x100000, /**< picks the data nodes, plgn_ctx will be a pointer to in3_req_t */ + PLGN_ACT_NL_PICK_FOLLOWUP = 0x200000, /**< called after receiving a response in order to decide whether a update is needed, plgn_ctx will be a pointer to in3_req_t */ PLGN_ACT_NL_BLACKLIST = 0x400000, /**< blacklist a particular node in the nodelist, plgn_ctx will be a pointer to the node's address. */ - PLGN_ACT_NL_FAILABLE = 0x800000, /**< handle fail-able request, plgn_ctx will be a pointer to in3_ctx_t */ + PLGN_ACT_NL_FAILABLE = 0x800000, /**< handle fail-able request, plgn_ctx will be a pointer to in3_req_t */ PLGN_ACT_NL_OFFLINE = 0x1000000, /**< mark a particular node in the nodelist as offline, plgn_ctx will be a pointer to in3_nl_offline_ctx_t. */ PLGN_ACT_CHAIN_CHANGE = 0x2000000, /**< chain id change event, called after setting new chain id */ PLGN_ACT_GET_DATA = 0x4000000, /**< get access to plugin data as a void ptr */ @@ -312,25 +197,15 @@ struct in3_plugin { in3_plugin_t* next; /**< pointer to next plugin in list */ }; -/** - * Handler which is added to client config in order to handle filter. - */ -typedef struct in3_filter_handler_t_ { - in3_filter_t** array; /** array of filters */ - size_t count; /** counter for filters */ -} in3_filter_handler_t; - /** Incubed Configuration. * * This struct holds the configuration and also point to internal resources such as filters or chain configs. * */ -struct in3_t_ { - uint8_t request_count; /**< the number of request send when getting a first answer */ +typedef struct in3_t_ { uint8_t signature_count; /**< the number of signatures used to proof the blockhash. */ uint8_t replace_latest_block; /**< if specified, the blocknumber *latest* will be replaced by blockNumber- specified value */ - uint_fast8_t flags; /**< a bit mask with flags defining the behavior of the incubed client. See the FLAG...-defines*/ - uint16_t node_limit; /**< the limit of nodes to store in the client. */ + uint_fast16_t flags; /**< a bit mask with flags defining the behavior of the incubed client. See the FLAG...-defines*/ uint16_t finality; /**< the number of signatures in percent required for the request*/ uint_fast16_t max_attempts; /**< the max number of attempts before giving up*/ uint_fast16_t max_verified_hashes; /**< max number of verified hashes to cache (actual number may temporarily exceed this value due to pending requests) */ @@ -341,12 +216,9 @@ struct in3_t_ { uint32_t id_count; /**< counter for use as JSON RPC id - incremented for every request */ in3_plugin_supp_acts_t plugin_acts; /**< bitmask of supported actions of all plugins registered with this client */ in3_proof_t proof; /**< the type of proof used */ - uint64_t min_deposit; /**< min stake of the server. Only nodes owning at least this amount will be chosen. */ - in3_node_props_t node_props; /**< used to identify the capabilities of the node. */ in3_chain_t chain; /**< chain spec and nodeList definitions*/ - in3_filter_handler_t* filters; /**< filter handler */ in3_plugin_t* plugins; /**< list of registered plugins */ -}; +} in3_t; /** creates a new Incubed configuration for a specified chain and returns the pointer. * when creating the client only the one chain will be configured. (saves memory). @@ -445,7 +317,6 @@ typedef in3_ret_t (*plgn_register)(in3_t* c); assert(c); \ assert((c)->chain.chain_id); \ assert((c)->plugins); \ - assert((c)->request_count > 0); \ assert((c)->max_attempts > 0); \ assert((c)->proof >= 0 && (c)->proof <= PROOF_FULL); \ assert((c)->proof >= 0 && (c)->proof <= PROOF_FULL); diff --git a/c/src/core/client/client_init.c b/c/src/core/client/client_init.c index 5eb2e3549..6d7bc8329 100644 --- a/c/src/core/client/client_init.c +++ b/c/src/core/client/client_init.c @@ -37,8 +37,8 @@ #include "../util/debug.h" #include "../util/log.h" #include "client.h" -#include "context_internal.h" #include "plugin.h" +#include "request_internal.h" #include #include #include @@ -51,14 +51,20 @@ typedef struct default_fn { static default_fn_t* default_registry = NULL; +// registers a default plugin, which means all registered reg_fn +// will be called whenever a new client is created void in3_register_default(plgn_register reg_fn) { assert(reg_fn); + // check if it already exists default_fn_t** d = &default_registry; default_fn_t** pre = NULL; for (; *d; d = &(*d)->next) { if ((*d)->fn == reg_fn) pre = d; } + + // so the plugin is already registered, + // but if registered again, we need to change the order. if (pre) { if ((*pre)->next) { // we are not the last one, so we need to make it the last default_fn_t* p = *pre; @@ -69,29 +75,11 @@ void in3_register_default(plgn_register reg_fn) { return; } + // not registered yet, so we create one and put it at the end (*d) = _calloc(1, sizeof(default_fn_t)); (*d)->fn = reg_fn; } -static void init_ipfs(in3_t* c) { - in3_client_register_chain(c, 0x7d0, CHAIN_IPFS, 2); -} - -static void init_mainnet(in3_t* c) { - in3_client_register_chain(c, 0x01, CHAIN_ETH, 2); -} -static void init_ewf(in3_t* c) { - in3_client_register_chain(c, 0xf6, CHAIN_ETH, 2); -} - -static void init_btc(in3_t* c) { - in3_client_register_chain(c, 0x99, CHAIN_BTC, 2); -} - -static void init_goerli(in3_t* c) { - in3_client_register_chain(c, 0x05, CHAIN_ETH, 2); -} - static in3_ret_t in3_client_init(in3_t* c, chain_id_t chain_id) { assert(c); @@ -101,31 +89,28 @@ static in3_ret_t in3_client_init(in3_t* c, chain_id_t chain_id) { c->max_attempts = 7; c->max_verified_hashes = 5; c->alloc_verified_hashes = 0; - c->min_deposit = 0; - c->node_limit = 0; c->proof = PROOF_STANDARD; c->replace_latest_block = 0; - c->request_count = 1; - c->filters = NULL; c->timeout = 10000; c->id_count = 1; if (chain_id == CHAIN_ID_MAINNET) - init_mainnet(c); + in3_client_register_chain(c, 0x01, CHAIN_ETH, 2); else if (chain_id == CHAIN_ID_GOERLI) - init_goerli(c); + in3_client_register_chain(c, 0x05, CHAIN_ETH, 2); else if (chain_id == CHAIN_ID_IPFS) - init_ipfs(c); + in3_client_register_chain(c, 0x7d0, CHAIN_IPFS, 2); else if (chain_id == CHAIN_ID_BTC) - init_btc(c); + in3_client_register_chain(c, 0x99, CHAIN_BTC, 2); else if (chain_id == CHAIN_ID_EWC) - init_ewf(c); + in3_client_register_chain(c, 0xf6, CHAIN_ETH, 2); else if (chain_id == CHAIN_ID_LOCAL) in3_client_register_chain(c, 0x11, CHAIN_ETH, 1); return IN3_OK; } +// init the chain with the given parameters in3_ret_t in3_client_register_chain(in3_t* c, chain_id_t chain_id, in3_chain_type_t type, uint8_t version) { assert(c); @@ -138,35 +123,20 @@ in3_ret_t in3_client_register_chain(in3_t* c, chain_id_t chain_id, in3_chain_typ return IN3_OK; } -static void chain_free(in3_chain_t* chain) { - if (chain->verified_hashes) _free(chain->verified_hashes); -} - /* frees the data */ void in3_free(in3_t* a) { if (!a) return; // cleanup plugins - in3_plugin_t *p = a->plugins, *n; - while (p) { - if (p->acts & PLGN_ACT_TERM) - p->action_fn(p->data, PLGN_ACT_TERM, a); - n = p->next; + for (in3_plugin_t* p = a->plugins; p;) { + // we let the plugin free the resources, but don't care about the return-value. + if (p->acts & PLGN_ACT_TERM) p->action_fn(p->data, PLGN_ACT_TERM, a); + in3_plugin_t* n = p->next; _free(p); p = n; } - chain_free(&a->chain); - - if (a->filters) { - in3_filter_t* f = NULL; - for (size_t j = 0; j < a->filters->count; j++) { - f = a->filters->array[j]; - if (f) f->release(f); - } - _free(a->filters->array); - _free(a->filters); - } + if (a->chain.verified_hashes) _free(a->chain.verified_hashes); _free(a); } @@ -183,8 +153,7 @@ in3_t* in3_for_chain_default(chain_id_t chain_id) { } // init from default plugins - for (default_fn_t* d = default_registry; d; d = d->next) - d->fn(c); + for (default_fn_t* d = default_registry; d; d = d->next) d->fn(c); return c; } @@ -206,7 +175,7 @@ static chain_id_t chain_id(d_token_t* t) { static int chain_type(d_token_t* t) { if (d_type(t) == T_STRING) { - char* c = d_string(t); + const char* c = d_string(t); if (!strcmp(c, "btc")) return CHAIN_BTC; if (!strcmp(c, "eth")) return CHAIN_ETH; if (!strcmp(c, "ipfs")) return CHAIN_IPFS; @@ -227,7 +196,8 @@ static in3_chain_type_t chain_type_from_id(chain_id_t id) { return CHAIN_IPFS; case CHAIN_ID_BTC: return CHAIN_BTC; - default: return CHAIN_GENERIC; + default: + return CHAIN_GENERIC; } } @@ -244,15 +214,12 @@ char* in3_get_config(in3_t* c) { add_bool(sb, ',', "stats", c->flags & FLAGS_STATS); add_bool(sb, ',', "useBinary", c->flags & FLAGS_BINARY); add_bool(sb, ',', "useHttp", c->flags & FLAGS_HTTP); + add_bool(sb, ',', "experimental", c->flags & FLAGS_ALLOW_EXPERIMENTAL); add_uint(sb, ',', "maxVerifiedHashes", c->max_verified_hashes); add_uint(sb, ',', "timeout", c->timeout); - add_uint(sb, ',', "minDeposit", c->min_deposit); - add_uint(sb, ',', "nodeProps", c->node_props); - add_uint(sb, ',', "nodeLimit", c->node_limit); add_string(sb, ',', "proof", (c->proof == PROOF_NONE) ? "none" : (c->proof == PROOF_STANDARD ? "standard" : "full")); if (c->replace_latest_block) add_uint(sb, ',', "replaceLatestBlock", c->replace_latest_block); - add_uint(sb, ',', "requestCount", c->request_count); in3_get_config_ctx_t cctx = {.client = c, .sb = sb}; in3_plugin_execute_all(c, PLGN_ACT_CONFIG_GET, &cctx); @@ -264,13 +231,20 @@ char* in3_get_config(in3_t* c) { } char* in3_configure(in3_t* c, const char* config) { - json_ctx_t* json = parse_json((char*) config); - char* res = NULL; + // config can not be changed as long as there are pending requests. + if (c->pending) return config_err("in3_configure", "can not change config because there are pending requests!"); + // make sure the json-config is parseable. + json_ctx_t* json = parse_json((char*) config); if (!json || !json->result) return config_err("in3_configure", "parse error"); - if (c->pending) return config_err("in3_configure", "can not change config because there are pending requests!"); + + // the error-message we will return in case of an error. + char* res = NULL; + + // we iterate over the root-props for (d_iterator_t iter = d_iter(json->result); iter.left; d_iter_next(&iter)) { d_token_t* token = iter.token; + if (token->key == key("autoUpdateList")) { EXPECT_TOK_BOOL(token); BITMASK_SET_BOOL(c->flags, FLAGS_AUTO_UPDATE_LIST, (d_int(token) ? true : false)); @@ -287,9 +261,8 @@ char* in3_configure(in3_t* c, const char* config) { ct_ = chain_type(ct_token); EXPECT_TOK(ct_token, ct_ != -1, "expected (btc|eth|ipfs|)"); } - else { + else ct_ = chain_type_from_id(c->chain.chain_id); - } bool changed = (c->chain.chain_id != chain_id(token)); c->chain.chain_id = chain_id(token); @@ -342,6 +315,10 @@ char* in3_configure(in3_t* c, const char* config) { EXPECT_TOK_BOOL(token); BITMASK_SET_BOOL(c->flags, FLAGS_BINARY, (d_int(token) ? true : false)); } + else if (token->key == key("experimental")) { + EXPECT_TOK_BOOL(token); + BITMASK_SET_BOOL(c->flags, FLAGS_ALLOW_EXPERIMENTAL, (d_int(token) ? true : false)); + } else if (token->key == key("useHttp")) { EXPECT_TOK_BOOL(token); BITMASK_SET_BOOL(c->flags, FLAGS_HTTP, (d_int(token) ? true : false)); @@ -362,18 +339,6 @@ char* in3_configure(in3_t* c, const char* config) { EXPECT_TOK_U32(token); c->timeout = d_long(token); } - else if (token->key == key("minDeposit")) { - EXPECT_TOK_U64(token); - c->min_deposit = d_long(token); - } - else if (token->key == key("nodeProps")) { - EXPECT_TOK_U64(token); - c->node_props = d_long(token); - } - else if (token->key == key("nodeLimit")) { - EXPECT_TOK_U16(token); - c->node_limit = (uint16_t) d_int(token); - } else if (token->key == key("proof")) { EXPECT_TOK_STR(token); EXPECT_TOK(token, !strcmp(d_string(token), "full") || !strcmp(d_string(token), "standard") || !strcmp(d_string(token), "none"), "expected values - full/standard/none"); @@ -381,15 +346,6 @@ char* in3_configure(in3_t* c, const char* config) { ? PROOF_FULL : (strcmp(d_string(token), "standard") == 0 ? PROOF_STANDARD : PROOF_NONE); } - else if (token->key == key("replaceLatestBlock")) { - EXPECT_TOK_U8(token); - c->replace_latest_block = (uint8_t) d_int(token); - } - else if (token->key == key("requestCount")) { - EXPECT_TOK_U8(token); - EXPECT_CFG(d_int(token), "requestCount must be at least 1"); - c->request_count = (uint8_t) d_int(token); - } else if (token->key == key("verifiedHashes")) { EXPECT_TOK_ARR(token); EXPECT_TOK(token, (unsigned) d_len(token) <= c->max_verified_hashes, "expected array len <= maxVerifiedHashes"); @@ -402,12 +358,13 @@ char* in3_configure(in3_t* c, const char* config) { for (d_iterator_t n = d_iter(token); n.left; d_iter_next(&n), i++) { EXPECT_TOK_U64(d_get(n.token, key("block"))); EXPECT_TOK_B256(d_get(n.token, key("hash"))); - c->chain.verified_hashes[i].block_number = d_get_longk(n.token, key("block")); + c->chain.verified_hashes[i].block_number = d_get_long(n.token, key("block")); memcpy(c->chain.verified_hashes[i].hash, d_get_byteskl(n.token, key("hash"), 32)->data, 32); } c->alloc_verified_hashes = c->max_verified_hashes; } else { + // since the token was not handled yet, we will ask the plugins.. in3_configure_ctx_t cctx = {.client = c, .json = json, .token = token, .error_msg = NULL}; bool handled = false; for (in3_plugin_t* p = c->plugins; p; p = p->next) { @@ -476,8 +433,7 @@ in3_ret_t in3_plugin_register(in3_t* c, in3_plugin_supp_acts_t acts, in3_plugin_ } in3_ret_t in3_plugin_execute_all(in3_t* c, in3_plugin_act_t action, void* plugin_ctx) { - if (!in3_plugin_is_registered(c, action)) - return IN3_OK; + if (!in3_plugin_is_registered(c, action)) return IN3_OK; in3_plugin_t* p = c->plugins; in3_ret_t ret = IN3_OK, ret_; @@ -530,7 +486,7 @@ static char* action_name(in3_plugin_act_t action) { } #endif -in3_ret_t in3_plugin_execute_first(in3_ctx_t* ctx, in3_plugin_act_t action, void* plugin_ctx) { +in3_ret_t in3_plugin_execute_first(in3_req_t* ctx, in3_plugin_act_t action, void* plugin_ctx) { assert(ctx); for (in3_plugin_t* p = ctx->client->plugins; p; p = p->next) { if (p->acts & action) { @@ -545,10 +501,10 @@ in3_ret_t in3_plugin_execute_first(in3_ctx_t* ctx, in3_plugin_act_t action, void #else char* msg = "E"; #endif - return ctx_set_error(ctx, msg, IN3_EPLGN_NONE); + return req_set_error(ctx, msg, IN3_EPLGN_NONE); } -in3_ret_t in3_plugin_execute_first_or_none(in3_ctx_t* ctx, in3_plugin_act_t action, void* plugin_ctx) { +in3_ret_t in3_plugin_execute_first_or_none(in3_req_t* ctx, in3_plugin_act_t action, void* plugin_ctx) { assert(ctx); if (!in3_plugin_is_registered(ctx->client, action)) return IN3_OK; diff --git a/c/src/core/client/execute.c b/c/src/core/client/execute.c index 30d635961..3b50eddde 100644 --- a/c/src/core/client/execute.c +++ b/c/src/core/client/execute.c @@ -32,26 +32,29 @@ * with this program. If not, see . *******************************************************************************/ -#include "../../nodeselect/cache.h" -#include "../../nodeselect/nodelist.h" #include "../../third-party/crypto/ecdsa.h" #include "../../third-party/crypto/secp256k1.h" #include "../util/data.h" +#include "../util/log.h" #include "client.h" -#include "context_internal.h" #include "keys.h" #include "plugin.h" +#include "request_internal.h" #include #include #include -NONULL static void response_free(in3_ctx_t* ctx) { - assert_in3_ctx(ctx); +NONULL static bool is_raw_http(in3_req_t* ctx) { + return !ctx->nodes && strcmp("in3_http", d_get_string(ctx->requests[0], K_METHOD)) == 0; +} + +NONULL static void response_free(in3_req_t* ctx) { + assert_in3_req(ctx); int nodes_count = 1; if (ctx->nodes) { - nodes_count = ctx_nodes_len(ctx->nodes); - in3_ctx_free_nodes(ctx->nodes); + nodes_count = req_nodes_len(ctx->nodes); + in3_req_free_nodes(ctx->nodes); } if (ctx->raw_response) { for (int i = 0; i < nodes_count; i++) { @@ -85,8 +88,8 @@ NONULL void in3_check_verified_hashes(in3_t* c) { } } -NONULL static void ctx_free_intern(in3_ctx_t* ctx, bool is_sub) { - assert_in3_ctx(ctx); +NONULL static void req_free_intern(in3_req_t* ctx, bool is_sub) { + assert_in3_req(ctx); // only for intern requests, we actually free the original request-string if (is_sub && ctx->request_context) _free(ctx->request_context->c); @@ -98,7 +101,7 @@ NONULL static void ctx_free_intern(in3_ctx_t* ctx, bool is_sub) { if (ctx->requests) _free(ctx->requests); if (ctx->cache) in3_cache_free(ctx->cache, !is_sub); - if (ctx->required) ctx_free_intern(ctx->required, true); + if (ctx->required) req_free_intern(ctx->required, true); in3_check_verified_hashes(ctx->client); _free(ctx); @@ -134,8 +137,8 @@ NONULL static void add_token_to_hash(struct SHA3_CTX* msg_hash, d_token_t* t) { } } -NONULL static in3_ret_t ctx_create_payload(in3_ctx_t* c, sb_t* sb, bool no_in3) { - assert_in3_ctx(c); +NONULL static in3_ret_t ctx_create_payload(in3_req_t* c, sb_t* sb, bool no_in3) { + assert_in3_req(c); assert(sb); char temp[100]; @@ -146,7 +149,7 @@ NONULL static in3_ret_t ctx_create_payload(in3_ctx_t* c, sb_t* sb, bool no_in3) for (uint16_t i = 0; i < c->len; i++) { d_token_t * request_token = c->requests[i], *t; - in3_proof_t proof = no_in3 ? PROOF_NONE : in3_ctx_get_proof(c, i); + in3_proof_t proof = no_in3 ? PROOF_NONE : in3_req_get_proof(c, i); if (msg_hash) sha3_256_Init(msg_hash); if (i > 0) sb_add_char(sb, ','); @@ -161,14 +164,14 @@ NONULL static in3_ret_t ctx_create_payload(in3_ctx_t* c, sb_t* sb, bool no_in3) sb_add_key_value(sb, "jsonrpc", "2.0", 3, true); sb_add_char(sb, ','); if ((t = d_get(request_token, K_METHOD)) == NULL) - return ctx_set_error(c, "missing method-property in request", IN3_EINVAL); + return req_set_error(c, "missing method-property in request", IN3_EINVAL); else sb_add_key_value(sb, "method", d_string(t), add_bytes_to_hash(msg_hash, d_string(t), d_len(t)), true); sb_add_char(sb, ','); if ((t = d_get(request_token, K_PARAMS)) == NULL) sb_add_key_value(sb, "params", "[]", 2, false); else { - if (d_is_binary_ctx(c->request_context)) return ctx_set_error(c, "only text json input is allowed", IN3_EINVAL); + if (d_is_binary_ctx(c->request_context)) return req_set_error(c, "only text json input is allowed", IN3_EINVAL); const str_range_t ps = d_to_json(t); if (msg_hash) add_token_to_hash(msg_hash, t); sb_add_key_value(sb, "params", ps.data, ps.len, false); @@ -180,10 +183,11 @@ NONULL static in3_ret_t ctx_create_payload(in3_ctx_t* c, sb_t* sb, bool no_in3) sb_add_range(sb, temp, 0, sprintf(temp, ",\"chainId\":\"0x%x\"", (unsigned int) rc->chain.chain_id)); // allow plugins to add their metadata - in3_plugin_execute_first_or_none(c, PLGN_ACT_ADD_PAYLOAD, sb); + in3_pay_payload_ctx_t pctx = {.req = c, .request = request_token, .sb = sb}; + TRY(in3_plugin_execute_first_or_none(c, PLGN_ACT_ADD_PAYLOAD, &pctx)) if (msg_hash) { - in3_pay_sign_req_ctx_t sctx = {.ctx = c, .request = request_token, .signature = {0}}; + in3_pay_sign_req_ctx_t sctx = {.req = c, .request = request_token, .signature = {0}}; bytes_t sig_bytes = bytes(sctx.signature, 65); keccak_Final(msg_hash, sctx.request_hash); TRY(in3_plugin_execute_first(c, PLGN_ACT_PAY_SIGN_REQ, &sctx)) @@ -199,7 +203,7 @@ NONULL static in3_ret_t ctx_create_payload(in3_ctx_t* c, sb_t* sb, bool no_in3) s[j] = bytes(c->signers + j * 20, 20); sb_add_bytes(sb, ",\"signers\":", s, c->signers_length, true); } - if ((rc->flags & FLAGS_INCLUDE_CODE) && strcmp(d_get_stringk(request_token, K_METHOD), "eth_call") == 0) + if ((rc->flags & FLAGS_INCLUDE_CODE) && strcmp(d_get_string(request_token, K_METHOD), "eth_call") == 0) sb_add_chars(sb, ",\"includeCode\":true"); if (proof == PROOF_FULL) sb_add_chars(sb, ",\"useFullProof\":true"); @@ -228,8 +232,8 @@ NONULL static in3_ret_t ctx_create_payload(in3_ctx_t* c, sb_t* sb, bool no_in3) } } - in3_pay_handle_ctx_t pctx = {.ctx = c, .payload = sb}; - in3_ret_t ret = in3_plugin_execute_first_or_none(c, PLGN_ACT_PAY_HANDLE, &pctx); + in3_pay_handle_ctx_t payload_ctx = {.req = c, .payload = sb}; + in3_ret_t ret = in3_plugin_execute_first_or_none(c, PLGN_ACT_PAY_HANDLE, &payload_ctx); if (ret != IN3_OK) return ret; @@ -242,39 +246,55 @@ NONULL static in3_ret_t ctx_create_payload(in3_ctx_t* c, sb_t* sb, bool no_in3) return IN3_OK; } -NONULL static in3_ret_t ctx_parse_response(in3_ctx_t* ctx, char* response_data, int len) { - assert_in3_ctx(ctx); +NONULL static in3_ret_t ctx_parse_response(in3_req_t* ctx, char* response_data, int len) { + assert_in3_req(ctx); assert(response_data); assert(len); + if (is_raw_http(ctx)) { + ctx->response_context = (response_data[0] == '{' || response_data[0] == '[') ? parse_json(response_data) : NULL; + if (!ctx->response_context) { + // we create a context only holding the raw data + ctx->response_context = _calloc(1, sizeof(json_ctx_t)); + ctx->response_context->c = response_data; + ctx->response_context->len = 1; + ctx->response_context->result = _calloc(1, sizeof(d_token_t)); + ctx->response_context->result->len = len; + ctx->response_context->result->data = (uint8_t*) response_data; + } + ctx->responses = _malloc(sizeof(d_token_t*)); + ctx->responses[0] = ctx->response_context->result; + return IN3_OK; + } + ctx->response_context = (response_data[0] == '{' || response_data[0] == '[') ? parse_json(response_data) : parse_binary_str(response_data, len); if (!ctx->response_context) - return ctx_set_error(ctx, "Error in JSON-response : ", ctx_set_error(ctx, str_remove_html(response_data), IN3_EINVALDT)); + return req_set_error(ctx, "Error in JSON-response : ", req_set_error(ctx, str_remove_html(response_data), IN3_EINVALDT)); if (d_type(ctx->response_context->result) == T_OBJECT) { // it is a single result ctx->responses = _malloc(sizeof(d_token_t*)); ctx->responses[0] = ctx->response_context->result; - if (ctx->len != 1) return ctx_set_error(ctx, "The response must be an array!", IN3_EINVALDT); + if (ctx->len != 1) return req_set_error(ctx, "The response must be an array!", IN3_EINVALDT); } else if (d_type(ctx->response_context->result) == T_ARRAY) { int i; d_token_t* t = NULL; if (d_len(ctx->response_context->result) != (int) ctx->len) - return ctx_set_error(ctx, "The responses must be a array with the same number as the requests!", IN3_EINVALDT); + return req_set_error(ctx, "The responses must be a array with the same number as the requests!", IN3_EINVALDT); ctx->responses = _malloc(sizeof(d_token_t*) * ctx->len); for (i = 0, t = ctx->response_context->result + 1; i < (int) ctx->len; i++, t = d_next(t)) ctx->responses[i] = t; } else - return ctx_set_error(ctx, "The response must be a Object or Array", IN3_EINVALDT); + return req_set_error(ctx, "The response must be a Object or Array", IN3_EINVALDT); return IN3_OK; } static bool is_user_error(d_token_t* error, char** err_msg) { - *err_msg = d_type(error) == T_STRING ? d_string(error) : d_get_stringk(error, K_MESSAGE); + *err_msg = d_type(error) == T_STRING ? d_string(error) : d_get_string(error, K_MESSAGE); // here we need to find a better way to detect user errors // currently we assume a error-message starting with 'Error:' is a server error and not a user error. return *err_msg && strncmp(*err_msg, "Error:", 6) != 0 && strncmp(*err_msg, "TypeError:", 10) != 0; @@ -292,20 +312,23 @@ NONULL static void clear_response(in3_response_t* response) { } } -static in3_ret_t handle_error_response(in3_ctx_t* ctx, node_match_t* node, in3_response_t* response) { - assert_in3_ctx(ctx); +static in3_ret_t handle_error_response(in3_req_t* ctx, node_match_t* node, in3_response_t* response) { + assert_in3_req(ctx); assert_in3_response(response); + + // and copy the error to the ctx + req_set_error(ctx, response->data.len ? response->data.data : "no response from node", IN3_ERPC); + // we block this node in3_nl_blacklist_ctx_t bctx = {.address = node->address, .is_addr = true}; - if (node && IN3_OK != in3_plugin_execute_first(ctx, PLGN_ACT_NL_BLACKLIST, &bctx)) { - ctx_set_error(ctx, response->data.len ? response->data.data : "no response from node", IN3_ERPC); // and copy the error to the ctx - clear_response(response); // free up memory - } + if (node && IN3_OK != in3_plugin_execute_first(ctx, PLGN_ACT_NL_BLACKLIST, &bctx)) + clear_response(response); // free up memory + return IN3_ERPC; } -static void clean_up_ctx(in3_ctx_t* ctx) { - assert_in3_ctx(ctx); +static void clean_up_ctx(in3_req_t* ctx) { + assert_in3_req(ctx); if (ctx->verification_state != IN3_OK && ctx->verification_state != IN3_WAITING) ctx->verification_state = IN3_WAITING; if (ctx->error) _free(ctx->error); @@ -314,35 +337,31 @@ static void clean_up_ctx(in3_ctx_t* ctx) { ctx->error = NULL; } -static in3_ret_t handle_payment(in3_vctx_t* vc, node_match_t* node, int index) { - in3_ctx_t* ctx = vc->ctx; - in3_pay_followup_ctx_t fctx = {.ctx = ctx, .node = node, .resp_in3 = vc->proof, .resp_error = d_get(ctx->responses[index], K_ERROR)}; - in3_ret_t res = in3_plugin_execute_first_or_none(ctx, PLGN_ACT_PAY_FOLLOWUP, &fctx); - - if (res == IN3_WAITING && ctx->attempt < ctx->client->max_attempts - 1) { - int nodes_count = ctx_nodes_len(ctx->nodes); - // this means we need to retry with the same node - ctx->attempt++; - for (int i = 0; i < nodes_count; i++) { - if (ctx->raw_response[i].data.data) - _free(ctx->raw_response[i].data.data); - } - _free(ctx->raw_response); - _free(ctx->responses); - json_free(ctx->response_context); - - ctx->raw_response = NULL; - ctx->response_context = NULL; - ctx->responses = NULL; - return res; +NONULL in3_ret_t in3_retry_same_node(in3_req_t* ctx) { + int nodes_count = req_nodes_len(ctx->nodes); + // this means we need to retry with the same node + for (int i = 0; i < nodes_count; i++) { + if (ctx->raw_response[i].data.data) + _free(ctx->raw_response[i].data.data); } - else if (res) - return ctx_set_error(ctx, "Error following up the payment data", res); + _free(ctx->raw_response); + _free(ctx->responses); + json_free(ctx->response_context); + + ctx->raw_response = NULL; + ctx->response_context = NULL; + ctx->responses = NULL; return IN3_OK; } -static in3_ret_t verify_response(in3_ctx_t* ctx, in3_chain_t* chain, node_match_t* node, in3_response_t* response) { - assert_in3_ctx(ctx); +static in3_ret_t handle_payment(in3_vctx_t* vc, node_match_t* node, int index) { + in3_req_t* ctx = vc->req; + in3_pay_followup_ctx_t fctx = {.req = ctx, .node = node, .resp_in3 = vc->proof, .resp_error = d_get(ctx->responses[index], K_ERROR)}; + return req_set_error(ctx, "Error following up the payment data", in3_plugin_execute_first_or_none(ctx, PLGN_ACT_PAY_FOLLOWUP, &fctx)); +} + +static in3_ret_t verify_response(in3_req_t* ctx, in3_chain_t* chain, node_match_t* node, in3_response_t* response) { + assert_in3_req(ctx); assert(chain); assert_in3_response(response); @@ -372,24 +391,26 @@ static in3_ret_t verify_response(in3_ctx_t* ctx, in3_chain_t* chain, node_match_ // check each request for (uint_fast16_t i = 0; i < ctx->len; i++) { in3_vctx_t vc; - vc.ctx = ctx; + vc.req = ctx; vc.chain = chain; vc.request = ctx->requests[i]; vc.result = d_get(ctx->responses[i], K_RESULT); vc.client = ctx->client; vc.index = (int) i; + vc.method = d_get_string(vc.request, K_METHOD); vc.node = node; vc.dont_blacklist = false; + vc.proof = d_get(ctx->responses[i], K_IN3); // vc.proof is temporary set to the in3-section. It will be updated to real proof in the next lines. + res = handle_payment(&vc, node, i); - if ((vc.proof = d_get(ctx->responses[i], K_IN3))) { // vc.proof is temporary set to the in3-section. It will be updated to real proof in the next lines. - if ((res = handle_payment(&vc, node, i))) return res; - vc.last_validator_change = d_get_longk(vc.proof, K_LAST_VALIDATOR_CHANGE); - vc.currentBlock = d_get_longk(vc.proof, K_CURRENT_BLOCK); + if (vc.proof) { // vc.proof is temporary set to the in3-section. It will be updated to real proof in the next lines. + vc.last_validator_change = d_get_long(vc.proof, K_LAST_VALIDATOR_CHANGE); + vc.currentBlock = d_get_long(vc.proof, K_CURRENT_BLOCK); vc.proof = d_get(vc.proof, K_PROOF); } // no result? - if (!vc.result) { + if (!res && !vc.result) { char* err_msg; // if we don't have a result, the node reported an error if (is_user_error(d_get(ctx->responses[i], K_ERROR), &err_msg)) { @@ -400,12 +421,12 @@ static in3_ret_t verify_response(in3_ctx_t* ctx, in3_chain_t* chain, node_match_ in3_log_debug("we have a system-error from node, so we block it ..\n"); in3_nl_blacklist_ctx_t bctx = {.address = node->address, .is_addr = true}; in3_plugin_execute_first(ctx, PLGN_ACT_NL_BLACKLIST, &bctx); - return ctx_set_error(ctx, err_msg ? err_msg : "Invalid response", IN3_EINVAL); + return req_set_error(ctx, err_msg ? err_msg : "Invalid response", IN3_EINVAL); } } // verify the response - res = ctx->verification_state = in3_plugin_execute_first(ctx, PLGN_ACT_RPC_VERIFY, &vc); + if (res == IN3_OK) res = ctx->verification_state = in3_plugin_execute_first(ctx, PLGN_ACT_RPC_VERIFY, &vc); // Waiting is ok, but we stop here if (res == IN3_WAITING) @@ -435,10 +456,14 @@ static in3_ret_t verify_response(in3_ctx_t* ctx, in3_chain_t* chain, node_match_ return (ctx->verification_state = IN3_OK); } -static in3_ret_t find_valid_result(in3_ctx_t* ctx, int nodes_count, in3_response_t* response, in3_chain_t* chain, node_match_t** vnode) { - node_match_t* node = ctx->nodes; - bool still_pending = false; - in3_ret_t state = IN3_ERPC; +static in3_ret_t find_valid_result(in3_req_t* ctx, node_match_t** vnode) { + + int nodes_count = ctx->nodes == NULL ? 1 : req_nodes_len(ctx->nodes); + in3_response_t* response = ctx->raw_response; + in3_chain_t* chain = &ctx->client->chain; + node_match_t* node = ctx->nodes; + bool still_pending = false; + in3_ret_t state = IN3_ERPC; // blacklist nodes for missing response for (int n = 0; n < nodes_count; n++, node = node ? node->next : NULL) { @@ -451,7 +476,7 @@ static in3_ret_t find_valid_result(in3_ctx_t* ctx, int nodes_count, in3_response state = verify_response(ctx, chain, node, response + n); if (state == IN3_OK) { - in3_log_debug(COLOR_GREEN "accepted response for %s from %s\n" COLOR_RESET, d_get_stringk(ctx->requests[0], K_METHOD), node ? node->url : "intern"); + in3_log_debug(COLOR_GREEN "accepted response for %s from %s\n" COLOR_RESET, d_get_string(ctx->requests[0], K_METHOD), node ? node->url : "intern"); break; } else if (state == IN3_WAITING) @@ -480,27 +505,73 @@ static in3_ret_t find_valid_result(in3_ctx_t* ctx, int nodes_count, in3_response return IN3_OK; } -NONULL in3_request_t* in3_create_request(in3_ctx_t* ctx) { - switch (in3_ctx_state(ctx)) { - case CTX_ERROR: - ctx_set_error(ctx, "You cannot create an request if the was an error!", IN3_EINVAL); +NONULL in3_http_request_t* in3_create_request(in3_req_t* ctx) { + switch (in3_req_state(ctx)) { + case REQ_ERROR: + req_set_error(ctx, "You cannot create an request if the was an error!", IN3_EINVAL); return NULL; - case CTX_SUCCESS: + case REQ_SUCCESS: return NULL; - case CTX_WAITING_FOR_RESPONSE: - ctx_set_error(ctx, "There are pending requests, finish them before creating a new one!", IN3_EINVAL); + case REQ_WAITING_FOR_RESPONSE: + req_set_error(ctx, "There are pending requests, finish them before creating a new one!", IN3_EINVAL); return NULL; - case CTX_WAITING_TO_SEND: { - in3_ctx_t* p = ctx; + case REQ_WAITING_TO_SEND: { + in3_req_t* p = ctx; for (; p; p = p->required) { if (!p->raw_response) ctx = p; } } } + if (is_raw_http(ctx)) { + // prepare response-object + d_token_t* params = d_get(ctx->requests[0], K_PARAMS); + if (d_len(params) < 2) { + req_set_error(ctx, "invalid number of arguments, must be [METHOD,URL,PAYLOAD,HEADER]", IN3_EINVAL); + return NULL; + } + char* method = d_get_string_at(params, 0); + d_token_t* tmp = d_get_at(params, 2); + in3_http_request_t* request = _calloc(sizeof(in3_http_request_t), 1); + request->req = ctx; + request->urls_len = 1; + request->urls = _malloc(sizeof(char*)); + request->urls[0] = _strdupn(d_get_string_at(params, 1), -1); + request->method = method ? method : (*request->payload ? "POST" : "GET"); + ctx->raw_response = _calloc(sizeof(in3_response_t), 1); + ctx->raw_response[0].state = IN3_WAITING; + + switch (d_type(tmp)) { + case T_NULL: + request->payload = _calloc(1, 1); + break; + case T_STRING: + request->payload = _strdupn(d_string(tmp), -1); + request->payload_len = d_len(tmp); + break; + case T_BYTES: + request->payload = _strdupn((void*) tmp->data, tmp->len); + request->payload_len = d_len(tmp); + break; + default: + request->payload = d_create_json(ctx->request_context, tmp); + request->payload_len = strlen(request->payload); + break; + } + + for (d_iterator_t iter = d_iter(d_get_at(params, 3)); iter.left; d_iter_next(&iter)) { + in3_req_header_t* t = _malloc(sizeof(in3_req_header_t)); + t->value = d_string(iter.token); + t->next = request->headers; + request->headers = t; + } + + return request; + } + in3_ret_t res; - char* rpc = d_get_stringk(d_get(ctx->requests[0], K_IN3), K_RPC); - int nodes_count = rpc ? 1 : ctx_nodes_len(ctx->nodes); + char* rpc = d_get_string(d_get(ctx->requests[0], K_IN3), K_RPC); + int nodes_count = rpc ? 1 : req_nodes_len(ctx->nodes); char** urls = nodes_count ? _malloc(sizeof(char*) * nodes_count) : NULL; node_match_t* node = ctx->nodes; @@ -522,18 +593,20 @@ NONULL in3_request_t* in3_create_request(in3_ctx_t* ctx) { sb_free(payload); free_urls(urls, nodes_count); // since we cannot return an error, we set the error in the context and return NULL, indicating the error. - ctx_set_error(ctx, "could not generate the payload", res); + req_set_error(ctx, "could not generate the payload", res); return NULL; } // prepare response-object - in3_request_t* request = _calloc(sizeof(in3_request_t), 1); - request->ctx = ctx; - request->payload = payload->data; - request->urls_len = nodes_count; - request->urls = urls; - request->cptr = NULL; - request->wait = d_get_intk(d_get(ctx->requests[0], K_IN3), K_WAIT); + in3_http_request_t* request = _calloc(sizeof(in3_http_request_t), 1); + request->req = ctx; + request->payload = payload->data; + request->payload_len = payload->len; + request->urls_len = nodes_count; + request->urls = urls; + request->cptr = NULL; + request->wait = d_get_int(d_get(ctx->requests[0], K_IN3), K_WAIT); + request->method = payload->len ? "POST" : "GET"; if (!nodes_count) nodes_count = 1; // at least one result, because for internal response we don't need nodes, but a result big enough. ctx->raw_response = _calloc(sizeof(in3_response_t), nodes_count); @@ -545,45 +618,49 @@ NONULL in3_request_t* in3_create_request(in3_ctx_t* ctx) { return request; } -NONULL void request_free(in3_request_t* req) { +NONULL void request_free(in3_http_request_t* req) { // free resources free_urls(req->urls, req->urls_len); + for (in3_req_header_t* h = req->headers; h; h = req->headers) { + req->headers = h->next; + _free(h); + } _free(req->payload); _free(req); } -NONULL static bool ctx_is_allowed_to_fail(in3_ctx_t* ctx) { - return ctx_is_method(ctx, "in3_nodeList"); +NONULL static bool ctx_is_allowed_to_fail(in3_req_t* ctx) { + return req_is_method(ctx, "in3_nodeList"); } -in3_ctx_t* in3_ctx_last_waiting(in3_ctx_t* ctx) { - in3_ctx_t* last = ctx; +in3_req_t* in3_req_last_waiting(in3_req_t* ctx) { + in3_req_t* last = ctx; for (; ctx; ctx = ctx->required) { if (!ctx->response_context) last = ctx; } return last; } -static void init_sign_ctx(in3_ctx_t* ctx, in3_sign_ctx_t* sign_ctx) { +static void init_sign_ctx(in3_req_t* ctx, in3_sign_ctx_t* sign_ctx) { d_token_t* params = d_get(ctx->requests[0], K_PARAMS); sign_ctx->message = d_to_bytes(d_get_at(params, 0)); sign_ctx->account = d_to_bytes(d_get_at(params, 1)); sign_ctx->type = SIGN_EC_HASH; - sign_ctx->ctx = ctx; + sign_ctx->req = ctx; sign_ctx->signature = bytes(NULL, 0); } -in3_sign_ctx_t* create_sign_ctx(in3_ctx_t* ctx) { +in3_sign_ctx_t* create_sign_ctx(in3_req_t* ctx) { in3_sign_ctx_t* res = _malloc(sizeof(in3_sign_ctx_t)); init_sign_ctx(ctx, res); return res; } -in3_ret_t in3_handle_sign(in3_ctx_t* ctx) { +in3_ret_t in3_handle_sign(in3_req_t* ctx) { in3_sign_ctx_t sign_ctx; init_sign_ctx(ctx, &sign_ctx); - if (!sign_ctx.message.data) return ctx_set_error(ctx, "missing data to sign", IN3_ECONFIG); - if (!sign_ctx.account.data) return ctx_set_error(ctx, "missing account to sign", IN3_ECONFIG); + if (!sign_ctx.message.data) return req_set_error(ctx, "missing data to sign", IN3_ECONFIG); + if (!sign_ctx.account.data) return req_set_error(ctx, "missing account to sign", IN3_ECONFIG); ctx->raw_response = _calloc(sizeof(in3_response_t), 1); sb_init(&ctx->raw_response[0].data); @@ -596,7 +673,7 @@ in3_ret_t in3_handle_sign(in3_ctx_t* ctx) { } typedef struct { - in3_ctx_t* ctx; + in3_req_t* req; void* ptr; } ctx_req_t; typedef struct { @@ -604,13 +681,13 @@ typedef struct { ctx_req_t* req; } ctx_req_transports_t; -static void transport_cleanup(in3_ctx_t* ctx, ctx_req_transports_t* transports, bool free_all) { +static void transport_cleanup(in3_req_t* ctx, ctx_req_transports_t* transports, bool free_all) { for (int i = 0; i < transports->len; i++) { - if (free_all || transports->req[i].ctx == ctx) { - in3_request_t req = {.ctx = ctx, .cptr = transports->req[i].ptr, .urls_len = 0, .urls = NULL, .payload = NULL}; + if (free_all || transports->req[i].req == ctx) { + in3_http_request_t req = {.req = ctx, .cptr = transports->req[i].ptr, .urls_len = 0, .urls = NULL, .payload = NULL}; in3_plugin_execute_first_or_none(ctx, PLGN_ACT_TRANSPORT_CLEAN, &req); if (!free_all) { - transports->req[i].ctx = NULL; + transports->req[i].req = NULL; return; } } @@ -618,12 +695,12 @@ static void transport_cleanup(in3_ctx_t* ctx, ctx_req_transports_t* transports, if (free_all && transports->req) _free(transports->req); } -static void in3_handle_rpc_next(in3_ctx_t* ctx, ctx_req_transports_t* transports) { +static void in3_handle_rpc_next(in3_req_t* ctx, ctx_req_transports_t* transports) { in3_log_debug("waiting for the next response ...\n"); - ctx = in3_ctx_last_waiting(ctx); + ctx = in3_req_last_waiting(ctx); for (int i = 0; i < transports->len; i++) { - if (transports->req[i].ctx == ctx) { - in3_request_t req = {.ctx = ctx, .cptr = transports->req[i].ptr, .urls_len = 0, .urls = NULL, .payload = NULL}; + if (transports->req[i].req == ctx) { + in3_http_request_t req = {.req = ctx, .cptr = transports->req[i].ptr, .urls_len = 0, .urls = NULL, .payload = NULL}; in3_plugin_execute_first(ctx, PLGN_ACT_TRANSPORT_RECEIVE, &req); #ifdef DEBUG node_match_t* w = ctx->nodes; @@ -645,12 +722,12 @@ static void in3_handle_rpc_next(in3_ctx_t* ctx, ctx_req_transports_t* transports } } - ctx_set_error(ctx, "waiting to fetch more responses, but no cptr was registered", IN3_ENOTSUP); + req_set_error(ctx, "waiting to fetch more responses, but no cptr was registered", IN3_ENOTSUP); } -void in3_handle_rpc(in3_ctx_t* ctx, ctx_req_transports_t* transports) { +void in3_handle_rpc(in3_req_t* ctx, ctx_req_transports_t* transports) { // if we can't create the request, this function will put it into error-state - in3_request_t* request = in3_create_request(ctx); + in3_http_request_t* request = in3_create_request(ctx); if (!request) return; // do we need to wait? @@ -667,14 +744,14 @@ void in3_handle_rpc(in3_ctx_t* ctx, ctx_req_transports_t* transports) { in3_plugin_execute_first(ctx, PLGN_ACT_TRANSPORT_SEND, request); // debug output - node_match_t* node = request->ctx->nodes; + node_match_t* node = request->req->nodes; for (unsigned int i = 0; i < request->urls_len; i++, node = node ? node->next : NULL) { - if (request->ctx->raw_response[i].state != IN3_WAITING) { - char* data = request->ctx->raw_response[i].data.data; + if (request->req->raw_response[i].state != IN3_WAITING) { + char* data = request->req->raw_response[i].data.data; #ifdef DEBUG data = format_json(data); #endif - in3_log_trace(request->ctx->raw_response[i].state + in3_log_trace(request->req->raw_response[i].state ? "... response(%s): \n... " COLOR_RED_STR "\n" : "... response(%s): \n... " COLOR_GREEN_STR "\n", node ? node->url : "intern", data); @@ -689,7 +766,7 @@ void in3_handle_rpc(in3_ctx_t* ctx, ctx_req_transports_t* transports) { // find a free spot int index = -1; for (int i = 0; i < transports->len; i++) { - if (!transports->req[i].ctx) { + if (!transports->req[i].req) { index = i; break; } @@ -700,7 +777,7 @@ void in3_handle_rpc(in3_ctx_t* ctx, ctx_req_transports_t* transports) { } // store the pointers - transports->req[index].ctx = request->ctx; + transports->req[index].req = request->req; transports->req[index].ptr = request->cptr; } @@ -708,24 +785,24 @@ void in3_handle_rpc(in3_ctx_t* ctx, ctx_req_transports_t* transports) { request_free(request); } -in3_ret_t in3_send_ctx(in3_ctx_t* ctx) { +in3_ret_t in3_send_req(in3_req_t* ctx) { ctx_req_transports_t transports = {0}; while (true) { - switch (in3_ctx_exec_state(ctx)) { - case CTX_ERROR: - case CTX_SUCCESS: + switch (in3_req_exec_state(ctx)) { + case REQ_ERROR: + case REQ_SUCCESS: transport_cleanup(ctx, &transports, true); return ctx->verification_state; - case CTX_WAITING_FOR_RESPONSE: + case REQ_WAITING_FOR_RESPONSE: in3_handle_rpc_next(ctx, &transports); break; - case CTX_WAITING_TO_SEND: { - in3_ctx_t* last = in3_ctx_last_waiting(ctx); + case REQ_WAITING_TO_SEND: { + in3_req_t* last = in3_req_last_waiting(ctx); switch (last->type) { - case CT_SIGN: + case RT_SIGN: in3_handle_sign(last); break; - case CT_RPC: + case RT_RPC: in3_handle_rpc(last, &transports); } } @@ -737,7 +814,7 @@ in3_ret_t in3_send_ctx(in3_ctx_t* ctx) { * helper function to set the signature on the signer context and rpc context */ void in3_sign_ctx_set_signature( - in3_ctx_t* ctx, + in3_req_t* ctx, in3_sign_ctx_t* sign_ctx) { ctx->raw_response = _calloc(sizeof(in3_response_t), 1); sb_init(&ctx->raw_response[0].data); @@ -745,32 +822,32 @@ void in3_sign_ctx_set_signature( _free(sign_ctx->signature.data); } -in3_ctx_t* ctx_find_required(const in3_ctx_t* parent, const char* search_method) { - in3_ctx_t* sub_ctx = parent->required; +in3_req_t* req_find_required(const in3_req_t* parent, const char* search_method) { + in3_req_t* sub_ctx = parent->required; while (sub_ctx) { if (!sub_ctx->requests) continue; - if (ctx_is_method(sub_ctx, search_method)) return sub_ctx; + if (req_is_method(sub_ctx, search_method)) return sub_ctx; sub_ctx = sub_ctx->required; } return NULL; } -in3_ret_t ctx_add_required(in3_ctx_t* parent, in3_ctx_t* ctx) { +in3_ret_t req_add_required(in3_req_t* parent, in3_req_t* ctx) { // printf(" ++ add required %s > %s\n", ctx_name(parent), ctx_name(ctx)); ctx->required = parent->required; parent->required = ctx; - return in3_ctx_execute(ctx); + return in3_req_execute(ctx); } -in3_ret_t ctx_remove_required(in3_ctx_t* parent, in3_ctx_t* ctx, bool rec) { +in3_ret_t req_remove_required(in3_req_t* parent, in3_req_t* ctx, bool rec) { if (!ctx) return IN3_OK; - in3_ctx_t* p = parent; + in3_req_t* p = parent; while (p) { if (p->required == ctx) { // printf(" -- remove required %s > %s\n", ctx_name(parent), ctx_name(ctx)); - in3_ctx_t* next = rec ? NULL : ctx->required; + in3_req_t* next = rec ? NULL : ctx->required; if (!rec) ctx->required = NULL; - ctx_free_intern(ctx, true); + req_free_intern(ctx, true); p->required = next; return IN3_OK; } @@ -779,121 +856,143 @@ in3_ret_t ctx_remove_required(in3_ctx_t* parent, in3_ctx_t* ctx, bool rec) { return IN3_EFIND; } -in3_ctx_state_t in3_ctx_state(in3_ctx_t* ctx) { - if (ctx == NULL) return CTX_SUCCESS; - in3_ctx_state_t required_state = ctx->required ? in3_ctx_state(ctx->required) : CTX_SUCCESS; - if (required_state == CTX_ERROR || ctx->error) return CTX_ERROR; - if (ctx->required && required_state != CTX_SUCCESS) return required_state; - if (!ctx->raw_response) return CTX_WAITING_TO_SEND; - if (ctx->type == CT_RPC && !ctx->response_context) return CTX_WAITING_FOR_RESPONSE; - if (ctx->type == CT_SIGN && ctx->raw_response->state == IN3_WAITING) return CTX_WAITING_FOR_RESPONSE; - return CTX_SUCCESS; +in3_req_state_t in3_req_state(in3_req_t* ctx) { + if (ctx == NULL) return REQ_SUCCESS; + in3_req_state_t required_state = ctx->required ? in3_req_state(ctx->required) : REQ_SUCCESS; + if (required_state == REQ_ERROR || ctx->error) return REQ_ERROR; + if (ctx->required && required_state != REQ_SUCCESS) return required_state; + if (!ctx->raw_response) return REQ_WAITING_TO_SEND; + if (ctx->type == RT_RPC && !ctx->response_context) return REQ_WAITING_FOR_RESPONSE; + if (ctx->type == RT_SIGN && ctx->raw_response->state == IN3_WAITING) return REQ_WAITING_FOR_RESPONSE; + return REQ_SUCCESS; } -void ctx_free(in3_ctx_t* ctx) { - if (ctx) ctx_free_intern(ctx, false); +void req_free(in3_req_t* ctx) { + if (ctx) req_free_intern(ctx, false); } -static inline in3_ret_t handle_internally(in3_ctx_t* ctx) { +static inline in3_ret_t handle_internally(in3_req_t* ctx) { if (ctx->len != 1) return IN3_OK; // currently we do not support bulk requests forr internal calls - in3_rpc_handle_ctx_t vctx = {.ctx = ctx, .response = &ctx->raw_response, .request = ctx->requests[0]}; + in3_rpc_handle_ctx_t vctx = {.req = ctx, .response = &ctx->raw_response, .request = ctx->requests[0], .method = d_get_string(ctx->requests[0], K_METHOD), .params = d_get(ctx->requests[0], K_PARAMS)}; in3_ret_t res = in3_plugin_execute_first_or_none(ctx, PLGN_ACT_RPC_HANDLE, &vctx); if (res == IN3_OK && ctx->raw_response && ctx->raw_response->data.data) in3_log_debug("internal response: %s\n", ctx->raw_response->data.data); return res == IN3_EIGNORE ? IN3_OK : res; } -in3_ctx_state_t in3_ctx_exec_state(in3_ctx_t* ctx) { - in3_ctx_execute(ctx); - return in3_ctx_state(ctx); +static inline char* get_error_message(in3_req_t* ctx, in3_ret_t e) { + if (e == IN3_WAITING) return NULL; + for (; ctx; ctx = ctx->required) { + if (ctx->error) return ctx->error; + } + + return in3_errmsg(e); } -in3_ret_t in3_ctx_execute(in3_ctx_t* ctx) { +in3_req_state_t in3_req_exec_state(in3_req_t* req) { + in3_req_execute(req); + return in3_req_state(req); +} + +static inline in3_ret_t select_nodes(in3_req_t* req) { + in3_ret_t ret = IN3_OK; + + // we only need to pick nodes, if we don't have an anser or no nodes picked + if (req->raw_response || req->nodes) return ret; + + // if the request has a rpc-url or a REST-request, we don't pick nodes. + if (d_get(d_get(req->requests[0], K_IN3), K_RPC) || is_raw_http(req)) return ret; + + // pick data nodes first + in3_nl_pick_ctx_t pctx = {.type = NL_DATA, .req = req}; + if ((ret = in3_plugin_execute_first(req, PLGN_ACT_NL_PICK, &pctx))) // did a plugin select the nodes successfully? + return req_set_error(req, "could not find any node", // report the error + ret < 0 && ret != IN3_WAITING && ctx_is_allowed_to_fail(req) ? IN3_EIGNORE : ret); // the error-code depends if it is allowed to fail + + // pick signer nodes now + pctx.type = NL_SIGNER; // we now select the signer-nodes + if ((ret = in3_plugin_execute_first(req, PLGN_ACT_NL_PICK, &pctx)) < 0) // did it fail? + return req_set_error(req, "error configuring the config for request", // report the error + ret < 0 && ret != IN3_WAITING && ctx_is_allowed_to_fail(req) ? IN3_EIGNORE : ret); // the error-code depends if it is allowed to fail + + // if a plugin needs to prepare some payment, now is a good time.... + return in3_plugin_execute_first_or_none(req, PLGN_ACT_PAY_PREPARE, req); +} + +in3_ret_t in3_req_execute(in3_req_t* req) { in3_ret_t ret = IN3_OK; // if there is an error it does not make sense to execute. - if (ctx->error) return (ctx->verification_state && ctx->verification_state != IN3_WAITING) ? ctx->verification_state : IN3_EUNKNOWN; + if (req->error) return (req->verification_state && req->verification_state != IN3_WAITING) ? req->verification_state : IN3_EUNKNOWN; // is it a valid request? - if (!ctx->request_context || d_type(d_get(ctx->requests[0], K_METHOD)) != T_STRING) return ctx_set_error(ctx, "No Method defined", IN3_ECONFIG); + if (!req->request_context || d_type(d_get(req->requests[0], K_METHOD)) != T_STRING) return req_set_error(req, "No Method defined", IN3_ECONFIG); // if there is response we are done. - if (ctx->response_context && ctx->verification_state == IN3_OK) return IN3_OK; + if (req->response_context && req->verification_state == IN3_OK) return IN3_OK; // if we have required-contextes, we need to check them first - if (ctx->required && (ret = in3_ctx_execute(ctx->required))) { + if (req->required && (ret = in3_req_execute(req->required))) { if (ret == IN3_EIGNORE) - in3_plugin_execute_first(ctx, PLGN_ACT_NL_FAILABLE, ctx); + in3_plugin_execute_first(req, PLGN_ACT_NL_FAILABLE, req); else - return ctx_set_error(ctx, ctx->required->error ? ctx->required->error : "error handling subrequest", ret); + return req_set_error(req, get_error_message(req->required, ret), ret); } - in3_log_debug("ctx_execute %s ... attempt %i\n", d_get_stringk(ctx->requests[0], K_METHOD), ctx->attempt + 1); + in3_log_debug("ctx_execute %s ... attempt %i\n", d_get_string(req->requests[0], K_METHOD), req->attempt + 1); - switch (ctx->type) { - case CT_RPC: { + switch (req->type) { + case RT_RPC: { // do we need to handle it internaly? - if (!ctx->raw_response && !ctx->response_context && (ret = handle_internally(ctx)) < 0) - return ctx->error ? ret : ctx_set_error(ctx, "The request could not be handled", ret); + if (!req->raw_response && !req->response_context && (ret = handle_internally(req)) < 0) + return req->error ? ret : req_set_error(req, get_error_message(req, ret), ret); // if we don't have a nodelist, we try to get it. - if (!ctx->raw_response && !ctx->nodes && !d_get(d_get(ctx->requests[0], K_IN3), K_RPC)) { - in3_nl_pick_ctx_t pctx = {.type = NL_DATA, .ctx = ctx}; - if ((ret = in3_plugin_execute_first(ctx, PLGN_ACT_NL_PICK, &pctx)) == IN3_OK) { - pctx.type = NL_SIGNER; - if ((ret = in3_plugin_execute_first(ctx, PLGN_ACT_NL_PICK, &pctx)) < 0) - return ctx_set_error(ctx, "error configuring the config for request", ret < 0 && ret != IN3_WAITING && ctx_is_allowed_to_fail(ctx) ? IN3_EIGNORE : ret); - - if ((ret = in3_plugin_execute_first_or_none(ctx, PLGN_ACT_PAY_PREPARE, ctx)) != IN3_OK) return ret; - } - else - // since we could not get the nodes, we either report it as error or wait. - return ctx_set_error(ctx, "could not find any node", ret < 0 && ret != IN3_WAITING && ctx_is_allowed_to_fail(ctx) ? IN3_EIGNORE : ret); - } + if ((ret = select_nodes(req))) return ret; // if we still don't have an response, we keep on waiting - if (!ctx->raw_response) return IN3_WAITING; + if (!req->raw_response) return IN3_WAITING; // ok, we have a response, then we try to evaluate the responses // verify responses and return the node with the correct result. node_match_t* node = NULL; - ret = find_valid_result(ctx, ctx->nodes == NULL ? 1 : ctx_nodes_len(ctx->nodes), ctx->raw_response, &ctx->client->chain, &node); - if (ret == IN3_OK) { - in3_nl_followup_ctx_t fctx = {.ctx = ctx, .node = node}; - in3_plugin_execute_first_or_none(ctx, PLGN_ACT_NL_PICK_FOLLOWUP, &fctx); + if ((ret = find_valid_result(req, &node)) == IN3_OK) { + // allow payments to to handle post actions + in3_nl_followup_ctx_t fctx = {.req = req, .node = node}; + in3_plugin_execute_first_or_none(req, PLGN_ACT_NL_PICK_FOLLOWUP, &fctx); } // we wait or are have successfully verified the response if (ret == IN3_WAITING || ret == IN3_OK) return ret; - // if not, then we clean up - response_free(ctx); + // we count this is an attempt ( if the raw_response is null, it means we retry because of payments, so we don't count it) + if (req->raw_response) req->attempt++; - // we count this is an attempt - ctx->attempt++; + // if not, then we clean up + response_free(req); // should we retry? - if (ctx->attempt < ctx->client->max_attempts) { + if (req->attempt < req->client->max_attempts) { in3_log_debug("Retrying send request...\n"); // reset the error and try again - if (ctx->error) _free(ctx->error); - ctx->error = NULL; - ctx->verification_state = IN3_WAITING; + if (req->error) _free(req->error); + req->error = NULL; + req->verification_state = IN3_WAITING; // now try again, which should end in waiting for the next request. - return in3_ctx_execute(ctx); + return in3_req_execute(req); } else { - if (ctx_is_allowed_to_fail(ctx)) - ctx->verification_state = ret = IN3_EIGNORE; + if (ctx_is_allowed_to_fail(req)) + req->verification_state = ret = IN3_EIGNORE; // we give up - return ctx->error ? (ret ? ret : IN3_ERPC) : ctx_set_error(ctx, "reaching max_attempts and giving up", IN3_ELIMIT); + return req->error ? (ret ? ret : IN3_ERPC) : req_set_error(req, "reaching max_attempts and giving up", IN3_ELIMIT); } } - case CT_SIGN: { - if (!ctx->raw_response || ctx->raw_response->state == IN3_WAITING) + case RT_SIGN: { + if (!req->raw_response || req->raw_response->state == IN3_WAITING) return IN3_WAITING; - else if (ctx->raw_response->state) + else if (req->raw_response->state) return IN3_ERPC; return IN3_OK; } diff --git a/c/src/core/client/plugin.h b/c/src/core/client/plugin.h index 559c22adb..5d8601723 100644 --- a/c/src/core/client/plugin.h +++ b/c/src/core/client/plugin.h @@ -45,12 +45,12 @@ extern "C" { #endif #include "client.h" -#include "context.h" +#include "request.h" // ---------- plugin management ----------------- /** checks if a plugin for specified action is registered with the client */ -#define in3_plugin_is_registered(client, action) ((client)->plugin_acts & (action)) +#define in3_plugin_is_registered(client, action) (((client)->plugin_acts & (action)) == (action)) /** registers a plugin with the client */ in3_ret_t in3_plugin_register( @@ -72,24 +72,21 @@ in3_ret_t in3_plugin_execute_all(in3_t* c, in3_plugin_act_t action, void* plugin /** * executes all plugin actions one-by-one, stops when a plugin returns anything other than IN3_EIGNORE. * returns IN3_EPLGN_NONE if no plugin was able to handle specified action, otherwise returns IN3_OK - * plugin errors are reported via the in3_ctx_t + * plugin errors are reported via the in3_req_t */ -in3_ret_t in3_plugin_execute_first(in3_ctx_t* ctx, in3_plugin_act_t action, void* plugin_ctx); +in3_ret_t in3_plugin_execute_first(in3_req_t* req, in3_plugin_act_t action, void* plugin_ctx); /** * same as in3_plugin_execute_first(), but returns IN3_OK even if no plugin could handle specified action */ -in3_ret_t in3_plugin_execute_first_or_none(in3_ctx_t* ctx, in3_plugin_act_t action, void* plugin_ctx); +in3_ret_t in3_plugin_execute_first_or_none(in3_req_t* req, in3_plugin_act_t action, void* plugin_ctx); /** * get direct access to plugin data (if registered) based on action function */ static inline void* in3_plugin_get_data(in3_t* c, in3_plugin_act_fn fn) { - in3_plugin_t* p = c->plugins; - while (p) { - if (p->action_fn == fn) - return p->data; - p = p->next; + for (in3_plugin_t* p = c->plugins; p; p = p->next) { + if (p->action_fn == fn) return p->data; } return NULL; } @@ -100,9 +97,11 @@ static inline void* in3_plugin_get_data(in3_t* c, in3_plugin_act_fn fn) { * verification context holding the pointers to all relevant toknes. */ typedef struct { - in3_ctx_t* ctx; /**< Request context. */ + in3_req_t* req; /**< Request context. */ d_token_t* request; /**< request */ in3_response_t** response; /**< the responses which a prehandle-method should set*/ + char* method; /**< the method of the request */ + d_token_t* params; /**< the params */ } in3_rpc_handle_ctx_t; /** @@ -132,45 +131,83 @@ NONULL in3_ret_t in3_rpc_handle_with_int(in3_rpc_handle_ctx_t* hctx, uint64_t va // -------------- TRANSPORT ------------- +/** + * optional request headers + */ +typedef struct in3_req_header { + char* value; /**< the value */ + struct in3_req_header* next; /**< pointer to next header */ +} in3_req_header_t; + /** request-object. * * represents a RPC-request */ -typedef struct in3_request { - char* payload; /**< the payload to send */ - char** urls; /**< array of urls */ - uint_fast16_t urls_len; /**< number of urls */ - struct in3_ctx* ctx; /**< the current context */ - void* cptr; /**< a custom ptr to hold information during */ - uint32_t wait; /**< time in ms to wait before sending out the request */ -} in3_request_t; +typedef struct in3_http_request { + char* method; /**< the http-method to be used */ + char* payload; /**< the payload to send */ + char** urls; /**< array of urls */ + uint_fast16_t urls_len; /**< number of urls */ + uint32_t payload_len; /**< length of the payload in bytes. */ + struct in3_req* req; /**< the current context */ + void* cptr; /**< a custom ptr to hold information during */ + uint32_t wait; /**< time in ms to wait before sending out the request */ + in3_req_header_t* headers; /**< optional additional headers to be send with the request */ +} in3_http_request_t; /** - * getter to retrieve the payload from a in3_request_t struct + * getter to retrieve the payload from a in3_http_request_t struct */ char* in3_get_request_payload( - in3_request_t* request /**< request struct */ + in3_http_request_t* request /**< request struct */ +); +/** + * getter to retrieve the length of the payload from a in3_http_request_t struct + */ +uint32_t in3_get_request_payload_len( + in3_http_request_t* request /**< request struct */ +); + +/** + * getter to retrieve the urls list length from a in3_http_request_t struct + */ +int in3_get_request_headers_len( + in3_http_request_t* request /**< request struct */ +); +/** + * getter to retrieve the urls list length from a in3_http_request_t struct + */ +char* in3_get_request_headers_at( + in3_http_request_t* request, /**< request struct */ + int index /**< the inde xof the header */ +); + +/** + * getter to retrieve the http-method from a in3_http_request_t struct + */ +char* in3_get_request_method( + in3_http_request_t* request /**< request struct */ ); /** - * getter to retrieve the urls list from a in3_request_t struct + * getter to retrieve the urls list from a in3_http_request_t struct */ char** in3_get_request_urls( - in3_request_t* request /**< request struct */ + in3_http_request_t* request /**< request struct */ ); /** - * getter to retrieve the urls list length from a in3_request_t struct + * getter to retrieve the urls list length from a in3_http_request_t struct */ int in3_get_request_urls_len( - in3_request_t* request /**< request struct */ + in3_http_request_t* request /**< request struct */ ); /** - * getter to retrieve the urls list length from a in3_request_t struct + * getter to retrieve the urls list length from a in3_http_request_t struct */ uint32_t in3_get_request_timeout( - in3_request_t* request /**< request struct */ + in3_http_request_t* request /**< request struct */ ); /** @@ -178,12 +215,12 @@ uint32_t in3_get_request_timeout( * This function should be used in the transport-function to set the response. */ NONULL void in3_req_add_response( - in3_request_t* req, /**< [in]the the request */ - int index, /**< [in] the index of the url, since this request could go out to many urls */ - bool is_error, /**< [in] if true this will be reported as error. the message should then be the error-message */ - const char* data, /**< the data or the the string*/ - int data_len, /**< the length of the data or the the string (use -1 if data is a null terminated string)*/ - uint32_t time /**< the time this request took in ms or 0 if not possible (it will be used to calculate the weights)*/ + in3_http_request_t* req, /**< [in]the the request */ + int index, /**< [in] the index of the url, since this request could go out to many urls */ + int error, /**< [in] if <0 this will be reported as error. the message should then be the error-message */ + const char* data, /**< the data or the the string*/ + int data_len, /**< the length of the data or the the string (use -1 if data is a null terminated string)*/ + uint32_t time /**< the time this request took in ms or 0 if not possible (it will be used to calculate the weights)*/ ); /** @@ -191,15 +228,15 @@ NONULL void in3_req_add_response( * This function should be used in the transport-function to set the response. */ NONULL void in3_ctx_add_response( - in3_ctx_t* ctx, /**< [in]the current context */ + in3_req_t* req, /**< [in]the current context */ int index, /**< [in] the index of the url, since this request could go out to many urls */ - bool is_error, /**< [in] if true this will be reported as error. the message should then be the error-message */ + int error, /**< [in] if <0 this will be reported as error. the message should then be the error-message */ const char* data, /**< the data or the the string*/ int data_len, /**< the length of the data or the the string (use -1 if data is a null terminated string)*/ uint32_t time /**< the time this request took in ms or 0 if not possible (it will be used to calculate the weights)*/ ); -typedef in3_ret_t (*in3_transport_legacy)(in3_request_t* request); +typedef in3_ret_t (*in3_transport_legacy)(in3_http_request_t* request); /** * defines a default transport which is used when creating a new client. */ @@ -219,7 +256,7 @@ typedef enum { * action context when retrieving the account of a signer. */ typedef struct sign_account_ctx { - struct in3_ctx* ctx; /**< the context of the request in order report errors */ + struct in3_req* req; /**< the context of the request in order report errors */ uint8_t* accounts; /**< the account to use for the signature */ int accounts_len; /**< number of accounts */ in3_signer_type_t signer_type; /**< the type of the signer used for this account.*/ @@ -231,7 +268,7 @@ typedef struct sign_account_ctx { * action context when retrieving the account of a signer. */ typedef struct sign_prepare_ctx { - struct in3_ctx* ctx; /**< the context of the request in order report errors */ + struct in3_req* req; /**< the context of the request in order report errors */ address_t account; /**< the account to use for the signature */ bytes_t old_tx; bytes_t new_tx; @@ -252,7 +289,7 @@ typedef enum { typedef struct sign_ctx { bytes_t signature; /**< the resulting signature */ d_signature_type_t type; /**< the type of signature*/ - struct in3_ctx* ctx; /**< the context of the request in order report errors */ + struct in3_req* req; /**< the context of the request in order report errors */ bytes_t message; /**< the message to sign*/ bytes_t account; /**< the account to use for the signature */ } in3_sign_ctx_t; @@ -283,7 +320,7 @@ void in3_sign_ctx_set_signature_hex( * creates a signer ctx to be used for async signing. */ NONULL in3_sign_ctx_t* create_sign_ctx( - in3_ctx_t* ctx /**< [in] the rpc context */ + in3_req_t* req /**< [in] the rpc context */ ); // -------- SET_CONFIG --------- @@ -337,7 +374,7 @@ typedef void (*in3_storage_clear)( * context used during get config */ typedef struct in3_cache_ctx { - in3_ctx_t* ctx; /**< the request context */ + in3_req_t* req; /**< the request context */ char* key; /**< the key to fetch */ bytes_t* content; /**< the content to set */ } in3_cache_ctx_t; @@ -367,7 +404,7 @@ void in3_set_storage_handler( * verification context holding the pointers to all relevant toknes. */ typedef struct { - in3_ctx_t* ctx; /**< Request context. */ + in3_req_t* req; /**< Request context. */ in3_chain_t* chain; /**< the chain definition. */ d_token_t* result; /**< the result to verify */ d_token_t* request; /**< the request sent. */ @@ -378,6 +415,7 @@ typedef struct { int index; /**< the index of the request within the bulk */ node_match_t* node; /**< the node who delivered this response */ bool dont_blacklist; /**< indicates whether the plugin would like the node to be blacklisted */ + char* method; /**< the rpc-method to verify agains */ } in3_vctx_t; #ifdef LOGGING @@ -395,7 +433,7 @@ in3_ret_t vc_set_error( // ---- PLGN_ACT_PAY_FOLLOWUP ----------- typedef struct { - in3_ctx_t* ctx; /**< Request context. */ + in3_req_t* req; /**< Request context. */ node_match_t* node; /**< the responding node. */ d_token_t* resp_in3; /**< the response's in3 section */ d_token_t* resp_error; /**< the response's error section */ @@ -404,7 +442,7 @@ typedef struct { // ---- PLGN_ACT_PAY_HANDLE ----------- typedef struct { - in3_ctx_t* ctx; /**< Request context. */ + in3_req_t* req; /**< Request context. */ sb_t* payload; /**< the request payload */ bytes32_t pk; /**< the private-key to sign with */ } in3_pay_handle_ctx_t; @@ -412,18 +450,26 @@ typedef struct { // ---- PAY_SIGN_REQ ----------- typedef struct { - in3_ctx_t* ctx; /**< Request context. */ + in3_req_t* req; /**< Request context. */ d_token_t* request; /**< the request sent. */ bytes32_t request_hash; /**< the hash to sign */ uint8_t signature[65]; /**< the signature */ } in3_pay_sign_req_ctx_t; +// ---- PLGN_ACT_ADD_PAYLOAD ----------- + +typedef struct { + in3_req_t* req; /**< Request context. */ + d_token_t* request; /**< the request sent. */ + sb_t* sb; /**< the string builder in the in3-section */ +} in3_pay_payload_ctx_t; + // ---- LOG_ERROR ----------- typedef struct { char* msg; /**< the error message. */ uint16_t error; /**< error code. */ - in3_ctx_t* ctx; /**< ctx . */ + in3_req_t* req; /**< ctx . */ } error_log_ctx_t; // -------- NL_PICK --------- @@ -434,12 +480,12 @@ typedef enum { typedef struct { in3_nl_pick_type_t type; /**< type of node to pick. */ - in3_ctx_t* ctx; /**< Request context. */ + in3_req_t* req; /**< Request context. */ } in3_nl_pick_ctx_t; // -------- NL_FOLLOWUP --------- typedef struct { - in3_ctx_t* ctx; /**< Request context. */ + in3_req_t* req; /**< Request context. */ node_match_t* node; /**< Node that gave us a valid response */ } in3_nl_followup_ctx_t; diff --git a/c/src/core/client/context.c b/c/src/core/client/request.c similarity index 70% rename from c/src/core/client/context.c rename to c/src/core/client/request.c index 93a5afa1d..c06ab8014 100644 --- a/c/src/core/client/context.c +++ b/c/src/core/client/request.c @@ -32,23 +32,35 @@ * with this program. If not, see . *******************************************************************************/ -#include "context.h" +#include "request.h" #include "../util/debug.h" #include "../util/log.h" #include "client.h" -#include "context_internal.h" #include "keys.h" #include "plugin.h" +#include "request_internal.h" #include #include #include -in3_ctx_t* ctx_new(in3_t* client, const char* req_data) { +static in3_ret_t in3_plugin_init(in3_req_t* ctx) { + if ((ctx->client->plugin_acts & PLGN_ACT_INIT) == 0) return IN3_OK; + for (in3_plugin_t* p = ctx->client->plugins; p; p = p->next) { + if (p->acts & PLGN_ACT_INIT) { + TRY(p->action_fn(p->data, PLGN_ACT_INIT, ctx)) + p->acts &= ~((uint64_t) PLGN_ACT_INIT); + } + } + ctx->client->plugin_acts &= ~((uint64_t) PLGN_ACT_INIT); + return IN3_OK; +} + +in3_req_t* req_new(in3_t* client, const char* req_data) { assert_in3(client); assert(req_data); if (client->pending == 0xFFFF) return NULL; // avoid overflows by not creating any new ctx anymore - in3_ctx_t* ctx = _calloc(1, sizeof(in3_ctx_t)); + in3_req_t* ctx = _calloc(1, sizeof(in3_req_t)); if (!ctx) return NULL; ctx->client = client; ctx->verification_state = IN3_WAITING; @@ -57,7 +69,7 @@ in3_ctx_t* ctx_new(in3_t* client, const char* req_data) { if (req_data != NULL) { ctx->request_context = parse_json(req_data); if (!ctx->request_context) { - ctx_set_error(ctx, "Error parsing the JSON-request!", IN3_EINVAL); + req_set_error(ctx, "Error parsing the JSON-request!", IN3_EINVAL); return ctx; } @@ -76,7 +88,7 @@ in3_ctx_t* ctx_new(in3_t* client, const char* req_data) { ctx->requests[i] = t; } else { - ctx_set_error(ctx, "The Request is not a valid structure!", IN3_EINVAL); + req_set_error(ctx, "The Request is not a valid structure!", IN3_EINVAL); return ctx; } @@ -88,15 +100,17 @@ in3_ctx_t* ctx_new(in3_t* client, const char* req_data) { else if (d_type(t) == T_INTEGER) ctx->id = d_int(t); } + // if this is the first request, we initialize the plugins now + in3_plugin_init(ctx); return ctx; } -char* ctx_get_error_data(in3_ctx_t* ctx) { +char* req_get_error_data(in3_req_t* ctx) { return ctx ? ctx->error : "No request context"; } -char* ctx_get_response_data(in3_ctx_t* ctx) { - assert_in3_ctx(ctx); +char* req_get_response_data(in3_req_t* ctx) { + assert_in3_req(ctx); sb_t sb = {0}; if (d_type(ctx->request_context->result) == T_ARRAY) sb_add_char(&sb, '['); @@ -116,13 +130,13 @@ char* ctx_get_response_data(in3_ctx_t* ctx) { return sb.data; } -ctx_type_t ctx_get_type(in3_ctx_t* ctx) { - assert_in3_ctx(ctx); +req_type_t req_get_type(in3_req_t* ctx) { + assert_in3_req(ctx); return ctx->type; } -in3_ret_t ctx_check_response_error(in3_ctx_t* c, int i) { - assert_in3_ctx(c); +in3_ret_t req_check_response_error(in3_req_t* c, int i) { + assert_in3_req(c); d_token_t* r = d_get(c->responses[i], K_ERROR); if (!r) @@ -132,17 +146,17 @@ in3_ret_t ctx_check_response_error(in3_ctx_t* c, int i) { char* req = alloca(s.len + 1); strncpy(req, s.data, s.len); req[s.len] = '\0'; - return ctx_set_error(c, req, IN3_ERPC); + return req_set_error(c, req, IN3_ERPC); } else - return ctx_set_error(c, d_string(r), IN3_ERPC); + return req_set_error(c, d_string(r), IN3_ERPC); } -in3_ret_t ctx_set_error_intern(in3_ctx_t* ctx, char* message, in3_ret_t errnumber) { +in3_ret_t req_set_error_intern(in3_req_t* ctx, char* message, in3_ret_t errnumber) { assert(ctx); // if this is just waiting, it is not an error! - if (errnumber == IN3_WAITING) return errnumber; + if (errnumber == IN3_WAITING || errnumber == IN3_OK) return errnumber; if (message) { const size_t l = strlen(message); char* dst = NULL; @@ -159,7 +173,7 @@ in3_ret_t ctx_set_error_intern(in3_ctx_t* ctx, char* message, in3_ret_t errnumbe } ctx->error = dst; - error_log_ctx_t sctx = {.msg = message, .error = -errnumber, .ctx = ctx}; + error_log_ctx_t sctx = {.msg = message, .error = -errnumber, .req = ctx}; in3_plugin_execute_first_or_none(ctx, PLGN_ACT_LOG_ERROR, &sctx); in3_log_trace("Intermediate error -> %s\n", message); @@ -173,7 +187,7 @@ in3_ret_t ctx_set_error_intern(in3_ctx_t* ctx, char* message, in3_ret_t errnumbe return errnumber; } -in3_ret_t ctx_get_error(in3_ctx_t* ctx, int id) { +in3_ret_t req_get_error(in3_req_t* ctx, int id) { if (ctx->error) return IN3_ERPC; else if (id >= (int) ctx->len) @@ -185,7 +199,7 @@ in3_ret_t ctx_get_error(in3_ctx_t* ctx, int id) { return IN3_OK; } -void in3_ctx_free_nodes(node_match_t* node) { +void in3_req_free_nodes(node_match_t* node) { node_match_t* last_node = NULL; while (node) { last_node = node; @@ -195,7 +209,7 @@ void in3_ctx_free_nodes(node_match_t* node) { } } -int ctx_nodes_len(node_match_t* node) { +int req_nodes_len(node_match_t* node) { int all = 0; while (node) { all++; @@ -204,14 +218,14 @@ int ctx_nodes_len(node_match_t* node) { return all; } -bool ctx_is_method(const in3_ctx_t* ctx, const char* method) { - const char* required_method = d_get_stringk(ctx->requests[0], K_METHOD); +bool req_is_method(const in3_req_t* ctx, const char* method) { + const char* required_method = d_get_string(ctx->requests[0], K_METHOD); return (required_method && strcmp(required_method, method) == 0); } -in3_proof_t in3_ctx_get_proof(in3_ctx_t* ctx, int i) { +in3_proof_t in3_req_get_proof(in3_req_t* ctx, int i) { if (ctx->requests) { - char* verfification = d_get_stringk(d_get(ctx->requests[i], K_IN3), key("verification")); + char* verfification = d_get_string(d_get(ctx->requests[i], K_IN3), key("verification")); if (verfification && strcmp(verfification, "none") == 0) return PROOF_NONE; if (verfification && strcmp(verfification, "proof") == 0) return PROOF_STANDARD; } @@ -220,34 +234,35 @@ in3_proof_t in3_ctx_get_proof(in3_ctx_t* ctx, int i) { } NONULL void in3_req_add_response( - in3_request_t* req, /**< [in]the the request */ - int index, /**< [in] the index of the url, since this request could go out to many urls */ - bool is_error, /**< [in] if true this will be reported as error. the message should then be the error-message */ - const char* data, /**< the data or the the string*/ - int data_len, /**< the length of the data or the the string (use -1 if data is a null terminated string)*/ - uint32_t time) { - in3_ctx_add_response(req->ctx, index, is_error, data, data_len, time); + in3_http_request_t* req, /**< [in]the the request */ + int index, /**< [in] the index of the url, since this request could go out to many urls */ + int error, /**< [in] if true this will be reported as error. the message should then be the error-message */ + const char* data, /**< the data or the the string*/ + int data_len, /**< the length of the data or the the string (use -1 if data is a null terminated string)*/ + uint32_t time) { + in3_ctx_add_response(req->req, index, error, data, data_len, time); } void in3_ctx_add_response( - in3_ctx_t* ctx, /**< [in] the context */ + in3_req_t* ctx, /**< [in] the context */ int index, /**< [in] the index of the url, since this request could go out to many urls */ - bool is_error, /**< [in] if true this will be reported as error. the message should then be the error-message */ + int error, /**< [in] if true this will be reported as error. the message should then be the error-message */ const char* data, /**< the data or the the string*/ int data_len, /**< the length of the data or the the string (use -1 if data is a null terminated string)*/ uint32_t time) { - assert_in3_ctx(ctx); + assert_in3_req(ctx); assert(data); + if (error == 1) error = IN3_ERPC; if (!ctx->raw_response) { - ctx_set_error(ctx, "no request created yet!", IN3_EINVAL); + req_set_error(ctx, "no request created yet!", IN3_EINVAL); return; } in3_response_t* response = ctx->raw_response + index; response->time += time; - if (response->state == IN3_OK && is_error) response->data.len = 0; - response->state = is_error ? IN3_ERPC : IN3_OK; + if (response->state == IN3_OK && error) response->data.len = 0; + response->state = error; if (data_len == -1) sb_add_chars(&response->data, data); else @@ -256,13 +271,13 @@ void in3_ctx_add_response( sb_t* in3_rpc_handle_start(in3_rpc_handle_ctx_t* hctx) { assert(hctx); - assert_in3_ctx(hctx->ctx); + assert_in3_req(hctx->req); assert(hctx->request); assert(hctx->response); *hctx->response = _calloc(1, sizeof(in3_response_t)); sb_add_chars(&(*hctx->response)->data, "{\"id\":"); - sb_add_int(&(*hctx->response)->data, hctx->ctx->id); + sb_add_int(&(*hctx->response)->data, hctx->req->id); return sb_add_chars(&(*hctx->response)->data, ",\"jsonrpc\":\"2.0\",\"result\":"); } in3_ret_t in3_rpc_handle_finish(in3_rpc_handle_ctx_t* hctx) { @@ -297,7 +312,7 @@ in3_ret_t in3_rpc_handle_with_int(in3_rpc_handle_ctx_t* hctx, uint64_t value) { return in3_rpc_handle_with_string(hctx, s); } -in3_ret_t ctx_send_sub_request(in3_ctx_t* parent, char* method, char* params, char* in3, d_token_t** result) { +in3_ret_t req_send_sub_request(in3_req_t* parent, char* method, char* params, char* in3, d_token_t** result) { bool use_cache = strcmp(method, "eth_sendTransaction") == 0; if (params == NULL) params = ""; char* req = NULL; @@ -309,7 +324,7 @@ in3_ret_t ctx_send_sub_request(in3_ctx_t* parent, char* method, char* params, ch sprintf(req, "{\"method\":\"%s\",\"params\":[%s]}", method, params); } - in3_ctx_t* ctx = parent->required; + in3_req_t* ctx = parent->required; for (; ctx; ctx = ctx->required) { if (use_cache) { // only check first entry @@ -321,7 +336,7 @@ in3_ret_t ctx_send_sub_request(in3_ctx_t* parent, char* method, char* params, ch } if (found) break; } - if (strcmp(d_get_stringk(ctx->requests[0], K_METHOD), method) != 0) continue; + if (strcmp(d_get_string(ctx->requests[0], K_METHOD), method) != 0) continue; d_token_t* t = d_get(ctx->requests[0], K_PARAMS); if (!t) continue; str_range_t p = d_to_json(t); @@ -329,18 +344,18 @@ in3_ret_t ctx_send_sub_request(in3_ctx_t* parent, char* method, char* params, ch } if (ctx) - switch (in3_ctx_state(ctx)) { - case CTX_ERROR: - return ctx_set_error(parent, ctx->error, ctx->verification_state ? ctx->verification_state : IN3_ERPC); - case CTX_SUCCESS: - *result = d_get(ctx->responses[0], K_RESULT); + switch (in3_req_state(ctx)) { + case REQ_ERROR: + return req_set_error(parent, ctx->error, ctx->verification_state ? ctx->verification_state : IN3_ERPC); + case REQ_SUCCESS: + *result = strcmp(method, "in3_http") == 0 ? ctx->responses[0] : d_get(ctx->responses[0], K_RESULT); if (!*result) { - char* s = d_get_stringk(d_get(ctx->responses[0], K_ERROR), K_MESSAGE); - return ctx_set_error(parent, s ? s : "error executing provider call", IN3_ERPC); + char* s = d_get_string(d_get(ctx->responses[0], K_ERROR), K_MESSAGE); + return req_set_error(parent, s ? s : "error executing provider call", IN3_ERPC); } return IN3_OK; - case CTX_WAITING_TO_SEND: - case CTX_WAITING_FOR_RESPONSE: + case REQ_WAITING_TO_SEND: + case REQ_WAITING_FOR_RESPONSE: return IN3_WAITING; } @@ -352,14 +367,22 @@ in3_ret_t ctx_send_sub_request(in3_ctx_t* parent, char* method, char* params, ch else sprintf(req, "{\"method\":\"%s\",\"params\":[%s]}", method, params); } - ctx = ctx_new(parent->client, req); - if (!ctx) return ctx_set_error(parent, "Invalid request!", IN3_ERPC); + ctx = req_new(parent->client, req); + if (!ctx) return req_set_error(parent, "Invalid request!", IN3_ERPC); if (use_cache) in3_cache_add_ptr(&ctx->cache, req)->props = CACHE_PROP_SRC_REQ; - return ctx_add_required(parent, ctx); + in3_ret_t ret = req_add_required(parent, ctx); + if (ret == IN3_OK && ctx->responses[0]) { + *result = d_get(ctx->responses[0], K_RESULT); + if (!*result) { + char* s = d_get_string(d_get(ctx->responses[0], K_ERROR), K_MESSAGE); + return req_set_error(parent, s ? s : "error executing provider call", IN3_ERPC); + } + } + return ret; } -in3_ret_t ctx_require_signature(in3_ctx_t* ctx, d_signature_type_t type, bytes_t* signature, bytes_t raw_data, bytes_t from) { +in3_ret_t req_require_signature(in3_req_t* ctx, d_signature_type_t type, bytes_t* signature, bytes_t raw_data, bytes_t from) { bytes_t cache_key = bytes(alloca(raw_data.len + from.len), raw_data.len + from.len); memcpy(cache_key.data, raw_data.data, raw_data.len); if (from.data) memcpy(cache_key.data + raw_data.len, from.data, from.len); @@ -371,40 +394,40 @@ in3_ret_t ctx_require_signature(in3_ctx_t* ctx, d_signature_type_t type, bytes_t // first try internal plugins for signing, before we create an context. if (in3_plugin_is_registered(ctx->client, PLGN_ACT_SIGN)) { - in3_sign_ctx_t sc = {.account = from, .ctx = ctx, .message = raw_data, .signature = bytes(NULL, 0), .type = type}; + in3_sign_ctx_t sc = {.account = from, .req = ctx, .message = raw_data, .signature = bytes(NULL, 0), .type = type}; in3_ret_t r = in3_plugin_execute_first_or_none(ctx, PLGN_ACT_SIGN, &sc); if (r == IN3_OK && sc.signature.data) { in3_cache_add_entry(&ctx->cache, cloned_bytes(cache_key), sc.signature); *signature = sc.signature; return IN3_OK; } - else if (r != IN3_EIGNORE) + else if (r != IN3_EIGNORE && r != IN3_OK) return r; } // get the signature from required const char* method = type == SIGN_EC_HASH ? "sign_ec_hash" : "sign_ec_raw"; - in3_ctx_t* c = ctx_find_required(ctx, method); + in3_req_t* c = req_find_required(ctx, method); if (c) - switch (in3_ctx_state(c)) { - case CTX_ERROR: - return ctx_set_error(ctx, c->error ? c->error : "Could not handle signing", IN3_ERPC); - case CTX_WAITING_FOR_RESPONSE: - case CTX_WAITING_TO_SEND: + switch (in3_req_state(c)) { + case REQ_ERROR: + return req_set_error(ctx, c->error ? c->error : "Could not handle signing", IN3_ERPC); + case REQ_WAITING_FOR_RESPONSE: + case REQ_WAITING_TO_SEND: return IN3_WAITING; - case CTX_SUCCESS: { + case REQ_SUCCESS: { if (c->raw_response && c->raw_response->state == IN3_OK && c->raw_response->data.len == 65) { *signature = cloned_bytes(bytes((uint8_t*) c->raw_response->data.data, c->raw_response->data.len)); in3_cache_add_entry(&ctx->cache, cloned_bytes(cache_key), *signature); - ctx_remove_required(ctx, c, false); + req_remove_required(ctx, c, false); return IN3_OK; } else if (c->raw_response && c->raw_response->state) - return ctx_set_error(ctx, c->raw_response->data.data, c->raw_response->state); + return req_set_error(ctx, c->raw_response->data.data, c->raw_response->state); else - return ctx_set_error(ctx, "no data to sign", IN3_EINVAL); + return req_set_error(ctx, "no data to sign", IN3_EINVAL); default: - return ctx_set_error(ctx, "invalid state", IN3_EINVAL); + return req_set_error(ctx, "invalid state", IN3_EINVAL); } } else { @@ -415,9 +438,19 @@ in3_ret_t ctx_require_signature(in3_ctx_t* ctx, d_signature_type_t type, bytes_t sb_add_chars(&req, ","); sb_add_bytes(&req, NULL, &from, 1, false); sb_add_chars(&req, "]}"); - c = ctx_new(ctx->client, req.data); + c = req_new(ctx->client, req.data); if (!c) return IN3_ECONFIG; - c->type = CT_SIGN; - return ctx_add_required(ctx, c); + c->type = RT_SIGN; + return req_add_required(ctx, c); } } + +in3_ret_t vc_set_error(in3_vctx_t* vc, char* msg) { +#ifdef LOGGING + (void) req_set_error(vc->req, msg, IN3_EUNKNOWN); +#else + (void) msg; + (void) vc; +#endif + return IN3_EUNKNOWN; +} diff --git a/c/src/core/client/context.h b/c/src/core/client/request.h similarity index 76% rename from c/src/core/client/context.h rename to c/src/core/client/request.h index 1faba32ff..5250efaae 100644 --- a/c/src/core/client/context.h +++ b/c/src/core/client/request.h @@ -56,9 +56,9 @@ extern "C" { * type of the request context, */ typedef enum ctx_type { - CT_RPC = 0, /**< a json-rpc request, which needs to be send to a incubed node */ - CT_SIGN = 1 /**< a sign request */ -} ctx_type_t; + RT_RPC = 0, /**< a json-rpc request, which needs to be send to a incubed node */ + RT_SIGN = 1 /**< a sign request */ +} req_type_t; /** * the weight of a certain node as linked list. @@ -89,12 +89,12 @@ typedef struct in3_response { * * This is generated for each request and represents the current state. it holds the state until the request is finished and must be freed afterwards. * */ -typedef struct in3_ctx { +typedef struct in3_req { uint_fast8_t signers_length; /**< number or addresses */ - uint16_t len; /**< the number of requests */ + uint_fast16_t len; /**< the number of requests */ uint_fast16_t attempt; /**< the number of attempts */ uint32_t id; /**< JSON RPC id of request at index 0 */ - ctx_type_t type; /**< the type of the request */ + req_type_t type; /**< the type of the request */ in3_ret_t verification_state; /**< state of the verification */ char* error; /**< in case of an error this will hold the message, if not it points to `NULL` */ json_ctx_t* request_context; /**< the result of the json-parser for the request.*/ @@ -105,9 +105,9 @@ typedef struct in3_ctx { uint8_t* signers; /**< the addresses of servers requested to sign the blockhash */ node_match_t* nodes; /**< selected nodes to process the request, which are stored as linked list.*/ cache_entry_t* cache; /** CTX [label="ctx_new()"] + RPC -> CTX [label="req_new()"] CTX -> exec @@ -192,8 +192,8 @@ NONULL in3_ctx_state_t in3_ctx_exec_state( exec -> response[label="IN3_OK"] exec -> waiting[label="IN3_WAITING"] - waiting -> sign[label=CT_SIGN] - waiting -> request[label=CT_RPC] + waiting -> sign[label=RT_SIGN] + waiting -> request[label=RT_RPC] sign -> exec [label="in3_ctx_add_response()"] request -> exec[label="in3_ctx_add_response()"] @@ -213,23 +213,23 @@ NONULL in3_ctx_state_t in3_ctx_exec_state( * * ```c * - in3_ret_t in3_send_ctx(in3_ctx_t* ctx) { + in3_ret_t in3_send_req(in3_req_t* req) { in3_ret_t ret; // execute the context and store the return value. // if the return value is 0 == IN3_OK, it was successful and we return, // if not, we keep on executing - while ((ret = in3_ctx_execute(ctx))) { + while ((ret = in3_req_execute(ctx))) { // error we stop here, because this means we got an error if (ret != IN3_WAITING) return ret; // handle subcontexts first, if they have not been finished - while (ctx->required && in3_ctx_state(ctx->required) != CTX_SUCCESS) { + while (ctx->required && in3_req_state(ctx->required) != REQ_SUCCESS) { // exxecute them, and return the status if still waiting or error - if ((ret = in3_send_ctx(ctx->required))) return ret; + if ((ret = in3_send_req(ctx->required))) return ret; // recheck in order to prepare the request. // if it is not waiting, then it we cannot do much, becaus it will an error or successfull. - if ((ret = in3_ctx_execute(ctx)) != IN3_WAITING) return ret; + if ((ret = in3_req_execute(ctx)) != IN3_WAITING) return ret; } // only if there is no response yet... @@ -239,10 +239,10 @@ NONULL in3_ctx_state_t in3_ctx_exec_state( switch (ctx->type) { // RPC-request to send to the nodes - case CT_RPC: { + case RT_RPC: { // build the request - in3_request_t* request = in3_create_request(ctx); + in3_http_request_t* request = in3_create_request(ctx); // here we use the transport, but you can also try to fetch the data in any other way. ctx->client->transport(request); @@ -253,7 +253,7 @@ NONULL in3_ctx_state_t in3_ctx_exec_state( } // this is a request to sign a transaction - case CT_SIGN: { + case RT_SIGN: { // read the data to sign from the request d_token_t* params = d_get(ctx->requests[0], K_PARAMS); // the data to sign @@ -271,7 +271,7 @@ NONULL in3_ctx_state_t in3_ctx_exec_state( // use the signer to create the signature ret = ctx->client->signer->sign(ctx, SIGN_EC_HASH, data, from, sig); // if it fails we report this as error - if (ret < 0) return ctx_set_error(ctx, ctx->raw_response->error.data, ret); + if (ret < 0) return req_set_error(ctx, ctx->raw_response->error.data, ret); // otherwise we simply add the raw 65 bytes to the response. sb_add_range(&ctx->raw_response->result, (char*) sig, 0, 65); } @@ -287,36 +287,36 @@ NONULL in3_ctx_state_t in3_ctx_exec_state( * * */ -NONULL in3_ret_t in3_ctx_execute( - in3_ctx_t* ctx /**< [in] the request context. */ +NONULL in3_ret_t in3_req_execute( + in3_req_t* req /**< [in] the request context. */ ); /** * returns the current state of the context. */ -NONULL in3_ctx_state_t in3_ctx_state( - in3_ctx_t* ctx /**< [in] the request context. */ +NONULL in3_req_state_t in3_req_state( + in3_req_t* req /**< [in] the request context. */ ); /** * returns the error of the context. */ -char* ctx_get_error_data( - in3_ctx_t* ctx /**< [in] the request context. */ +char* req_get_error_data( + in3_req_t* req /**< [in] the request context. */ ); /** * returns json response for that context */ -char* ctx_get_response_data( - in3_ctx_t* ctx /**< [in] the request context. */ +char* req_get_response_data( + in3_req_t* req /**< [in] the request context. */ ); /** * returns the type of the request */ -NONULL ctx_type_t ctx_get_type( - in3_ctx_t* ctx /**< [in] the request context. */ +NONULL req_type_t req_get_type( + in3_req_t* req /**< [in] the request context. */ ); /** @@ -324,8 +324,8 @@ NONULL ctx_type_t ctx_get_type( * * But this will not free the request string passed when creating the context! */ -NONULL void ctx_free( - in3_ctx_t* ctx /**< [in] the request context. */ +NONULL void req_free( + in3_req_t* req /**< [in] the request context. */ ); /** * adds a new context as a requirment. @@ -337,22 +337,22 @@ NONULL void ctx_free( * Here is an example of how to use it: * * ```c -in3_ret_t get_from_nodes(in3_ctx_t* parent, char* method, char* params, bytes_t* dst) { +in3_ret_t get_from_nodes(in3_req_t* parent, char* method, char* params, bytes_t* dst) { // check if the method is already existing - in3_ctx_t* ctx = ctx_find_required(parent, method); + in3_req_t* req = req_find_required(parent, method); if (ctx) { // found one - so we check if it is useable. - switch (in3_ctx_state(ctx)) { + switch (in3_req_state(ctx)) { // in case of an error, we report it back to the parent context - case CTX_ERROR: - return ctx_set_error(parent, ctx->error, IN3_EUNKNOWN); + case REQ_ERROR: + return req_set_error(parent, ctx->error, IN3_EUNKNOWN); // if we are still waiting, we stop here and report it. case CTX_WAITING_FOR_REQUIRED_CTX: - case CTX_WAITING_FOR_RESPONSE: + case REQ_WAITING_FOR_RESPONSE: return IN3_WAITING; // if it is useable, we can now handle the result. - case CTX_SUCCESS: { + case REQ_SUCCESS: { d_token_t* r = d_get(ctx->responses[0], K_RESULT); if (r) { // we have a result, so write it back to the dst @@ -360,7 +360,7 @@ in3_ret_t get_from_nodes(in3_ctx_t* parent, char* method, char* params, bytes_t* return IN3_OK; } else // or check the error and report it - return ctx_check_response_error(parent, 0); + return req_check_response_error(parent, 0); } } } @@ -373,54 +373,54 @@ in3_ret_t get_from_nodes(in3_ctx_t* parent, char* method, char* params, bytes_t* // create it sprintf(req, "{\"method\":\"%s\",\"jsonrpc\":\"2.0\",\"id\":1,\"params\":%s}", method, params); // and add the request context to the parent. - return ctx_add_required(parent, ctx_new(parent->client, req)); + return req_add_required(parent, req_new(parent->client, req)); } * ``` */ -NONULL in3_ret_t ctx_add_required( - in3_ctx_t* parent, /**< [in] the current request context. */ - in3_ctx_t* ctx /**< [in] the new request context to add. */ +NONULL in3_ret_t req_add_required( + in3_req_t* parent, /**< [in] the current request context. */ + in3_req_t* req /**< [in] the new request context to add. */ ); /** * searches within the required request contextes for one with the given method. * * This method is used internaly to find a previously added context. */ -NONULL in3_ctx_t* ctx_find_required( - const in3_ctx_t* parent, /**< [in] the current request context. */ +NONULL in3_req_t* req_find_required( + const in3_req_t* parent, /**< [in] the current request context. */ const char* method /**< [in] the method of the rpc-request. */ ); /** * removes a required context after usage. * removing will also call free_ctx to free resources. */ -NONULL in3_ret_t ctx_remove_required( - in3_ctx_t* parent, /**< [in] the current request context. */ - in3_ctx_t* ctx, /**< [in] the request context to remove. */ +NONULL in3_ret_t req_remove_required( + in3_req_t* parent, /**< [in] the current request context. */ + in3_req_t* req, /**< [in] the request context to remove. */ bool rec /**< [in] if true all sub contexts will aösp be removed*/ ); /** * check if the response contains a error-property and reports this as error in the context. */ -NONULL in3_ret_t ctx_check_response_error( - in3_ctx_t* c, /**< [in] the current request context. */ +NONULL in3_ret_t req_check_response_error( + in3_req_t* c, /**< [in] the current request context. */ int i /**< [in] the index of the request to check (if this is a batch-request, otherwise 0). */ ); /** * determins the errorcode for the given request. */ -NONULL in3_ret_t ctx_get_error( - in3_ctx_t* ctx, /**< [in] the current request context. */ +NONULL in3_ret_t req_get_error( + in3_req_t* req, /**< [in] the current request context. */ int id /**< [in] the index of the request to check (if this is a batch-request, otherwise 0). */ ); /** * sends a request and returns a context used to access the result or errors. * - * This context *MUST* be freed with ctx_free(ctx) after usage to release the resources. + * This context *MUST* be freed with req_free(ctx) after usage to release the resources. */ -NONULL in3_ctx_t* in3_client_rpc_ctx_raw( +NONULL in3_req_t* in3_client_rpc_ctx_raw( in3_t* c, /**< [in] the client config. */ const char* request /**< [in] rpc request. */ ); @@ -428,9 +428,9 @@ NONULL in3_ctx_t* in3_client_rpc_ctx_raw( /** * sends a request and returns a context used to access the result or errors. * - * This context *MUST* be freed with ctx_free(ctx) after usage to release the resources. + * This context *MUST* be freed with req_free(ctx) after usage to release the resources. */ -NONULL in3_ctx_t* in3_client_rpc_ctx( +NONULL in3_req_t* in3_client_rpc_ctx( in3_t* c, /**< [in] the clientt config. */ const char* method, /**< [in] rpc method. */ const char* params /**< [in] params as string. */ @@ -439,10 +439,11 @@ NONULL in3_ctx_t* in3_client_rpc_ctx( /** * determines the proof as set in the request. */ -NONULL in3_proof_t in3_ctx_get_proof( - in3_ctx_t* ctx, /**< [in] the current request. */ +NONULL in3_proof_t in3_req_get_proof( + in3_req_t* req, /**< [in] the current request. */ int i /**< [in] the index within the request. */ ); + #ifdef __cplusplus } #endif diff --git a/c/src/core/client/context_internal.h b/c/src/core/client/request_internal.h similarity index 74% rename from c/src/core/client/context_internal.h rename to c/src/core/client/request_internal.h index 6886225b5..64e80f383 100644 --- a/c/src/core/client/context_internal.h +++ b/c/src/core/client/request_internal.h @@ -31,18 +31,19 @@ * You should have received a copy of the GNU Affero General Public License along * with this program. If not, see . *******************************************************************************/ -#ifndef CONTEXT_INTERNAL_H -#define CONTEXT_INTERNAL_H +#ifndef REQ_INTERNAL_H +#define REQ_INTERNAL_H -#include "context.h" #include "plugin.h" +#include "request.h" #ifdef LOGGING -#define ctx_set_error(c, msg, err) ctx_set_error_intern(c, msg, err) +#define req_set_error(c, msg, err) req_set_error_intern(c, msg, err) #else -#define ctx_set_error(c, msg, err) ctx_set_error_intern(c, NULL, err) +#define req_set_error(c, msg, err) req_set_error_intern(c, NULL, err) #endif - +#define REQUIRE_EXPERIMENTAL(req, feature) \ + if ((req->client->flags & FLAGS_ALLOW_EXPERIMENTAL) == 0) return req_set_error(req, "The feature " feature " is still experimental. You need to explicitly allow it in the config.", IN3_ECONFIG); /** * creates a request-object, which then need to be filled with the responses. * @@ -55,15 +56,15 @@ * sb_add_chars(&request->results[0].error, my_error); * ``` */ -NONULL in3_request_t* in3_create_request( - in3_ctx_t* ctx /**< [in] the request context. */ +NONULL in3_http_request_t* in3_create_request( + in3_req_t* req /**< [in] the request context. */ ); /** * frees a previuosly allocated request. */ NONULL void request_free( - in3_request_t* req /**< [in] the request. */ + in3_http_request_t* req /**< [in] the request. */ ); /** @@ -73,11 +74,11 @@ NONULL void request_free( * the return value will simply be passed so you can use it like * * ```c - * return ctx_set_error(ctx, "wrong number of arguments", IN3_EINVAL) + * return req_set_error(ctx, "wrong number of arguments", IN3_EINVAL) * ``` */ -in3_ret_t ctx_set_error_intern( - in3_ctx_t* c, /**< [in] the current request context. */ +in3_ret_t req_set_error_intern( + in3_req_t* c, /**< [in] the current request context. */ char* msg, /**< [in] the error message. (This string will be copied) */ in3_ret_t errnumber /**< [in] the error code to return */ ); @@ -85,20 +86,21 @@ in3_ret_t ctx_set_error_intern( /** * handles a failable context * - * This context *MUST* be freed with ctx_free(ctx) after usage to release the resources. + * This context *MUST* be freed with req_free(ctx) after usage to release the resources. */ -in3_ret_t ctx_handle_failable( - in3_ctx_t* ctx /**< [in] the current request context. */ +in3_ret_t req_handle_failable( + in3_req_t* req /**< [in] the current request context. */ ); NONULL_FOR((1, 2, 3, 5)) -in3_ret_t ctx_send_sub_request(in3_ctx_t* parent, char* method, char* params, char* in3, d_token_t** result); -NONULL in3_ret_t ctx_require_signature(in3_ctx_t* ctx, d_signature_type_t type, bytes_t* sig, bytes_t raw_data, bytes_t from); +in3_ret_t req_send_sub_request(in3_req_t* parent, char* method, char* params, char* in3, d_token_t** result); +NONULL in3_ret_t req_require_signature(in3_req_t* req, d_signature_type_t type, bytes_t* sig, bytes_t raw_data, bytes_t from); +NONULL in3_ret_t in3_retry_same_node(in3_req_t* req); -#define assert_in3_ctx(ctx) \ +#define assert_in3_req(ctx) \ assert(ctx); \ assert_in3(ctx->client); \ - assert(ctx->signers_length <= (ctx->type == CT_RPC ? ctx->client->signature_count + 1 : 0)); \ + assert(ctx->signers_length <= (ctx->type == RT_RPC ? ctx->client->signature_count + 1 : 0)); \ assert(ctx->signers_length ? (ctx->signers != NULL) : (ctx->signers == NULL)); \ assert(ctx->len >= 1 || ctx->error); \ assert(ctx->attempt <= ctx->client->max_attempts); \ @@ -112,8 +114,8 @@ NONULL in3_ret_t ctx_require_signature(in3_ctx_t* ctx, d_signature_type_t type, assert(r); \ assert(r->state != IN3_OK || r->data.data); -NONULL void in3_ctx_free_nodes(node_match_t* c); -int ctx_nodes_len(node_match_t* root); -NONULL bool ctx_is_method(const in3_ctx_t* ctx, const char* method); +NONULL void in3_req_free_nodes(node_match_t* c); +int req_nodes_len(node_match_t* root); +NONULL bool req_is_method(const in3_req_t* req, const char* method); -#endif // CONTEXT_INTERNAL_H \ No newline at end of file +#endif // REQ_INTERNAL_H \ No newline at end of file diff --git a/c/src/core/client/verifier.c b/c/src/core/client/verifier.c deleted file mode 100644 index fe0536db5..000000000 --- a/c/src/core/client/verifier.c +++ /dev/null @@ -1,48 +0,0 @@ -/******************************************************************************* - * This file is part of the Incubed project. - * Sources: https://github.com/blockchainsllc/in3 - * - * Copyright (C) 2018-2020 slock.it GmbH, Blockchains LLC - * - * - * COMMERCIAL LICENSE USAGE - * - * Licensees holding a valid commercial license may use this file in accordance - * with the commercial license agreement provided with the Software or, alternatively, - * in accordance with the terms contained in a written agreement between you and - * slock.it GmbH/Blockchains LLC. For licensing terms and conditions or further - * information please contact slock.it at in3@slock.it. - * - * Alternatively, this file may be used under the AGPL license as follows: - * - * AGPL LICENSE USAGE - * - * This program is free software: you can redistribute it and/or modify it under the - * terms of the GNU Affero General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A - * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. - * [Permissions of this strong copyleft license are conditioned on making available - * complete source code of licensed works and modifications, which include larger - * works using a licensed work, under the same license. Copyright and license notices - * must be preserved. Contributors provide an express grant of patent rights.] - * You should have received a copy of the GNU Affero General Public License along - * with this program. If not, see . - *******************************************************************************/ - -#include "client.h" -#include "context_internal.h" -#include "keys.h" -#include "plugin.h" - -in3_ret_t vc_set_error(in3_vctx_t* vc, char* msg) { -#ifdef LOGGING - (void) ctx_set_error(vc->ctx, msg, IN3_EUNKNOWN); -#else - (void) msg; - (void) vc; -#endif - return IN3_EUNKNOWN; -} diff --git a/c/src/core/util/bytes.h b/c/src/core/util/bytes.h index 4bb0ca95f..de07d151f 100644 --- a/c/src/core/util/bytes.h +++ b/c/src/core/util/bytes.h @@ -122,6 +122,15 @@ NONULL static inline void b_optimize_len(bytes_t* b) { b->len--; } } + +#define b_to_stack(d) \ + { \ + bytes_t o = d; \ + d.data = alloca(d.len); \ + memcpy(d.data, o.data, o.len); \ + _free(o.data); \ + } /**< converts bytes from heap to stack */ + #ifdef __cplusplus } #endif diff --git a/c/src/core/util/data.c b/c/src/core/util/data.c index 37e2dca40..f062a4716 100644 --- a/c/src/core/util/data.c +++ b/c/src/core/util/data.c @@ -45,6 +45,8 @@ #ifdef LOGGING #include "used_keys.h" #endif +// Here we check the pointer-size, because pointers smaller than 32bit may result in a undefined behavior, when calling d_to_bytes() for a T_INTEGER +// verify(sizeof(void*) >= 4); // number of tokens to allocate memory for when parsing #define JSON_INIT_TOKENS 10 @@ -161,10 +163,13 @@ int d_bytes_to(d_token_t* item, uint8_t* dst, const int max_size) { switch (d_type(item)) { case T_BYTES: if (max > l) { - d_bytesl(item, max); + memset(dst, 0, max - l); + memcpy(dst + max - l, item->data, l); + d_bytesl(item, max); //TODO we should not need this! l = max; } - memcpy(dst, item->data, l); + else + memcpy(dst, item->data, l); return l; case T_STRING: @@ -284,11 +289,11 @@ bool d_eq(const d_token_t* a, const d_token_t* b) { } d_token_t* d_get(d_token_t* item, const uint16_t key) { - if (item == NULL /*|| item->len & 0xF0000000 != 0x30000000*/) return NULL; - int i = 0, l = item->len & 0xFFFFFFF; - item += 1; - for (; i < l; i++, item += d_token_size(item)) { - if (item->key == key) return item; + if (item == NULL || (item->len & 0xF0000000) != 0x30000000) return NULL; // is it an object? + int i = 0, l = item->len & 0xFFFFFFF; // l is the number of properties in the object + item += 1; // we start with the first, which is the next token + for (; i < l; i++, item += d_token_size(item)) { // and iterate through all + if (item->key == key) return item; // until we find the one with the matching key } return NULL; } @@ -305,7 +310,7 @@ d_token_t* d_get_or(d_token_t* item, const uint16_t key, const uint16_t key2) { } d_token_t* d_get_at(d_token_t* item, const uint32_t index) { - if (item == NULL) return NULL; + if (item == NULL || (item->len & 0xF0000000) != 0x20000000) return NULL; // is it an array? uint32_t i = 0, l = item->len & 0xFFFFFFF; item += 1; for (; i < l; i++, item += d_token_size(item)) { @@ -720,10 +725,11 @@ static d_token_t* next_item(json_ctx_t* jp, d_type_t type, int len) { jp->result = _malloc(10 * sizeof(d_token_t)); jp->allocated = 10; } - else if (jp->len + 1 > jp->allocated) { + else if (jp->len >= jp->allocated) { jp->result = _realloc(jp->result, (jp->allocated << 1) * sizeof(d_token_t), jp->allocated * sizeof(d_token_t)); jp->allocated <<= 1; } + assert(jp->len < jp->allocated); d_token_t* n = jp->result + jp->len; jp->len += 1; n->key = 0; @@ -777,6 +783,7 @@ static int read_token(json_ctx_t* jp, const uint8_t* d, size_t* p, size_t max) { for (i = 0; i < len; i++) { ll = jp->len; TRY(read_token(jp, d, p, max)); + assert(ll < jp->allocated); jp->result[ll].key = i; } break; @@ -787,6 +794,7 @@ static int read_token(json_ctx_t* jp, const uint8_t* d, size_t* p, size_t max) { *p += 2; ll = jp->len; TRY(read_token(jp, d, p, max)); + assert(ll < jp->allocated); jp->result[ll].key = key; } break; diff --git a/c/src/core/util/data.h b/c/src/core/util/data.h index a1770b86e..016a41daa 100644 --- a/c/src/core/util/data.h +++ b/c/src/core/util/data.h @@ -144,7 +144,8 @@ NONULL json_ctx_t* parse_json_indexed(const char* js); /**< parses NONULL void json_free(json_ctx_t* parser_ctx); /**< frees the parse-context after usage */ NONULL str_range_t d_to_json(const d_token_t* item); /**< returns the string for a object or array. This only works for json as string. For binary it will not work! */ char* d_create_json(json_ctx_t* ctx, d_token_t* item); /**< creates a json-string. It does not work for objects if the parsed data were binary!*/ -json_ctx_t* json_create(); + +json_ctx_t* json_create(); NONULL d_token_t* json_create_null(json_ctx_t* jp); NONULL d_token_t* json_create_bool(json_ctx_t* jp, bool value); NONULL d_token_t* json_create_int(json_ctx_t* jp, uint64_t value); @@ -165,21 +166,17 @@ NONULL static inline d_key_t key(const char* c) { return val; } -static inline char* d_get_stringk(d_token_t* r, d_key_t k) { return d_string(d_get(r, k)); } /**< reads token of a property as string. */ -static inline char* d_get_string(d_token_t* r, char* k) { return d_get_stringk(r, key(k)); } /**< reads token of a property as string. */ -static inline char* d_get_string_at(d_token_t* r, uint32_t pos) { return d_string(d_get_at(r, pos)); } /**< reads string at given pos of an array. */ -static inline int32_t d_get_intk(d_token_t* r, d_key_t k) { return d_int(d_get(r, k)); } /**< reads token of a property as int. */ -static inline int32_t d_get_intkd(d_token_t* r, d_key_t k, uint32_t d) { return d_intd(d_get(r, k), d); } /**< reads token of a property as int. */ -static inline int32_t d_get_int(d_token_t* r, char* k) { return d_get_intk(r, key(k)); } /**< reads token of a property as int. */ -static inline int32_t d_get_int_at(d_token_t* r, uint32_t pos) { return d_int(d_get_at(r, pos)); } /**< reads a int at given pos of an array. */ -static inline uint64_t d_get_longk(d_token_t* r, d_key_t k) { return d_long(d_get(r, k)); } /**< reads token of a property as long. */ -static inline uint64_t d_get_longkd(d_token_t* r, d_key_t k, uint64_t d) { return d_longd(d_get(r, k), d); } /**< reads token of a property as long. */ -static inline uint64_t d_get_long(d_token_t* r, char* k) { return d_get_longk(r, key(k)); } /**< reads token of a property as long. */ -static inline uint64_t d_get_long_at(d_token_t* r, uint32_t pos) { return d_long(d_get_at(r, pos)); } /**< reads long at given pos of an array. */ -static inline bytes_t* d_get_bytesk(d_token_t* r, d_key_t k) { return d_bytes(d_get(r, k)); } /**< reads token of a property as bytes. */ -static inline bytes_t* d_get_bytes(d_token_t* r, char* k) { return d_get_bytesk(r, key(k)); } /**< reads token of a property as bytes. */ -static inline bytes_t* d_get_bytes_at(d_token_t* r, uint32_t pos) { return d_bytes(d_get_at(r, pos)); } /**< reads bytes at given pos of an array. */ -static inline bool d_is_binary_ctx(json_ctx_t* ctx) { return ctx->allocated == 0; } /**< check if the parser context was created from binary data. */ +static inline char* d_get_string(d_token_t* r, d_key_t k) { return d_string(d_get(r, k)); } /**< reads token of a property as string. */ +static inline char* d_get_string_at(d_token_t* r, uint32_t pos) { return d_string(d_get_at(r, pos)); } /**< reads string at given pos of an array. */ +static inline int32_t d_get_int(d_token_t* r, d_key_t k) { return d_int(d_get(r, k)); } /**< reads token of a property as int. */ +static inline int32_t d_get_intd(d_token_t* r, d_key_t k, uint32_t d) { return d_intd(d_get(r, k), d); } /**< reads token of a property as int. */ +static inline int32_t d_get_int_at(d_token_t* r, uint32_t pos) { return d_int(d_get_at(r, pos)); } /**< reads a int at given pos of an array. */ +static inline uint64_t d_get_long(d_token_t* r, d_key_t k) { return d_long(d_get(r, k)); } /**< reads token of a property as long. */ +static inline uint64_t d_get_longd(d_token_t* r, d_key_t k, uint64_t d) { return d_longd(d_get(r, k), d); } /**< reads token of a property as long. */ +static inline uint64_t d_get_long_at(d_token_t* r, uint32_t pos) { return d_long(d_get_at(r, pos)); } /**< reads long at given pos of an array. */ +static inline bytes_t* d_get_bytes(d_token_t* r, d_key_t k) { return d_bytes(d_get(r, k)); } /**< reads token of a property as bytes. */ +static inline bytes_t* d_get_bytes_at(d_token_t* r, uint32_t pos) { return d_bytes(d_get_at(r, pos)); } /**< reads bytes at given pos of an array. */ +static inline bool d_is_binary_ctx(json_ctx_t* ctx) { return ctx->allocated == 0; } /**< check if the parser context was created from binary data. */ bytes_t* d_get_byteskl(d_token_t* r, d_key_t k, uint32_t minl); d_token_t* d_getl(d_token_t* item, uint16_t k, uint32_t minl); diff --git a/c/src/core/util/debug.c b/c/src/core/util/debug.c index d157d9830..7cf66c6b7 100644 --- a/c/src/core/util/debug.c +++ b/c/src/core/util/debug.c @@ -101,6 +101,21 @@ char* in3_errmsg(in3_ret_t err /**< the error code */) { case IN3_ENODEVICE: return "no hardware wallet connected"; case IN3_EAPDU: return "error in usb communication protocol"; case IN3_EPLGN_NONE: return "no plugin could handle specified action"; + case IN3_HTTP_BAD_REQUEST: return "400 - Bad Request"; + case IN3_HTTP_UNAUTHORIZED: return "401 - Unauthorized"; + case IN3_HTTP_PAYMENT_REQUIRED: return "402 - Payment required"; + case IN3_HTTP_FORBIDDEN: return "403 - Forbidden"; + case IN3_HTTP_NOT_FOUND: return "404 - Not found"; + case IN3_HTTP_M_NOT_ALLOWED: return "405 - Method not allowed"; + case IN3_HTTP_NOT_ACCEPTABLE: return "406 - Not acceptable"; + case IN3_HTTP_PROX_AUTH_REQUIRED: return "407 - Proxy Authetification required"; + case IN3_HTTP_TIMEOUT: return "408 - Request timeout"; + case IN3_HTTP_CONFLICT: return "409 - Conclict"; + case IN3_HTTP_GONE: return "410 - Gone"; + case IN3_HTTP_INTERNAL_ERROR: return "500 - Internal Server Error"; + case IN3_HTTP_NOT_IMPLEMENTED: return "501 - Not Implemented"; + case IN3_HTTP_BAD_GATEWAY: return "502 - Bad Gateway"; + case IN3_HTTP_UNAVAILABLE: return "503 - Service Unavailable"; } return NULL; #else diff --git a/c/src/core/util/debug.h b/c/src/core/util/debug.h index 451fb04d6..72d0b5e09 100644 --- a/c/src/core/util/debug.h +++ b/c/src/core/util/debug.h @@ -147,33 +147,33 @@ static inline void add_hex(sb_t* sb, char prefix, const char* property, bytes_t // macros for checking params #define CHECK_PARAMS_LEN(ctx, params, len) \ - if (d_type(params) != T_ARRAY || d_len(params) < len) return ctx_set_error(ctx, "arguments need to be a array with at least " #len " arguments", IN3_EINVAL); + if (d_type(params) != T_ARRAY || d_len(params) < len) return req_set_error(ctx, "arguments need to be a array with at least " #len " arguments", IN3_EINVAL); #define CHECK_PARAM_TYPE(ctx, params, index, type) \ - if (d_type(d_get_at(params, index)) != type) return ctx_set_error(ctx, "argument at index " #index " must be a " #type, IN3_EINVAL); + if (d_type(d_get_at(params, index)) != type) return req_set_error(ctx, "argument at index " #index " must be a " #type, IN3_EINVAL); #define CHECK_PARAM_NUMBER(ctx, params, index) \ switch (d_type(d_get_at(params, index))) { \ case T_INTEGER: \ case T_BYTES: break; \ - default: return ctx_set_error(ctx, "argument at index " #index " must be a number", IN3_EINVAL); \ + default: return req_set_error(ctx, "argument at index " #index " must be a number", IN3_EINVAL); \ } #define CHECK_PARAM_ADDRESS(ctx, params, index) \ { \ const d_token_t* val = d_get_at(params, index); \ - if (d_type(val) != T_BYTES || val->len != 20) return ctx_set_error(ctx, "argument at index " #index " must be a valid address", IN3_EINVAL); \ + if (d_type(val) != T_BYTES || val->len != 20) return req_set_error(ctx, "argument at index " #index " must be a valid address", IN3_EINVAL); \ } #define CHECK_PARAM_LEN(ctx, params, index, len) \ - if (d_len(d_get_at(params, index)) != len) return ctx_set_error(ctx, "argument at index " #index " must have a length of " #len, IN3_EINVAL); + if (d_len(d_get_at(params, index)) != len) return req_set_error(ctx, "argument at index " #index " must have a length of " #len, IN3_EINVAL); #define CHECK_PARAM_MAX_LEN(ctx, params, index, len) \ - if (d_len(d_get_at(params, index)) > len) return ctx_set_error(ctx, "argument at index " #index " must be smaller than " #len, IN3_EINVAL); + if (d_len(d_get_at(params, index)) > len) return req_set_error(ctx, "argument at index " #index " must be smaller than " #len, IN3_EINVAL); #define CHECK_PARAM_MIN_LEN(ctx, params, index, len) \ - if (d_len(d_get_at(params, index)) < len) return ctx_set_error(ctx, "argument at index " #index " must be at least " #len, IN3_EINVAL); + if (d_len(d_get_at(params, index)) < len) return req_set_error(ctx, "argument at index " #index " must be at least " #len, IN3_EINVAL); #define CHECK_PARAM(ctx, params, index, cond) \ { \ const d_token_t* val = d_get_at(params, index); \ - if (!(cond)) return ctx_set_error(ctx, "argument at index " #index " must match " #cond, IN3_EINVAL); \ + if (!(cond)) return req_set_error(ctx, "argument at index " #index " must match " #cond, IN3_EINVAL); \ } /** used for exeuting a function based on the name. This macro will return if the name matches. */ #define TRY_RPC(name, fn) \ - if (strcmp(method, name) == 0) return fn; + if (strcmp(ctx->method, name) == 0) return fn; #endif /* DEBUG_H */ \ No newline at end of file diff --git a/c/src/core/util/error.h b/c/src/core/util/error.h index b0c6fbd2f..78d678346 100644 --- a/c/src/core/util/error.h +++ b/c/src/core/util/error.h @@ -68,7 +68,7 @@ typedef enum { IN3_EVERS = -8, /**< Version mismatch */ IN3_EINVALDT = -9, /**< Data invalid, eg. invalid/incomplete JSON */ IN3_EPASS = -10, /**< Wrong password */ - IN3_ERPC = -11, /**< RPC error (i.e. in3_ctx_t::error set) */ + IN3_ERPC = -11, /**< RPC error (i.e. in3_req_t::error set) */ IN3_ERPCNRES = -12, /**< RPC no response */ IN3_EUSNURL = -13, /**< USN URL parse error */ IN3_ETRANS = -14, /**< Transport error */ @@ -79,6 +79,23 @@ typedef enum { IN3_ENODEVICE = -19, /**< harware wallet device not connected */ IN3_EAPDU = -20, /**< error in hardware wallet communication */ IN3_EPLGN_NONE = -21, /**< no plugin could handle specified action */ + + IN3_HTTP_BAD_REQUEST = -400, /**< Bad Request */ + IN3_HTTP_UNAUTHORIZED = -401, /**< Unauthorized */ + IN3_HTTP_PAYMENT_REQUIRED = -402, /**< Unauthorized */ + IN3_HTTP_FORBIDDEN = -403, /**< Forbidden */ + IN3_HTTP_NOT_FOUND = -404, /**< not found */ + IN3_HTTP_M_NOT_ALLOWED = -405, /**< method not allowed */ + IN3_HTTP_NOT_ACCEPTABLE = -406, /**< Not acceptable */ + IN3_HTTP_PROX_AUTH_REQUIRED = -407, /**< Proxy Authentification required */ + IN3_HTTP_TIMEOUT = -408, /**< Request timeout */ + IN3_HTTP_CONFLICT = -409, /**< conflict */ + IN3_HTTP_GONE = -410, /**< gone */ + IN3_HTTP_INTERNAL_ERROR = -500, /**< Internal Server Error */ + IN3_HTTP_NOT_IMPLEMENTED = -501, /**< not implemented */ + IN3_HTTP_BAD_GATEWAY = -502, /**< Bad Gateway */ + IN3_HTTP_UNAVAILABLE = -503 /**< service unavailable */ + } in3_ret_t; /** Optional type similar to C++ std::optional diff --git a/c/src/core/util/mem.c b/c/src/core/util/mem.c index 445900156..0f96e0346 100644 --- a/c/src/core/util/mem.c +++ b/c/src/core/util/mem.c @@ -147,16 +147,11 @@ void* t_realloc(void* ptr, size_t size, size_t oldsize, char* file, const char* return _realloc_(ptr, size, oldsize, file, func, line); } -size_t mem_get_max_heap() { - return 0; -} - int mem_get_memleak_cnt() { return mem_count; } -void mem_reset(int cnt) { - UNUSED_VAR(cnt); +void mem_reset() { mem_count = 0; } diff --git a/c/src/core/util/mem.h b/c/src/core/util/mem.h index 65eedd6fa..9ab43e032 100644 --- a/c/src/core/util/mem.h +++ b/c/src/core/util/mem.h @@ -92,14 +92,12 @@ #define _calloc(n, s) t_calloc(n, s, __FILE__, __func__, __LINE__) #define _free(p) t_free(p, __FILE__, __func__, __LINE__) #define _realloc(p, s, o) t_realloc(p, s, o, __FILE__, __func__, __LINE__) -size_t mem_get_max_heap(); -void* t_malloc(size_t size, char* file, const char* func, int line); -void* t_realloc(void* ptr, size_t size, size_t oldsize, char* file, const char* func, int line); -void* t_calloc(size_t n, size_t size, char* file, const char* func, int line); -void t_free(void* ptr, char* file, const char* func, int line); -int mem_get_memleak_cnt(); -void mem_reset(int cnt); -void memstack(); +void* t_malloc(size_t size, char* file, const char* func, int line); +void* t_realloc(void* ptr, size_t size, size_t oldsize, char* file, const char* func, int line); +void* t_calloc(size_t n, size_t size, char* file, const char* func, int line); +void t_free(void* ptr, char* file, const char* func, int line); +int mem_get_memleak_cnt(); +void mem_reset(); #else /* TEST */ #ifdef LOGGING #define _malloc(s) _malloc_(s, __FILE__, __func__, __LINE__) diff --git a/c/src/core/util/scache.h b/c/src/core/util/scache.h index e486eca95..4f3970b64 100644 --- a/c/src/core/util/scache.h +++ b/c/src/core/util/scache.h @@ -52,7 +52,8 @@ extern "C" { typedef enum cache_props { CACHE_PROP_MUST_FREE = 0x1, /**< indicates the content must be freed*/ CACHE_PROP_SRC_REQ = 0x2, /**< the value holds the src-request */ - CACHE_PROP_ONLY_EXTERNAL = 0x4 /**< should only be freed if the context is external */ + CACHE_PROP_ONLY_EXTERNAL = 0x4, /**< should only be freed if the context is external */ + CACHE_PROP_PAYMENT = 0x80 /**< This cache-entry is a payment.data */ } cache_props_t; /** * represents a single cache entry in a linked list. diff --git a/c/src/core/util/used_keys.h b/c/src/core/util/used_keys.h index 8b01d62d2..d1ceac0ee 100644 --- a/c/src/core/util/used_keys.h +++ b/c/src/core/util/used_keys.h @@ -1,12 +1,8 @@ // this is a autogenerated file (scripts/updqate_keys.sh)! Do not edit manually! static char* USED_KEYS[] = { - "0x1", - "0x2a", - "0x5", - "0x7d0", - "0x99", - "0xf6", + "account", + "accountId", "accountProof", "accounts", "action", @@ -17,6 +13,7 @@ static char* USED_KEYS[] = { "autoUpdateList", "avgBlockTime", "balance", + "bits", "block", "blockHash", "blockNumber", @@ -25,31 +22,47 @@ static char* USED_KEYS[] = { "bootWeights", "bulkSize", "bypassFinality", + "c", "capacity", "cbtx", "cbtxMerkleProof", "chainId", + "chainType", + "chainwork", + "cipher", "cipherparams", + "ciphertext", "code", "codeHash", + "codehash", "coinbase", + "commitment", + "committed", "confirmations", "contract", "contractAddress", "count", + "create2", + "create_proof_method", + "creator", "crypto", "cumulativeGasUsed", "currentBlock", "data", "dataNodes", "debug", + "decimals", "deposit", "depositTo", "difficulty", + "dklen", "engine", "error", + "ethAddress", "execTime", + "experimental", "extraData", + "fee", "final", "finality", "finalityBlocks", @@ -59,14 +72,19 @@ static char* USED_KEYS[] = { "gasLimit", "gasPrice", "gasUsed", + "govContract", "hash", + "height", "hex", "id", "in3", "in_active_chain", + "incentive", "includeCode", "index", "input", + "iv", + "kdf", "kdfparams", "keepIn3", "key", @@ -81,37 +99,58 @@ static char* USED_KEYS[] = { "logProof", "logs", "logsBloom", + "mac", "mainContract", + "main_contract", "maxAttempts", "maxDAP", "maxDiff", "maxPrice", "maxVerifiedHashes", + "max_price", "merkleProof", + "merkleroot", "message", "method", "minDeposit", "miner", "mixHash", + "msSigs", "msgHash", "msgType", + "musig_pub_keys", + "musig_urls", "n", + "nTx", + "name", "needsUpdate", "nextblockhash", "nodeLimit", "nodeList", "nodeProps", + "nodeRegistry", "nodes", "nonce", "number", + "offer", + "p", "params", "parentHash", "pay", "payed", "performance", + "pk", + "pre_commitment", + "preselect_nodes", + "previousblockhash", + "prf", "price", + "priceList", "proof", "props", + "provider_url", + "pubKeyHash", + "pub_keys", "publicKey", "r", "raw", @@ -128,14 +167,20 @@ static char* USED_KEYS[] = { "rpc", "rpcCount", "rpcTime", + "running", "s", + "salt", + "saltarg", "sealFields", "sequence", "sha3Uncles", + "sig", "signature", "signatureCount", "signatures", + "signedError", "signerNodes", + "signer_type", "size", "standardV", "stateRoot", @@ -144,6 +189,8 @@ static char* USED_KEYS[] = { "status", "storageHash", "storageProof", + "symbol", + "sync_key", "time", "timeout", "timestamp", @@ -152,6 +199,7 @@ static char* USED_KEYS[] = { "token", "topics", "total", + "totalFee", "totalServers", "transactionHash", "transactionIndex", @@ -175,7 +223,9 @@ static char* USED_KEYS[] = { "value", "verification", "verifiedHashes", + "verify_proof_method", "version", + "versionHex", "vin", "vout", "vsize", diff --git a/c/src/core/util/utils.c b/c/src/core/util/utils.c index f2511fbc9..09a4f2409 100644 --- a/c/src/core/util/utils.c +++ b/c/src/core/util/utils.c @@ -87,7 +87,7 @@ static time_func in3_time_fn = time_libc; static rand_func in3_rand_fn = rand_libc; static srand_func in3_srand_fn = srand_libc; #endif /* __ZEPHYR__ */ - +#define MAX_UINT64 0xFFFFFFFFFFFFFFFF void in3_sleep(uint32_t ms) { #if defined(_WIN32) || defined(WIN32) Sleep(ms); @@ -111,20 +111,11 @@ void uint256_set(const uint8_t* src, wlen_t src_len, bytes32_t dst) { } void long_to_bytes(uint64_t val, uint8_t* dst) { - *dst = val >> 56 & 0xFF; - *(dst + 1) = val >> 48 & 0xFF; - *(dst + 2) = val >> 40 & 0xFF; - *(dst + 3) = val >> 32 & 0xFF; - *(dst + 4) = val >> 24 & 0xFF; - *(dst + 5) = val >> 16 & 0xFF; - *(dst + 6) = val >> 8 & 0xFF; - *(dst + 7) = val & 0xFF; + for (int i = 7; i >= 0; i--, val >>= 8) dst[i] = val & 0xFF; } + void int_to_bytes(uint32_t val, uint8_t* dst) { - *dst = val >> 24 & 0xFF; - *(dst + 1) = val >> 16 & 0xFF; - *(dst + 2) = val >> 8 & 0xFF; - *(dst + 3) = val & 0xFF; + for (int i = 3; i >= 0; i--, val >>= 8) dst[i] = val & 0xFF; } uint8_t hexchar_to_int(char c) { @@ -136,11 +127,12 @@ uint8_t hexchar_to_int(char c) { return c - 'A' + 10; return 255; } + #ifdef __ZEPHYR__ const char* u64_to_str(uint64_t value, char* buffer, int buffer_len) { // buffer has to be at least 21 bytes (max u64 val = 18446744073709551615 has 20 digits + '\0') - if (buffer_len < 21) return ""; + if (buffer_len < 21) return ""; buffer[buffer_len - 1] = '\0'; int pos = buffer_len - 1; @@ -161,9 +153,11 @@ int hex_to_bytes(const char* buf, int len, uint8_t* out, int outbuf_size) { len -= 2; } if (len == 0) return 0; + int bytes_len = (len + 1) / 2, i = 0, j = 0; if (bytes_len > outbuf_size) return -1; if (len & 1) { + // for a odd number of bytes, we use the first 4bit and then start with index 1 out[0] = hexchar_to_int(buf[0]); j = i = 1; } @@ -173,6 +167,7 @@ int hex_to_bytes(const char* buf, int len, uint8_t* out, int outbuf_size) { return bytes_len; } + bytes_t* hex_to_new_bytes(const char* buf, int len) { bytes_t* bytes = _malloc(sizeof(bytes_t)); bytes->len = (len + 1) / 2; @@ -202,23 +197,11 @@ int keccak(bytes_t data, void* dst) { return 0; } -bytes_t* sha3(const bytes_t* data) { - bytes_t* out = NULL; - struct SHA3_CTX ctx; - - out = _calloc(1, sizeof(bytes_t)); - - sha3_256_Init(&ctx); - sha3_Update(&ctx, data->data, data->len); - - out->data = _calloc(1, 32 * sizeof(uint8_t)); - out->len = 32; - - keccak_Final(&ctx, out->data); - return out; -} - uint64_t bytes_to_long(const uint8_t* data, int len) { + if (len > 8) { + data += len - 8; + len = 8; + } uint64_t res = 0; int i; for (i = 0; i < len; i++) { @@ -227,10 +210,11 @@ uint64_t bytes_to_long(const uint8_t* data, int len) { } return res; } + uint64_t char_to_long(const char* a, int l) { - if (!a) return -1; + if (!a || l < -1) return MAX_UINT64; if (l == -1) l = strlen(a); - if (a[0] == '0' && a[1] == 'x') { + if (a[0] == '0' && a[1] == 'x') { // it's a hex number long val = 0; for (int i = l - 1; i > 1; i--) val |= ((uint64_t) hexchar_to_int(a[i])) << (4 * (l - 1 - i)); @@ -242,7 +226,7 @@ uint64_t char_to_long(const char* a, int l) { temp[l] = 0; return atoi(temp); } - return -1; + return MAX_UINT64; } char* _strdupn(const char* src, int len) { @@ -252,9 +236,9 @@ char* _strdupn(const char* src, int len) { dst[len] = 0; return dst; } + int min_bytes_len(uint64_t val) { - int i; - for (i = 0; i < 8; i++, val >>= 8) { + for (int i = 0; i < 8; i++, val >>= 8) { if (val == 0) return i; } return 8; diff --git a/c/src/core/util/utils.h b/c/src/core/util/utils.h index c02ced227..64acd9d1c 100644 --- a/c/src/core/util/utils.h +++ b/c/src/core/util/utils.h @@ -45,6 +45,7 @@ extern "C" { #endif #include "bytes.h" +#include #include #ifdef __ZEPHYR__ @@ -53,6 +54,7 @@ extern "C" { #else #define _strtoull(str, endptr, base) strtoull(str, endptr, base) #endif + /** simple swap macro for integral types */ #define SWAP(a, b) \ { \ @@ -85,7 +87,7 @@ extern "C" { #define STR_IMPL_(x) #x #define STR(x) STR_IMPL_(x) -/** converts the bytes to a unsigned long (at least the last max len bytes) */ +/** converts the bytes to a unsigned long (at least the last max len bytes). */ uint64_t bytes_to_long(const uint8_t* data, int len); /** converts the bytes to a unsigned int (at least the last max len bytes) */ @@ -105,12 +107,17 @@ static inline uint32_t bytes_to_int(const uint8_t* data, int len) { /** converts a character into a uint64_t*/ uint64_t char_to_long(const char* a, int l); -/** converts a hexchar to byte (4bit) */ +/** converts a hexchar to byte (4bit). In case of a nonhex char 0xff will be returned. */ uint8_t hexchar_to_int(char c); +#ifdef __ZEPHYR__ +// this function is only used in zephyr, because there it does not support printf("%ull",u64); + /** converts a uint64_t to string (char*); buffer-size min. 21 bytes */ const char* u64_to_str(uint64_t value, char* pBuf, int szBuf); +#endif + /** * convert a c hex string to a byte array storing it into an existing buffer. * @@ -128,19 +135,16 @@ bytes_t* hex_to_new_bytes(const char* buf, int len); /** convefrts a bytes into hex */ int bytes_to_hex(const uint8_t* buffer, int len, char* out); -/** hashes the bytes and creates a new bytes_t */ -bytes_t* sha3(const bytes_t* data); - /** writes 32 bytes to the pointer. */ int keccak(bytes_t data, void* dst); -/** converts a long to 8 bytes */ +/** converts a a uin64_t to 8 bytes written to dst using big endian*/ void long_to_bytes(uint64_t val, uint8_t* dst); -/** converts a int to 4 bytes */ +/** converts a unsigned int to 4 bytes written to dst using big endian*/ void int_to_bytes(uint32_t val, uint8_t* dst); -/** duplicate the string */ +/** duplicate the string. A len=-1 will determine the len with strlen. */ char* _strdupn(const char* src, int len); /** calculate the min number of byte to represents the len */ @@ -148,6 +152,9 @@ int min_bytes_len(uint64_t val); /** * sets a variable value to 32byte word. + * @param src The src data + * @param src_len the number of bytes + * @param dst target pointer */ void uint256_set(const uint8_t* src, wlen_t src_len, bytes32_t dst); @@ -168,7 +175,7 @@ char* str_replace_pos(char* orig, size_t pos, size_t len, const char* rep); char* str_find(char* haystack, const char* needle); /** - * remove all html-tags in the text. + * remove all html-tags in the text. This function will modify the orifinal data and return the same pointer as the input. */ char* str_remove_html(char* data); @@ -177,7 +184,7 @@ char* str_remove_html(char* data); */ uint64_t current_ms(); -/** changes to pointer (a) and it length (l) to remove leading 0 bytes.*/ +/** changes to pointer (a) and it length (l) to remove leading 0 bytes. it will reduce it to max len=1*/ #define optimize_len(a, l) \ while (l > 1 && *a == 0) { \ l--; \ @@ -205,6 +212,19 @@ uint64_t current_ms(); if (_r < 0) return _r; \ } +/** + * executes the expression and expects the return value to be a int indicating the error. + * if the return value is negative it will stop and return this value otherwise continue. + */ +#define TRY_CATCH(exp, catch) \ + { \ + int _r = (exp); \ + if (_r < 0) { \ + catch; \ + return _r; \ + } \ + } + /** * executes the expression and expects value to equal val. * if not it will return IN3_EINVAL @@ -234,12 +254,17 @@ uint64_t current_ms(); if (res < 0) goto clean; \ } +/** + * returns true if all pytes (specified by l) of pts have a value of zero. + */ static inline bool memiszero(uint8_t* ptr, size_t l) { - while (l > 0 && *ptr == 0) { + assert(l > 0); + while (l) { + if (*ptr) return false; l--; ptr++; } - return !l; + return true; } /** @@ -294,6 +319,47 @@ int64_t parse_float_val(const char* data, /**< the data string*/ int32_t expo /**< the exponent */ ); +#ifdef THREADSAFE +#define _NAME(x, y) x##y +#if defined(_MSC_VER) || defined(__MINGW32__) + +#include + +#define INIT_LOCK(NAME) \ + static HANDLE _NAME(_lock_handle_, NAME) = NULL; \ + static void _NAME(_lock, NAME)() { \ + if (!_NAME(_lock_handle_, NAME)) { \ + HANDLE p = CreateMutex(NULL, FALSE, NULL); \ + if (InterlockedCompareExchangePointer((PVOID*) &_NAME(_lock_handle_, NAME), (PVOID) p, NULL)) CloseHandle(p); \ + } \ + WaitForSingleObject(_NAME(_lock_handle_, NAME), INFINITE); \ + } + +#define LOCK(NAME, code) \ + { \ + _NAME(_lock, NAME) \ + (); \ + code \ + ReleaseMutex(_NAME(_lock_handle_, NAME)); \ + } + +#else +#include +#define INIT_LOCK(NAME) static pthread_mutex_t _NAME(_lock_handle_, NAME) = PTHREAD_MUTEX_INITIALIZER; +#define LOCK(NAME, code) \ + { \ + pthread_mutex_lock(&(_NAME(_lock_handle_, NAME))); \ + code \ + pthread_mutex_unlock(&(_NAME(_lock_handle_, NAME))); \ + } +#endif +#else +#define INIT_LOCK(NAME) \ + {} +#define LOCK(NAME, code) \ + { code } +#endif + #ifdef __cplusplus } #endif diff --git a/c/src/init/CMakeLists.txt b/c/src/init/CMakeLists.txt new file mode 100644 index 000000000..f360ef427 --- /dev/null +++ b/c/src/init/CMakeLists.txt @@ -0,0 +1,49 @@ +############################################################################### +# This file is part of the Incubed project. +# Sources: https://github.com/blockchainsllc/in3 +# +# Copyright (C) 2018-2020 slock.it GmbH, Blockchains LLC +# +# +# COMMERCIAL LICENSE USAGE +# +# Licensees holding a valid commercial license may use this file in accordance +# with the commercial license agreement provided with the Software or, alternatively, +# in accordance with the terms contained in a written agreement between you and +# slock.it GmbH/Blockchains LLC. For licensing terms and conditions or further +# information please contact slock.it at in3@slock.it. +# +# Alternatively, this file may be used under the AGPL license as follows: +# +# AGPL LICENSE USAGE +# +# This program is free software: you can redistribute it and/or modify it under the +# terms of the GNU Affero General Public License as published by the Free Software +# Foundation, either version 3 of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. +# [Permissions of this strong copyleft license are conditioned on making available +# complete source code of licensed works and modifications, which include larger +# works using a licensed work, under the same license. Copyright and license notices +# must be preserved. Contributors provide an express grant of patent rights.] +# You should have received a copy of the GNU Affero General Public License along +# with this program. If not, see . +############################################################################### +# main incubed module defining the interfaces for transport, verifier and storage. +# +# This module does not have any dependencies and cannot be used without additional modules providing verification and transport. + +add_static_library( + NAME init + + SOURCES + in3_init.c + + DEPENDS + ${IN3_VERIFIER} + ${IN3_API} + ${IN3_TRANSPORT} + ${IN3_NODESELECT} +) diff --git a/c/src/verifier/in3_init.c b/c/src/init/in3_init.c similarity index 97% rename from c/src/verifier/in3_init.c rename to c/src/init/in3_init.c index 33c2630bb..b0ae5338d 100644 --- a/c/src/verifier/in3_init.c +++ b/c/src/init/in3_init.c @@ -13,7 +13,7 @@ #include "../transport/http/in3_http.h" #endif #ifdef NODESELECT_DEF -#include "../nodeselect/nodeselect_def.h" +#include "../nodeselect/full/nodeselect_def.h" #endif #include "../verifier/btc/btc.h" #include "../verifier/eth1/basic/eth_basic.h" diff --git a/c/src/verifier/in3_init.h b/c/src/init/in3_init.h similarity index 100% rename from c/src/verifier/in3_init.h rename to c/src/init/in3_init.h diff --git a/c/src/nodeselect/CMakeLists.txt b/c/src/nodeselect/CMakeLists.txt index b91ff6288..530748e37 100644 --- a/c/src/nodeselect/CMakeLists.txt +++ b/c/src/nodeselect/CMakeLists.txt @@ -1,8 +1,8 @@ ############################################################################### # This file is part of the Incubed project. -# Sources: https://github.com/slockit/in3-c +# Sources: https://github.com/blockchainsllc/in3 # -# Copyright (C) 2018-2019 slock.it GmbH, Blockchains LLC +# Copyright (C) 2018-2020 slock.it GmbH, Blockchains LLC # # # COMMERCIAL LICENSE USAGE @@ -31,17 +31,8 @@ # You should have received a copy of the GNU Affero General Public License along # with this program. If not, see . ############################################################################### - - -add_static_library( - NAME nodeselect_def - - SOURCES - nodeselect_def.c - nodelist.c - cache.c - registry.c - - DEPENDS - core -) +if (NODESELECT_DEF_WL AND NOT NODESELECT_DEF) + message(SEND_ERROR "Nodeselect - whitelisting enabled without enabling the plugin itself!") +elseif (NODESELECT_DEF) + add_subdirectory(full) +endif() diff --git a/c/src/nodeselect/full/CMakeLists.txt b/c/src/nodeselect/full/CMakeLists.txt new file mode 100644 index 000000000..9c3fea64d --- /dev/null +++ b/c/src/nodeselect/full/CMakeLists.txt @@ -0,0 +1,57 @@ +############################################################################### +# This file is part of the Incubed project. +# Sources: https://github.com/slockit/in3-c +# +# Copyright (C) 2018-2019 slock.it GmbH, Blockchains LLC +# +# +# COMMERCIAL LICENSE USAGE +# +# Licensees holding a valid commercial license may use this file in accordance +# with the commercial license agreement provided with the Software or, alternatively, +# in accordance with the terms contained in a written agreement between you and +# slock.it GmbH/Blockchains LLC. For licensing terms and conditions or further +# information please contact slock.it at in3@slock.it. +# +# Alternatively, this file may be used under the AGPL license as follows: +# +# AGPL LICENSE USAGE +# +# This program is free software: you can redistribute it and/or modify it under the +# terms of the GNU Affero General Public License as published by the Free Software +# Foundation, either version 3 of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. +# [Permissions of this strong copyleft license are conditioned on making available +# complete source code of licensed works and modifications, which include larger +# works using a licensed work, under the same license. Copyright and license notices +# must be preserved. Contributors provide an express grant of patent rights.] +# You should have received a copy of the GNU Affero General Public License along +# with this program. If not, see . +############################################################################### + + +add_static_library( + NAME nodeselect_def + + SOURCES + nodeselect_def.c + nodelist.c + cache.c + registry.c + + DEPENDS + core +) + + +if (THREADSAFE) +if (MSVC OR MSYS OR MINGW) +elseif (NOT DEFINED ANDROID_ABI) + # for detecting Windows compilers + # target_link_libraries(nodeselect_def_o pthread) + target_link_libraries(nodeselect_def pthread) +endif () +endif() \ No newline at end of file diff --git a/c/src/nodeselect/cache.c b/c/src/nodeselect/full/cache.c similarity index 94% rename from c/src/nodeselect/cache.c rename to c/src/nodeselect/full/cache.c index df2116053..16a88f60a 100644 --- a/c/src/nodeselect/cache.c +++ b/c/src/nodeselect/full/cache.c @@ -33,12 +33,12 @@ *******************************************************************************/ #include "cache.h" -#include "../core/client/context.h" -#include "../core/client/plugin.h" -#include "../core/util/bitset.h" -#include "../core/util/log.h" -#include "../core/util/mem.h" -#include "../core/util/utils.h" +#include "../../core/client/plugin.h" +#include "../../core/client/request.h" +#include "../../core/util/bitset.h" +#include "../../core/util/log.h" +#include "../../core/util/mem.h" +#include "../../core/util/utils.h" #include "nodelist.h" #include "stdio.h" #include @@ -97,7 +97,7 @@ in3_ret_t in3_cache_update_nodelist(in3_t* c, in3_nodeselect_def_t* data) { write_cache_key(key, c->chain.chain_id, data->contract); // get from cache - in3_cache_ctx_t cctx = {.ctx = NULL, .content = NULL, .key = key}; + in3_cache_ctx_t cctx = {.req = NULL, .content = NULL, .key = key}; in3_plugin_execute_all(c, PLGN_ACT_CACHE_GET, &cctx); bytes_t* b = cctx.content; if (!b) return IN3_OK; @@ -193,7 +193,7 @@ in3_ret_t in3_cache_store_nodelist(in3_t* c, in3_nodeselect_def_t* data) { write_cache_key(key, c->chain.chain_id, data->contract); // store it and ignore return value since failing when writing cache should not stop us. - in3_cache_ctx_t cctx = {.ctx = NULL, .content = &bb->b, .key = key}; + in3_cache_ctx_t cctx = {.req = NULL, .content = &bb->b, .key = key}; in3_plugin_execute_all(c, PLGN_ACT_CACHE_SET, &cctx); data->dirty = false; @@ -218,7 +218,7 @@ in3_ret_t in3_cache_update_whitelist(in3_t* c, in3_nodeselect_def_t* data) { write_cache_key(key, c->chain.chain_id, wl->contract); // get from cache - in3_cache_ctx_t cctx = {.ctx = NULL, .content = NULL, .key = key}; + in3_cache_ctx_t cctx = {.req = NULL, .content = NULL, .key = key}; in3_plugin_execute_all(c, PLGN_ACT_CACHE_GET, &cctx); bytes_t* cached_data = cctx.content; if (cached_data) { @@ -262,8 +262,8 @@ in3_ret_t in3_cache_store_whitelist(in3_t* c, in3_nodeselect_def_t* data) { write_cache_key(key, c->chain.chain_id, wl->contract); // store it and ignore return value since failing when writing cache should not stop us. - in3_ctx_t tmp_ctx = {.client = c}; - in3_cache_ctx_t cctx = {.ctx = &tmp_ctx, .key = key, .content = &bb->b}; + in3_req_t tmp_ctx = {.client = c}; + in3_cache_ctx_t cctx = {.req = &tmp_ctx, .key = key, .content = &bb->b}; in3_plugin_execute_first_or_none(&tmp_ctx, PLGN_ACT_CACHE_SET, &cctx); // clear buffer diff --git a/c/src/nodeselect/cache.h b/c/src/nodeselect/full/cache.h similarity index 97% rename from c/src/nodeselect/cache.h rename to c/src/nodeselect/full/cache.h index 9e1c594e4..ac37f1883 100644 --- a/c/src/nodeselect/cache.h +++ b/c/src/nodeselect/full/cache.h @@ -39,9 +39,9 @@ * If no storage handler is specified nothing will be cached. * */ -#include "../core/client/client.h" -#include "../core/client/context.h" -#include "../core/util/bytes.h" +#include "../../core/client/client.h" +#include "../../core/client/request.h" +#include "../../core/util/bytes.h" #include "nodelist.h" #ifndef CACHE_H diff --git a/c/src/nodeselect/nodelist.c b/c/src/nodeselect/full/nodelist.c similarity index 77% rename from c/src/nodeselect/nodelist.c rename to c/src/nodeselect/full/nodelist.c index e27744350..8147f1187 100644 --- a/c/src/nodeselect/nodelist.c +++ b/c/src/nodeselect/full/nodelist.c @@ -33,11 +33,11 @@ *******************************************************************************/ #include "nodelist.h" -#include "../core/client/context_internal.h" -#include "../core/client/keys.h" -#include "../core/util/bitset.h" -#include "../core/util/data.h" -#include "../core/util/debug.h" +#include "../../core/client/keys.h" +#include "../../core/client/request_internal.h" +#include "../../core/util/bitset.h" +#include "../../core/util/data.h" +#include "../../core/util/debug.h" #include "cache.h" #include #include @@ -66,7 +66,7 @@ NONULL static inline bool nodelist_exp_last_block_neq(in3_nodeselect_def_t* data return (data->nodelist_upd8_params != NULL && data->nodelist_upd8_params->exp_last_block != exp_last_block); } -NONULL static in3_ret_t fill_chain(in3_nodeselect_def_t* data, in3_ctx_t* ctx, d_token_t* result) { +NONULL static in3_ret_t fill_chain(in3_nodeselect_def_t* data, in3_req_t* ctx, d_token_t* result) { in3_ret_t res = IN3_OK; uint64_t _now = in3_time(NULL); const uint64_t now = (uint64_t) _now; @@ -76,10 +76,10 @@ NONULL static in3_ret_t fill_chain(in3_nodeselect_def_t* data, in3_ctx_t* ctx, d unsigned int len = d_len(nodes); if (!nodes || d_type(nodes) != T_ARRAY) - return ctx_set_error(ctx, "No Nodes in the result", IN3_EINVALDT); + return req_set_error(ctx, "No Nodes in the result", IN3_EINVALDT); if (!(t = d_get(result, K_LAST_BLOCK_NUMBER))) - return ctx_set_error(ctx, "LastBlockNumer is missing", IN3_EINVALDT); + return req_set_error(ctx, "LastBlockNumer is missing", IN3_EINVALDT); // update last blockNumber const uint64_t last_block = d_long(t); @@ -98,29 +98,29 @@ NONULL static in3_ret_t fill_chain(in3_nodeselect_def_t* data, in3_ctx_t* ctx, d in3_node_t* n = newList + i; node = node ? d_next(node) : d_get_at(nodes, i); if (!node) { - res = ctx_set_error(ctx, "node missing", IN3_EINVALDT); + res = req_set_error(ctx, "node missing", IN3_EINVALDT); break; } int old_index = (int) i; - n->capacity = d_get_intkd(node, K_CAPACITY, 1); - n->index = d_get_intkd(node, K_INDEX, i); - n->deposit = d_get_longk(node, K_DEPOSIT); - n->props = d_get_longkd(node, K_PROPS, 65535); - n->url = d_get_stringk(node, K_URL); + n->capacity = d_get_intd(node, K_CAPACITY, 1); + n->index = d_get_intd(node, K_INDEX, i); + n->deposit = d_get_long(node, K_DEPOSIT); + n->props = d_get_longd(node, K_PROPS, 65535); + n->url = d_get_string(node, K_URL); bytes_t* adr_bytes = d_get_byteskl(node, K_ADDRESS, 20); if (adr_bytes && adr_bytes->len == 20) memcpy(n->address, adr_bytes->data, 20); else { - res = ctx_set_error(ctx, "missing address in nodelist", IN3_EINVALDT); + res = req_set_error(ctx, "missing address in nodelist", IN3_EINVALDT); break; } BIT_CLEAR(n->attrs, ATTR_BOOT_NODE); // nodes are considered boot nodes only until first nodeList update succeeds if ((ctx->client->flags & FLAGS_BOOT_WEIGHTS) && (t = d_get(node, K_PERFORMANCE))) { - weights[i].blacklisted_until = d_get_longk(t, K_LAST_FAILED) / 1000 + (24 * 3600); - weights[i].response_count = d_get_intk(t, K_COUNT); - weights[i].total_response_time = d_get_intk(t, K_TOTAL); + weights[i].blacklisted_until = d_get_long(t, K_LAST_FAILED) / 1000 + (24 * 3600); + weights[i].response_count = d_get_int(t, K_COUNT); + weights[i].total_response_time = d_get_int(t, K_TOTAL); } // restore the nodeweights if the address was known in the old nodeList @@ -136,7 +136,7 @@ NONULL static in3_ret_t fill_chain(in3_nodeselect_def_t* data, in3_ctx_t* ctx, d if (old_index >= 0) memcpy(weights + i, data->weights + old_index, sizeof(in3_node_weight_t)); // if this is a newly registered node, we wait 24h before we use it, since this is the time where mallicous nodes may be unregistered. - const uint64_t register_time = d_get_longk(node, K_REGISTER_TIME); + const uint64_t register_time = d_get_long(node, K_REGISTER_TIME); if (now && register_time + DAY > now && now > register_time) weights[i].blacklisted_until = register_time + DAY; @@ -144,7 +144,7 @@ NONULL static in3_ret_t fill_chain(in3_nodeselect_def_t* data, in3_ctx_t* ctx, d if (n->url) n->url = _strdupn(n->url, -1); else { - res = ctx_set_error(ctx, "missing url in nodelist", IN3_EINVALDT); + res = req_set_error(ctx, "missing url in nodelist", IN3_EINVALDT); break; } } @@ -181,17 +181,17 @@ NONULL void in3_client_run_chain_whitelisting(in3_nodeselect_def_t* data) { } } -NONULL static in3_ret_t in3_client_fill_chain_whitelist(in3_nodeselect_def_t* data, in3_ctx_t* ctx, d_token_t* result) { +NONULL static in3_ret_t in3_client_fill_chain_whitelist(in3_nodeselect_def_t* data, in3_req_t* ctx, d_token_t* result) { in3_whitelist_t* wl = data->whitelist; int i = 0; d_token_t * nodes = d_get(result, K_NODES), *t = NULL; - if (!wl) return ctx_set_error(ctx, "No whitelist set", IN3_EINVALDT); - if (!nodes || d_type(nodes) != T_ARRAY) return ctx_set_error(ctx, "No Nodes in the result", IN3_EINVALDT); + if (!wl) return req_set_error(ctx, "No whitelist set", IN3_EINVALDT); + if (!nodes || d_type(nodes) != T_ARRAY) return req_set_error(ctx, "No Nodes in the result", IN3_EINVALDT); const int len = d_len(nodes); if (!(t = d_get(result, K_LAST_BLOCK_NUMBER))) - return ctx_set_error(ctx, "LastBlockNumer is missing", IN3_EINVALDT); + return req_set_error(ctx, "LastBlockNumer is missing", IN3_EINVALDT); // update last blockNumber const uint64_t last_block = d_long(t); @@ -212,12 +212,12 @@ NONULL static in3_ret_t in3_client_fill_chain_whitelist(in3_nodeselect_def_t* da } #endif -NONULL static in3_ret_t update_nodelist(in3_t* c, in3_nodeselect_def_t* data, in3_ctx_t* parent_ctx) { +NONULL static in3_ret_t update_nodelist(in3_t* c, in3_nodeselect_def_t* data, in3_req_t* parent_ctx) { // is there a useable required ctx? - in3_ctx_t* ctx = ctx_find_required(parent_ctx, "in3_nodeList"); + in3_req_t* ctx = req_find_required(parent_ctx, "in3_nodeList"); if (ctx) { - if (in3_ctx_state(ctx) == CTX_ERROR || (in3_ctx_state(ctx) == CTX_SUCCESS && !d_get(ctx->responses[0], K_RESULT))) { + if (in3_req_state(ctx) == REQ_ERROR || (in3_req_state(ctx) == REQ_SUCCESS && !d_get(ctx->responses[0], K_RESULT))) { // blacklist node that gave us an error response for nodelist (if not first update) // and clear nodelist params if (nodelist_not_first_upd8(data)) @@ -228,29 +228,29 @@ NONULL static in3_ret_t update_nodelist(in3_t* c, in3_nodeselect_def_t* data, in // if first update return error otherwise return IN3_OK, this is because first update is // always from a boot node which is presumed to be trusted return nodelist_first_upd8(data) - ? ctx_set_error(parent_ctx, "Error updating node_list", ctx_set_error(parent_ctx, ctx->error, IN3_ERPC)) + ? req_set_error(parent_ctx, "Error updating node_list", req_set_error(parent_ctx, ctx->error, IN3_ERPC)) : IN3_OK; } - switch (in3_ctx_state(ctx)) { - case CTX_ERROR: return IN3_OK; /* already handled before*/ - case CTX_WAITING_FOR_RESPONSE: - case CTX_WAITING_TO_SEND: + switch (in3_req_state(ctx)) { + case REQ_ERROR: return IN3_OK; /* already handled before*/ + case REQ_WAITING_FOR_RESPONSE: + case REQ_WAITING_TO_SEND: return IN3_WAITING; - case CTX_SUCCESS: { + case REQ_SUCCESS: { d_token_t* r = d_get(ctx->responses[0], K_RESULT); // if the `lastBlockNumber` != `exp_last_block`, we can be certain that `data->nodelist_upd8_params->node` lied to us // about the nodelist update, so we blacklist it for an hour - if (nodelist_exp_last_block_neq(data, d_get_longk(r, K_LAST_BLOCK_NUMBER))) + if (nodelist_exp_last_block_neq(data, d_get_long(r, K_LAST_BLOCK_NUMBER))) blacklist_node_addr(data, data->nodelist_upd8_params->node, BLACKLISTTIME); _free(data->nodelist_upd8_params); data->nodelist_upd8_params = NULL; const in3_ret_t res = fill_chain(data, ctx, r); if (res < 0) - return ctx_set_error(parent_ctx, "Error updating node_list", ctx_set_error(parent_ctx, ctx->error, res)); + return req_set_error(parent_ctx, "Error updating node_list", req_set_error(parent_ctx, ctx->error, res)); in3_cache_store_nodelist(ctx->client, data); - ctx_remove_required(parent_ctx, ctx, true); + req_remove_required(parent_ctx, ctx, true); #ifdef NODESELECT_DEF_WL in3_client_run_chain_whitelisting(data); @@ -274,43 +274,44 @@ NONULL static in3_ret_t update_nodelist(in3_t* c, in3_nodeselect_def_t* data, in } // create request - char* req = _malloc(350); + in3_nodeselect_config_t* w = in3_get_nodelist(c); + char* req = _malloc(350); sprintf(req, "{\"method\":\"in3_nodeList\",\"jsonrpc\":\"2.0\",\"params\":[%i,\"%s\",[]%s],\"in3\":%s}", - c->node_limit, seed, + w->node_limit, seed, ((c->flags & FLAGS_BOOT_WEIGHTS) && nodelist_first_upd8(data)) ? ",true" : "", sb_add_char(in3_sec, '}')->data); sb_free(in3_sec); // new client - return ctx_add_required(parent_ctx, ctx_new(c, req)); + return req_add_required(parent_ctx, req_new(c, req)); } #ifdef NODESELECT_DEF_WL -NONULL static in3_ret_t update_whitelist(in3_t* c, in3_nodeselect_def_t* data, in3_ctx_t* parent_ctx) { +NONULL static in3_ret_t update_whitelist(in3_t* c, in3_nodeselect_def_t* data, in3_req_t* parent_ctx) { // is there a useable required ctx? - in3_ctx_t* ctx = ctx_find_required(parent_ctx, "in3_whiteList"); + in3_req_t* ctx = req_find_required(parent_ctx, "in3_whiteList"); if (ctx) - switch (in3_ctx_state(ctx)) { - case CTX_ERROR: - return ctx_set_error(parent_ctx, "Error updating white_list", ctx_set_error(parent_ctx, ctx->error, IN3_ERPC)); - case CTX_WAITING_FOR_RESPONSE: - case CTX_WAITING_TO_SEND: + switch (in3_req_state(ctx)) { + case REQ_ERROR: + return req_set_error(parent_ctx, "Error updating white_list", req_set_error(parent_ctx, ctx->error, IN3_ERPC)); + case REQ_WAITING_FOR_RESPONSE: + case REQ_WAITING_TO_SEND: return IN3_WAITING; - case CTX_SUCCESS: { + case REQ_SUCCESS: { d_token_t* result = d_get(ctx->responses[0], K_RESULT); if (result) { // we have a result.... const in3_ret_t res = in3_client_fill_chain_whitelist(data, ctx, result); if (res < 0) - return ctx_set_error(parent_ctx, "Error updating white_list", ctx_set_error(parent_ctx, ctx->error, res)); + return req_set_error(parent_ctx, "Error updating white_list", req_set_error(parent_ctx, ctx->error, res)); in3_cache_store_whitelist(ctx->client, data); in3_client_run_chain_whitelisting(data); - ctx_remove_required(parent_ctx, ctx, true); + req_remove_required(parent_ctx, ctx, true); return IN3_OK; } else - return ctx_set_error(parent_ctx, "Error updating white_list", ctx_check_response_error(ctx, 0)); + return req_set_error(parent_ctx, "Error updating white_list", req_check_response_error(ctx, 0)); } } @@ -323,12 +324,12 @@ NONULL static in3_ret_t update_whitelist(in3_t* c, in3_nodeselect_def_t* data, i sprintf(req, "{\"method\":\"in3_whiteList\",\"jsonrpc\":\"2.0\",\"params\":[\"0x%s\"]}", tmp); // new client - return ctx_add_required(parent_ctx, ctx_new(c, req)); + return req_add_required(parent_ctx, req_new(c, req)); } #endif in3_ret_t update_nodes(in3_t* c, in3_nodeselect_def_t* data) { - in3_ctx_t* ctx = _calloc(1, sizeof(in3_ctx_t)); + in3_req_t* ctx = _calloc(1, sizeof(in3_req_t)); ctx->verification_state = IN3_EIGNORE; ctx->error = _calloc(1, 1); ctx->client = c; @@ -339,11 +340,11 @@ in3_ret_t update_nodes(in3_t* c, in3_nodeselect_def_t* data) { in3_ret_t ret = update_nodelist(c, data, ctx); if (ret == IN3_WAITING && ctx->required) { - ret = in3_send_ctx(ctx->required); + ret = in3_send_req(ctx->required); if (!ret) ret = update_nodelist(c, data, ctx); } - ctx_free(ctx); + req_free(ctx); return ret; } @@ -380,23 +381,34 @@ NONULL static char* to_http_url(char* src_url) { return _strdupn(src_url, l); } -node_match_t* in3_node_list_fill_weight(in3_t* c, in3_nodeselect_def_t* data, in3_node_t* all_nodes, in3_node_weight_t* weights, - unsigned int len, uint64_t now, uint32_t* total_weight, unsigned int* total_found, - const in3_node_filter_t* filter) { +static bool in_address_list(bytes_t* filter, address_t adr) { + if (filter->len == 0) return true; + for (unsigned int i = 0; i < filter->len; i += 20) { + if (memcmp(filter->data + i, adr, 20) == 0) return true; + } + return false; +} - int found = 0; - uint32_t weight_sum = 0; - in3_node_t* node_def = NULL; - in3_node_weight_t* weight_def = NULL; - node_match_t* prev = NULL; - node_match_t* current = NULL; - node_match_t* first = NULL; - *total_found = 0; +node_match_t* in3_node_list_fill_weight(in3_t* c, in3_nodeselect_config_t* w, in3_node_t* all_nodes, in3_node_weight_t* weights, + unsigned int len, uint64_t now, uint32_t* total_weight, unsigned int* total_found, + const in3_node_filter_t* filter, bytes_t* pre_filter) { + + in3_nodeselect_def_t* data = w->data; + int found = 0; + uint32_t weight_sum = 0; + in3_node_t* node_def = NULL; + in3_node_weight_t* weight_def = NULL; + node_match_t* prev = NULL; + node_match_t* current = NULL; + node_match_t* first = NULL; + *total_found = 0; for (unsigned int i = 0; i < len; i++) { node_def = all_nodes + i; weight_def = weights + i; + if (pre_filter && !in_address_list(pre_filter, node_def->address)) continue; + if (filter && filter->nodes) { bool in_filter_nodes = false; for (d_iterator_t it = d_iter(filter->nodes); it.left; d_iter_next(&it)) { @@ -430,7 +442,7 @@ node_match_t* in3_node_list_fill_weight(in3_t* c, in3_nodeselect_def_t* data, in UNUSED_VAR(data); #endif - if (node_def->deposit < c->min_deposit) continue; + if (node_def->deposit < w->min_deposit) continue; if (filter && !in3_node_props_match(filter->props, node_def->props)) continue; SKIP_FILTERING: @@ -453,15 +465,15 @@ node_match_t* in3_node_list_fill_weight(in3_t* c, in3_nodeselect_def_t* data, in return first; } -static bool update_in_progress(const in3_ctx_t* ctx) { - return ctx_is_method(ctx, "in3_nodeList"); +static bool update_in_progress(const in3_req_t* ctx) { + return req_is_method(ctx, "in3_nodeList"); } -in3_ret_t in3_node_list_get(in3_ctx_t* ctx, in3_nodeselect_def_t* data, bool update, in3_node_t** nodelist, unsigned int* nodelist_length, in3_node_weight_t** weights) { +in3_ret_t in3_node_list_get(in3_req_t* ctx, in3_nodeselect_def_t* data, bool update, in3_node_t** nodelist, unsigned int* nodelist_length, in3_node_weight_t** weights) { in3_ret_t res; // do we need to update the nodelist? - if (data->nodelist_upd8_params || update || ctx_find_required(ctx, "in3_nodeList")) { + if (data->nodelist_upd8_params || update || req_find_required(ctx, "in3_nodeList")) { // skip update if update has been postponed or there's already one in progress if (postpone_update(data) || update_in_progress(ctx)) goto SKIP_UPDATE; @@ -476,7 +488,7 @@ in3_ret_t in3_node_list_get(in3_ctx_t* ctx, in3_nodeselect_def_t* data, bool upd #ifdef NODESELECT_DEF_WL // do we need to update the whitelist? if (data->whitelist // only if we have a whitelist - && (data->whitelist->needs_update || update || ctx_find_required(ctx, "in3_whiteList")) // which has the needs_update-flag (or forced) or we have already sent the request and are now picking up the result + && (data->whitelist->needs_update || update || req_find_required(ctx, "in3_whiteList")) // which has the needs_update-flag (or forced) or we have already sent the request and are now picking up the result && !memiszero(data->whitelist->contract, 20)) { // and we need to have a contract set, zero-contract = manual whitelist, which will not be updated. data->whitelist->needs_update = false; // now update the whiteList @@ -492,22 +504,23 @@ in3_ret_t in3_node_list_get(in3_ctx_t* ctx, in3_nodeselect_def_t* data, bool upd return IN3_OK; } -in3_ret_t in3_node_list_pick_nodes(in3_ctx_t* ctx, in3_nodeselect_def_t* data, node_match_t** nodes, unsigned int request_count, const in3_node_filter_t* filter) { +in3_ret_t in3_node_list_pick_nodes(in3_req_t* ctx, in3_nodeselect_config_t* w, node_match_t** nodes, unsigned int request_count, const in3_node_filter_t* filter) { // get all nodes from the nodelist - uint64_t now = in3_time(NULL); - in3_node_t* all_nodes = NULL; - in3_node_weight_t* weights = NULL; - uint32_t total_weight; - unsigned int all_nodes_len, total_found; + in3_nodeselect_def_t* data = w->data; + uint64_t now = in3_time(NULL); + in3_node_t* all_nodes = NULL; + in3_node_weight_t* weights = NULL; + uint32_t total_weight; + unsigned int all_nodes_len, total_found; in3_ret_t res = in3_node_list_get(ctx, data, false, &all_nodes, &all_nodes_len, &weights); if (res < 0) - return ctx_set_error(ctx, "could not find the data", res); + return req_set_error(ctx, "could not find the data", res); // filter out nodes node_match_t* found = in3_node_list_fill_weight( - ctx->client, data, all_nodes, weights, all_nodes_len, - now, &total_weight, &total_found, filter); + ctx->client, w, all_nodes, weights, all_nodes_len, + now, &total_weight, &total_found, filter, data->pre_address_filter); if (total_found == 0) { // no node available, so we should check if we can retry some blacklisted @@ -517,14 +530,14 @@ in3_ret_t in3_node_list_pick_nodes(in3_ctx_t* ctx, in3_nodeselect_def_t* data, n } // if morethan 50% of the nodes are blacklisted, we remove the mark and try again - if (blacklisted > all_nodes_len / 2) { + if (blacklisted > all_nodes_len / 2 || data->pre_address_filter) { for (unsigned int i = 0; i < all_nodes_len; i++) weights[i].blacklisted_until = 0; - found = in3_node_list_fill_weight(ctx->client, data, all_nodes, weights, all_nodes_len, now, &total_weight, &total_found, filter); + found = in3_node_list_fill_weight(ctx->client, w, all_nodes, weights, all_nodes_len, now, &total_weight, &total_found, filter, NULL); } if (total_found == 0) - return ctx_set_error(ctx, "No nodes found that match the criteria", IN3_EFIND); + return req_set_error(ctx, "No nodes found that match the criteria", IN3_EFIND); } unsigned int filled_len = total_found < request_count ? total_found : request_count; @@ -580,7 +593,7 @@ in3_ret_t in3_node_list_pick_nodes(in3_ctx_t* ctx, in3_nodeselect_def_t* data, n } *nodes = first; - if (found) in3_ctx_free_nodes(found); + if (found) in3_req_free_nodes(found); // select them based on random return res; diff --git a/c/src/nodeselect/nodelist.h b/c/src/nodeselect/full/nodelist.h similarity index 51% rename from c/src/nodeselect/nodelist.h rename to c/src/nodeselect/full/nodelist.h index 03668bab3..9ce7389b1 100644 --- a/c/src/nodeselect/nodelist.h +++ b/c/src/nodeselect/full/nodelist.h @@ -37,17 +37,97 @@ * * */ -#include "../core/client/client.h" -#include "../core/client/context.h" -#include "../core/util/log.h" -#include "../core/util/mem.h" +#include "../../core/client/client.h" +#include "../../core/client/request.h" +#include "../../core/util/log.h" +#include "../../core/util/mem.h" #include #ifndef NODELIST_H #define NODELIST_H -#define NODE_FILTER_INIT \ - (in3_node_filter_t) { .props = 0, .nodes = NULL } +#ifdef THREADSAFE +#if defined(_MSC_VER) || defined(__MINGW32__) +#include +typedef HANDLE in3_mutex_t; +#define MUTEX_INIT(mutex) mutex = CreateMutex(NULL, FALSE, NULL); +#define MUTEX_LOCK(mutex) WaitForSingleObject(mutex, INFINITE); +#define MUTEX_UNLOCK(mutex) ReleaseMutex(mutex); +#define MUTEX_FREE(mutex) CloseHandle(mutex); +#else +#include +typedef pthread_mutex_t in3_mutex_t; +#define MUTEX_INIT(mutex) \ + { \ + pthread_mutexattr_t attr; \ + pthread_mutexattr_init(&attr); \ + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); \ + pthread_mutex_init(&(mutex), &attr); \ + } +#define MUTEX_LOCK(mutex) pthread_mutex_lock(&(mutex)); +#define MUTEX_UNLOCK(mutex) pthread_mutex_unlock(&(mutex)); +#define MUTEX_FREE(mutex) pthread_mutex_destroy(&(mutex)); +#endif +#endif + +/** + * a list of node attributes (mostly used internally) + */ +typedef enum { + ATTR_WHITELISTED = 1, /**< indicates if node exists in whiteList */ + ATTR_BOOT_NODE = 2, /**< used to avoid filtering manually added nodes before first nodeList update */ +} in3_node_attr_type_t; + +/** incubed node-configuration. + * + * These information are read from the Registry contract and stored in this struct representing a server or node. + */ +typedef struct in3_node { + address_t address; /**< address of the server */ + bool blocked; /**< if true this node has been blocked for sending wrong responses */ + uint_fast16_t index; /**< index within the nodelist, also used in the contract as key */ + uint_fast16_t capacity; /**< the maximal capacity able to handle */ + uint64_t deposit; /**< the deposit stored in the registry contract, which this would lose if it sends a wrong blockhash */ + in3_node_props_t props; /**< used to identify the capabilities of the node. See in3_node_props_type_t in nodelist.h */ + char* url; /**< the url of the node */ + uint_fast8_t attrs; /**< bitmask of internal attributes */ +} in3_node_t; + +/** + * Weight or reputation of a node. + * + * Based on the past performance of the node a weight is calculated given faster nodes a higher weight + * and chance when selecting the next node from the nodelist. + * These weights will also be stored in the cache (if available) + */ +typedef struct in3_node_weight { + uint32_t response_count; /**< counter for responses */ + uint32_t total_response_time; /**< total of all response times */ + uint64_t blacklisted_until; /**< if >0 this node is blacklisted until k. k is a unix timestamp */ +} in3_node_weight_t; + +/** + * defines a whitelist structure used for the nodelist. + */ +typedef struct in3_whitelist { + bool needs_update; /**< if true the nodelist should be updated and will trigger a `in3_nodeList`-request before the next request is send. */ + uint64_t last_block; /**< last blocknumber the whiteList was updated, which is used to detect changed in the whitelist */ + address_t contract; /**< address of whiteList contract. If specified, whiteList is always auto-updated and manual whiteList is overridden */ + bytes_t addresses; /**< serialized list of node addresses that constitute the whiteList */ +} in3_whitelist_t; + +typedef enum { + NODE_PROP_PROOF = 0x1, /**< filter out nodes which are providing no proof */ + NODE_PROP_MULTICHAIN = 0x2, /**< filter out nodes other then which have capability of the same RPC endpoint may also accept requests for different chains */ + NODE_PROP_ARCHIVE = 0x4, /**< filter out non-archive supporting nodes */ + NODE_PROP_HTTP = 0x8, /**< filter out non-http nodes */ + NODE_PROP_BINARY = 0x10, /**< filter out nodes that don't support binary encoding */ + NODE_PROP_ONION = 0x20, /**< filter out non-onion nodes */ + NODE_PROP_SIGNER = 0x40, /**< filter out non-signer nodes */ + NODE_PROP_DATA = 0x80, /**< filter out non-data provider nodes */ + NODE_PROP_STATS = 0x100, /**< filter out nodes that do not provide stats */ + NODE_PROP_MIN_BLOCK_HEIGHT = 0x400, /**< filter out nodes that will sign blocks with lower min block height than specified */ +} in3_node_props_type_t; typedef struct { in3_node_props_t props; @@ -61,7 +141,7 @@ typedef struct node_offline_ { struct node_offline_* next; } node_offline_t; -typedef struct { +typedef struct in3_nodeselect_def { bool dirty; /**< indicates whether the nodelist has been modified after last read from cache */ uint16_t avg_block_time; /**< average block time (seconds) for this data (calculated internally) */ unsigned int nodelist_length; /**< number of nodes in the nodeList */ @@ -82,8 +162,29 @@ typedef struct { uint64_t timestamp; /**< approx. time when nodelist must be updated (i.e. when reported last_block will be considered final) */ address_t node; /**< node that reported the last_block which necessitated a nodeList update */ } * nodelist_upd8_params; + + chain_id_t chain_id; /**< the chain_id of the data */ + struct in3_nodeselect_def* next; /**< the next in the linked list */ + uint32_t ref_counter; /**< number of client using this nodelist */ + bytes_t* pre_address_filter; /**< addresses of allowed list (usually because those nodes where paid for) */ + +#ifdef THREADSAFE + in3_mutex_t mutex; /**< mutex to lock this nodelist */ +#endif } in3_nodeselect_def_t; +/** config for each client pointing to the global data*/ +typedef struct in3_nodeselect_config { + in3_nodeselect_def_t* data; /**< points to the global nodelist data*/ + in3_node_props_t node_props; /**< used to identify the capabilities of the node. */ + uint64_t min_deposit; /**< min stake of the server. Only nodes owning at least this amount will be chosen. */ + uint16_t node_limit; /**< the limit of nodes to store in the client. */ + uint8_t request_count; /**< the number of request send when getting a first answer */ +} in3_nodeselect_config_t; + +/** returns the nodelistwrapper.*/ +NONULL in3_nodeselect_config_t* in3_get_nodelist(in3_t* c); + /** removes all nodes and their weights from the nodelist */ NONULL void in3_nodelist_clear(in3_nodeselect_def_t* data); @@ -99,13 +200,13 @@ NONULL void in3_client_run_chain_whitelisting(in3_nodeselect_def_t* data); * * if not it will fetch a new version first (if the needs_update-flag is set). */ -NONULL in3_ret_t in3_node_list_get(in3_ctx_t* ctx, in3_nodeselect_def_t* data, bool update, in3_node_t** nodelist, unsigned int* nodelist_length, in3_node_weight_t** weights); +NONULL in3_ret_t in3_node_list_get(in3_req_t* req, in3_nodeselect_def_t* data, bool update, in3_node_t** nodelist, unsigned int* nodelist_length, in3_node_weight_t** weights); /** * filters and fills the weights on a returned linked list. */ NONULL_FOR((1, 2, 3, 4, 7, 8)) -node_match_t* in3_node_list_fill_weight(in3_t* c, in3_nodeselect_def_t* data, in3_node_t* all_nodes, in3_node_weight_t* weights, unsigned int len, uint64_t now, uint32_t* total_weight, unsigned int* total_found, const in3_node_filter_t* filter); +node_match_t* in3_node_list_fill_weight(in3_t* c, in3_nodeselect_config_t* w, in3_node_t* all_nodes, in3_node_weight_t* weights, unsigned int len, uint64_t now, uint32_t* total_weight, unsigned int* total_found, const in3_node_filter_t* filter, bytes_t* pre_filter); /** * calculates the weight for a node. @@ -115,13 +216,47 @@ NONULL uint32_t in3_node_calculate_weight(in3_node_weight_t* n, uint32_t capa, u * picks (based on the config) a random number of nodes and returns them as weightslist. */ NONULL_FOR((1, 2, 3)) -in3_ret_t in3_node_list_pick_nodes(in3_ctx_t* ctx, in3_nodeselect_def_t* data, node_match_t** nodes, unsigned int request_count, const in3_node_filter_t* filter); +in3_ret_t in3_node_list_pick_nodes(in3_req_t* req, in3_nodeselect_config_t* w, node_match_t** nodes, unsigned int request_count, const in3_node_filter_t* filter); /** * forces the client to update the nodelist */ in3_ret_t update_nodes(in3_t* c, in3_nodeselect_def_t* data); +#define NODE_FILTER_INIT \ + (in3_node_filter_t) { .props = 0, .nodes = NULL } + +/** + * Initializer for in3_node_props_t + */ +#define in3_node_props_init(np) *(np) = 0 + +/** + * setter method for interacting with in3_node_props_t. + */ +NONULL void in3_node_props_set(in3_node_props_t* node_props, /**< pointer to the properties to change */ + in3_node_props_type_t type, /**< key or type of the property */ + uint8_t value /**< value to set */ +); + +/** + * returns the value of the specified property-type. + * @return value as a number + */ +static inline uint32_t in3_node_props_get(in3_node_props_t np, /**< property to read from */ + in3_node_props_type_t t) { /**< the value to extract */ + return ((t == NODE_PROP_MIN_BLOCK_HEIGHT) ? ((np >> 32U) & 0xFFU) : !!(np & t)); +} + +/** + * checks if the given type is set in the properties + * @return true if set + */ +static inline bool in3_node_props_matches(in3_node_props_t np, /**< property to read from */ + in3_node_props_type_t t) { /**< the value to extract */ + return !!(np & t); +} + NONULL static inline bool nodelist_first_upd8(const in3_nodeselect_def_t* data) { return (data->nodelist_upd8_params != NULL && data->nodelist_upd8_params->exp_last_block == 0); } diff --git a/c/src/nodeselect/nodeselect_def.c b/c/src/nodeselect/full/nodeselect_def.c similarity index 60% rename from c/src/nodeselect/nodeselect_def.c rename to c/src/nodeselect/full/nodeselect_def.c index 0dd42e391..971b15f94 100644 --- a/c/src/nodeselect/nodeselect_def.c +++ b/c/src/nodeselect/full/nodeselect_def.c @@ -1,9 +1,13 @@ +#define __USE_GNU +#define _XOPEN_SOURCE 600 +#define _POSIX_C_SOURCE 200809L + #include "nodeselect_def.h" -#include "../core/client/context_internal.h" -#include "../core/client/keys.h" -#include "../core/util/bitset.h" -#include "../core/util/debug.h" -#include "../core/util/log.h" +#include "../../core/client/keys.h" +#include "../../core/client/request_internal.h" +#include "../../core/util/bitset.h" +#include "../../core/util/debug.h" +#include "../../core/util/log.h" #include "cache.h" #include "nodeselect_def_cfg.h" #include "registry.h" @@ -12,24 +16,55 @@ #define BLACKLISTTIME (24 * 3600) #define WAIT_TIME_CAP 3600 +// global nodelist-data for all nodelist instances without any special configurations +in3_nodeselect_def_t* nodelist_registry = NULL; + +// define function to lock the registry while reading from or even changing the registry +#ifdef THREADSAFE +#if defined(_MSC_VER) || defined(__MINGW32__) +static HANDLE lock_registry = NULL; +static void _lock_registry() { + if (!lock_registry) { + HANDLE p = CreateMutex(NULL, FALSE, NULL); + if (InterlockedCompareExchangePointer((PVOID*) &lock_registry, (PVOID) p, NULL)) CloseHandle(p); + } + MUTEX_LOCK(lock_registry); +} +#define LOCK_REGISTRY(code) \ + { \ + _lock_registry(); \ + code \ + MUTEX_UNLOCK(lock_registry) \ + } +#else +static pthread_mutex_t lock_registry = PTHREAD_MUTEX_INITIALIZER; +#define LOCK_REGISTRY(code) \ + { \ + MUTEX_LOCK(lock_registry); \ + code \ + MUTEX_UNLOCK(lock_registry) \ + } +#endif +#else +#define LOCK_REGISTRY(code) \ + { code } +#endif + static in3_ret_t rpc_verify(in3_nodeselect_def_t* data, in3_vctx_t* vc) { - char* method = NULL; - d_token_t* params = d_get(vc->request, K_PARAMS); // do we support this request? - if (!(method = d_get_stringk(vc->request, K_METHOD))) - return vc_err(vc, "No Method in request defined!"); - if (vc->chain->type != CHAIN_ETH && strcmp(method, "in3_nodeList")) return IN3_EIGNORE; - if (in3_ctx_get_proof(vc->ctx, vc->index) == PROOF_NONE) return IN3_OK; + if (vc->chain->type != CHAIN_ETH && strcmp(vc->method, "in3_nodeList")) return IN3_EIGNORE; + if (in3_req_get_proof(vc->req, vc->index) == PROOF_NONE) return IN3_OK; // do we have a result? if not it is a valid error-response - if (!vc->result) - return IN3_OK; + if (!vc->result) return IN3_OK; - if (strcmp(method, "in3_nodeList") == 0) + if (strcmp(vc->method, "in3_nodeList") == 0) { + d_token_t* params = d_get(vc->request, K_PARAMS); return eth_verify_in3_nodelist(data, vc, d_get_int_at(params, 0), d_get_bytes_at(params, 1), d_get_at(params, 2)); + } #ifdef NODESELECT_DEF_WL - else if (strcmp(method, "in3_whiteList") == 0) + else if (strcmp(vc->method, "in3_whiteList") == 0) return eth_verify_in3_whitelist(data, vc); #endif else @@ -100,14 +135,76 @@ static in3_ret_t clear_nodes(in3_nodeselect_def_t* data) { return IN3_OK; } -static in3_ret_t config_set(in3_nodeselect_def_t* data, in3_configure_ctx_t* ctx) { +static inline bool is_shared_nodelist(in3_nodeselect_def_t* n) { + for (in3_nodeselect_def_t* t = nodelist_registry; t; t = t->next) { + if (t == n) return true; + } + return false; +} + +static in3_ret_t nodelist_seperate_from_registry(in3_nodeselect_def_t** src, in3_nodeselect_config_t* w) { + LOCK_REGISTRY( + if (w && is_shared_nodelist(*src)) { + // create a custom nodelist + (*src)->ref_counter--; // detach from old + in3_nodeselect_def_t* data = _calloc(1, sizeof(*data)); // create new empty list + data->avg_block_time = avg_block_time_for_chain_id((*src)->chain_id); // with default blocktime + data->nodelist_upd8_params = _calloc(1, sizeof(*(data->nodelist_upd8_params))); // but marked as needed to be updated + data->chain_id = (*src)->chain_id; // clone the chain_id + data->ref_counter = 1; // this will never changed, since it is not a shared list + w->data = data; // change the pointer in the wrapper + *src = data; // and in the calling function +#ifdef THREADSAFE + MUTEX_INIT(data->mutex) // mutex is still needed to be threadsafe +#endif + }) + return IN3_OK; +} + +static in3_ret_t config_set(in3_nodeselect_def_t* data, in3_configure_ctx_t* ctx, in3_nodeselect_config_t* w) { char* res = NULL; json_ctx_t* json = ctx->json; d_token_t* token = ctx->token; - if (token->key == key("nodeRegistry")) { + if (token->key == key("preselect_nodes")) { + if (data->pre_address_filter) b_free(data->pre_address_filter); + if (d_type(token) == T_BYTES && d_len(token) % 20 == 0) + data->pre_address_filter = b_dup(d_bytes(token)); + else if (d_type(token) == T_NULL) + data->pre_address_filter = NULL; + else { + EXPECT_CFG(d_type(token) == T_NULL, "invalid preselect_nodes "); + } + } + else if (token->key == key("replaceLatestBlock")) { + EXPECT_TOK_U8(token); + ctx->client->replace_latest_block = (uint8_t) d_int(token); + const uint64_t dp_ = ctx->client->replace_latest_block; + w->node_props = (w->node_props & 0xFFFFFFFF) | (dp_ << 32U); + } + else if (token->key == key("requestCount")) { + EXPECT_TOK_U8(token); + EXPECT_CFG(d_int(token), "requestCount must be at least 1"); + w->request_count = (uint8_t) d_int(token); + } + else if (token->key == key("minDeposit")) { + EXPECT_TOK_U64(token); + w->min_deposit = d_long(token); + } + else if (token->key == key("nodeProps")) { + EXPECT_TOK_U64(token); + w->node_props = d_long(token); + } + else if (token->key == key("nodeLimit")) { + EXPECT_TOK_U16(token); + w->node_limit = (uint16_t) d_int(token); + } + else if (token->key == key("nodeRegistry")) { EXPECT_TOK_OBJ(token); + // this is changing the nodelist config, so we need to make sure we have our own nodelist + TRY(nodelist_seperate_from_registry(&data, w)) + #ifdef NODESELECT_DEF_WL bool has_wlc = false, has_man_wl = false; #endif @@ -171,31 +268,33 @@ static in3_ret_t config_set(in3_nodeselect_def_t* data, in3_configure_ctx_t* ctx else if (cp.token->key == key("nodeList")) { EXPECT_TOK_ARR(cp.token); if (clear_nodes(data) < 0) goto cleanup; - int i = 0; - for (d_iterator_t n = d_iter(cp.token); n.left; d_iter_next(&n), i++) { + for (d_iterator_t n = d_iter(cp.token); n.left; d_iter_next(&n)) { EXPECT_CFG(d_get(n.token, key("url")) && d_get(n.token, key("address")), "expected URL & address"); EXPECT_TOK_STR(d_get(n.token, key("url"))); EXPECT_TOK_ADDR(d_get(n.token, key("address"))); - EXPECT_CFG(add_node(data, d_get_string(n.token, "url"), - d_get_longkd(n.token, key("props"), 65535), + EXPECT_CFG(add_node(data, d_get_string(n.token, key("url")), + d_get_longd(n.token, key("props"), 65535), d_get_byteskl(n.token, key("address"), 20)->data) == IN3_OK, "add node failed"); -#ifndef __clang_analyzer__ - BIT_SET(data->nodelist[i].attrs, ATTR_BOOT_NODE); -#endif + assert(data->nodelist_length > 0); + BIT_SET(data->nodelist[data->nodelist_length - 1].attrs, ATTR_BOOT_NODE); } } } #ifdef NODESELECT_DEF_WL in3_client_run_chain_whitelisting(data); #endif + // for supported chains we will get the registryId & contract from def cfg lazily + if (!nodeselect_def_cfg_data(ctx->client->chain.chain_id).data) + EXPECT_CFG(!memiszero(data->registry_id, 32) && !memiszero(data->contract, 20), "missing registryId/contract!"); } else if (token->key == key("rpc")) { EXPECT_TOK_STR(token); + TRY(nodelist_seperate_from_registry(&data, w)) in3_t* c = ctx->client; c->proof = PROOF_NONE; c->chain.chain_id = CHAIN_ID_LOCAL; - c->request_count = 1; + w->request_count = 1; clear_nodes(data); data->nodelist = _calloc(1, sizeof(in3_node_t)); @@ -206,29 +305,26 @@ static in3_ret_t config_set(in3_nodeselect_def_t* data, in3_configure_ctx_t* ctx _free(data->nodelist_upd8_params); data->nodelist_upd8_params = NULL; } - else if (token->key == key("replaceLatestBlock")) { - EXPECT_TOK_U8(token); - in3_node_props_set(&ctx->client->node_props, NODE_PROP_MIN_BLOCK_HEIGHT, d_int(token)); - } else { return IN3_EIGNORE; } - // for supported chains we will get the registryId & contract from def cfg lazily - if (!nodeselect_def_cfg_data(ctx->client->chain.chain_id).data) - EXPECT_CFG(!memiszero(data->registry_id, 32) && !memiszero(data->contract, 20), "missing registryId/contract!"); - cleanup: ctx->error_msg = res; return ctx->error_msg ? IN3_ECONFIG : IN3_OK; } -static in3_ret_t config_get(in3_nodeselect_def_t* data, in3_get_config_ctx_t* ctx) { - sb_t* sb = ctx->sb; - in3_t* c = ctx->client; +static in3_ret_t config_get(in3_nodeselect_config_t* w, in3_get_config_ctx_t* ctx) { + in3_nodeselect_def_t* data = w->data; + sb_t* sb = ctx->sb; + in3_t* c = ctx->client; if (c->chain.chain_id == CHAIN_ID_LOCAL) add_string(sb, ',', "rpc", data->nodelist->url); + add_uint(sb, ',', "requestCount", w->request_count); + add_uint(sb, ',', "minDeposit", w->min_deposit); + add_uint(sb, ',', "nodeProps", w->node_props); + add_uint(sb, ',', "nodeLimit", w->node_limit); sb_add_chars(sb, ",\"nodeRegistry\":"); add_hex(sb, '{', "contract", bytes(data->contract, 20)); @@ -265,7 +361,7 @@ static in3_ret_t init_boot_nodes(in3_nodeselect_def_t* data, in3_t* c) { return IN3_ECONFIG; in3_configure_ctx_t cctx = {.client = c, .json = json, .token = json->result + 1, .error_msg = NULL}; - in3_ret_t ret = config_set(data, &cctx); + in3_ret_t ret = config_set(data, &cctx, NULL); json_free(json); if (IN3_OK != ret) { in3_log_error("nodeselect config error: %s\n", cctx.error_msg); @@ -304,34 +400,39 @@ static void free_signers(node_match_t* signers) { } } -static in3_ret_t pick_data(in3_nodeselect_def_t* data, in3_ctx_t* ctx) { +static in3_ret_t pick_data(in3_nodeselect_config_t* w, in3_req_t* ctx) { + in3_nodeselect_def_t* data = w->data; + // init cache lazily this also means we can be sure that all other related plugins are registered by now if (data->nodelist == NULL && IN3_ECONFIG == init_boot_nodes(data, ctx->client)) return IN3_ECONFIG; in3_node_filter_t filter = NODE_FILTER_INIT; filter.nodes = d_get(d_get(ctx->requests[0], K_IN3), K_DATA_NODES); - filter.props = (ctx->client->node_props & 0xFFFFFFFF) | NODE_PROP_DATA | ((ctx->client->flags & FLAGS_HTTP) ? NODE_PROP_HTTP : 0) | (in3_ctx_get_proof(ctx, 0) != PROOF_NONE ? NODE_PROP_PROOF : 0); + filter.props = (w->node_props & 0xFFFFFFFF) | NODE_PROP_DATA | ((ctx->client->flags & FLAGS_HTTP) ? NODE_PROP_HTTP : 0) | (in3_req_get_proof(ctx, 0) != PROOF_NONE ? NODE_PROP_PROOF : 0); filter.exclusions = parse_signers(d_get(d_get(ctx->requests[0], K_IN3), K_SIGNER_NODES)); // we must exclude any manually specified signer nodes + // if incentive is active we should now + // Send parallel requests if signatures have been requested - int rc = ctx->client->request_count; - if (ctx->client->signature_count && ctx->client->request_count <= 1) + int rc = w->request_count; + if (ctx->client->signature_count && w->request_count <= 1) rc = 2; - in3_ret_t ret = in3_node_list_pick_nodes(ctx, data, &ctx->nodes, rc, &filter); + in3_ret_t ret = in3_node_list_pick_nodes(ctx, w, &ctx->nodes, rc, &filter); free_signers(filter.exclusions); return ret; } -NONULL static bool auto_ask_sig(const in3_ctx_t* ctx) { - return (ctx_is_method(ctx, "in3_nodeList") && !(ctx->client->flags & FLAGS_NODE_LIST_NO_SIG) && ctx->client->chain.chain_id != CHAIN_ID_BTC); +NONULL static bool auto_ask_sig(const in3_req_t* ctx) { + return (req_is_method(ctx, "in3_nodeList") && !(ctx->client->flags & FLAGS_NODE_LIST_NO_SIG) && ctx->client->chain.chain_id != CHAIN_ID_BTC); } -static in3_ret_t pick_signer(in3_nodeselect_def_t* data, in3_ctx_t* ctx) { - const in3_t* c = ctx->client; +static in3_ret_t pick_signer(in3_nodeselect_config_t* w, in3_req_t* ctx) { + in3_nodeselect_def_t* data = w->data; + const in3_t* c = ctx->client; - if (in3_ctx_get_proof(ctx, 0) == PROOF_NONE && !auto_ask_sig(ctx)) + if (in3_req_get_proof(ctx, 0) == PROOF_NONE && !auto_ask_sig(ctx)) return IN3_OK; // For nodeList request, we always ask for proof & atleast one signature @@ -343,13 +444,13 @@ static in3_ret_t pick_signer(in3_nodeselect_def_t* data, in3_ctx_t* ctx) { node_match_t* signer_nodes = NULL; in3_node_filter_t filter = NODE_FILTER_INIT; filter.nodes = d_get(d_get(ctx->requests[0], K_IN3), K_SIGNER_NODES); - filter.props = c->node_props | NODE_PROP_SIGNER; + filter.props = w->node_props | NODE_PROP_SIGNER; filter.exclusions = ctx->nodes; - const in3_ret_t res = in3_node_list_pick_nodes(ctx, data, &signer_nodes, total_sig_cnt, &filter); + const in3_ret_t res = in3_node_list_pick_nodes(ctx, w, &signer_nodes, total_sig_cnt, &filter); if (res < 0) - return ctx_set_error(ctx, "Could not find any nodes for requesting signatures", res); + return req_set_error(ctx, "Could not find any nodes for requesting signatures", res); if (ctx->signers) _free(ctx->signers); - const int node_count = ctx_nodes_len(signer_nodes); + const int node_count = req_nodes_len(signer_nodes); ctx->signers_length = node_count; ctx->signers = _malloc(20 * node_count); // 20 bytes per address const node_match_t* w = signer_nodes; @@ -359,13 +460,13 @@ static in3_ret_t pick_signer(in3_nodeselect_def_t* data, in3_ctx_t* ctx) { if (n) memcpy(ctx->signers + i * 20, n->address, 20); w = w->next; } - if (signer_nodes) in3_ctx_free_nodes(signer_nodes); + if (signer_nodes) in3_req_free_nodes(signer_nodes); } return IN3_OK; } -NONULL in3_ret_t handle_failable(in3_nodeselect_def_t* data, in3_ctx_t* ctx) { +NONULL in3_ret_t handle_failable(in3_nodeselect_def_t* data, in3_req_t* ctx) { in3_ret_t res = IN3_OK; // blacklist node that gave us an error response for nodelist (if not first update) @@ -379,9 +480,9 @@ NONULL in3_ret_t handle_failable(in3_nodeselect_def_t* data, in3_ctx_t* ctx) { // if first update return error otherwise return IN3_OK, this is because first update is // always from a boot node which is presumed to be trusted if (nodelist_first_upd8(data)) - res = ctx_set_error(ctx, ctx->required->error ? ctx->required->error : "error handling subrequest", IN3_ERPC); + res = req_set_error(ctx, ctx->required->error ? ctx->required->error : "error handling subrequest", IN3_ERPC); - if (res == IN3_OK) res = ctx_remove_required(ctx, ctx->required, true); + if (res == IN3_OK) res = req_remove_required(ctx, ctx->required, true); } return res; @@ -432,7 +533,7 @@ NONULL in3_ret_t handle_offline(in3_nodeselect_def_t* data, in3_nl_offline_ctx_t if (!BIT_CHECK(ctx->missing, pos)) continue; - const uint8_t* address = ctx->vctx->ctx->signers + (pos * 20); + const uint8_t* address = ctx->vctx->req->signers + (pos * 20); for (unsigned int i = 0; i < data->nodelist_length; ++i) { if (memcmp(data->nodelist[i].address, address, 20) != 0) continue; @@ -467,33 +568,33 @@ static uint16_t update_waittime(uint64_t nodelist_block, uint64_t current_blk, u return min((repl_latest - diff) * avg_blktime, WAIT_TIME_CAP); } -static void check_autoupdate(const in3_ctx_t* ctx, in3_nodeselect_def_t* data, d_token_t* response_in3, node_match_t* node) { - assert_in3_ctx(ctx); +static void check_autoupdate(const in3_req_t* ctx, in3_nodeselect_def_t* data, d_token_t* response_in3, node_match_t* node) { + assert_in3_req(ctx); assert(data); if ((ctx->client->flags & FLAGS_AUTO_UPDATE_LIST) == 0) return; - if (d_get_longk(response_in3, K_LAST_NODE_LIST) > d_get_longk(response_in3, K_CURRENT_BLOCK)) { + if (d_get_long(response_in3, K_LAST_NODE_LIST) > d_get_long(response_in3, K_CURRENT_BLOCK)) { // this shouldn't be possible, so we ignore this lastNodeList and do NOT try to update the nodeList return; } - if (d_get_longk(response_in3, K_LAST_NODE_LIST) > data->last_block) { + if (d_get_long(response_in3, K_LAST_NODE_LIST) > data->last_block) { if (data->nodelist_upd8_params == NULL) data->nodelist_upd8_params = _malloc(sizeof(*(data->nodelist_upd8_params))); in3_node_t* n = get_node(data, node); if (n) { // overwrite old params since we have a newer nodelist update now memcpy(data->nodelist_upd8_params->node, n->address, 20); - data->nodelist_upd8_params->exp_last_block = d_get_longk(response_in3, K_LAST_NODE_LIST); - data->nodelist_upd8_params->timestamp = in3_time(NULL) + update_waittime(d_get_longk(response_in3, K_LAST_NODE_LIST), - d_get_longk(response_in3, K_CURRENT_BLOCK), + data->nodelist_upd8_params->exp_last_block = d_get_long(response_in3, K_LAST_NODE_LIST); + data->nodelist_upd8_params->timestamp = in3_time(NULL) + update_waittime(d_get_long(response_in3, K_LAST_NODE_LIST), + d_get_long(response_in3, K_CURRENT_BLOCK), ctx->client->replace_latest_block, data->avg_block_time); } } #ifdef NODESELECT_DEF_WL - if (data->whitelist && d_get_longk(response_in3, K_LAST_WHITE_LIST) > data->whitelist->last_block) + if (data->whitelist && d_get_long(response_in3, K_LAST_WHITE_LIST) > data->whitelist->last_block) data->whitelist->needs_update = true; #endif } @@ -509,10 +610,13 @@ static void handle_times(in3_nodeselect_def_t* data, node_match_t* node, in3_res } static in3_ret_t pick_followup(in3_nodeselect_def_t* data, in3_nl_followup_ctx_t* fctx) { - in3_ctx_t* ctx = fctx->ctx; + in3_req_t* ctx = fctx->req; node_match_t* vnode = fctx->node; node_match_t* node = ctx->nodes; - int nodes_count = ctx->nodes == NULL ? 1 : ctx_nodes_len(ctx->nodes); + int nodes_count = ctx->nodes == NULL ? 1 : req_nodes_len(ctx->nodes); + + // no node - nothing to do here. + if (!node) return IN3_EIGNORE; for (int n = 0; n < nodes_count; n++, node = node ? node->next : NULL) handle_times(data, node, ctx->raw_response + n); @@ -534,49 +638,128 @@ static void free_(void* p) { _free(p); } -in3_ret_t in3_nodeselect_def(void* plugin_data, in3_plugin_act_t action, void* plugin_ctx) { - in3_nodeselect_def_t* data = plugin_data; - switch (action) { - case PLGN_ACT_INIT: - return IN3_OK; - case PLGN_ACT_TERM: - offline_free(data); - in3_nodelist_clear(data); +static void nodelist_return_or_free(in3_nodeselect_def_t* chain) { + bool needs_freeing = false; + LOCK_REGISTRY( + chain->ref_counter--; + if (chain->ref_counter == 0) { + needs_freeing = true; + for (in3_nodeselect_def_t** p = &nodelist_registry; *p; p = &((*p)->next)) { + if (*p == chain) { + *p = chain->next; + break; + } + } + }) +#ifdef THREADSAFE + MUTEX_UNLOCK(chain->mutex) // Important: this function is always called in a context where we have locked this mutex, so we need to unlock it here! +#endif + + if (!needs_freeing) return; + offline_free(chain); + in3_nodelist_clear(chain); #ifdef NODESELECT_DEF_WL - in3_whitelist_clear(data->whitelist); + in3_whitelist_clear(chain->whitelist); +#endif +#ifdef THREADSAFE + MUTEX_FREE(chain->mutex) +#endif + b_free(chain->pre_address_filter); + _free(chain->nodelist_upd8_params); + _free(chain); +} + +// finds or creates a new nodelist +static in3_nodeselect_def_t* nodelist_get_or_create(chain_id_t chain_id) { + in3_nodeselect_def_t* data = NULL; + LOCK_REGISTRY( + for (data = nodelist_registry; data; data = data->next) { + if (data->chain_id == chain_id) { + data->ref_counter++; + break; + } + } + + if (data == NULL) { + data = _calloc(1, sizeof(*data)); + data->avg_block_time = avg_block_time_for_chain_id(chain_id); + data->nodelist_upd8_params = _calloc(1, sizeof(*(data->nodelist_upd8_params))); + data->chain_id = chain_id; + data->next = nodelist_registry; + data->ref_counter = 1; + nodelist_registry = data; +#ifdef THREADSAFE + MUTEX_INIT(data->mutex) #endif - _free(data->nodelist_upd8_params); - _free(data); + }) + return data; +} +#ifdef THREADSAFE +#define UNLOCK_AND_RETURN(val) \ + { \ + in3_ret_t r = val; \ + MUTEX_UNLOCK(data->mutex); \ + return r; \ + } +#else +#define UNLOCK_AND_RETURN(val) return val; +#endif + +in3_ret_t in3_nodeselect_handle_action(void* plugin_data, in3_plugin_act_t action, void* plugin_ctx) { + in3_nodeselect_config_t* w = plugin_data; + in3_nodeselect_def_t* data = w->data; + +#ifdef THREADSAFE + // lock only the nodelist + MUTEX_LOCK(data->mutex) +#endif + + switch (action) { + case PLGN_ACT_INIT: + UNLOCK_AND_RETURN(IN3_OK) + case PLGN_ACT_TERM: { + nodelist_return_or_free(data); // the unlocking of the mutex is done inside nodelist_return_or_free! + _free(plugin_data); return IN3_OK; + } case PLGN_ACT_RPC_VERIFY: - return rpc_verify(data, (in3_vctx_t*) plugin_ctx); + UNLOCK_AND_RETURN(rpc_verify(data, (in3_vctx_t*) plugin_ctx)) case PLGN_ACT_CONFIG_SET: - return config_set(data, (in3_configure_ctx_t*) plugin_ctx); + UNLOCK_AND_RETURN(config_set(data, (in3_configure_ctx_t*) plugin_ctx, plugin_data)) case PLGN_ACT_CONFIG_GET: - return config_get(data, (in3_get_config_ctx_t*) plugin_ctx); + UNLOCK_AND_RETURN(config_get(w, (in3_get_config_ctx_t*) plugin_ctx)) case PLGN_ACT_NL_PICK: { in3_nl_pick_ctx_t* pctx = plugin_ctx; - return pctx->type == NL_DATA ? pick_data(data, pctx->ctx) : pick_signer(data, pctx->ctx); + UNLOCK_AND_RETURN(pctx->type == NL_DATA ? pick_data(w, pctx->req) : pick_signer(w, pctx->req)) } case PLGN_ACT_NL_PICK_FOLLOWUP: - return pick_followup(data, plugin_ctx); + UNLOCK_AND_RETURN(pick_followup(data, plugin_ctx)) case PLGN_ACT_NL_BLACKLIST: { in3_nl_blacklist_ctx_t* bctx = plugin_ctx; - return bctx->is_addr ? blacklist_node_addr(data, bctx->address, BLACKLISTTIME) - : blacklist_node_url(data, bctx->url, BLACKLISTTIME); + UNLOCK_AND_RETURN(bctx->is_addr ? blacklist_node_addr(data, bctx->address, BLACKLISTTIME) + : blacklist_node_url(data, bctx->url, BLACKLISTTIME)) } case PLGN_ACT_NL_FAILABLE: - return handle_failable(data, plugin_ctx); + UNLOCK_AND_RETURN(handle_failable(data, plugin_ctx)) case PLGN_ACT_NL_OFFLINE: - return handle_offline(data, plugin_ctx); - case PLGN_ACT_CHAIN_CHANGE: - return chain_change(data, plugin_ctx); + UNLOCK_AND_RETURN(handle_offline(data, plugin_ctx)) + case PLGN_ACT_CHAIN_CHANGE: { + nodelist_return_or_free(data); // this will always unlock the mutex of the nodelist and update the ref_counter! + in3_nodeselect_config_t* w = plugin_data; + in3_t* c = plugin_ctx; + w->data = nodelist_get_or_create(c->chain.chain_id); + data = w->data; // update data-pointer to the new nodelist +#ifdef THREADSAFE + MUTEX_LOCK(data->mutex) // and lock it because we are about to initialize the chain +#endif + UNLOCK_AND_RETURN(data->nodelist ? IN3_OK : chain_change(w->data, c)) + } case PLGN_ACT_GET_DATA: { in3_get_data_ctx_t* pctx = plugin_ctx; if (pctx->type == GET_DATA_REGISTRY_ID) { pctx->data = data->registry_id; pctx->cleanup = NULL; - return IN3_OK; + UNLOCK_AND_RETURN(IN3_OK) } else if (pctx->type == GET_DATA_NODE_MIN_BLK_HEIGHT) { assert(pctx->data); @@ -604,28 +787,40 @@ in3_ret_t in3_nodeselect_def(void* plugin_data, in3_plugin_act_t action, void* p pctx->data = NULL; pctx->cleanup = NULL; } - return IN3_OK; + UNLOCK_AND_RETURN(IN3_OK) } - return IN3_EIGNORE; + UNLOCK_AND_RETURN(IN3_EIGNORE) } case PLGN_ACT_ADD_PAYLOAD: { #ifdef NODESELECT_DEF_WL - sb_t* payload = plugin_ctx; + in3_pay_payload_ctx_t* payload = plugin_ctx; if (data->whitelist) { const bytes_t adr = bytes(data->whitelist->contract, 20); - sb_add_bytes(payload, ",\"whiteListContract\":", &adr, 1, false); + sb_add_bytes(payload->sb, ",\"whiteListContract\":", &adr, 1, false); } #endif - return IN3_OK; + UNLOCK_AND_RETURN(IN3_OK) } default: break; } - return IN3_EIGNORE; + UNLOCK_AND_RETURN(IN3_EIGNORE) } in3_ret_t in3_register_nodeselect_def(in3_t* c) { - in3_nodeselect_def_t* data = _calloc(1, sizeof(*data)); - data->avg_block_time = avg_block_time_for_chain_id(c->chain.chain_id); - data->nodelist_upd8_params = _calloc(1, sizeof(*(data->nodelist_upd8_params))); - return in3_plugin_register(c, PLGN_ACT_LIFECYCLE | PLGN_ACT_RPC_VERIFY | PLGN_ACT_NODELIST | PLGN_ACT_CONFIG | PLGN_ACT_CHAIN_CHANGE | PLGN_ACT_GET_DATA | PLGN_ACT_ADD_PAYLOAD, in3_nodeselect_def, data, false); + if (in3_plugin_is_registered(c, PLGN_ACT_LIFECYCLE | PLGN_ACT_RPC_VERIFY | PLGN_ACT_NODELIST | PLGN_ACT_CONFIG | PLGN_ACT_CHAIN_CHANGE | PLGN_ACT_GET_DATA | PLGN_ACT_ADD_PAYLOAD)) + return IN3_EIGNORE; + in3_nodeselect_config_t* data = _malloc(sizeof(*data)); + data->request_count = 1; + data->min_deposit = 0; + data->node_limit = 0; + data->node_props = 0; + data->data = nodelist_get_or_create(c->chain.chain_id); + return in3_plugin_register(c, PLGN_ACT_LIFECYCLE | PLGN_ACT_RPC_VERIFY | PLGN_ACT_NODELIST | PLGN_ACT_CONFIG | PLGN_ACT_CHAIN_CHANGE | PLGN_ACT_GET_DATA | PLGN_ACT_ADD_PAYLOAD, in3_nodeselect_handle_action, data, false); +} + +in3_nodeselect_config_t* in3_get_nodelist(in3_t* c) { + for (in3_plugin_t* p = c->plugins; p; p = p->next) { + if (p->action_fn == in3_nodeselect_handle_action) return p->data; + } + return NULL; } diff --git a/c/src/nodeselect/nodeselect_def.h b/c/src/nodeselect/full/nodeselect_def.h similarity index 60% rename from c/src/nodeselect/nodeselect_def.h rename to c/src/nodeselect/full/nodeselect_def.h index 50206bff6..8326ed346 100644 --- a/c/src/nodeselect/nodeselect_def.h +++ b/c/src/nodeselect/full/nodeselect_def.h @@ -1,8 +1,8 @@ #ifndef IN3_NODE_SELECT_DEF_H #define IN3_NODE_SELECT_DEF_H -#include "../core/client/context.h" -#include "../core/client/plugin.h" +#include "../../core/client/plugin.h" +#include "../../core/client/request.h" #include "nodelist.h" #ifdef NODESELECT_DEF @@ -10,13 +10,14 @@ /** * default nodeselect implementation */ -in3_ret_t in3_nodeselect_def(void* plugin_data, in3_plugin_act_t action, void* plugin_ctx); +in3_ret_t in3_nodeselect_handle_action(void* plugin_data, in3_plugin_act_t action, void* plugin_ctx); /** * get access to internal plugin data if registered */ static inline in3_nodeselect_def_t* in3_nodeselect_def_data(in3_t* c) { - return in3_plugin_get_data(c, in3_nodeselect_def); + in3_nodeselect_config_t* w = in3_plugin_get_data(c, in3_nodeselect_handle_action); + return w ? w->data : NULL; } /** diff --git a/c/src/nodeselect/nodeselect_def_cfg.h b/c/src/nodeselect/full/nodeselect_def_cfg.h similarity index 82% rename from c/src/nodeselect/nodeselect_def_cfg.h rename to c/src/nodeselect/full/nodeselect_def_cfg.h index 486c5a1b8..349a03107 100644 --- a/c/src/nodeselect/nodeselect_def_cfg.h +++ b/c/src/nodeselect/full/nodeselect_def_cfg.h @@ -3,7 +3,7 @@ #define JSON_TO_BIN(x) x // marker for pre-build stage -#include "../core/client/client.h" +#include "../../core/client/client.h" #ifndef NO_BOOT_NODES_MAINNET /* @@ -16,26 +16,26 @@ " \"url\": \"https://in3-v2.slock.it/mainnet/nd-1\"," \ " \"props\": \"0xFFFF\"" \ " }, {" \ - " \"address\": \"0x1fe2e9bf29aa1938859af64c413361227d04059a\"," \ - " \"url\": \"https://in3-v2.slock.it/mainnet/nd-2\"," \ + " \"address\": \"0x2e333ec090f1028df0a3c39a918063443be82b2b\"," \ + " \"url\": \"https://mainnet.incubed.net\"," \ " \"props\": \"0xFFFF\"" \ " }, {" \ - " \"address\": \"0x0cea2ff03adcfa047e8f54f98d41d9147c3ccd4d\"," \ - " \"url\": \"https://in3-v2.slock.it/mainnet/nd-3\"," \ + " \"address\": \"0x510ee7f6f198e018e3529164da2473a96eeb3dc8\"," \ + " \"url\": \"https://0001.mainnet.in3.anyblock.tools\"," \ " \"props\": \"0xFFFF\"" \ " }, {" \ - " \"address\": \"0xccd12a2222995e62eca64426989c2688d828aa47\"," \ + " \"address\": \"0xc513a534de5a9d3f413152c41b09bd8116237fc8\"," \ " \"url\": \"https://in3-v2.slock.it/mainnet/nd-4\"," \ " \"props\": \"0xFFFF\"" \ " }, {" \ - " \"address\": \"0x510ee7f6f198e018e3529164da2473a96eeb3dc8\"," \ + " \"address\": \"0xbcdf4e3e90cc7288b578329efd7bcc90655148d2\"," \ " \"url\": \"https://in3-v2.slock.it/mainnet/nd-5\"," \ " \"props\": \"0xFFFF\"" \ " }]" \ " }" \ "}") */ -unsigned char BOOT_NODES_MAINNET_BIN[] = { +const unsigned char BOOT_NODES_MAINNET_BIN[] = { 0xd9, 0x61, 0x5f, 0x35, 0x63, 0xce, 0x12, 0x14, 0xac, 0x1b, 0x82, 0x47, 0x95, 0xe1, 0xeb, 0x1f, 0x6e, 0x60, 0x9f, 0xe0, 0xda, 0x9b, 0x9a, 0xf8, 0xbe, 0xaa, 0xb6, 0x0f, 0x6e, 0xb8, 0x1c, 0x20, 0x23, 0xd5, 0x34, 0x5c, @@ -47,31 +47,32 @@ unsigned char BOOT_NODES_MAINNET_BIN[] = { 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x69, 0x6e, 0x33, 0x2d, 0x76, 0x32, 0x2e, 0x73, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x69, 0x74, 0x2f, 0x6d, 0x61, 0x69, 0x6e, 0x6e, 0x65, 0x74, 0x2f, 0x6e, 0x64, 0x2d, 0x31, 0x00, - 0x41, 0x6e, 0xbd, 0xff, 0xff, 0x63, 0xb2, 0xf6, 0x14, 0x1f, 0xe2, 0xe9, - 0xbf, 0x29, 0xaa, 0x19, 0x38, 0x85, 0x9a, 0xf6, 0x4c, 0x41, 0x33, 0x61, - 0x22, 0x7d, 0x04, 0x05, 0x9a, 0x79, 0x6b, 0x3c, 0x24, 0x68, 0x74, 0x74, - 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x69, 0x6e, 0x33, 0x2d, 0x76, 0x32, 0x2e, - 0x73, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x69, 0x74, 0x2f, 0x6d, 0x61, 0x69, - 0x6e, 0x6e, 0x65, 0x74, 0x2f, 0x6e, 0x64, 0x2d, 0x32, 0x00, 0x41, 0x6e, - 0xbd, 0xff, 0xff, 0x63, 0xb2, 0xf6, 0x14, 0x0c, 0xea, 0x2f, 0xf0, 0x3a, - 0xdc, 0xfa, 0x04, 0x7e, 0x8f, 0x54, 0xf9, 0x8d, 0x41, 0xd9, 0x14, 0x7c, - 0x3c, 0xcd, 0x4d, 0x79, 0x6b, 0x3c, 0x24, 0x68, 0x74, 0x74, 0x70, 0x73, - 0x3a, 0x2f, 0x2f, 0x69, 0x6e, 0x33, 0x2d, 0x76, 0x32, 0x2e, 0x73, 0x6c, - 0x6f, 0x63, 0x6b, 0x2e, 0x69, 0x74, 0x2f, 0x6d, 0x61, 0x69, 0x6e, 0x6e, - 0x65, 0x74, 0x2f, 0x6e, 0x64, 0x2d, 0x33, 0x00, 0x41, 0x6e, 0xbd, 0xff, - 0xff, 0x63, 0xb2, 0xf6, 0x14, 0xcc, 0xd1, 0x2a, 0x22, 0x22, 0x99, 0x5e, - 0x62, 0xec, 0xa6, 0x44, 0x26, 0x98, 0x9c, 0x26, 0x88, 0xd8, 0x28, 0xaa, - 0x47, 0x79, 0x6b, 0x3c, 0x24, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, - 0x2f, 0x69, 0x6e, 0x33, 0x2d, 0x76, 0x32, 0x2e, 0x73, 0x6c, 0x6f, 0x63, - 0x6b, 0x2e, 0x69, 0x74, 0x2f, 0x6d, 0x61, 0x69, 0x6e, 0x6e, 0x65, 0x74, - 0x2f, 0x6e, 0x64, 0x2d, 0x34, 0x00, 0x41, 0x6e, 0xbd, 0xff, 0xff, 0x63, - 0xb2, 0xf6, 0x14, 0x51, 0x0e, 0xe7, 0xf6, 0xf1, 0x98, 0xe0, 0x18, 0xe3, - 0x52, 0x91, 0x64, 0xda, 0x24, 0x73, 0xa9, 0x6e, 0xeb, 0x3d, 0xc8, 0x79, - 0x6b, 0x3c, 0x24, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x69, - 0x6e, 0x33, 0x2d, 0x76, 0x32, 0x2e, 0x73, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, - 0x69, 0x74, 0x2f, 0x6d, 0x61, 0x69, 0x6e, 0x6e, 0x65, 0x74, 0x2f, 0x6e, - 0x64, 0x2d, 0x35, 0x00, 0x41, 0x6e, 0xbd, 0xff, 0xff}; -unsigned int BOOT_NODES_MAINNET_BIN_LEN = 417; + 0x41, 0x6e, 0xbd, 0xff, 0xff, 0x63, 0xb2, 0xf6, 0x14, 0x2e, 0x33, 0x3e, + 0xc0, 0x90, 0xf1, 0x02, 0x8d, 0xf0, 0xa3, 0xc3, 0x9a, 0x91, 0x80, 0x63, + 0x44, 0x3b, 0xe8, 0x2b, 0x2b, 0x79, 0x6b, 0x3b, 0x68, 0x74, 0x74, 0x70, + 0x73, 0x3a, 0x2f, 0x2f, 0x6d, 0x61, 0x69, 0x6e, 0x6e, 0x65, 0x74, 0x2e, + 0x69, 0x6e, 0x63, 0x75, 0x62, 0x65, 0x64, 0x2e, 0x6e, 0x65, 0x74, 0x00, + 0x41, 0x6e, 0xbd, 0xff, 0xff, 0x63, 0xb2, 0xf6, 0x14, 0x51, 0x0e, 0xe7, + 0xf6, 0xf1, 0x98, 0xe0, 0x18, 0xe3, 0x52, 0x91, 0x64, 0xda, 0x24, 0x73, + 0xa9, 0x6e, 0xeb, 0x3d, 0xc8, 0x79, 0x6b, 0x3c, 0x27, 0x68, 0x74, 0x74, + 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x30, 0x30, 0x30, 0x31, 0x2e, 0x6d, 0x61, + 0x69, 0x6e, 0x6e, 0x65, 0x74, 0x2e, 0x69, 0x6e, 0x33, 0x2e, 0x61, 0x6e, + 0x79, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x74, 0x6f, 0x6f, 0x6c, 0x73, + 0x00, 0x41, 0x6e, 0xbd, 0xff, 0xff, 0x63, 0xb2, 0xf6, 0x14, 0xc5, 0x13, + 0xa5, 0x34, 0xde, 0x5a, 0x9d, 0x3f, 0x41, 0x31, 0x52, 0xc4, 0x1b, 0x09, + 0xbd, 0x81, 0x16, 0x23, 0x7f, 0xc8, 0x79, 0x6b, 0x3c, 0x24, 0x68, 0x74, + 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x69, 0x6e, 0x33, 0x2d, 0x76, 0x32, + 0x2e, 0x73, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x69, 0x74, 0x2f, 0x6d, 0x61, + 0x69, 0x6e, 0x6e, 0x65, 0x74, 0x2f, 0x6e, 0x64, 0x2d, 0x34, 0x00, 0x41, + 0x6e, 0xbd, 0xff, 0xff, 0x63, 0xb2, 0xf6, 0x14, 0xbc, 0xdf, 0x4e, 0x3e, + 0x90, 0xcc, 0x72, 0x88, 0xb5, 0x78, 0x32, 0x9e, 0xfd, 0x7b, 0xcc, 0x90, + 0x65, 0x51, 0x48, 0xd2, 0x79, 0x6b, 0x3c, 0x24, 0x68, 0x74, 0x74, 0x70, + 0x73, 0x3a, 0x2f, 0x2f, 0x69, 0x6e, 0x33, 0x2d, 0x76, 0x32, 0x2e, 0x73, + 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x69, 0x74, 0x2f, 0x6d, 0x61, 0x69, 0x6e, + 0x6e, 0x65, 0x74, 0x2f, 0x6e, 0x64, 0x2d, 0x35, 0x00, 0x41, 0x6e, 0xbd, + 0xff, 0xff}; +const unsigned int BOOT_NODES_MAINNET_BIN_LEN = 410; + #endif // NO_BOOT_NODES_MAINNET #ifdef IN3_STAGING @@ -94,7 +95,7 @@ unsigned int BOOT_NODES_MAINNET_BIN_LEN = 417; " }" \ "}") */ -unsigned char BOOT_NODES_GOERLI_BIN[] = { +const unsigned char BOOT_NODES_GOERLI_BIN[] = { 0xcd, 0x61, 0x5f, 0x35, 0x63, 0xce, 0x12, 0x14, 0x81, 0x4f, 0xb2, 0x20, 0x3f, 0x98, 0x48, 0x19, 0x23, 0x07, 0x09, 0x23, 0x37, 0x34, 0x0d, 0xcf, 0x79, 0x1a, 0x3f, 0xed, 0x6e, 0xb8, 0x1c, 0x20, 0x0f, 0x68, 0x73, 0x41, @@ -113,7 +114,8 @@ unsigned char BOOT_NODES_GOERLI_BIN[] = { 0x74, 0x61, 0x67, 0x65, 0x2e, 0x73, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x69, 0x74, 0x2f, 0x67, 0x6f, 0x65, 0x72, 0x6c, 0x69, 0x2f, 0x6e, 0x64, 0x2d, 0x32, 0x00, 0x41, 0x6e, 0xbd, 0xff, 0xff}; -unsigned int BOOT_NODES_GOERLI_BIN_LEN = 211; +const unsigned int BOOT_NODES_GOERLI_BIN_LEN = 211; + #endif // NO_BOOT_NODES_GOERLI #else /* IN3_STAGING */ @@ -132,17 +134,21 @@ unsigned int BOOT_NODES_GOERLI_BIN_LEN = 211; " \"address\": \"0x1fe2e9bf29aa1938859af64c413361227d04059a\"," \ " \"url\": \"https://in3-v2.slock.it/goerli/nd-2\"," \ " \"props\": \"0xFFFF\"" \ + " }, {" \ + " \"address\": \"0x7c1f2b5c1e2fe8300f3e0865818faf43ad22d99d\"," \ + " \"url\": \"https://in3.jentzschfamily.de\"," \ + " \"props\": \"0xFFFF\"" \ " }]" \ " }" \ "}") */ -unsigned char BOOT_NODES_GOERLI_BIN[] = { - 0xcd, 0x61, 0x5f, 0x35, 0x63, 0xce, 0x12, 0x14, 0x5f, 0x51, 0xe4, 0x13, +const unsigned char BOOT_NODES_GOERLI_BIN[] = { + 0xd1, 0x61, 0x5f, 0x35, 0x63, 0xce, 0x12, 0x14, 0x5f, 0x51, 0xe4, 0x13, 0x58, 0x1d, 0xd7, 0x67, 0x59, 0xe9, 0xee, 0xd5, 0x1e, 0x63, 0xd1, 0x4c, 0x8d, 0x13, 0x79, 0xc8, 0x6e, 0xb8, 0x1c, 0x20, 0x67, 0xc0, 0x2e, 0x5e, 0x27, 0x2f, 0x9d, 0x6b, 0x4a, 0x33, 0x71, 0x66, 0x14, 0x06, 0x1d, 0xd2, 0x98, 0x28, 0x3f, 0x86, 0x35, 0x10, 0x79, 0xef, 0x90, 0x3b, 0xf0, 0xd4, - 0x41, 0x0a, 0x44, 0xea, 0x1a, 0xa2, 0x42, 0x63, 0xb2, 0xf6, 0x14, 0x45, + 0x41, 0x0a, 0x44, 0xea, 0x1a, 0xa2, 0x43, 0x63, 0xb2, 0xf6, 0x14, 0x45, 0xd4, 0x5e, 0x6f, 0xf9, 0x9e, 0x6c, 0x34, 0xa2, 0x35, 0xd2, 0x63, 0x96, 0x59, 0x10, 0x29, 0x89, 0x85, 0xfc, 0xfe, 0x79, 0x6b, 0x3c, 0x23, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x69, 0x6e, 0x33, 0x2d, 0x76, @@ -154,11 +160,18 @@ unsigned char BOOT_NODES_GOERLI_BIN[] = { 0x73, 0x3a, 0x2f, 0x2f, 0x69, 0x6e, 0x33, 0x2d, 0x76, 0x32, 0x2e, 0x73, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x69, 0x74, 0x2f, 0x67, 0x6f, 0x65, 0x72, 0x6c, 0x69, 0x2f, 0x6e, 0x64, 0x2d, 0x32, 0x00, 0x41, 0x6e, 0xbd, 0xff, - 0xff}; -unsigned int BOOT_NODES_GOERLI_BIN_LEN = 205; + 0xff, 0x63, 0xb2, 0xf6, 0x14, 0x7c, 0x1f, 0x2b, 0x5c, 0x1e, 0x2f, 0xe8, + 0x30, 0x0f, 0x3e, 0x08, 0x65, 0x81, 0x8f, 0xaf, 0x43, 0xad, 0x22, 0xd9, + 0x9d, 0x79, 0x6b, 0x3c, 0x1d, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, + 0x2f, 0x69, 0x6e, 0x33, 0x2e, 0x6a, 0x65, 0x6e, 0x74, 0x7a, 0x73, 0x63, + 0x68, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x2e, 0x64, 0x65, 0x00, 0x41, + 0x6e, 0xbd, 0xff, 0xff}; +const unsigned int BOOT_NODES_GOERLI_BIN_LEN = 268; + #endif // NO_BOOT_NODES_GOERLI #ifndef NO_BOOT_NODES_IPFS + /* #define BOOT_NODES_IPFS JSON_TO_BIN("{" \ " \"nodeRegistry\": {" \ @@ -176,7 +189,7 @@ unsigned int BOOT_NODES_GOERLI_BIN_LEN = 205; " }" \ "}") */ -unsigned char BOOT_NODES_IPFS_BIN[] = { +const unsigned char BOOT_NODES_IPFS_BIN[] = { 0xcd, 0x61, 0x5f, 0x35, 0x63, 0xce, 0x12, 0x14, 0xa9, 0x3b, 0x57, 0x28, 0x90, 0x70, 0x55, 0x0c, 0x82, 0xed, 0xb1, 0x10, 0x6e, 0x12, 0xbb, 0x37, 0x13, 0x89, 0x48, 0xb8, 0x6e, 0xb8, 0x1c, 0x20, 0xf0, 0x16, 0x2e, 0xc6, @@ -194,7 +207,8 @@ unsigned char BOOT_NODES_IPFS_BIN[] = { 0x2f, 0x2f, 0x69, 0x6e, 0x33, 0x2d, 0x76, 0x32, 0x2e, 0x73, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x69, 0x74, 0x2f, 0x69, 0x70, 0x66, 0x73, 0x2f, 0x6e, 0x64, 0x2d, 0x32, 0x00, 0x41, 0x6e, 0xbd, 0xff, 0xff}; -unsigned int BOOT_NODES_IPFS_BIN_LEN = 201; +const unsigned int BOOT_NODES_IPFS_BIN_LEN = 201; + #endif // NO_BOOT_NODES_IPFS #ifndef NO_BOOT_NODES_BTC @@ -215,7 +229,7 @@ unsigned int BOOT_NODES_IPFS_BIN_LEN = 201; " }" \ "}") */ -unsigned char BOOT_NODES_BTC_BIN[] = { +const unsigned char BOOT_NODES_BTC_BIN[] = { 0xcd, 0x61, 0x5f, 0x35, 0x63, 0xce, 0x12, 0x14, 0xc2, 0xc0, 0x5f, 0xbf, 0xe7, 0x6e, 0xe7, 0x74, 0x8a, 0xe5, 0xf5, 0xb6, 0x1b, 0x57, 0xa4, 0x6c, 0xc4, 0x06, 0x1c, 0x32, 0x6e, 0xb8, 0x1c, 0x20, 0x53, 0x78, 0x6c, 0x93, @@ -233,7 +247,8 @@ unsigned char BOOT_NODES_BTC_BIN[] = { 0x2f, 0x69, 0x6e, 0x33, 0x2d, 0x76, 0x32, 0x2e, 0x73, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x69, 0x74, 0x2f, 0x62, 0x74, 0x63, 0x2f, 0x6e, 0x64, 0x2d, 0x32, 0x00, 0x41, 0x6e, 0xbd, 0xff, 0xff}; -unsigned int BOOT_NODES_BTC_BIN_LEN = 199; +const unsigned int BOOT_NODES_BTC_BIN_LEN = 199; + #endif // NO_BOOT_NODES_BTC #ifndef NO_BOOT_NODES_EWC @@ -254,7 +269,7 @@ unsigned int BOOT_NODES_BTC_BIN_LEN = 199; " }" \ "}") */ -unsigned char BOOT_NODES_EWC_BIN[] = { +const unsigned char BOOT_NODES_EWC_BIN[] = { 0xcd, 0x61, 0x5f, 0x35, 0x63, 0xce, 0x12, 0x14, 0x03, 0x95, 0x62, 0x87, 0x20, 0x08, 0xf7, 0xa7, 0x66, 0x74, 0xa6, 0xe7, 0x84, 0x28, 0x04, 0xf0, 0xad, 0x37, 0xcb, 0x13, 0x6e, 0xb8, 0x1c, 0x20, 0x31, 0x34, 0x54, 0xc0, @@ -272,7 +287,8 @@ unsigned char BOOT_NODES_EWC_BIN[] = { 0x2f, 0x69, 0x6e, 0x33, 0x2d, 0x76, 0x32, 0x2e, 0x73, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x69, 0x74, 0x2f, 0x65, 0x77, 0x63, 0x2f, 0x6e, 0x64, 0x2d, 0x32, 0x00, 0x41, 0x6e, 0xbd, 0xff, 0xff}; -unsigned int BOOT_NODES_EWC_BIN_LEN = 199; +const unsigned int BOOT_NODES_EWC_BIN_LEN = 199; + #endif // NO_BOOT_NODES_EWC #ifndef NO_BOOT_NODES_LOCAL @@ -288,7 +304,7 @@ unsigned int BOOT_NODES_EWC_BIN_LEN = 199; " }" \ "}") */ -unsigned char BOOT_NODES_LOCAL_BIN[] = { +const unsigned char BOOT_NODES_LOCAL_BIN[] = { 0xc8, 0x61, 0x5f, 0x35, 0x62, 0xce, 0x12, 0x14, 0xf0, 0xfb, 0x87, 0xf4, 0x75, 0x7c, 0x77, 0xea, 0x34, 0x16, 0xaf, 0xe8, 0x7f, 0x36, 0xac, 0xaa, 0x04, 0x96, 0xc7, 0xe9, 0x1a, 0xa2, 0x41, 0x63, 0xb2, 0xf6, 0x14, 0x78, @@ -297,7 +313,8 @@ unsigned char BOOT_NODES_LOCAL_BIN[] = { 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x68, 0x6f, 0x73, 0x74, 0x3a, 0x38, 0x35, 0x34, 0x35, 0x00, 0x41, 0x6e, 0xbd, 0xff, 0xff}; -unsigned int BOOT_NODES_LOCAL_BIN_LEN = 85; +const unsigned int BOOT_NODES_LOCAL_BIN_LEN = 85; + #endif // NO_BOOT_NODES_LOCAL #endif /* IN3_STAGING */ @@ -305,32 +322,32 @@ unsigned int BOOT_NODES_LOCAL_BIN_LEN = 85; static inline bytes_t nodeselect_def_cfg_data(chain_id_t chain_id) { #ifndef NO_BOOT_NODES_MAINNET if (chain_id == CHAIN_ID_MAINNET) - return bytes(BOOT_NODES_MAINNET_BIN, BOOT_NODES_MAINNET_BIN_LEN); + return bytes((uint8_t*) BOOT_NODES_MAINNET_BIN, BOOT_NODES_MAINNET_BIN_LEN); #endif // NO_BOOT_NODES_MAINNET #ifndef NO_BOOT_NODES_GOERLI if (chain_id == CHAIN_ID_GOERLI) - return bytes(BOOT_NODES_GOERLI_BIN, BOOT_NODES_GOERLI_BIN_LEN); + return bytes((uint8_t*) BOOT_NODES_GOERLI_BIN, BOOT_NODES_GOERLI_BIN_LEN); #endif // NO_BOOT_NODES_GOERLI #ifndef NO_BOOT_NODES_IPFS if (chain_id == CHAIN_ID_IPFS) - return bytes(BOOT_NODES_IPFS_BIN, BOOT_NODES_IPFS_BIN_LEN); + return bytes((uint8_t*) BOOT_NODES_IPFS_BIN, BOOT_NODES_IPFS_BIN_LEN); #endif // NO_BOOT_NODES_IPFS #ifndef NO_BOOT_NODES_BTC if (chain_id == CHAIN_ID_BTC) - return bytes(BOOT_NODES_BTC_BIN, BOOT_NODES_BTC_BIN_LEN); + return bytes((uint8_t*) BOOT_NODES_BTC_BIN, BOOT_NODES_BTC_BIN_LEN); #endif // NO_BOOT_NODES_BTC #ifndef NO_BOOT_NODES_EWC if (chain_id == CHAIN_ID_EWC) - return bytes(BOOT_NODES_EWC_BIN, BOOT_NODES_EWC_BIN_LEN); + return bytes((uint8_t*) BOOT_NODES_EWC_BIN, BOOT_NODES_EWC_BIN_LEN); #endif // NO_BOOT_NODES_EWC #ifndef NO_BOOT_NODES_LOCAL if (chain_id == CHAIN_ID_LOCAL) - return bytes(BOOT_NODES_LOCAL_BIN, BOOT_NODES_LOCAL_BIN_LEN); + return bytes((uint8_t*) BOOT_NODES_LOCAL_BIN, BOOT_NODES_LOCAL_BIN_LEN); #endif // NO_BOOT_NODES_LOCAL return bytes(NULL, 0); diff --git a/c/src/nodeselect/full/nodeselect_def_cfg_template.h b/c/src/nodeselect/full/nodeselect_def_cfg_template.h new file mode 100644 index 000000000..3d45da25a --- /dev/null +++ b/c/src/nodeselect/full/nodeselect_def_cfg_template.h @@ -0,0 +1,209 @@ +#ifndef IN3_NODE_SELECT_DEF_CFG_H +#define IN3_NODE_SELECT_DEF_CFG_H + +#define JSON_TO_BIN(x) x // marker for pre-build stage + +#include "../../core/client/client.h" + +#ifndef NO_BOOT_NODES_MAINNET +/* +#define BOOT_NODES_MAINNET JSON_TO_BIN("{" \ + " \"nodeRegistry\": {" \ + " \"contract\": \"0xac1b824795e1eb1f6e609fe0da9b9af8beaab60f\"," \ + " \"registryId\": \"0x23d5345c5c13180a8080bd5ddbe7cde64683755dcce6e734d95b7b573845facb\"," \ + " \"nodeList\": [{" \ + " \"address\": \"0x45d45e6ff99e6c34a235d263965910298985fcfe\"," \ + " \"url\": \"https://in3-v2.slock.it/mainnet/nd-1\"," \ + " \"props\": \"0xFFFF\"" \ + " }, {" \ + " \"address\": \"0x2e333ec090f1028df0a3c39a918063443be82b2b\"," \ + " \"url\": \"https://mainnet.incubed.net\"," \ + " \"props\": \"0xFFFF\"" \ + " }, {" \ + " \"address\": \"0x510ee7f6f198e018e3529164da2473a96eeb3dc8\"," \ + " \"url\": \"https://0001.mainnet.in3.anyblock.tools\"," \ + " \"props\": \"0xFFFF\"" \ + " }, {" \ + " \"address\": \"0xc513a534de5a9d3f413152c41b09bd8116237fc8\"," \ + " \"url\": \"https://in3-v2.slock.it/mainnet/nd-4\"," \ + " \"props\": \"0xFFFF\"" \ + " }, {" \ + " \"address\": \"0xbcdf4e3e90cc7288b578329efd7bcc90655148d2\"," \ + " \"url\": \"https://in3-v2.slock.it/mainnet/nd-5\"," \ + " \"props\": \"0xFFFF\"" \ + " }]" \ + " }" \ + "}") + +#endif // NO_BOOT_NODES_MAINNET + +#ifdef IN3_STAGING + +#ifndef NO_BOOT_NODES_GOERLI +/* +#define BOOT_NODES_GOERLI JSON_TO_BIN("{" \ + " \"nodeRegistry\": {" \ + " \"contract\": \"0x814fb2203f9848192307092337340dcf791a3fed\"," \ + " \"registryId\": \"0x0f687341e0823fa5288dc9edd8a00950b35cc7e481ad7eaccaf61e4e04a61e08\"," \ + " \"nodeList\": [{" \ + " \"address\": \"0x784bfa9eb182c3a02dbeb5285e3dba92d717e07a\"," \ + " \"url\": \"https://in3.stage.slock.it/goerli/nd-1\"," \ + " \"props\": \"0xFFFF\"" \ + " }, {" \ + " \"address\": \"0x17cdf9ec6dcae05c5686265638647e54b14b41a2\"," \ + " \"url\": \"https://in3.stage.slock.it/goerli/nd-2\"," \ + " \"props\": \"0xFFFF\"" \ + " }]" \ + " }" \ + "}") + +#endif // NO_BOOT_NODES_GOERLI + +#else /* IN3_STAGING */ + +#ifndef NO_BOOT_NODES_GOERLI +/* +#define BOOT_NODES_GOERLI JSON_TO_BIN("{" \ + " \"nodeRegistry\": {" \ + " \"contract\": \"0x5f51e413581dd76759e9eed51e63d14c8d1379c8\"," \ + " \"registryId\": \"0x67c02e5e272f9d6b4a33716614061dd298283f86351079ef903bf0d4410a44ea\"," \ + " \"nodeList\": [{" \ + " \"address\": \"0x45d45e6ff99e6c34a235d263965910298985fcfe\"," \ + " \"url\": \"https://in3-v2.slock.it/goerli/nd-1\"," \ + " \"props\": \"0xFFFF\"" \ + " }, {" \ + " \"address\": \"0x1fe2e9bf29aa1938859af64c413361227d04059a\"," \ + " \"url\": \"https://in3-v2.slock.it/goerli/nd-2\"," \ + " \"props\": \"0xFFFF\"" \ + " }, {" \ + " \"address\": \"0x7c1f2b5c1e2fe8300f3e0865818faf43ad22d99d\"," \ + " \"url\": \"https://in3.jentzschfamily.de\"," \ + " \"props\": \"0xFFFF\"" \ + " }]" \ + " }" \ + "}") + + +#endif // NO_BOOT_NODES_GOERLI + +#ifndef NO_BOOT_NODES_IPFS + +/* +#define BOOT_NODES_IPFS JSON_TO_BIN("{" \ + " \"nodeRegistry\": {" \ + " \"contract\": \"0xa93b57289070550c82edb1106e12bb37138948b8\"," \ + " \"registryId\": \"0xf0162ec6d785ee990e36bad865251f45af0916cf136169540c02b0dd9cb69196\"," \ + " \"nodeList\": [{" \ + " \"address\": \"0x45d45e6ff99e6c34a235d263965910298985fcfe\"," \ + " \"url\": \"https://in3-v2.slock.it/ipfs/nd-1\"," \ + " \"props\": \"0xFFFF\"" \ + " }, {" \ + " \"address\": \"0x1fe2e9bf29aa1938859af64c413361227d04059a\"," \ + " \"url\": \"https://in3-v2.slock.it/ipfs/nd-2\"," \ + " \"props\": \"0xFFFF\"" \ + " }]" \ + " }" \ + "}") + + +#endif // NO_BOOT_NODES_IPFS + +#ifndef NO_BOOT_NODES_BTC +/* +#define BOOT_NODES_BTC JSON_TO_BIN("{" \ + " \"nodeRegistry\": {" \ + " \"contract\": \"0xc2c05fbfe76ee7748ae5f5b61b57a46cc4061c32\"," \ + " \"registryId\": \"0x53786c93e54c21d9852d093c394eee9df8d714d8f2534cdf92f9c9998c528d19\"," \ + " \"nodeList\": [{" \ + " \"address\": \"0x45d45e6ff99e6c34a235d263965910298985fcfe\"," \ + " \"url\": \"https://in3-v2.slock.it/btc/nd-1\"," \ + " \"props\": \"0xFFFF\"" \ + " }, {" \ + " \"address\": \"0x1fe2e9bf29aa1938859af64c413361227d04059a\"," \ + " \"url\": \"https://in3-v2.slock.it/btc/nd-2\"," \ + " \"props\": \"0xFFFF\"" \ + " }]" \ + " }" \ + "}") + + +#endif // NO_BOOT_NODES_BTC + +#ifndef NO_BOOT_NODES_EWC +/* +#define BOOT_NODES_EWC JSON_TO_BIN("{" \ + " \"nodeRegistry\": {" \ + " \"contract\": \"0x039562872008f7a76674a6e7842804f0ad37cb13\"," \ + " \"registryId\": \"0x313454c05fc6e5336a3315ed2233da6b831d4cb826d836c3d603f2e2a9f1ed75\"," \ + " \"nodeList\": [{" \ + " \"address\": \"0x45d45e6ff99e6c34a235d263965910298985fcfe\"," \ + " \"url\": \"https://in3-v2.slock.it/ewc/nd-1\"," \ + " \"props\": \"0xFFFF\"" \ + " }, {" \ + " \"address\": \"0x1fe2e9bf29aa1938859af64c413361227d04059a\"," \ + " \"url\": \"https://in3-v2.slock.it/ewc/nd-2\"," \ + " \"props\": \"0xFFFF\"" \ + " }]" \ + " }" \ + "}") + + +#endif // NO_BOOT_NODES_EWC + +#ifndef NO_BOOT_NODES_LOCAL +/* +#define BOOT_NODES_LOCAL JSON_TO_BIN("{" \ + " \"nodeRegistry\": {" \ + " \"contract\": \"0xf0fb87f4757c77ea3416afe87f36acaa0496c7e9\"," \ + " \"nodeList\": [{" \ + " \"address\": \"0x784bfa9eb182c3a02dbeb5285e3dba92d717e07a\"," \ + " \"url\": \"http://localhost:8545\"," \ + " \"props\": \"0xFFFF\"" \ + " }]" \ + " }" \ + "}") + +#endif // NO_BOOT_NODES_LOCAL + +#endif /* IN3_STAGING */ + +static inline bytes_t nodeselect_def_cfg_data(chain_id_t chain_id) { +#ifndef NO_BOOT_NODES_MAINNET + if (chain_id == CHAIN_ID_MAINNET) + return bytes((uint8_t*) BOOT_NODES_MAINNET_BIN, BOOT_NODES_MAINNET_BIN_LEN); +#endif // NO_BOOT_NODES_MAINNET + +#ifndef NO_BOOT_NODES_GOERLI + if (chain_id == CHAIN_ID_GOERLI) + return bytes((uint8_t*) BOOT_NODES_GOERLI_BIN, BOOT_NODES_GOERLI_BIN_LEN); +#endif // NO_BOOT_NODES_GOERLI + +#ifndef NO_BOOT_NODES_IPFS + if (chain_id == CHAIN_ID_IPFS) + return bytes((uint8_t*) BOOT_NODES_IPFS_BIN, BOOT_NODES_IPFS_BIN_LEN); +#endif // NO_BOOT_NODES_IPFS + +#ifndef NO_BOOT_NODES_BTC + if (chain_id == CHAIN_ID_BTC) + return bytes((uint8_t*) BOOT_NODES_BTC_BIN, BOOT_NODES_BTC_BIN_LEN); +#endif // NO_BOOT_NODES_BTC + +#ifndef NO_BOOT_NODES_EWC + if (chain_id == CHAIN_ID_EWC) + return bytes((uint8_t*) BOOT_NODES_EWC_BIN, BOOT_NODES_EWC_BIN_LEN); +#endif // NO_BOOT_NODES_EWC + +#ifndef NO_BOOT_NODES_LOCAL + if (chain_id == CHAIN_ID_LOCAL) + return bytes((uint8_t*) BOOT_NODES_LOCAL_BIN, BOOT_NODES_LOCAL_BIN_LEN); +#endif // NO_BOOT_NODES_LOCAL + + return bytes(NULL, 0); +} + +static inline json_ctx_t* nodeselect_def_cfg(chain_id_t chain_id) { + bytes_t bincfg = nodeselect_def_cfg_data(chain_id); + return bincfg.data ? parse_binary(&bincfg) : NULL; +} + +#endif //IN3_NODE_SELECT_DEF_CFG_H diff --git a/c/src/nodeselect/registry.c b/c/src/nodeselect/full/registry.c similarity index 94% rename from c/src/nodeselect/registry.c rename to c/src/nodeselect/full/registry.c index bd04e586f..57abd6ab8 100644 --- a/c/src/nodeselect/registry.c +++ b/c/src/nodeselect/full/registry.c @@ -33,13 +33,13 @@ *******************************************************************************/ #include "registry.h" -#include "../core/client/context.h" -#include "../core/client/keys.h" -#include "../core/util/mem.h" -#include "../verifier/eth1/nano/eth_nano.h" -#include "../verifier/eth1/nano/merkle.h" -#include "../verifier/eth1/nano/rlp.h" -#include "../verifier/eth1/nano/serialize.h" +#include "../../core/client/keys.h" +#include "../../core/client/request.h" +#include "../../core/util/mem.h" +#include "../../verifier/eth1/nano/eth_nano.h" +#include "../../verifier/eth1/nano/merkle.h" +#include "../../verifier/eth1/nano/rlp.h" +#include "../../verifier/eth1/nano/serialize.h" #include #define SERVER_STRUCT_SIZE 6 @@ -160,7 +160,7 @@ _NOINLINE_ static void create_node_hash(d_token_t* t, bytes32_t dst) { static in3_ret_t verify_nodelist_data(in3_vctx_t* vc, const uint32_t node_limit, bytes_t* seed, d_token_t* required_addresses, d_token_t* server_list, d_token_t* storage_proofs) { bytes32_t skey, svalue; - uint32_t total_servers = d_get_intk(vc->result, K_TOTAL_SERVERS); + uint32_t total_servers = d_get_int(vc->result, K_TOTAL_SERVERS); TRY(check_storage(vc, storage_proofs, get_storage_array_key(0, 0, 0, 0, skey), as_bytes32(svalue, d_to_bytes(d_get(vc->result, K_TOTAL_SERVERS))))); @@ -178,7 +178,7 @@ static in3_ret_t verify_nodelist_data(in3_vctx_t* vc, const uint32_t node_limit, for (d_iterator_t itn = d_iter(server_list); itn.left; d_iter_next(&itn)) { if (b_cmp(d_get_byteskl(itn.token, K_ADDRESS, 20), adr)) { found = true; - seed_indexes[i] = d_get_intk(itn.token, K_INDEX); + seed_indexes[i] = d_get_int(itn.token, K_INDEX); break; } } @@ -193,7 +193,7 @@ static in3_ret_t verify_nodelist_data(in3_vctx_t* vc, const uint32_t node_limit, // check that we have the correct indexes in the nodelist i = 0; for (d_iterator_t it = d_iter(server_list); it.left && i < node_limit; d_iter_next(&it), i++) { - uint32_t index = d_get_intk(it.token, K_INDEX); + uint32_t index = d_get_int(it.token, K_INDEX); if (index != indexes[i]) return vc_err(vc, "wrong index in partial nodelist"); } } @@ -202,7 +202,7 @@ static in3_ret_t verify_nodelist_data(in3_vctx_t* vc, const uint32_t node_limit, // now check the content of the nodelist for (d_iterator_t it = d_iter(server_list); it.left; d_iter_next(&it)) { - uint32_t index = d_get_intk(it.token, K_INDEX); + uint32_t index = d_get_int(it.token, K_INDEX); create_node_hash(it.token, svalue); TRY(check_storage(vc, storage_proofs, get_storage_array_key(0, index, 5, 4, skey), svalue)); } @@ -213,7 +213,7 @@ static in3_ret_t verify_nodelist_data(in3_vctx_t* vc, const uint32_t node_limit, #ifdef NODESELECT_DEF_WL static in3_ret_t verify_whitelist_data(in3_vctx_t* vc, d_token_t* server_list, d_token_t* storage_proofs) { bytes32_t skey; - uint32_t total_servers = d_get_intk(vc->result, K_TOTAL_SERVERS); + uint32_t total_servers = d_get_int(vc->result, K_TOTAL_SERVERS); if ((int) total_servers != d_len(server_list)) return vc_err(vc, "wrong number of nodes in the whitelist"); @@ -242,7 +242,7 @@ static in3_ret_t verify_account(in3_vctx_t* vc, address_t required_contract, d_t if (d_type(vc->result) != T_OBJECT || !vc->proof || !server_list) return vc_err(vc, "Invalid nodelist response!"); // verify the header - bytes_t* blockHeader = d_get_bytesk(vc->proof, K_BLOCK); + bytes_t* blockHeader = d_get_bytes(vc->proof, K_BLOCK); if (!blockHeader) return vc_err(vc, "No Block-Proof!"); TRY(eth_verify_blockheader(vc, blockHeader, NULL)); @@ -252,7 +252,7 @@ static in3_ret_t verify_account(in3_vctx_t* vc, address_t required_contract, d_t return vc_err(vc, "No or wrong Contract!"); // check last block - if (rlp_decode_in_list(blockHeader, BLOCKHEADER_NUMBER, &root) != 1 || bytes_to_long(root.data, root.len) < d_get_longk(vc->result, K_LAST_BLOCK_NUMBER)) + if (rlp_decode_in_list(blockHeader, BLOCKHEADER_NUMBER, &root) != 1 || bytes_to_long(root.data, root.len) < d_get_long(vc->result, K_LAST_BLOCK_NUMBER)) return vc_err(vc, "The signature is based on older block!"); // check accounts diff --git a/c/src/nodeselect/registry.h b/c/src/nodeselect/full/registry.h similarity index 79% rename from c/src/nodeselect/registry.h rename to c/src/nodeselect/full/registry.h index f1bc74ab0..06477b2c2 100644 --- a/c/src/nodeselect/registry.h +++ b/c/src/nodeselect/full/registry.h @@ -1,9 +1,9 @@ #ifndef IN3_NODE_SELECT_REGISTRY_H #define IN3_NODE_SELECT_REGISTRY_H -#include "../core/client/plugin.h" -#include "../core/util/data.h" -#include "../core/util/error.h" +#include "../../core/client/plugin.h" +#include "../../core/util/data.h" +#include "../../core/util/error.h" #include "nodeselect_def.h" NONULL_FOR((1)) diff --git a/c/src/pay/eth/pay_eth.c b/c/src/pay/eth/pay_eth.c index 8de0f4986..25a091e38 100644 --- a/c/src/pay/eth/pay_eth.c +++ b/c/src/pay/eth/pay_eth.c @@ -32,8 +32,8 @@ * with this program. If not, see . *******************************************************************************/ #include "pay_eth.h" -#include "../../core/client/context.h" #include "../../core/client/keys.h" +#include "../../core/client/request.h" #include "../../core/util/debug.h" #include "../../core/util/mem.h" #include "../../third-party/crypto/ecdsa.h" @@ -45,7 +45,7 @@ #include #include -static uint64_t calc_request_units(in3_ctx_t* ctx) { +static uint64_t calc_request_units(in3_req_t* ctx) { return ctx->len; } @@ -88,7 +88,7 @@ static void node_free(in3_pay_eth_t* data) { } static in3_ret_t pay_eth_follow_up(in3_pay_eth_t* data, in3_pay_followup_ctx_t* plugin_ctx) { - in3_ctx_t* ctx = plugin_ctx->ctx; + in3_req_t* ctx = plugin_ctx->req; d_token_t *pay = d_get(plugin_ctx->resp_in3, key("pay")), *t; if (!pay || !ctx) return IN3_OK; @@ -101,7 +101,7 @@ static in3_ret_t pay_eth_follow_up(in3_pay_eth_t* data, in3_pay_followup_ctx_t* if (node) { if ((t = d_get(pay, key("payed")))) node->payed = d_long(t); if ((t = d_get(pay, key("price")))) node->price = d_long(t); - if (plugin_ctx->resp_error && d_get_intk(plugin_ctx->resp_error, K_CODE) == IN3_EPAYMENT_REQUIRED) { + if (plugin_ctx->resp_error && d_get_int(plugin_ctx->resp_error, K_CODE) == IN3_EPAYMENT_REQUIRED) { // TODO now we need to decide whether it's worth to pay if (node->price && (data->max_price == 0 || node->price < data->max_price)) return IN3_WAITING; @@ -111,7 +111,7 @@ static in3_ret_t pay_eth_follow_up(in3_pay_eth_t* data, in3_pay_followup_ctx_t* return IN3_OK; } -static in3_ret_t pay_eth_prepare(in3_pay_eth_t* data, in3_ctx_t* ctx) { +static in3_ret_t pay_eth_prepare(in3_pay_eth_t* data, in3_req_t* ctx) { if (data == NULL || ctx == NULL) return IN3_EINVAL; return IN3_OK; } @@ -137,7 +137,7 @@ static void create_signed_tx(in3_pay_eth_t* data, bytes32_t key, sb_t* sb, addre } static in3_ret_t pay_eth_handle_request(in3_pay_eth_t* data, in3_pay_handle_ctx_t* plugin_ctx) { - in3_ctx_t* ctx = plugin_ctx->ctx; + in3_req_t* ctx = plugin_ctx->req; const uint64_t units = calc_request_units(ctx); bool started = false; sb_t* sb = plugin_ctx->payload; diff --git a/c/src/pay/zksync/CMakeLists.txt b/c/src/pay/zksync/CMakeLists.txt index eb489d51c..95eb4efee 100644 --- a/c/src/pay/zksync/CMakeLists.txt +++ b/c/src/pay/zksync/CMakeLists.txt @@ -44,6 +44,7 @@ add_static_library( zk_transfer.c zk_deposit.c zk_musig.c + zk_incentive.c DEPENDS eth_basic diff --git a/c/src/pay/zksync/zk_deposit.c b/c/src/pay/zksync/zk_deposit.c index 36d1d25cf..a8f5d7931 100644 --- a/c/src/pay/zksync/zk_deposit.c +++ b/c/src/pay/zksync/zk_deposit.c @@ -1,6 +1,6 @@ -#include "../../core/client/context_internal.h" #include "../../core/client/keys.h" #include "../../core/client/plugin.h" +#include "../../core/client/request_internal.h" #include "../../core/util/debug.h" #include "../../core/util/mem.h" #include "../../third-party/zkcrypto/lib.h" @@ -11,37 +11,37 @@ #include #include -in3_ret_t zksync_deposit(zksync_config_t* conf, in3_rpc_handle_ctx_t* ctx, d_token_t* params) { - // check params - if (!(d_len(params) == 1 && d_type(params + 1) == T_OBJECT)) { - CHECK_PARAMS_LEN(ctx->ctx, params, 2) - CHECK_PARAM_NUMBER(ctx->ctx, params, 0) - CHECK_PARAM_TOKEN(ctx->ctx, params, 1) +in3_ret_t zksync_deposit(zksync_config_t* conf, in3_rpc_handle_ctx_t* ctx) { + // check ctx->params + if (!(d_len(ctx->params) == 1 && d_type(ctx->params + 1) == T_OBJECT)) { + CHECK_PARAMS_LEN(ctx->req, ctx->params, 2) + CHECK_PARAM_NUMBER(ctx->req, ctx->params, 0) + CHECK_PARAM_TOKEN(ctx->req, ctx->params, 1) } // amount - d_token_t* tmp = NULL; - bytes_t amount = d_to_bytes(params_get(params, key("amount"), 0)); - d_token_t* token = params_get(params, key("token"), 1); - bool approve = d_int(params_get(params, key("approveDepositAmountForERC20"), 2)); - uint8_t* main_contract = conf->main_contract; + d_token_t* tmp = NULL; + d_token_t* tx_receipt = NULL; + zksync_token_t* token_conf = NULL; + bytes_t amount = d_to_bytes(params_get(ctx->params, key("amount"), 0)); + d_token_t* token = params_get(ctx->params, key("token"), 1); + bool approve = d_int(params_get(ctx->params, key("approveDepositAmountForERC20"), 2)); + uint8_t* main_contract = conf->main_contract; // make sure we have an account uint8_t* account = conf->account; - if ((tmp = params_get(params, key("depositTo"), 3))) { - if (tmp->len != 20) return ctx_set_error(ctx->ctx, "invalid depositTo", IN3_ERPC); + if ((tmp = params_get(ctx->params, key("depositTo"), 3))) { + if (tmp->len != 20) return req_set_error(ctx->req, "invalid depositTo", IN3_ERPC); account = tmp->data; } else if (!account) - TRY(zksync_get_account(conf, ctx->ctx, &account)) + TRY(zksync_get_account(conf, ctx->req, &account)) // check main_contract - if (!main_contract) TRY(zksync_get_contracts(conf, ctx->ctx, &main_contract)) + if (!main_contract) TRY(zksync_get_contracts(conf, ctx->req, &main_contract)) - d_token_t* tx_receipt = NULL; - zksync_token_t* token_conf = NULL; - TRY(resolve_tokens(conf, ctx->ctx, token, &token_conf)) - if (!token_conf) return IN3_EUNKNOWN; + // get token from the tokenlist + TRY(resolve_tokens(conf, ctx->req, token, &token_conf)) if (memiszero(token_conf->address, 20)) { // is eth sb_t sb = {0}; @@ -49,7 +49,7 @@ in3_ret_t zksync_deposit(zksync_config_t* conf, in3_rpc_handle_ctx_t* ctx, d_tok sb_add_rawbytes(&sb, "\",\"data\":\"0x2d2da806", bytes(account, 20), 32); sb_add_rawbytes(&sb, "\",\"value\":\"0x", amount, 0); sb_add_chars(&sb, "\",\"gas\":\"0x30d40\"}"); - TRY_FINAL(send_provider_request(ctx->ctx, NULL, "eth_sendTransactionAndWait", sb.data, &tx_receipt), _free(sb.data)) + TRY_FINAL(send_provider_request(ctx->req, NULL, "eth_sendTransactionAndWait", sb.data, &tx_receipt), _free(sb.data)) } else { @@ -60,7 +60,7 @@ in3_ret_t zksync_deposit(zksync_config_t* conf, in3_rpc_handle_ctx_t* ctx, d_tok sb_add_rawbytes(&sb, NULL, amount, 32); sb_add_chars(&sb, "\",\"gas\":\"0x30d40\"}"); - TRY_FINAL(send_provider_request(ctx->ctx, NULL, "eth_sendTransactionAndWait", sb.data, &tx_receipt), _free(sb.data)) + TRY_FINAL(send_provider_request(ctx->req, NULL, "eth_sendTransactionAndWait", sb.data, &tx_receipt), _free(sb.data)) } sb_t sb = {0}; @@ -70,16 +70,15 @@ in3_ret_t zksync_deposit(zksync_config_t* conf, in3_rpc_handle_ctx_t* ctx, d_tok sb_add_rawbytes(&sb, NULL, bytes(account, 20), 32); sb_add_chars(&sb, "\",\"gas\":\"0xffd40\"}"); - TRY_FINAL(send_provider_request(ctx->ctx, NULL, "eth_sendTransactionAndWait", sb.data, &tx_receipt), _free(sb.data)) + TRY_FINAL(send_provider_request(ctx->req, NULL, "eth_sendTransactionAndWait", sb.data, &tx_receipt), _free(sb.data)) } // now that we have the receipt, we need to find the opId in the log - bytes32_t event_hash; - hex_to_bytes("d0943372c08b438a88d4b39d77216901079eda9ca59d45349841c099083b6830", -1, event_hash, 32); + const uint8_t event_hash[] = {0xd0, 0x94, 0x33, 0x72, 0xc0, 0x8b, 0x43, 0x8a, 0x88, 0xd4, 0xb3, 0x9d, 0x77, 0x21, 0x69, 0x01, 0x07, 0x9e, 0xda, 0x9c, 0xa5, 0x9d, 0x45, 0x34, 0x98, 0x41, 0xc0, 0x99, 0x08, 0x3b, 0x68, 0x30}; for (d_iterator_t iter = d_iter(d_get(tx_receipt, K_LOGS)); iter.left; d_iter_next(&iter)) { bytes_t* ev = d_get_bytes_at(d_get(iter.token, K_TOPICS), 0); if (ev && ev->len == 32 && memcmp(event_hash, ev->data, 32) == 0) { - bytes_t* data = d_get_bytesk(iter.token, K_DATA); + bytes_t* data = d_get_bytes(iter.token, K_DATA); if (data && data->len > 64) { str_range_t r = d_to_json(tx_receipt); sb_t* sb = in3_rpc_handle_start(ctx); @@ -88,16 +87,16 @@ in3_ret_t zksync_deposit(zksync_config_t* conf, in3_rpc_handle_ctx_t* ctx, d_tok sb_add_chars(sb, ",\"priorityOpId\":"); sb_add_int(sb, bytes_to_long(data->data + 64 - 8, 8)); sb_add_chars(sb, "}"); - ctx_remove_required(ctx->ctx, ctx_find_required(ctx->ctx, "eth_sendTransactionAndWait"), true); + req_remove_required(ctx->req, req_find_required(ctx->req, "eth_sendTransactionAndWait"), true); return in3_rpc_handle_finish(ctx); } } } - return ctx_set_error(ctx->ctx, "Could not find the serial in the receipt", IN3_EFIND); + return req_set_error(ctx->req, "Could not find the serial in the receipt", IN3_EFIND); } -in3_ret_t zksync_emergency_withdraw(zksync_config_t* conf, in3_rpc_handle_ctx_t* ctx, d_token_t* params) { +in3_ret_t zksync_emergency_withdraw(zksync_config_t* conf, in3_rpc_handle_ctx_t* ctx) { uint8_t aid[4]; zksync_token_t* token_conf = NULL; uint8_t* main_contract = conf->main_contract; @@ -106,13 +105,13 @@ in3_ret_t zksync_emergency_withdraw(zksync_config_t* conf, in3_rpc_handle_ctx_t* d_token_t* tx_receipt = NULL; sb_t sb = {0}; - CHECK_PARAM_TOKEN(ctx->ctx, params, 0) + CHECK_PARAM_TOKEN(ctx->req, ctx->params, 0) // check main_contract - TRY(zksync_get_contracts(conf, ctx->ctx, &main_contract)) - TRY(resolve_tokens(conf, ctx->ctx, params_get(params, key("token"), 0), &token_conf)) - TRY(zksync_get_account_id(conf, ctx->ctx, &account_id)) - TRY(zksync_get_account(conf, ctx->ctx, &account)) + TRY(zksync_get_contracts(conf, ctx->req, &main_contract)) + TRY(resolve_tokens(conf, ctx->req, params_get(ctx->params, key("token"), 0), &token_conf)) + TRY(zksync_get_account_id(conf, ctx->req, &account_id)) + TRY(zksync_get_account(conf, ctx->req, &account)) int_to_bytes(account_id, aid); sb_add_rawbytes(&sb, "{\"to\":\"0x", bytes(main_contract, 20), 0); @@ -120,8 +119,8 @@ in3_ret_t zksync_emergency_withdraw(zksync_config_t* conf, in3_rpc_handle_ctx_t* sb_add_rawbytes(&sb, "", bytes(token_conf->address, 20), 32); sb_add_rawbytes(&sb, "\",\"from\":\"0x", bytes(account, 20), 20); sb_add_chars(&sb, "\",\"gas\":\"0x7a120\"}"); - TRY_FINAL(send_provider_request(ctx->ctx, NULL, "eth_sendTransactionAndWait", sb.data, &tx_receipt), _free(sb.data)) - if (d_type(tx_receipt) != T_OBJECT) return ctx_set_error(ctx->ctx, "no txreceipt found, which means the transaction was not succesful", IN3_EFIND); + TRY_FINAL(send_provider_request(ctx->req, NULL, "eth_sendTransactionAndWait", sb.data, &tx_receipt), _free(sb.data)) + if (d_type(tx_receipt) != T_OBJECT) return req_set_error(ctx->req, "no txreceipt found, which means the transaction was not succesful", IN3_EFIND); str_range_t r = d_to_json(tx_receipt); r.data[r.len] = 0; return in3_rpc_handle_with_string(ctx, r.data); diff --git a/c/src/pay/zksync/zk_helper.c b/c/src/pay/zksync/zk_helper.c index 205dbd873..d4fa570dc 100644 --- a/c/src/pay/zksync/zk_helper.c +++ b/c/src/pay/zksync/zk_helper.c @@ -33,9 +33,9 @@ *******************************************************************************/ #include "zk_helper.h" -#include "../../core/client/context_internal.h" #include "../../core/client/keys.h" #include "../../core/client/plugin.h" +#include "../../core/client/request_internal.h" #include "../../core/util/debug.h" #include "../../core/util/mem.h" #include "../../third-party/zkcrypto/lib.h" @@ -59,19 +59,19 @@ void set_quoted_address(char* c, uint8_t* address) { c[44] = 0; } -static in3_ret_t ensure_provider(zksync_config_t* conf, in3_ctx_t* ctx) { +static in3_ret_t ensure_provider(zksync_config_t* conf, in3_req_t* ctx) { if (conf->provider_url) return IN3_OK; switch (ctx->client->chain.chain_id) { case CHAIN_ID_MAINNET: conf->provider_url = _strdupn("https://api.zksync.io/jsrpc", -1); break; default: - return ctx_set_error(ctx, "no provider_url in config", IN3_EINVAL); + return req_set_error(ctx, "no provider_url in config", IN3_EINVAL); } return IN3_OK; } -in3_ret_t send_provider_request(in3_ctx_t* parent, zksync_config_t* conf, char* method, char* params, d_token_t** result) { +in3_ret_t send_provider_request(in3_req_t* parent, zksync_config_t* conf, char* method, char* params, d_token_t** result) { if (params == NULL) params = ""; char* in3 = NULL; if (conf) { @@ -79,7 +79,7 @@ in3_ret_t send_provider_request(in3_ctx_t* parent, zksync_config_t* conf, char* in3 = alloca(strlen(conf->provider_url) + 26); sprintf(in3, "{\"rpc\":\"%s\"}", conf->provider_url); } - return ctx_send_sub_request(parent, method, params, in3, result); + return req_send_sub_request(parent, method, params, in3, result); } void zksync_calculate_account(address_t creator, bytes32_t codehash, bytes32_t saltarg, address_t pub_key_hash, address_t dst) { @@ -95,13 +95,13 @@ void zksync_calculate_account(address_t creator, bytes32_t codehash, bytes32_t s memcpy(dst, tmp + 12, 20); } -in3_ret_t zksync_check_create2(zksync_config_t* conf, in3_ctx_t* ctx) { +in3_ret_t zksync_check_create2(zksync_config_t* conf, in3_req_t* ctx) { if (conf->sign_type != ZK_SIGN_CREATE2) return IN3_OK; if (conf->account) return IN3_OK; - if (!conf->create2) return ctx_set_error(ctx, "missing create2 section in zksync-config", IN3_ECONFIG); - if (memiszero(conf->create2->creator, 20)) return ctx_set_error(ctx, "no creator in create2-config", IN3_ECONFIG); - if (memiszero(conf->create2->codehash, 32)) return ctx_set_error(ctx, "no codehash in create2-config", IN3_ECONFIG); - if (memiszero(conf->create2->salt_arg, 32)) return ctx_set_error(ctx, "no saltarg in create2-config", IN3_ECONFIG); + if (!conf->create2) return req_set_error(ctx, "missing create2 section in zksync-config", IN3_ECONFIG); + if (memiszero(conf->create2->creator, 20)) return req_set_error(ctx, "no creator in create2-config", IN3_ECONFIG); + if (memiszero(conf->create2->codehash, 32)) return req_set_error(ctx, "no codehash in create2-config", IN3_ECONFIG); + if (memiszero(conf->create2->salt_arg, 32)) return req_set_error(ctx, "no saltarg in create2-config", IN3_ECONFIG); if (!conf->account) { address_t pub_key_hash; TRY(zksync_get_pubkey_hash(conf, ctx, pub_key_hash)) @@ -111,13 +111,13 @@ in3_ret_t zksync_check_create2(zksync_config_t* conf, in3_ctx_t* ctx) { return IN3_OK; } -in3_ret_t zksync_get_account(zksync_config_t* conf, in3_ctx_t* ctx, uint8_t** account) { +in3_ret_t zksync_get_account(zksync_config_t* conf, in3_req_t* ctx, uint8_t** account) { TRY(zksync_check_create2(conf, ctx)) if (!conf->account) { - in3_sign_account_ctx_t sctx = {.ctx = ctx, .accounts = NULL, .accounts_len = 0}; + in3_sign_account_ctx_t sctx = {.req = ctx, .accounts = NULL, .accounts_len = 0}; if (in3_plugin_execute_first(ctx, PLGN_ACT_SIGN_ACCOUNT, &sctx) || !sctx.accounts_len) { if (sctx.accounts) _free(sctx.accounts); - return ctx_set_error(ctx, "No account configured or signer set", IN3_ECONFIG); + return req_set_error(ctx, "No account configured or signer set", IN3_ECONFIG); } conf->account = (uint8_t*) sctx.accounts; } @@ -127,7 +127,7 @@ in3_ret_t zksync_get_account(zksync_config_t* conf, in3_ctx_t* ctx, uint8_t** ac } // sends a account_info request and updates the config -in3_ret_t zksync_update_account(zksync_config_t* conf, in3_ctx_t* ctx) { +in3_ret_t zksync_update_account(zksync_config_t* conf, in3_req_t* ctx) { uint8_t* account = NULL; d_token_t* result; char adr[45]; @@ -137,9 +137,9 @@ in3_ret_t zksync_update_account(zksync_config_t* conf, in3_ctx_t* ctx) { TRY(send_provider_request(ctx, conf, "account_info", adr, &result)) d_token_t* committed = d_get(result, key("committed")); - conf->account_id = d_get_intk(result, K_ID); - conf->nonce = d_get_longk(committed, K_NONCE); - char* kh = d_get_stringk(committed, key("pubKeyHash")); + conf->account_id = d_get_int(result, K_ID); + conf->nonce = d_get_long(committed, K_NONCE); + char* kh = d_get_string(committed, key("pubKeyHash")); if (kh && strlen(kh) == 45) hex_to_bytes(kh + 5, 40, conf->pub_key_hash_set, 20); @@ -147,7 +147,7 @@ in3_ret_t zksync_update_account(zksync_config_t* conf, in3_ctx_t* ctx) { } // resolves the account_id -in3_ret_t zksync_get_account_id(zksync_config_t* conf, in3_ctx_t* ctx, uint32_t* account_id) { +in3_ret_t zksync_get_account_id(zksync_config_t* conf, in3_req_t* ctx, uint32_t* account_id) { uint8_t* account = NULL; char* cache_name = NULL; TRY(zksync_get_account(conf, ctx, &account)) @@ -156,7 +156,7 @@ in3_ret_t zksync_get_account_id(zksync_config_t* conf, in3_ctx_t* ctx, uint32_t* cache_name = alloca(60); strcpy(cache_name, "zksync_ac_"); bytes_to_hex(account, 20, cache_name + 9); - in3_cache_ctx_t cctx = {.ctx = ctx, .key = cache_name, .content = NULL}; + in3_cache_ctx_t cctx = {.req = ctx, .key = cache_name, .content = NULL}; TRY(in3_plugin_execute_first_or_none(ctx, PLGN_ACT_CACHE_GET, &cctx)) if (cctx.content) { conf->account_id = bytes_to_int(cctx.content->data, 4); @@ -165,7 +165,7 @@ in3_ret_t zksync_get_account_id(zksync_config_t* conf, in3_ctx_t* ctx, uint32_t* } if (!conf->account_id) TRY(zksync_update_account(conf, ctx)) - if (!conf->account_id) return ctx_set_error(ctx, "This user has no account yet!", IN3_EFIND); + if (!conf->account_id) return req_set_error(ctx, "This user has no account yet!", IN3_EFIND); if (account_id) *account_id = conf->account_id; // add to cache @@ -173,17 +173,17 @@ in3_ret_t zksync_get_account_id(zksync_config_t* conf, in3_ctx_t* ctx, uint32_t* uint8_t data[4]; bytes_t content = bytes(data, 4); int_to_bytes(conf->account_id, data); - in3_cache_ctx_t cctx = {.ctx = ctx, .key = cache_name, .content = &content}; + in3_cache_ctx_t cctx = {.req = ctx, .key = cache_name, .content = &content}; TRY(in3_plugin_execute_first_or_none(ctx, PLGN_ACT_CACHE_SET, &cctx)) } return IN3_OK; } -in3_ret_t zksync_get_sync_key(zksync_config_t* conf, in3_ctx_t* ctx, uint8_t* sync_key) { +in3_ret_t zksync_get_sync_key(zksync_config_t* conf, in3_req_t* ctx, uint8_t* sync_key) { if (!conf) return IN3_EUNKNOWN; if (!memiszero(conf->sync_key, 32)) { - memcpy(sync_key, conf->sync_key, 32); + if (sync_key) memcpy(sync_key, conf->sync_key, 32); return IN3_OK; } uint8_t* account = NULL; @@ -193,15 +193,15 @@ in3_ret_t zksync_get_sync_key(zksync_config_t* conf, in3_ctx_t* ctx, uint8_t* sy "Access zkSync account.\n\nOnly sign this message for a trusted client!"; TRY(zksync_get_account(conf, ctx, &account)) assert(account); - TRY(ctx_require_signature(ctx, SIGN_EC_HASH, &signature, bytes((uint8_t*) message, strlen(message)), bytes(account, 20))) + TRY(req_require_signature(ctx, SIGN_EC_HASH, &signature, bytes((uint8_t*) message, strlen(message)), bytes(account, 20))) if (signature.len == 65 && signature.data[64] < 2) signature.data[64] += 27; zkcrypto_pk_from_seed(signature, conf->sync_key); - memcpy(sync_key, conf->sync_key, 32); + if (sync_key) memcpy(sync_key, conf->sync_key, 32); return IN3_OK; } -in3_ret_t zksync_get_pubkey_hash(zksync_config_t* conf, in3_ctx_t* ctx, uint8_t* pubkey_hash) { +in3_ret_t zksync_get_pubkey_hash(zksync_config_t* conf, in3_req_t* ctx, uint8_t* pubkey_hash) { if (!conf) return IN3_EUNKNOWN; if (!memiszero(conf->pub_key_hash_pk, 20) && !conf->musig_pub_keys.data) { memcpy(pubkey_hash, conf->pub_key_hash_pk, 20); @@ -227,7 +227,7 @@ in3_ret_t zksync_get_pubkey_hash(zksync_config_t* conf, in3_ctx_t* ctx, uint8_t* return IN3_OK; } -in3_ret_t zksync_get_contracts(zksync_config_t* conf, in3_ctx_t* ctx, uint8_t** main) { +in3_ret_t zksync_get_contracts(zksync_config_t* conf, in3_req_t* ctx, uint8_t** main) { char* cache_name = NULL; if (!conf->main_contract) { @@ -236,7 +236,7 @@ in3_ret_t zksync_get_contracts(zksync_config_t* conf, in3_ctx_t* ctx, uint8_t** TRY(ensure_provider(conf, ctx)) cache_name = alloca(100); sprintf(cache_name, "zksync_contracts_%x", key(conf->provider_url)); - in3_cache_ctx_t cctx = {.ctx = ctx, .key = cache_name, .content = NULL}; + in3_cache_ctx_t cctx = {.req = ctx, .key = cache_name, .content = NULL}; TRY(in3_plugin_execute_first_or_none(ctx, PLGN_ACT_CACHE_GET, &cctx)) if (cctx.content) { conf->main_contract = _malloc(20); @@ -251,12 +251,12 @@ in3_ret_t zksync_get_contracts(zksync_config_t* conf, in3_ctx_t* ctx, uint8_t** if (!conf->main_contract) { d_token_t* result; TRY(send_provider_request(ctx, conf, "contract_address", "", &result)) - bytes_t* main_contract = d_get_bytesk(result, key("mainContract")); - if (!main_contract || main_contract->len != 20) return ctx_set_error(ctx, "could not get the main_contract from provider", IN3_ERPC); + bytes_t* main_contract = d_get_bytes(result, key("mainContract")); + if (!main_contract || main_contract->len != 20) return req_set_error(ctx, "could not get the main_contract from provider", IN3_ERPC); memcpy(conf->main_contract = _malloc(20), main_contract->data, 20); - bytes_t* gov_contract = d_get_bytesk(result, key("govContract")); - if (!gov_contract || gov_contract->len != 20) return ctx_set_error(ctx, "could not get the gov_contract from provider", IN3_ERPC); + bytes_t* gov_contract = d_get_bytes(result, key("govContract")); + if (!gov_contract || gov_contract->len != 20) return req_set_error(ctx, "could not get the gov_contract from provider", IN3_ERPC); memcpy(conf->gov_contract = _malloc(20), gov_contract->data, 20); if (cache_name) { @@ -264,19 +264,19 @@ in3_ret_t zksync_get_contracts(zksync_config_t* conf, in3_ctx_t* ctx, uint8_t** bytes_t content = bytes(data, 40); memcpy(data, main_contract->data, 20); memcpy(data + 20, gov_contract->data, 20); - in3_cache_ctx_t cctx = {.ctx = ctx, .key = cache_name, .content = &content}; + in3_cache_ctx_t cctx = {.req = ctx, .key = cache_name, .content = &content}; TRY(in3_plugin_execute_first_or_none(ctx, PLGN_ACT_CACHE_SET, &cctx)) } // clean up - ctx_remove_required(ctx, ctx_find_required(ctx, "contract_address"), false); + req_remove_required(ctx, req_find_required(ctx, "contract_address"), false); } if (main) *main = conf->main_contract; return IN3_OK; } -in3_ret_t zksync_get_nonce(zksync_config_t* conf, in3_ctx_t* ctx, d_token_t* nonce_in, uint32_t* nonce) { +in3_ret_t zksync_get_nonce(zksync_config_t* conf, in3_req_t* ctx, d_token_t* nonce_in, uint32_t* nonce) { if (nonce_in && (d_type(nonce_in) == T_INTEGER || d_type(nonce_in) == T_BYTES)) { *nonce = d_long(nonce_in); return IN3_OK; @@ -286,7 +286,7 @@ in3_ret_t zksync_get_nonce(zksync_config_t* conf, in3_ctx_t* ctx, d_token_t* non return IN3_OK; } -in3_ret_t zksync_get_fee(zksync_config_t* conf, in3_ctx_t* ctx, d_token_t* fee_in, bytes_t to, d_token_t* token, char* type, zk_fee_p_t* fee) { +in3_ret_t zksync_get_fee(zksync_config_t* conf, in3_req_t* ctx, d_token_t* fee_in, bytes_t to, d_token_t* token, char* type, zk_fee_p_t* fee) { if (fee_in && (d_type(fee_in) == T_INTEGER || d_type(fee_in) == T_BYTES)) { #ifdef ZKSYNC_256 bytes_t b = d_to_bytes(fee_in); @@ -315,19 +315,19 @@ in3_ret_t zksync_get_fee(zksync_config_t* conf, in3_ctx_t* ctx, d_token_t* fee_i break; } default: - return ctx_set_error(ctx, "invalid token-value", IN3_EINVAL); + return req_set_error(ctx, "invalid token-value", IN3_EINVAL); } TRY(send_provider_request(ctx, conf, "get_tx_fee", sb.data, &result)) #ifdef ZKSYNC_256 memset(fee, 0, 32); - long_to_bytes(d_get_longk(result, key("totalFee")), fee + 24); + long_to_bytes(d_get_long(result, key("totalFee")), fee + 24); #else - *fee = d_get_longk(result, key("totalFee")); + *fee = d_get_long(result, key("totalFee")); #endif return IN3_OK; } -in3_ret_t resolve_tokens(zksync_config_t* conf, in3_ctx_t* ctx, d_token_t* token_src, zksync_token_t** token_dst) { +in3_ret_t resolve_tokens(zksync_config_t* conf, in3_req_t* ctx, d_token_t* token_src, zksync_token_t** token_dst) { char* cache_name = NULL; if (!conf->token_len) { // check cache first @@ -335,7 +335,7 @@ in3_ret_t resolve_tokens(zksync_config_t* conf, in3_ctx_t* ctx, d_token_t* token TRY(ensure_provider(conf, ctx)) cache_name = alloca(100); sprintf(cache_name, "zksync_tokens_%x", key(conf->provider_url)); - in3_cache_ctx_t cctx = {.ctx = ctx, .key = cache_name, .content = NULL}; + in3_cache_ctx_t cctx = {.req = ctx, .key = cache_name, .content = NULL}; TRY(in3_plugin_execute_first_or_none(ctx, PLGN_ACT_CACHE_GET, &cctx)) if (cctx.content) { conf->token_len = cctx.content->len / sizeof(zksync_token_t); @@ -353,22 +353,22 @@ in3_ret_t resolve_tokens(zksync_config_t* conf, in3_ctx_t* ctx, d_token_t* token conf->tokens = _calloc(conf->token_len, sizeof(zksync_token_t)); int i = 0; for (d_iterator_t it = d_iter(result); it.left; d_iter_next(&it), i++) { - conf->tokens[i].id = d_get_intk(it.token, K_ID); - conf->tokens[i].decimals = d_get_intk(it.token, key("decimals")); - char* name = d_get_stringk(it.token, key("symbol")); - if (!name || strlen(name) > 7) return ctx_set_error(ctx, "invalid token name", IN3_EINVAL); + conf->tokens[i].id = d_get_int(it.token, K_ID); + conf->tokens[i].decimals = d_get_int(it.token, key("decimals")); + char* name = d_get_string(it.token, key("symbol")); + if (!name || strlen(name) > 7) return req_set_error(ctx, "invalid token name", IN3_EINVAL); strcpy(conf->tokens[i].symbol, name); - bytes_t* adr = d_get_bytesk(it.token, K_ADDRESS); - if (!adr || !adr->data || adr->len != 20) return ctx_set_error(ctx, "invalid token addr", IN3_EINVAL); + bytes_t* adr = d_get_bytes(it.token, K_ADDRESS); + if (!adr || !adr->data || adr->len != 20) return req_set_error(ctx, "invalid token addr", IN3_EINVAL); memcpy(conf->tokens[i].address, adr->data, 20); } // clean up - ctx_remove_required(ctx, ctx_find_required(ctx, "tokens"), false); + req_remove_required(ctx, req_find_required(ctx, "tokens"), false); if (cache_name) { bytes_t data = bytes((void*) conf->tokens, conf->token_len * sizeof(zksync_token_t)); - in3_cache_ctx_t cctx = {.ctx = ctx, .key = cache_name, .content = &data}; + in3_cache_ctx_t cctx = {.req = ctx, .key = cache_name, .content = &data}; TRY(in3_plugin_execute_first_or_none(ctx, PLGN_ACT_CACHE_SET, &cctx)) } } @@ -388,5 +388,5 @@ in3_ret_t resolve_tokens(zksync_config_t* conf, in3_ctx_t* ctx, d_token_t* token } } - return ctx_set_error(ctx, "could not find the specifed token", IN3_EFIND); + return req_set_error(ctx, "could not find the specifed token", IN3_EFIND); } diff --git a/c/src/pay/zksync/zk_helper.h b/c/src/pay/zksync/zk_helper.h index 17e9ad6b0..8af5e54b7 100644 --- a/c/src/pay/zksync/zk_helper.h +++ b/c/src/pay/zksync/zk_helper.h @@ -37,26 +37,26 @@ #include "zksync.h" -in3_ret_t zksync_get_fee(zksync_config_t* conf, in3_ctx_t* ctx, d_token_t* fee_in, bytes_t to, d_token_t* token, char* type, zk_fee_p_t* fee); /**< resolves the fees */ +in3_ret_t zksync_get_fee(zksync_config_t* conf, in3_req_t* req, d_token_t* fee_in, bytes_t to, d_token_t* token, char* type, zk_fee_p_t* fee); /**< resolves the fees */ void set_quoted_address(char* c, uint8_t* address); /**< writes the address as hex into the string.*/ d_token_t* params_get(d_token_t* params, d_key_t k, uint32_t index); /**< returns the token either by index or key depending on the token-type */ -in3_ret_t send_provider_request(in3_ctx_t* parent, zksync_config_t* conf, char* method, char* params, d_token_t** result); /**< send a request to the zksync-server*/ -in3_ret_t zksync_get_account(zksync_config_t* conf, in3_ctx_t* ctx, uint8_t** account); /**< resolves the account */ -in3_ret_t zksync_update_account(zksync_config_t* conf, in3_ctx_t* ctx); /**< updates the account data from the server to the config*/ -in3_ret_t zksync_get_account_id(zksync_config_t* conf, in3_ctx_t* ctx, uint32_t* account_id); /**< resolves the account_id*/ -in3_ret_t zksync_get_sync_key(zksync_config_t* conf, in3_ctx_t* ctx, uint8_t* sync_key); /**< resolves the sync key*/ -in3_ret_t zksync_get_contracts(zksync_config_t* conf, in3_ctx_t* ctx, uint8_t** main); /**< resolves the main contract */ -in3_ret_t zksync_get_nonce(zksync_config_t* conf, in3_ctx_t* ctx, d_token_t* nonce_in, uint32_t* nonce); /**< resolves the nonce */ -in3_ret_t resolve_tokens(zksync_config_t* conf, in3_ctx_t* ctx, d_token_t* token_src, zksync_token_t** token_dst); /**< resolve token list */ -in3_ret_t zksync_get_pubkey_hash(zksync_config_t* conf, in3_ctx_t* ctx, uint8_t* pubkey_hash); /**< get pubkeyhash */ - +in3_ret_t send_provider_request(in3_req_t* parent, zksync_config_t* conf, char* method, char* params, d_token_t** result); /**< send a request to the zksync-server*/ +in3_ret_t zksync_get_account(zksync_config_t* conf, in3_req_t* req, uint8_t** account); /**< resolves the account */ +in3_ret_t zksync_update_account(zksync_config_t* conf, in3_req_t* req); /**< updates the account data from the server to the config*/ +in3_ret_t zksync_get_account_id(zksync_config_t* conf, in3_req_t* req, uint32_t* account_id); /**< resolves the account_id*/ +in3_ret_t zksync_get_sync_key(zksync_config_t* conf, in3_req_t* req, uint8_t* sync_key); /**< resolves the sync key*/ +in3_ret_t zksync_get_contracts(zksync_config_t* conf, in3_req_t* req, uint8_t** main); /**< resolves the main contract */ +in3_ret_t zksync_get_nonce(zksync_config_t* conf, in3_req_t* req, d_token_t* nonce_in, uint32_t* nonce); /**< resolves the nonce */ +in3_ret_t resolve_tokens(zksync_config_t* conf, in3_req_t* req, d_token_t* token_src, zksync_token_t** token_dst); /**< resolve token list */ +in3_ret_t zksync_get_pubkey_hash(zksync_config_t* conf, in3_req_t* req, uint8_t* pubkey_hash); /**< get pubkeyhash */ +void zksync_calculate_account(address_t creator, bytes32_t codehash, bytes32_t saltarg, address_t pub_key_hash, address_t dst); #define CHECK_PARAM_TOKEN(ctx, params, index) \ switch (d_type(d_get_at(params, index))) { \ case T_STRING: break; \ case T_BYTES: \ - if (d_len(d_get_at(params, index)) != 20) return ctx_set_error(ctx, "argument at index " #index " must be a 20 byte address", IN3_EINVAL); \ + if (d_len(d_get_at(params, index)) != 20) return req_set_error(ctx, "argument at index " #index " must be a 20 byte address", IN3_EINVAL); \ break; \ - default: return ctx_set_error(ctx, "argument at index " #index " must be a token name or an address", IN3_EINVAL); \ + default: return req_set_error(ctx, "argument at index " #index " must be a token name or an address", IN3_EINVAL); \ } #endif \ No newline at end of file diff --git a/c/src/pay/zksync/zk_incentive.c b/c/src/pay/zksync/zk_incentive.c new file mode 100644 index 000000000..7a232aab3 --- /dev/null +++ b/c/src/pay/zksync/zk_incentive.c @@ -0,0 +1,282 @@ +/******************************************************************************* + * This file is part of the Incubed project. + * Sources: https://github.com/blockchainsllc/in3 + * + * Copyright (C) 2018-2019 slock.it GmbH, Blockchains LLC + * + * + * COMMERCIAL LICENSE USAGE + * + * Licensees holding a valid commercial license may use this file in accordance + * with the commercial license agreement provided with the Software or, alternatively, + * in accordance with the terms contained in a written agreement between you and + * slock.it GmbH/Blockchains LLC. For licensing terms and conditions or further + * information please contact slock.it at in3@slock.it. + * + * Alternatively, this file may be used under the AGPL license as follows: + * + * AGPL LICENSE USAGE + * + * This program is free software: you can redistribute it and/or modify it under the + * terms of the GNU Affero General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. + * [Permissions of this strong copyleft license are conditioned on making available + * complete source code of licensed works and modifications, which include larger + * works using a licensed work, under the same license. Copyright and license notices + * must be preserved. Contributors provide an express grant of patent rights.] + * You should have received a copy of the GNU Affero General Public License along + * with this program. If not, see . + *******************************************************************************/ +#include "../../core/client/keys.h" +#include "../../core/client/request_internal.h" +#include "../../core/util/debug.h" +#include "../../third-party/crypto/ecdsa.h" +#include "../../third-party/crypto/secp256k1.h" +#include "../../third-party/zkcrypto/lib.h" +#include "zk_helper.h" +#include "zksync.h" +#include +#include +#include +#include + +#define ERROR_PAYMENT_REQUIRED -33005 + +static char* get_payment_data(in3_req_t* ctx) { + for (cache_entry_t* ce = ctx->cache; ce; ce = ce->next) { + if (ce->props & CACHE_PROP_PAYMENT) return (char*) (void*) ce->value.data; + } + return NULL; +} + +in3_ret_t zksync_add_payload(in3_pay_payload_ctx_t* ctx) { + // we only use this, if we also have a request signer + if (ctx->req->client->plugin_acts & PLGN_ACT_PAY_SIGN_REQ) { + sb_add_chars(ctx->sb, ",\"payType\":\"zksync\""); + char* payment_data = get_payment_data(ctx->req); + if (payment_data) + sb_add_chars(ctx->sb, payment_data); + } + return IN3_OK; +} + +static in3_ret_t ensure_payment_data(in3_req_t* req, zksync_config_t* conf) { + // do we have a sync_key and account already? + if (!memiszero(conf->sync_key, 32)) return IN3_OK; + uint8_t pub[65]; + bytes_t pubkey_bytes = {.len = 64, .data = ((uint8_t*) &pub) + 1}; + char* message = "\x19" + "Ethereum Signed Message:\n68" + "Access zkSync account.\n\nOnly sign this message for a trusted client!"; + + in3_pay_sign_req_ctx_t sctx = {.req = req, .request = NULL, .signature = {0}}; + bytes_t sig_bytes = bytes(sctx.signature, 65); + keccak(bytes((void*) message, strlen(message)), sctx.request_hash); + TRY(in3_plugin_execute_first(req, PLGN_ACT_PAY_SIGN_REQ, &sctx)) + if (sig_bytes.len == 65 && sig_bytes.data[64] < 2) sig_bytes.data[64] += 27; + + // copy sync_key based on signature as seed + zkcrypto_pk_from_seed(sig_bytes, conf->sync_key); + + // determine address + if (ecdsa_recover_pub_from_sig(&secp256k1, pub, sig_bytes.data, sctx.request_hash, sig_bytes.data[64] >= 27 ? sig_bytes.data[64] - 27 : sig_bytes.data[64])) + return req_set_error(req, "Invalid Signature", IN3_EINVAL); + keccak(pubkey_bytes, sctx.request_hash); + if (conf->account) _free(conf->account); + conf->account = _malloc(20); + memcpy(conf->account, sctx.request_hash + 12, 20); + return IN3_OK; +} + +static in3_ret_t set_amount(zk_fee_t* dst, in3_req_t* ctx, d_token_t* t) { + if (!t) return req_set_error(ctx, "No value set", IN3_EINVAL); +#ifdef ZKSYNC_256 + bytes_t tmp = d_to_bytes(t); + memset(*dst, 0, 32); + memcpy(*dst + 32 - tmp.len, tmp.data, tmp.len); +#else + *dst = d_long(t); +#endif + return IN3_OK; +} + +static in3_ret_t get_payed_addresses(in3_req_t* ctx, bytes_t* dst) { + in3_cache_ctx_t c = {.content = NULL, .req = ctx, .key = alloca(20)}; + sprintf(c.key, "payed_%d", (uint32_t) ctx->client->chain.chain_id); + TRY(in3_plugin_execute_first_or_none(ctx, PLGN_ACT_CACHE_GET, &c)) + if (c.content) { + *dst = *c.content; + _free(c.content); + } + return IN3_OK; +} + +static in3_ret_t update_payed_addresses(in3_req_t* ctx, unsigned int nodes, bytes_t payed, bool update_cache) { + if (update_cache) { + in3_cache_ctx_t c = {.content = &payed, .req = ctx, .key = alloca(20)}; + sprintf(c.key, "payed_%d", (uint32_t) ctx->client->chain.chain_id); + TRY(in3_plugin_execute_first_or_none(ctx, PLGN_ACT_CACHE_SET, &c)) + } + + sb_t sb = {0}; + if (nodes > payed.len / 20) + sb_add_chars(&sb, "{\"preselect_nodes\":null}"); + else { + sb_add_rawbytes(&sb, "{\"preselect_nodes\":\"0x", payed, 0); + sb_add_chars(&sb, "\"}"); + } + in3_configure_ctx_t cctx = {.client = ctx->client, .json = parse_json(sb.data), .token = NULL, .error_msg = NULL}; + cctx.token = cctx.json->result + 1; + in3_ret_t ret = in3_plugin_execute_first_or_none(ctx, PLGN_ACT_CONFIG_SET, &cctx); + if (ret && ret != IN3_EIGNORE) req_set_error(ctx, cctx.error_msg ? cctx.error_msg : "Could not update the preselect nodelist", ret); + if (cctx.error_msg) _free(cctx.error_msg); + json_free(cctx.json); + _free(sb.data); + return ret; +} + +static in3_ret_t find_acceptable_offer(in3_req_t* ctx, pay_criteria_t* criteria, d_token_t* offer, d_token_t** dst_offer, d_token_t** dst_price) { + + d_token_t* price_list = d_get(offer, key("priceList")); + if (!price_list || d_type(price_list) != T_ARRAY || d_len(price_list) < 0) return req_set_error(ctx, "no pricelist in the offer", IN3_ERPC); + + // find a acceptable offer + d_token_t* price = NULL; + d_token_t* selected_offer = NULL; + for (d_iterator_t offer_iter = d_iter(price_list); offer_iter.left; d_iter_next(&offer_iter)) { + price = NULL; + for (d_iterator_t p_iter = d_iter(d_get(offer_iter.token, key("price"))); p_iter.left; d_iter_next(&p_iter)) { + char* token = d_get_string(p_iter.token, key("token")); + if (token && strcmp(token, criteria->token ? criteria->token : "ETH") == 0) { + price = p_iter.token; + break; + } + } + + if (price) { + uint64_t amount = d_get_long(offer_iter.token, key("amount")); + uint64_t price_amount = d_get_long(price, key("amount")); + if (!amount) return req_set_error(ctx, "no amount defined in offer from node", IN3_ERPC); + if (!price_amount) return req_set_error(ctx, "no price defined in offer from node", IN3_ERPC); + if (!criteria->max_price_per_hundred_igas || ((price_amount * 100) / amount) <= criteria->max_price_per_hundred_igas) { + selected_offer = offer_iter.token; + break; + } + } + } + + if (!selected_offer) return req_set_error(ctx, "no accetable offer found in node response", IN3_ERPC); + + *dst_offer = selected_offer; + *dst_price = price; + return IN3_OK; +} + +static in3_ret_t add_to_payed_nodelist(in3_req_t* ctx, address_t address, unsigned int nodelen) { + bytes_t payed_addresses = bytes(NULL, 0); + TRY(get_payed_addresses(ctx, &payed_addresses)) + uint8_t* addresses = alloca(payed_addresses.len + 20); + if (payed_addresses.data) { + memcpy(addresses, payed_addresses.data, payed_addresses.len); + _free(payed_addresses.data); + } + + for (unsigned int i = 0; i < payed_addresses.len; i += 20) { + if (memcmp(address, addresses + i, 20) == 0) return IN3_OK; + } + + if (payed_addresses.len) { + memcpy(addresses + payed_addresses.len, address, 20); + TRY(update_payed_addresses(ctx, nodelen, bytes(addresses, payed_addresses.len + 20), true)) + } + else + TRY(update_payed_addresses(ctx, nodelen, bytes(address, 20), true)) + + return IN3_OK; +} + +in3_ret_t update_nodelist_from_cache(in3_req_t* ctx, unsigned int nodelen) { + bytes_t payed_addresses = bytes(NULL, 0); + TRY(get_payed_addresses(ctx, &payed_addresses)) + + if (payed_addresses.len) + TRY(update_payed_addresses(ctx, nodelen, payed_addresses, false)) + + return IN3_OK; +} + +in3_ret_t zksync_check_payment(zksync_config_t* conf, in3_pay_followup_ctx_t* ctx) { + if (!ctx->resp_error || d_type(ctx->resp_error) != T_OBJECT || d_get_int(ctx->resp_error, K_CODE) != ERROR_PAYMENT_REQUIRED || get_payment_data(ctx->req)) return IN3_OK; + + // the server wants payment + d_token_t* offer = d_get(ctx->resp_error, key("offer")); + if (!offer) return req_set_error(ctx->req, "A payment rejection without an offer", IN3_ERPC); + + // TODO right now we always accept any offer within the range if it matches the config + pay_criteria_t* criteria = conf->incentive; + if (!criteria) return req_set_error(ctx->req, "No Payment configuration set in zksync.incentive", IN3_ECONFIG); + + d_token_t* price = NULL; + d_token_t* selected_offer = NULL; + TRY(find_acceptable_offer(ctx->req, criteria, offer, &selected_offer, &price)) + TRY(ensure_payment_data(ctx->req, &criteria->config)) + + // now prepare the payment + criteria->config.account_id = d_get_long(offer, key("accountId")); + criteria->config.nonce = d_get_long(offer, key("nonce")); + criteria->config.sign_type = ZK_SIGN_PK; + + // prepare the token-struct + zksync_token_t _token = { + .id = d_get_int(price, K_ID), + .decimals = d_get_int(price, key("decimals"))}; + strncpy(_token.symbol, d_get_string(price, key("token")), 6); + bytes_t tmp = d_to_bytes(d_get(price, K_ADDRESS)); + if (tmp.len == 20) + memcpy(_token.address, tmp.data, 20); + else + memset(_token.address, 0, 20); + + // create tx + zksync_tx_data_t tx = { + .account_id = criteria->config.account_id, + .conf = &criteria->config, + .nonce = (uint32_t) criteria->config.nonce, + .token = &_token, + .type = ZK_TRANSFER}; + TRY(set_amount(&tx.amount, ctx->req, d_get(price, key("amount")))) + TRY(set_amount(&tx.fee, ctx->req, d_get(price, key("fee")))) + tmp = d_to_bytes(d_get(selected_offer, K_ADDRESS)); + if (tmp.len != 20) return req_set_error(ctx->req, "invalid address in offer", IN3_ERPC); + memcpy(tx.to, tmp.data, 20); + memcpy(tx.from, criteria->config.account, 20); + + // prepare the payTx + sb_t sb = {0}; + sb_add_chars(&sb, ",\"payTx\":{\"offer_id\":"); + sb_add_int(&sb, d_get_int(selected_offer, K_ID)); + sb_add_chars(&sb, ",\"method\":\"tx_submit\",\"params\":["); + + // sign tx + in3_ret_t ret = zksync_sign_transfer(&sb, &tx, ctx->req, &criteria->config); + if (ret) { + _free(sb.data); + return ret; + } + sb_add_chars(&sb, "]}"); + + // add data as cache, so we can add it when we create the next payload. + in3_cache_add_entry(&ctx->req->cache, bytes(NULL, 0), bytes((void*) sb.data, strlen(sb.data)))->props = CACHE_PROP_MUST_FREE | CACHE_PROP_PAYMENT; + + // now we make sure we try again. + TRY(in3_retry_same_node(ctx->req)) + + TRY(add_to_payed_nodelist(ctx->req, ctx->node->address, criteria->payed_nodes)) + + // we use IN3_WAITING, which causes it to cancel verification and try again. + return IN3_WAITING; +} diff --git a/c/src/pay/zksync/zk_message.c b/c/src/pay/zksync/zk_message.c index 0255d378a..a370d425c 100644 --- a/c/src/pay/zksync/zk_message.c +++ b/c/src/pay/zksync/zk_message.c @@ -1,4 +1,4 @@ -#include "../../core/client/context_internal.h" +#include "../../core/client/request_internal.h" #include "../../core/util/log.h" #include "../../third-party/crypto/bignum.h" #include "../../third-party/zkcrypto/lib.h" @@ -70,7 +70,7 @@ static int bitlen(uint64_t val) { const char* MAX_MANTISSA_35 = "34359738368"; const char* MAX_MANTISSA_11 = "2048"; -static in3_ret_t pack(char* dec, int mantissa_len, int exp_len, uint8_t* dst, in3_ctx_t* ctx) { +static in3_ret_t pack(char* dec, int mantissa_len, int exp_len, uint8_t* dst, in3_req_t* ctx) { while (*dec == '0') dec++; // remove leading zeros (if any) int l = strlen(dec); // trimmed size int total = (exp_len + mantissa_len) / 8; // the target size in bytes @@ -88,18 +88,18 @@ static in3_ret_t pack(char* dec, int mantissa_len, int exp_len, uint8_t* dst, in } if (dec[i] != '0') - return ctx_set_error(ctx, "The value (mantissa) can not be packed", IN3_EINVAL); // its an error + return req_set_error(ctx, "The value (mantissa) can not be packed", IN3_EINVAL); // its an error } dec[cl] = 0; // terminate the string after the value cutting off all zeros uint64_t c = strtoull(dec, NULL, 10); // and convert this value if (c == ULLONG_MAX || bitlen(c) > mantissa_len) // if the value can be represented with the max bits - return ctx_set_error(ctx, "The value (mantissa) can not be packed", IN3_EINVAL); // its an error + return req_set_error(ctx, "The value (mantissa) can not be packed", IN3_EINVAL); // its an error long_to_bytes(c, tmp); // we copy the value to bytes shift_left(tmp, 64 - mantissa_len); // and shift it so the bits are on the start and memcpy(dst, tmp, total); // copy the bytes to the dest long_to_bytes(l - cl, tmp); // now we do the same wit the exp which are the number of zeros counted (l-cl) if (bitlen(l - cl) > exp_len) // if the exp does not fit in the expected bytes - return ctx_set_error(ctx, "The value (exp) can not be packed", IN3_EINVAL); // its an error + return req_set_error(ctx, "The value (exp) can not be packed", IN3_EINVAL); // its an error shift_left(tmp, 64 - exp_len - mantissa_len); // now we shift it to the position after the mantissa for (int i = 0; i < total; i++) dst[i] |= tmp[i]; // and copy them to the destination using or since we already have bytes there return IN3_OK; @@ -138,7 +138,7 @@ static void create_signed_bytes(sb_t* sb) { memcpy(sb->data + l - strlen(len_num), len_num, strlen(len_num)); } -static in3_ret_t sign_sync_transfer(zksync_tx_data_t* data, in3_ctx_t* ctx, zksync_config_t* conf, uint8_t* raw, uint8_t* sig) { +static in3_ret_t sign_sync_transfer(zksync_tx_data_t* data, in3_req_t* ctx, zksync_config_t* conf, uint8_t* raw, uint8_t* sig) { uint32_t total; char dec[80]; uint16_t tid = data->token ? data->token->id : 0; @@ -173,7 +173,7 @@ static in3_ret_t sign_sync_transfer(zksync_tx_data_t* data, in3_ctx_t* ctx, zksy return zksync_sign(conf, bytes(raw, total), ctx, sig); } -in3_ret_t zksync_sign_transfer(sb_t* sb, zksync_tx_data_t* data, in3_ctx_t* ctx, zksync_config_t* conf) { +in3_ret_t zksync_sign_transfer(sb_t* sb, zksync_tx_data_t* data, in3_req_t* ctx, zksync_config_t* conf) { char msg_data[200]; bytes_t signature; sb_t msg = sb_stack(msg_data); @@ -184,7 +184,7 @@ in3_ret_t zksync_sign_transfer(sb_t* sb, zksync_tx_data_t* data, in3_ctx_t* ctx, memset(signature.data, 0, 65); } else - TRY(ctx_require_signature(ctx, SIGN_EC_HASH, &signature, bytes((uint8_t*) msg_data, msg.len), bytes(data->from, 20))) + TRY(req_require_signature(ctx, SIGN_EC_HASH, &signature, bytes((uint8_t*) msg_data, msg.len), bytes(data->from, 20))) in3_log_debug("zksync_sign_transfer human readable :\n%s\n", msg_data); if (signature.len == 65 && signature.data[64] < 27) @@ -234,8 +234,8 @@ in3_ret_t zksync_sign_transfer(sb_t* sb, zksync_tx_data_t* data, in3_ctx_t* ctx, return IN3_OK; } -in3_ret_t zksync_sign(zksync_config_t* conf, bytes_t msg, in3_ctx_t* ctx, uint8_t* sig) { - if (memiszero(conf->sync_key, 32)) return ctx_set_error(ctx, "no signing key set", IN3_ECONFIG); +in3_ret_t zksync_sign(zksync_config_t* conf, bytes_t msg, in3_req_t* ctx, uint8_t* sig) { + if (memiszero(conf->sync_key, 32)) return req_set_error(ctx, "no signing key set", IN3_ECONFIG); if (!conf->musig_pub_keys.data) return zkcrypto_sign_musig(conf->sync_key, msg, sig); char* p = alloca(msg.len * 2 + 5); p[0] = '"'; @@ -245,13 +245,13 @@ in3_ret_t zksync_sign(zksync_config_t* conf, bytes_t msg, in3_ctx_t* ctx, uint8_ p[msg.len * 2 + 3] = '"'; p[msg.len * 2 + 4] = 0; d_token_t* result; - TRY(ctx_send_sub_request(ctx, "zk_sign", p, NULL, &result)) - if (d_type(result) != T_BYTES || d_len(result) != 96) return ctx_set_error(ctx, "invalid signature returned", IN3_ECONFIG); + TRY(req_send_sub_request(ctx, "zk_sign", p, NULL, &result)) + if (d_type(result) != T_BYTES || d_len(result) != 96) return req_set_error(ctx, "invalid signature returned", IN3_ECONFIG); memcpy(sig, result->data, 96); return IN3_OK; } -in3_ret_t zksync_sign_change_pub_key(sb_t* sb, in3_ctx_t* ctx, uint8_t* sync_pub_key, uint32_t nonce, zksync_config_t* conf, zk_fee_t fee, zksync_token_t* token) { +in3_ret_t zksync_sign_change_pub_key(sb_t* sb, in3_req_t* ctx, uint8_t* sync_pub_key, uint32_t nonce, zksync_config_t* conf, zk_fee_t fee, zksync_token_t* token) { // create sign_msg for the rollup char dec[80]; @@ -283,7 +283,7 @@ in3_ret_t zksync_sign_change_pub_key(sb_t* sb, in3_ctx_t* ctx, uint8_t* sync_pub create_signed_bytes(&msg); if (conf->sign_type != ZK_SIGN_CONTRACT) - TRY(ctx_require_signature(ctx, SIGN_EC_HASH, &signature, bytes((uint8_t*) msg_data, msg.len), bytes(conf->account, 20))) + TRY(req_require_signature(ctx, SIGN_EC_HASH, &signature, bytes((uint8_t*) msg_data, msg.len), bytes(conf->account, 20))) if (signature.len == 65 && signature.data[64] < 27) signature.data[64] += 27; //because EIP155 chainID = 0 diff --git a/c/src/pay/zksync/zk_musig.c b/c/src/pay/zksync/zk_musig.c index 784527a10..e24ead148 100644 --- a/c/src/pay/zksync/zk_musig.c +++ b/c/src/pay/zksync/zk_musig.c @@ -1,5 +1,6 @@ -#include "../../core/client/context_internal.h" +#include "../../core/client/keys.h" #include "../../core/client/plugin.h" +#include "../../core/client/request_internal.h" #include "../../core/util/debug.h" #include "../../core/util/log.h" #include "../../third-party/crypto/bignum.h" @@ -9,6 +10,7 @@ #include #include /* strtoull */ #include /* strtoull */ +#define MAX_SESSIONS 20 #define TRY_SIGNER(x) TRY_FINAL(x, zkcrypto_signer_free(signer)) #define TRY_SIG(exp) \ @@ -22,10 +24,10 @@ return _r; \ } \ } - -static int get_pubkey_pos(zksync_config_t* conf, bytes_t pub_keys, in3_ctx_t* ctx) { - if (!pub_keys.data) return ctx_set_error(ctx, "missing public keys in config", IN3_EINVAL); - if (memiszero(conf->sync_key, 32)) return ctx_set_error(ctx, "missing signing keys in config", IN3_EINVAL); +void cleanup_session(zk_musig_session_t* s, zksync_config_t* conf); +static int get_pubkey_pos(zksync_config_t* conf, bytes_t pub_keys, in3_req_t* ctx) { + if (!pub_keys.data) return req_set_error(ctx, "missing public keys in config", IN3_EINVAL); + if (memiszero(conf->sync_key, 32)) return req_set_error(ctx, "missing signing keys in config", IN3_EINVAL); if (memiszero(conf->pub_key, 32)) { TRY(zkcrypto_pk_to_pubkey(conf->sync_key, conf->pub_key)); } @@ -35,32 +37,32 @@ static int get_pubkey_pos(zksync_config_t* conf, bytes_t pub_keys, in3_ctx_t* ct return -1; } -static in3_ret_t send_sign_request(in3_ctx_t* parent, int pos, zksync_config_t* conf, char* method, char* params, d_token_t** result) { +static in3_ret_t send_sign_request(in3_req_t* parent, int pos, zksync_config_t* conf, char* method, char* params, d_token_t** result) { if (params == NULL) params = ""; char* url = conf->musig_urls ? conf->musig_urls[pos] : NULL; - if (!url) return ctx_set_error(parent, "missing url to fetch a signature", IN3_EINVAL); + if (!url) return req_set_error(parent, "missing url to fetch a signature", IN3_EINVAL); char* in3 = alloca(strlen(url) + 26); sprintf(in3, "{\"rpc\":\"%s\"}", url); - return ctx_send_sub_request(parent, method, params, in3, result); + return req_send_sub_request(parent, method, params, in3, result); } -static in3_ret_t update_session(zk_musig_session_t* s, in3_ctx_t* ctx, d_token_t* data) { - if (!data || d_type(data) != T_OBJECT) return ctx_set_error(ctx, "invalid response from signer handler", IN3_EINVAL); +static in3_ret_t update_session(zk_musig_session_t* s, in3_req_t* ctx, d_token_t* data) { + if (!data || d_type(data) != T_OBJECT) return req_set_error(ctx, "invalid response from signer handler", IN3_EINVAL); bytes_t d = d_to_bytes(d_get(data, key("pre_commitment"))); - if (!d.data || d.len != s->len * 32) return ctx_set_error(ctx, "invalid precommitment from signer handler", IN3_EINVAL); + if (!d.data || d.len != s->len * 32) return req_set_error(ctx, "invalid precommitment from signer handler", IN3_EINVAL); for (unsigned int i = 0; i < s->len; i++) { if (i != s->pos && memiszero(s->precommitments.data + i * 32, 32) && !memiszero(d.data + i * 32, 32)) memcpy(s->precommitments.data + i * 32, d.data + i * 32, 32); } d = d_to_bytes(d_get(data, key("commitment"))); if (d.data) { - if (d.len != s->len * 32) return ctx_set_error(ctx, "invalid commitment from signer handler", IN3_EINVAL); + if (d.len != s->len * 32) return req_set_error(ctx, "invalid commitment from signer handler", IN3_EINVAL); for (unsigned int i = 0; i < s->len; i++) { if (i != s->pos && memiszero(s->commitments.data + i * 32, 32) && !memiszero(d.data + i * 32, 32)) memcpy(s->commitments.data + i * 32, d.data + i * 32, 32); } } d = d_to_bytes(d_get(data, key("sig"))); if (d.data) { - if (d.len != s->len * 32) return ctx_set_error(ctx, "invalid sigshares from signer handler", IN3_EINVAL); + if (d.len != s->len * 32) return req_set_error(ctx, "invalid sigshares from signer handler", IN3_EINVAL); for (unsigned int i = 0; i < s->len; i++) { if (i != s->pos && memiszero(s->signature_shares.data + i * 32, 32) && !memiszero(d.data + i * 32, 32)) memcpy(s->signature_shares.data + i * 32, d.data + i * 32, 32); } @@ -76,10 +78,18 @@ static void add_sessiondata(sb_t* sb, zk_musig_session_t* s) { sb_add_bytes(sb, ",\"sig\":", &s->signature_shares, 1, false); } -static in3_ret_t request_message(zksync_config_t* conf, zk_musig_session_t* s, int pos, bytes_t* message, in3_ctx_t* ctx, d_token_t** result) { +static in3_ret_t request_message(zksync_config_t* conf, zk_musig_session_t* s, int pos, bytes_t* message, in3_req_t* ctx, d_token_t** result) { sb_t sb = {0}; sb_add_bytes(&sb, "{\"message\":", message, 1, false); sb_add_bytes(&sb, ",\"pub_keys\":", &s->pub_keys, 1, false); + if (s->proof_data) { + sb_add_chars(&sb, ",\"proof\":"); + sb_add_chars(&sb, s->proof_data); + if (conf->account) { + sb_add_rawbytes(&sb, ",\"account\":\"0x", bytes(conf->account, 20), 0); + sb_add_chars(&sb, "\""); + } + } sb_add_char(&sb, ','); add_sessiondata(&sb, s); sb_add_char(&sb, '}'); @@ -96,6 +106,16 @@ static zk_musig_session_t* get_session(zksync_config_t* conf, uint64_t id) { return NULL; } +static void check_max_sessions(zksync_config_t* conf) { + int c = 0; + for (zk_musig_session_t* s = conf->musig_sessions; s; s = s->next, c++) { + if (c == MAX_SESSIONS) { + cleanup_session(s, conf); + return; + } + } +} + zk_musig_session_t* zk_musig_session_free(zk_musig_session_t* s) { in3_log_debug("Freeing session %p\n", s); if (!s) return NULL; @@ -104,6 +124,7 @@ zk_musig_session_t* zk_musig_session_free(zk_musig_session_t* s) { if (s->precommitments.data) _free(s->precommitments.data); if (s->signature_shares.data) _free(s->signature_shares.data); if (s->pub_keys.data) _free(s->pub_keys.data); + if (s->proof_data) _free(s->proof_data); if (s->signer) zkcrypto_signer_free(s->signer); _free(s); return next; @@ -118,6 +139,75 @@ void cleanup_session(zk_musig_session_t* s, zksync_config_t* conf) { } } +static in3_ret_t verify_proof(zksync_config_t* conf, in3_req_t* ctx, bytes_t* account, d_token_t* proof, bytes_t* msg, bytes_t* pub_keys) { + if (!conf->proof_verify_method && !proof) return IN3_OK; // no method to verify configured -> so we accept all + if (!conf->proof_verify_method) return req_set_error(ctx, "No proof_method configured to verify the proof", IN3_ECONFIG); + if (!account || account->len != 20) return req_set_error(ctx, "The account is missing in the sign data", IN3_EINVAL); + + bytes32_t pubkey; + uint8_t* signer_key = NULL; + + if (memiszero(conf->pub_key, 32)) { + bytes32_t k; + TRY(zksync_get_sync_key(conf, ctx, k)) + TRY(zkcrypto_pk_to_pubkey(k, pubkey)) + } + else + memcpy(pubkey, conf->pub_key, 32); + for (unsigned int i = 0; i < pub_keys->len; i += 32) { + if (memcmp(pubkey, pub_keys->data + i, 32) == 0) continue; + signer_key = pub_keys->data + i; + break; + } + + if (!signer_key) return req_set_error(ctx, "the signer key could not be found!", IN3_EINVAL); + d_token_t* result = NULL; + char* proof_data = d_create_json(ctx->request_context, proof); + sb_t sb = {0}; + sb_add_rawbytes(&sb, "\"0x", *msg, 0); + sb_add_rawbytes(&sb, "\",\"0x", *account, 0); + sb_add_rawbytes(&sb, "\",\"0x", bytes(signer_key, 32), 0); + sb_add_chars(&sb, "\","); + sb_add_chars(&sb, proof_data); + _free(proof_data); + + TRY_FINAL(req_send_sub_request(ctx, conf->proof_verify_method, sb.data, NULL, &result), _free(sb.data)) + + in3_ret_t ret = (d_type(result) == T_BOOLEAN && d_int(result)) ? IN3_OK : req_set_error(ctx, "Proof could not be verified!", IN3_EINVAL); + req_remove_required(ctx, req_find_required(ctx, conf->proof_verify_method), false); + return ret; +} + +static in3_ret_t create_proof(zksync_config_t* conf, in3_req_t* ctx, bytes_t* msg, char** proof_data) { + if (!conf->proof_create_method) return req_set_error(ctx, "No proof_method configured to verify the proof", IN3_ECONFIG); + + // prepare the arguments to create the proof + d_token_t* result = NULL; + uint8_t* account; + TRY(zksync_get_account(conf, ctx, &account)) + sb_t sb = {0}; + sb_add_rawbytes(&sb, "\"0x", *msg, 0); + sb_add_rawbytes(&sb, "\",\"0x", bytes(account, 20), 0); + sb_add_chars(&sb, "\""); + + // send the subrequest and wait for a response + TRY_FINAL(req_send_sub_request(ctx, conf->proof_create_method, sb.data, NULL, &result), _free(sb.data)) + + // handle error + if (!result) req_set_error(ctx, "Proof could not be created!", IN3_EINVAL); + + // all is well, so we find the subrequest + in3_req_t* sub = req_find_required(ctx, conf->proof_create_method); + + // only copy the data as json, so we can store them without a json_ctx and can clean up. + if (sub) { + *proof_data = d_create_json(sub->response_context, result); + req_remove_required(ctx, sub, false); + return IN3_OK; + } + return IN3_ERPC; +} + static bool is_complete(bytes_t data) { for (unsigned int i = 0; i < data.len; i += 32) { if (memiszero(data.data + i, 32)) return false; @@ -125,23 +215,28 @@ static bool is_complete(bytes_t data) { return true; } -in3_ret_t zksync_musig_sign(zksync_config_t* conf, in3_rpc_handle_ctx_t* ctx, d_token_t* params) { +in3_ret_t zksync_musig_sign(zksync_config_t* conf, in3_rpc_handle_ctx_t* ctx) { if (d_get(d_get(ctx->request, key("in3")), key("rpc"))) return IN3_EIGNORE; - CHECK_PARAMS_LEN(ctx->ctx, params, 1); - d_token_t* result = NULL; + CHECK_PARAMS_LEN(ctx->req, ctx->params, 1); + d_token_t* result = NULL; + d_token_t* proof = NULL; + bytes_t* account = NULL; bytes_t message; - if (d_type(params + 1) == T_OBJECT) { - result = params + 1; + if (d_type(ctx->params + 1) == T_OBJECT) { + result = ctx->params + 1; message = d_to_bytes(d_get(result, key("message"))); - if (!message.data) return ctx_set_error(ctx->ctx, "missing message in request", IN3_EINVAL); + account = d_get_bytes(result, key("account")); + proof = d_get(result, K_PROOF); + if (!message.data) return req_set_error(ctx->req, "missing message in request", IN3_EINVAL); } else { - message = d_to_bytes(params + 1); + message = d_to_bytes(ctx->params + 1); + if (d_len(ctx->params) > 1) proof = d_get_at(ctx->params, 1); if (!conf->musig_pub_keys.data) { bytes32_t pk; uint8_t sig[96]; - TRY(zksync_get_sync_key(conf, ctx->ctx, pk)) + TRY(zksync_get_sync_key(conf, ctx->req, pk)) TRY(zkcrypto_sign_musig(pk, message, sig)) return in3_rpc_handle_with_bytes(ctx, bytes(sig, 96)); } @@ -151,17 +246,30 @@ in3_ret_t zksync_musig_sign(zksync_config_t* conf, in3_rpc_handle_ctx_t* ctx, d_ uint64_t session_id = *((uint64_t*) (void*) hash); zk_musig_session_t* s = get_session(conf, session_id); if (s == NULL) { - bytes_t pub_keys = result ? d_to_bytes(d_get(result, key("pub_keys"))) : bytes(NULL, 0); + TRY(zksync_get_sync_key(conf, ctx->req, NULL)) + + char* proof_data = NULL; + bytes_t pub_keys = result ? d_to_bytes(d_get(result, key("pub_keys"))) : bytes(NULL, 0); if (!pub_keys.data && conf->musig_pub_keys.data) pub_keys = conf->musig_pub_keys; - if (!pub_keys.data) return ctx_set_error(ctx->ctx, "no public keys found for musig signature", IN3_EINVAL); - int pos = get_pubkey_pos(conf, pub_keys, ctx->ctx); + if (!pub_keys.data) return req_set_error(ctx->req, "no public keys found for musig signature", IN3_EINVAL); + int pos = get_pubkey_pos(conf, pub_keys, ctx->req); in3_log_debug("create new session with pub_key pos %d\n", pos); TRY(pos) + // if a method is specified we create the proof here + if (conf->proof_create_method && proof == NULL) + TRY(create_proof(conf, ctx->req, &message, &proof_data)) + else + TRY(verify_proof(conf, ctx->req, account, proof, &message, &pub_keys)) + + // make sure we don't have too many old sessions. + check_max_sessions(conf); + // create a new session s = _calloc(1, sizeof(zk_musig_session_t)); s->id = session_id; s->pos = (unsigned int) pos; + s->proof_data = proof_data; s->next = conf->musig_sessions; conf->musig_sessions = s; s->pub_keys = bytes_dup(pub_keys); @@ -185,13 +293,13 @@ in3_ret_t zksync_musig_sign(zksync_config_t* conf, in3_rpc_handle_ctx_t* ctx, d_ bool commit_complete = is_complete(s->commitments); // update data from incoming request - if (result) TRY_SIG(update_session(s, ctx->ctx, result)) + if (result) TRY_SIG(update_session(s, ctx->req, result)) // do we have all precommits? for (unsigned int i = 0; i < s->len; i++) { if (s->pos != i && memiszero(s->precommitments.data + i * 32, 32) && conf->musig_urls && conf->musig_urls[i]) { - TRY_SIG(request_message(conf, s, i, &message, ctx->ctx, &result)) - if (memiszero(s->precommitments.data + i * 32, 32)) TRY_SIG(ctx_set_error(ctx->ctx, "no precommit from signer set", IN3_EINVAL)) + TRY_SIG(request_message(conf, s, i, &message, ctx->req, &result)) + if (memiszero(s->precommitments.data + i * 32, 32)) TRY_SIG(req_set_error(ctx->req, "no precommit from signer set", IN3_EINVAL)) } } @@ -201,8 +309,8 @@ in3_ret_t zksync_musig_sign(zksync_config_t* conf, in3_rpc_handle_ctx_t* ctx, d_ // do we have all commits? for (unsigned int i = 0; i < s->len; i++) { if (s->pos != i && memiszero(s->commitments.data + i * 32, 32) && conf->musig_urls && conf->musig_urls[i]) { - TRY_SIG(request_message(conf, s, i, &message, ctx->ctx, &result)) - if (memiszero(s->commitments.data + i * 32, 32)) TRY_SIG(ctx_set_error(ctx->ctx, "no commit from signer set", IN3_EINVAL)) + TRY_SIG(request_message(conf, s, i, &message, ctx->req, &result)) + if (memiszero(s->commitments.data + i * 32, 32)) TRY_SIG(req_set_error(ctx->req, "no commit from signer set", IN3_EINVAL)) } } @@ -215,30 +323,28 @@ in3_ret_t zksync_musig_sign(zksync_config_t* conf, in3_rpc_handle_ctx_t* ctx, d_ // do we have all signatures? for (unsigned int i = 0; i < s->len; i++) { if (s->pos != i && memiszero(s->signature_shares.data + i * 32, 32) && conf->musig_urls && conf->musig_urls[i]) { - TRY_SIG(request_message(conf, s, i, &message, ctx->ctx, &result)) - if (memiszero(s->signature_shares.data + i * 32, 32)) TRY_SIG(ctx_set_error(ctx->ctx, "no signature from signer set", IN3_EINVAL)) + TRY_SIG(request_message(conf, s, i, &message, ctx->req, &result)) + if (memiszero(s->signature_shares.data + i * 32, 32)) TRY_SIG(req_set_error(ctx->req, "no signature from signer set", IN3_EINVAL)) } } - if (is_complete(s->signature_shares) && d_type(params + 1) != T_OBJECT) { + if (is_complete(s->signature_shares) && d_type(ctx->params + 1) != T_OBJECT) { uint8_t res[96]; TRY_SIG(zkcrypto_compute_aggregated_pubkey(s->pub_keys, res)) TRY_SIG(zkcrypto_signer_receive_signature_shares(s->signer, s->signature_shares, res + 32)) cleanup_session(s, conf); - in3_log_debug("message:\n"); - b_print(&message); - in3_log_debug("sig:\n"); - ba_print(res, 96); - ; - in3_log_debug("check signature:\n"); if (!zkcrypto_verify_signatures(message, conf->musig_pub_keys, bytes(res, 96))) - return ctx_set_error(ctx->ctx, "invalid signature", IN3_EINVAL); + return req_set_error(ctx->req, "invalid signature", IN3_EINVAL); return in3_rpc_handle_with_bytes(ctx, bytes(res, 96)); } sb_t* rr = in3_rpc_handle_start(ctx); sb_add_char(rr, '{'); add_sessiondata(rr, s); + if (s->proof_data) { + sb_add_chars(rr, ",\"proof\":"); + sb_add_chars(rr, s->proof_data); + } sb_add_char(rr, '}'); return in3_rpc_handle_finish(ctx); } diff --git a/c/src/pay/zksync/zk_setkey.c b/c/src/pay/zksync/zk_setkey.c index 220241e7a..8587cc39b 100644 --- a/c/src/pay/zksync/zk_setkey.c +++ b/c/src/pay/zksync/zk_setkey.c @@ -1,6 +1,6 @@ -#include "../../core/client/context_internal.h" #include "../../core/client/keys.h" #include "../../core/client/plugin.h" +#include "../../core/client/request_internal.h" #include "../../core/util/debug.h" #include "../../core/util/mem.h" #include "../../third-party/zkcrypto/lib.h" @@ -20,7 +20,7 @@ static in3_ret_t auth_pub_key(zksync_config_t* conf, in3_rpc_handle_ctx_t* ctx, memset(data, 0, 128); // clear the data memcpy(data + 12, conf->account, 20); // account to check int_to_bytes(nonce, data + 60); // nonce - TRY(zksync_get_contracts(conf, ctx->ctx, &main_contract)) + TRY(zksync_get_contracts(conf, ctx->req, &main_contract)) // check if the key is already authorized by calling // authFacts(address account,uint32 nonce) == keccak256(pubkey_hash) @@ -29,7 +29,7 @@ static in3_ret_t auth_pub_key(zksync_config_t* conf, in3_rpc_handle_ctx_t* ctx, sb_add_chars(&sb, "\"},\"latest\""); // send request - TRY_FINAL(send_provider_request(ctx->ctx, NULL, "eth_call", sb.data, &result), _free(sb.data)) + TRY_FINAL(send_provider_request(ctx->req, NULL, "eth_call", sb.data, &result), _free(sb.data)) // check result bytes32_t pub_hash_hash; @@ -48,36 +48,36 @@ static in3_ret_t auth_pub_key(zksync_config_t* conf, in3_rpc_handle_ctx_t* ctx, sb_add_rawbytes(&sb, "\",\"data\":\"0x595a5ebc", bytes(data, 128), 0); sb_add_chars(&sb, "\",\"gas\":\"0x30d40\"}"); - TRY_FINAL(send_provider_request(ctx->ctx, NULL, "eth_sendTransactionAndWait", sb.data, &result), _free(sb.data)) + TRY_FINAL(send_provider_request(ctx->req, NULL, "eth_sendTransactionAndWait", sb.data, &result), _free(sb.data)) // was it successfull? - if (result == NULL || d_type(result) != T_OBJECT || d_get_intk(result, K_STATUS) == 0) - return ctx_set_error(ctx->ctx, "setAuthPubkeyHash-Transaction failed", IN3_EINVAL); + if (result == NULL || d_type(result) != T_OBJECT || d_get_int(result, K_STATUS) == 0) + return req_set_error(ctx->req, "setAuthPubkeyHash-Transaction failed", IN3_EINVAL); return IN3_OK; } -in3_ret_t zksync_set_key(zksync_config_t* conf, in3_rpc_handle_ctx_t* ctx, d_token_t* params) { +in3_ret_t zksync_set_key(zksync_config_t* conf, in3_rpc_handle_ctx_t* ctx) { address_t pub_hash; uint32_t nonce; - d_token_t* token = d_len(params) == 1 ? params + 1 : NULL; - bytes_t* new_key = d_get_bytes_at(params, 1); + d_token_t* token = d_len(ctx->params) == 1 ? ctx->params + 1 : NULL; + bytes_t* new_key = d_get_bytes_at(ctx->params, 1); zksync_token_t* token_data = NULL; - if (!token) return ctx_set_error(ctx->ctx, "Missing fee token as first token", IN3_EINVAL); + if (!token) return req_set_error(ctx->req, "Missing fee token as first token", IN3_EINVAL); zk_fee_t fee; if (new_key && new_key->len == 32) memcpy(conf->sync_key, new_key->data, 32); - TRY(zksync_get_nonce(conf, ctx->ctx, NULL, &nonce)) - TRY(resolve_tokens(conf, ctx->ctx, token, &token_data)) - TRY(zksync_get_pubkey_hash(conf, ctx->ctx, pub_hash)) + TRY(zksync_get_nonce(conf, ctx->req, NULL, &nonce)) + TRY(resolve_tokens(conf, ctx->req, token, &token_data)) + TRY(zksync_get_pubkey_hash(conf, ctx->req, pub_hash)) - if (memcmp(pub_hash, conf->pub_key_hash_set, 20) == 0) return ctx_set_error(ctx->ctx, "Signer key is already set", IN3_EINVAL); // and check if it is already set - if (!conf->account_id) return ctx_set_error(ctx->ctx, "No Account set yet", IN3_EINVAL); + if (memcmp(pub_hash, conf->pub_key_hash_set, 20) == 0) return req_set_error(ctx->req, "Signer key is already set", IN3_EINVAL); // and check if it is already set + if (!conf->account_id) return req_set_error(ctx->req, "No Account set yet", IN3_EINVAL); // for contracts we need to pre authorized on layer 1 if (conf->sign_type == ZK_SIGN_CONTRACT) TRY(auth_pub_key(conf, ctx, nonce, pub_hash)) // get fees - TRY(zksync_get_fee(conf, ctx->ctx, NULL, bytes(conf->account, 20), token, conf->sign_type == ZK_SIGN_PK ? "{\"ChangePubKey\":{\"onchainPubkeyAuth\":false}}" : "{\"ChangePubKey\":{\"onchainPubkeyAuth\":true}}", + TRY(zksync_get_fee(conf, ctx->req, NULL, bytes(conf->account, 20), token, conf->sign_type == ZK_SIGN_PK ? "{\"ChangePubKey\":{\"onchainPubkeyAuth\":false}}" : "{\"ChangePubKey\":{\"onchainPubkeyAuth\":true}}", #ifdef ZKSYNC_256 fee #else @@ -86,23 +86,23 @@ in3_ret_t zksync_set_key(zksync_config_t* conf, in3_rpc_handle_ctx_t* ctx, d_tok )) // create payload for change key tx - cache_entry_t* cached = ctx->ctx->cache; + cache_entry_t* cached = ctx->req->cache; while (cached) { if (cached->props & 0x10) break; cached = cached->next; } if (!cached) { sb_t sb = {0}; - in3_ret_t ret = zksync_sign_change_pub_key(&sb, ctx->ctx, pub_hash, nonce, conf, fee, token_data); + in3_ret_t ret = zksync_sign_change_pub_key(&sb, ctx->req, pub_hash, nonce, conf, fee, token_data); if (ret && sb.data) _free(sb.data); TRY(ret) if (!sb.data) return IN3_EUNKNOWN; - cached = in3_cache_add_entry(&ctx->ctx->cache, bytes(NULL, 0), bytes((void*) sb.data, strlen(sb.data))); + cached = in3_cache_add_entry(&ctx->req->cache, bytes(NULL, 0), bytes((void*) sb.data, strlen(sb.data))); cached->props = CACHE_PROP_MUST_FREE | 0x10; } d_token_t* result = NULL; - in3_ret_t ret = send_provider_request(ctx->ctx, conf, "tx_submit", (void*) cached->value.data, &result); + in3_ret_t ret = send_provider_request(ctx->req, conf, "tx_submit", (void*) cached->value.data, &result); if (ret == IN3_OK) { // return only the pubkeyhash as result sb_t* sb = in3_rpc_handle_start(ctx); diff --git a/c/src/pay/zksync/zk_transfer.c b/c/src/pay/zksync/zk_transfer.c index 5f35c6a24..79b4ac6e6 100644 --- a/c/src/pay/zksync/zk_transfer.c +++ b/c/src/pay/zksync/zk_transfer.c @@ -1,8 +1,8 @@ -#include "../../core/client/context_internal.h" #include "../../core/client/keys.h" #include "../../core/client/plugin.h" +#include "../../core/client/request_internal.h" #include "../../core/util/debug.h" #include "../../core/util/mem.h" #include "../../third-party/zkcrypto/lib.h" @@ -13,38 +13,38 @@ #include #include -in3_ret_t zksync_transfer(zksync_config_t* conf, in3_rpc_handle_ctx_t* ctx, d_token_t* params, zk_msg_type_t type) { - // check params - if (!(d_len(params) == 1 && d_type(params + 1) == T_OBJECT)) { - CHECK_PARAMS_LEN(ctx->ctx, params, 3) - CHECK_PARAM_ADDRESS(ctx->ctx, params, 0) - CHECK_PARAM_NUMBER(ctx->ctx, params, 1) - CHECK_PARAM_TOKEN(ctx->ctx, params, 2) +in3_ret_t zksync_transfer(zksync_config_t* conf, in3_rpc_handle_ctx_t* ctx, zk_msg_type_t type) { + // check ctx->params + if (!(d_len(ctx->params) == 1 && d_type(ctx->params + 1) == T_OBJECT)) { + CHECK_PARAMS_LEN(ctx->req, ctx->params, 3) + CHECK_PARAM_ADDRESS(ctx->req, ctx->params, 0) + CHECK_PARAM_NUMBER(ctx->req, ctx->params, 1) + CHECK_PARAM_TOKEN(ctx->req, ctx->params, 2) } bytes32_t sync_key; - TRY(zksync_get_sync_key(conf, ctx->ctx, sync_key)); + TRY(zksync_get_sync_key(conf, ctx->req, sync_key)); // prepare tx data zksync_tx_data_t tx_data = {0}; tx_data.conf = conf; - bytes_t to = d_to_bytes(params_get(params, type == ZK_WITHDRAW ? key("ethAddress") : K_TO, 0)); - if (!to.data || to.len != 20) return ctx_set_error(ctx->ctx, "invalid to address", IN3_EINVAL); + bytes_t to = d_to_bytes(params_get(ctx->params, type == ZK_WITHDRAW ? key("ethAddress") : K_TO, 0)); + if (!to.data || to.len != 20) return req_set_error(ctx->req, "invalid to address", IN3_EINVAL); memcpy(tx_data.to, to.data, 20); tx_data.type = type; #ifdef ZKSYNC_256 - bytes_t amount = d_to_bytes(params_get(params, key("amount"), 1)); - if (amount.len > 33) return ctx_set_error(ctx->ctx, "invalid to amount", IN3_EINVAL); + bytes_t amount = d_to_bytes(params_get(ctx->params, key("amount"), 1)); + if (amount.len > 33) return req_set_error(ctx->req, "invalid to amount", IN3_EINVAL); memcpy(tx_data.amount + 32 - amount.len, amount.data, amount.len); #else - tx_data.amount = d_long(params_get(params, key("amount"), 1)); + tx_data.amount = d_long(params_get(ctx->params, key("amount"), 1)); #endif // prepare tx_data - TRY(zksync_get_account_id(conf, ctx->ctx, &tx_data.account_id)) - TRY(resolve_tokens(conf, ctx->ctx, params_get(params, key("token"), 2), &tx_data.token)) - TRY(zksync_get_nonce(conf, ctx->ctx, params_get(params, K_NONCE, 4), &tx_data.nonce)) - TRY(zksync_get_fee(conf, ctx->ctx, params_get(params, key("fee"), 3), to, params_get(params, key("token"), 2), type == ZK_WITHDRAW ? "Withdraw" : "Transfer", + TRY(zksync_get_account_id(conf, ctx->req, &tx_data.account_id)) + TRY(resolve_tokens(conf, ctx->req, params_get(ctx->params, key("token"), 2), &tx_data.token)) + TRY(zksync_get_nonce(conf, ctx->req, params_get(ctx->params, K_NONCE, 4), &tx_data.nonce)) + TRY(zksync_get_fee(conf, ctx->req, params_get(ctx->params, key("fee"), 3), to, params_get(ctx->params, key("token"), 2), type == ZK_WITHDRAW ? "Withdraw" : "Transfer", #ifdef ZKSYNC_256 tx_data.fee #else @@ -54,23 +54,23 @@ in3_ret_t zksync_transfer(zksync_config_t* conf, in3_rpc_handle_ctx_t* ctx, d_to memcpy(tx_data.from, conf->account, 20); // create payload - cache_entry_t* cached = ctx->ctx->cache; + cache_entry_t* cached = ctx->req->cache; while (cached) { if (cached->props & 0x10) break; cached = cached->next; } if (!cached) { sb_t sb = {0}; - in3_ret_t ret = zksync_sign_transfer(&sb, &tx_data, ctx->ctx, conf); + in3_ret_t ret = zksync_sign_transfer(&sb, &tx_data, ctx->req, conf); if (ret && sb.data) _free(sb.data); TRY(ret) if (!sb.data) return IN3_EUNKNOWN; - cached = in3_cache_add_entry(&ctx->ctx->cache, bytes(NULL, 0), bytes((void*) sb.data, strlen(sb.data))); + cached = in3_cache_add_entry(&ctx->req->cache, bytes(NULL, 0), bytes((void*) sb.data, strlen(sb.data))); cached->props = CACHE_PROP_MUST_FREE | 0x10; } d_token_t* result = NULL; - in3_ret_t ret = send_provider_request(ctx->ctx, conf, "tx_submit", (void*) cached->value.data, &result); + in3_ret_t ret = send_provider_request(ctx->req, conf, "tx_submit", (void*) cached->value.data, &result); if (ret == IN3_OK && cached && cached->value.data) { uint8_t* start_sig = (void*) strstr((void*) cached->value.data, ",\"signature\":"); sb_t* sb = in3_rpc_handle_start(ctx); diff --git a/c/src/pay/zksync/zksync.c b/c/src/pay/zksync/zksync.c index 384da4815..5498291a7 100644 --- a/c/src/pay/zksync/zksync.c +++ b/c/src/pay/zksync/zksync.c @@ -32,8 +32,8 @@ * with this program. If not, see . *******************************************************************************/ #include "zksync.h" -#include "../../core/client/context_internal.h" #include "../../core/client/keys.h" +#include "../../core/client/request_internal.h" #include "../../core/util/debug.h" #include "../../third-party/zkcrypto/lib.h" #include "zk_helper.h" @@ -52,19 +52,19 @@ static zk_sign_type_t get_sign_type(d_token_t* type) { static in3_ret_t zksync_get_key(zksync_config_t* conf, in3_rpc_handle_ctx_t* ctx) { bytes32_t k; - TRY(zksync_get_sync_key(conf, ctx->ctx, k)) + TRY(zksync_get_sync_key(conf, ctx->req, k)) return in3_rpc_handle_with_bytes(ctx, bytes(k, 32)); } -static in3_ret_t zksync_get_pubkeyhash(zksync_config_t* conf, in3_rpc_handle_ctx_t* ctx, d_token_t* params) { +static in3_ret_t zksync_get_pubkeyhash(zksync_config_t* conf, in3_rpc_handle_ctx_t* ctx) { address_t pubkey_hash; - if (d_len(params) == 1) { - CHECK_PARAM_TYPE(ctx->ctx, params, 0, T_BYTES) - CHECK_PARAM_LEN(ctx->ctx, params, 0, 32) - TRY(zkcrypto_pubkey_hash(d_to_bytes(params + 1), pubkey_hash)); + if (d_len(ctx->params) == 1) { + CHECK_PARAM_TYPE(ctx->req, ctx->params, 0, T_BYTES) + CHECK_PARAM_LEN(ctx->req, ctx->params, 0, 32) + TRY(zkcrypto_pubkey_hash(d_to_bytes(ctx->params + 1), pubkey_hash)); } else - TRY(zksync_get_pubkey_hash(conf, ctx->ctx, pubkey_hash)) + TRY(zksync_get_pubkey_hash(conf, ctx->req, pubkey_hash)) char res[48]; strcpy(res, "\"sync:"); bytes_to_hex(pubkey_hash, 20, res + 6); @@ -80,31 +80,31 @@ static in3_ret_t zksync_get_pubkey(zksync_config_t* conf, in3_rpc_handle_ctx_t* memcpy(pubkey, conf->pub_key, 32); else { bytes32_t k; - TRY(zksync_get_sync_key(conf, ctx->ctx, k)) + TRY(zksync_get_sync_key(conf, ctx->req, k)) TRY(zkcrypto_pk_to_pubkey(k, pubkey)) memcpy(conf->pub_key, pubkey, 32); } return in3_rpc_handle_with_bytes(ctx, bytes(pubkey, 32)); } -static in3_ret_t zksync_aggregate_pubkey(in3_rpc_handle_ctx_t* ctx, d_token_t* params) { +static in3_ret_t zksync_aggregate_pubkey(in3_rpc_handle_ctx_t* ctx) { bytes32_t dst; - CHECK_PARAM_TYPE(ctx->ctx, params, 0, T_BYTES) - CHECK_PARAM(ctx->ctx, params, 0, d_len(val) % 32 == 0) + CHECK_PARAM_TYPE(ctx->req, ctx->params, 0, T_BYTES) + CHECK_PARAM(ctx->req, ctx->params, 0, d_len(val) % 32 == 0) - TRY(zkcrypto_compute_aggregated_pubkey(d_to_bytes(params + 1), dst)) + TRY(zkcrypto_compute_aggregated_pubkey(d_to_bytes(ctx->params + 1), dst)) return in3_rpc_handle_with_bytes(ctx, bytes(dst, 32)); } static in3_ret_t zksync_account_address(zksync_config_t* conf, in3_rpc_handle_ctx_t* ctx) { uint8_t* account = NULL; - TRY(zksync_get_account(conf, ctx->ctx, &account)); + TRY(zksync_get_account(conf, ctx->req, &account)); return in3_rpc_handle_with_bytes(ctx, bytes(account, 20)); } static in3_ret_t zksync_contract_address(zksync_config_t* conf, in3_rpc_handle_ctx_t* ctx) { uint8_t* adr; - TRY(zksync_get_contracts(conf, ctx->ctx, &adr)) + TRY(zksync_get_contracts(conf, ctx->req, &adr)) sb_t* sb = in3_rpc_handle_start(ctx); sb_add_rawbytes(sb, "{\"govContract\":\"0x", bytes(conf->gov_contract, 20), 0); sb_add_rawbytes(sb, "\",\"mainContract\":\"0x", bytes(conf->main_contract, 20), 0); @@ -112,7 +112,7 @@ static in3_ret_t zksync_contract_address(zksync_config_t* conf, in3_rpc_handle_c return in3_rpc_handle_finish(ctx); } static in3_ret_t zksync_tokens(zksync_config_t* conf, in3_rpc_handle_ctx_t* ctx) { - TRY(resolve_tokens(conf, ctx->ctx, NULL, NULL)) + TRY(resolve_tokens(conf, ctx->req, NULL, NULL)) sb_t* sb = in3_rpc_handle_start(ctx); sb_add_char(sb, '{'); for (unsigned int i = 0; i < conf->token_len; i++) { @@ -134,58 +134,58 @@ static in3_ret_t zksync_tokens(zksync_config_t* conf, in3_rpc_handle_ctx_t* ctx) // --- handle rpc---- static in3_ret_t zksync_rpc(zksync_config_t* conf, in3_rpc_handle_ctx_t* ctx) { - char* method = d_get_stringk(ctx->ctx->requests[0], K_METHOD); - d_token_t* params = d_get(ctx->ctx->requests[0], K_PARAMS); - // check the prefix (zksync_ or zk_ is supported) - if (strncmp(method, "zksync_", 7) == 0) - method += 7; - else if (strncmp(method, "zk_", 3) == 0) - method += 3; + if (strncmp(ctx->method, "zksync_", 7) == 0) + ctx->method += 7; + else if (strncmp(ctx->method, "zk_", 3) == 0) + ctx->method += 3; else return IN3_EIGNORE; + // mark zksync as experimental + REQUIRE_EXPERIMENTAL(ctx->req, "zksync") + // handle rpc -functions - TRY_RPC("deposit", zksync_deposit(conf, ctx, params)) - TRY_RPC("transfer", zksync_transfer(conf, ctx, params, ZK_TRANSFER)) - TRY_RPC("withdraw", zksync_transfer(conf, ctx, params, ZK_WITHDRAW)) - TRY_RPC("set_key", zksync_set_key(conf, ctx, params)) - TRY_RPC("emergency_withdraw", zksync_emergency_withdraw(conf, ctx, params)) + TRY_RPC("deposit", zksync_deposit(conf, ctx)) + TRY_RPC("transfer", zksync_transfer(conf, ctx, ZK_TRANSFER)) + TRY_RPC("withdraw", zksync_transfer(conf, ctx, ZK_WITHDRAW)) + TRY_RPC("set_key", zksync_set_key(conf, ctx)) + TRY_RPC("emergency_withdraw", zksync_emergency_withdraw(conf, ctx)) TRY_RPC("sync_key", zksync_get_key(conf, ctx)) - TRY_RPC("aggregate_pubkey", zksync_aggregate_pubkey(ctx, params)) - TRY_RPC("pubkeyhash", zksync_get_pubkeyhash(conf, ctx, params)) + TRY_RPC("aggregate_pubkey", zksync_aggregate_pubkey(ctx)) + TRY_RPC("pubkeyhash", zksync_get_pubkeyhash(conf, ctx)) TRY_RPC("pubkey", zksync_get_pubkey(conf, ctx)) TRY_RPC("account_address", zksync_account_address(conf, ctx)) TRY_RPC("contract_address", zksync_contract_address(conf, ctx)) TRY_RPC("tokens", zksync_tokens(conf, ctx)) - TRY_RPC("sign", zksync_musig_sign(conf, ctx, params)) + TRY_RPC("sign", zksync_musig_sign(conf, ctx)) TRY_RPC("verify", in3_rpc_handle_with_int(ctx, conf->musig_pub_keys.data - ? zkcrypto_verify_signatures(d_to_bytes(params + 1), conf->musig_pub_keys, d_to_bytes(params + 2)) - : zkcrypto_verify_musig(d_to_bytes(params + 1), d_to_bytes(params + 2)))) + ? zkcrypto_verify_signatures(d_to_bytes(ctx->params + 1), conf->musig_pub_keys, d_to_bytes(ctx->params + 2)) + : zkcrypto_verify_musig(d_to_bytes(ctx->params + 1), d_to_bytes(ctx->params + 2)))) // prepare fallback to send to zksync-server - str_range_t p = d_to_json(params); + str_range_t p = d_to_json(ctx->params); char* param_string = alloca(p.len - 1); memcpy(param_string, p.data + 1, p.len - 2); param_string[p.len - 2] = 0; - if (strcmp(method, "account_info") == 0) { + if (strcmp(ctx->method, "account_info") == 0) { if (*param_string == 0) { - TRY(zksync_get_account(conf, ctx->ctx, NULL)) + TRY(zksync_get_account(conf, ctx->req, NULL)) param_string = alloca(45); set_quoted_address(param_string, conf->account); } else - CHECK_PARAM_ADDRESS(ctx->ctx, params, 0) + CHECK_PARAM_ADDRESS(ctx->req, ctx->params, 0) } // we need to show the arguments as integers - if (strcmp(method, "ethop_info") == 0) - sprintf(param_string, "%i", d_get_int_at(params, 0)); + if (strcmp(ctx->method, "ethop_info") == 0) + sprintf(param_string, "%i", d_get_int_at(ctx->params, 0)); // send request to the server d_token_t* result; - TRY(send_provider_request(ctx->ctx, conf, method, param_string, &result)) + TRY(send_provider_request(ctx->req, conf, ctx->method, param_string, &result)) // format result char* json = d_create_json(NULL, result); @@ -194,7 +194,7 @@ static in3_ret_t zksync_rpc(zksync_config_t* conf, in3_rpc_handle_ctx_t* ctx) { return IN3_OK; } -static in3_ret_t config_free(zksync_config_t* conf) { +static in3_ret_t config_free(zksync_config_t* conf, bool free_conf) { if (conf->musig_urls) { for (unsigned int i = 0; i < conf->musig_pub_keys.len / 32; i++) { if (conf->musig_urls[i]) _free(conf->musig_urls[i]); @@ -206,9 +206,16 @@ static in3_ret_t config_free(zksync_config_t* conf) { if (conf->account) _free(conf->account); if (conf->tokens) _free(conf->tokens); if (conf->create2) _free(conf->create2); + if (conf->proof_verify_method) _free(conf->proof_verify_method); if (conf->musig_pub_keys.data) _free(conf->musig_pub_keys.data); + if (conf->incentive && conf->incentive->token) _free(conf->incentive->token); + if (conf->incentive) { + config_free(&conf->incentive->config, false); + _free(conf->incentive); + } + while (conf->musig_sessions) conf->musig_sessions = zk_musig_session_free(conf->musig_sessions); - _free(conf); + if (free_conf) _free(conf); return IN3_OK; } @@ -233,13 +240,24 @@ static in3_ret_t config_get(zksync_config_t* conf, in3_get_config_ctx_t* ctx) { static in3_ret_t config_set(zksync_config_t* conf, in3_configure_ctx_t* ctx) { if (ctx->token->key != key("zksync")) return IN3_EIGNORE; + // TODO error-reporting for invalid config - const char* provider = d_get_string(ctx->token, "provider_url"); + const char* provider = d_get_string(ctx->token, key("provider_url")); if (provider) { if (conf->provider_url) _free(conf->provider_url); conf->provider_url = _strdupn(provider, -1); } - bytes_t* account = d_get_bytes(ctx->token, "account"); + const char* pvm = d_get_string(ctx->token, key("verify_proof_method")); + if (pvm) { + if (conf->proof_verify_method) _free(conf->proof_verify_method); + conf->proof_verify_method = _strdupn(pvm, -1); + } + const char* pcm = d_get_string(ctx->token, key("create_proof_method")); + if (pcm) { + if (conf->proof_create_method) _free(conf->proof_create_method); + conf->proof_create_method = _strdupn(pcm, -1); + } + bytes_t* account = d_get_bytes(ctx->token, key("account")); if (account && account->len == 20) memcpy(conf->account = _malloc(20), account->data, 20); bytes_t sync_key = d_to_bytes(d_get(ctx->token, key("sync_key"))); if (sync_key.len) { @@ -248,7 +266,7 @@ static in3_ret_t config_set(zksync_config_t* conf, in3_configure_ctx_t* ctx) { zkcrypto_pubkey_hash(bytes(conf->pub_key, 32), conf->pub_key_hash_pk); } - bytes_t* main_contract = d_get_bytes(ctx->token, "main_contract"); + bytes_t* main_contract = d_get_bytes(ctx->token, key("main_contract")); if (main_contract && main_contract->len == 20) memcpy(conf->main_contract = _malloc(20), main_contract->data, 20); d_token_t* st = d_get(ctx->token, key("signer_type")); if (st) @@ -280,22 +298,59 @@ static in3_ret_t config_set(zksync_config_t* conf, in3_configure_ctx_t* ctx) { if (create2) { conf->sign_type = ZK_SIGN_CREATE2; if (!conf->create2) conf->create2 = _calloc(1, sizeof(zk_create2_t)); - bytes_t* t = d_get_bytesk(create2, key("creator")); + bytes_t* t = d_get_bytes(create2, key("creator")); if (t && t->len == 20) memcpy(conf->create2->creator, t->data, 20); - t = d_get_bytesk(create2, key("saltarg")); + t = d_get_bytes(create2, key("saltarg")); if (t && t->len == 32) memcpy(conf->create2->salt_arg, t->data, 32); - t = d_get_bytesk(create2, key("codehash")); + t = d_get_bytes(create2, key("codehash")); if (t && t->len == 32) memcpy(conf->create2->codehash, t->data, 32); } + + d_token_t* incentive = d_get(ctx->token, key("incentive")); + if (incentive) { + if (!conf->incentive) conf->incentive = _calloc(1, sizeof(pay_criteria_t)); + for (d_iterator_t iter = d_iter(incentive); iter.left; d_iter_next(&iter)) { + if (iter.token->key == key("nodes")) { + conf->incentive->payed_nodes = d_int(iter.token); + in3_req_t c = {0}; + c.client = ctx->client; + in3_ret_t ret = update_nodelist_from_cache(&c, conf->incentive->payed_nodes); + if (c.error) { + ctx->error_msg = c.error; + return ret; + } + } + else if (iter.token->key == key("max_price")) + conf->incentive->max_price_per_hundred_igas = d_long(iter.token); + else if (iter.token->key == key("token")) { + _free(conf->incentive->token); + conf->incentive->token = _strdupn(d_string(iter.token), -1); + } + } + } + return IN3_OK; +} + +static in3_ret_t zksync_init(zksync_config_t* conf, in3_req_t* ctx) { + if (ctx->client->plugin_acts & PLGN_ACT_PAY_SIGN_REQ) { + if (!conf->incentive) { + conf->incentive = _calloc(1, sizeof(pay_criteria_t)); + conf->incentive->payed_nodes = 1; + } + return update_nodelist_from_cache(ctx, conf->incentive->payed_nodes); + } return IN3_OK; } -static in3_ret_t handle_zksync(void* conf, in3_plugin_act_t action, void* arg) { +in3_ret_t handle_zksync(void* conf, in3_plugin_act_t action, void* arg) { switch (action) { - case PLGN_ACT_TERM: return config_free(conf); + case PLGN_ACT_TERM: return config_free(conf, true); case PLGN_ACT_CONFIG_GET: return config_get(conf, arg); case PLGN_ACT_CONFIG_SET: return config_set(conf, arg); case PLGN_ACT_RPC_HANDLE: return zksync_rpc(conf, arg); + case PLGN_ACT_ADD_PAYLOAD: return zksync_add_payload(arg); + case PLGN_ACT_PAY_FOLLOWUP: return zksync_check_payment(conf, arg); + case PLGN_ACT_INIT: return zksync_init(conf, arg); default: return IN3_ENOTSUP; } return IN3_EIGNORE; @@ -304,5 +359,7 @@ static in3_ret_t handle_zksync(void* conf, in3_plugin_act_t action, void* arg) { in3_ret_t in3_register_zksync(in3_t* c) { zksync_config_t* conf = _calloc(sizeof(zksync_config_t), 1); conf->version = 1; - return in3_plugin_register(c, PLGN_ACT_RPC_HANDLE | PLGN_ACT_TERM | PLGN_ACT_CONFIG_GET | PLGN_ACT_CONFIG_SET, handle_zksync, conf, false); + return in3_plugin_register(c, + PLGN_ACT_RPC_HANDLE | PLGN_ACT_INIT | PLGN_ACT_TERM | PLGN_ACT_CONFIG_GET | PLGN_ACT_CONFIG_SET | PLGN_ACT_ADD_PAYLOAD | PLGN_ACT_PAY_FOLLOWUP, + handle_zksync, conf, false); } \ No newline at end of file diff --git a/c/src/pay/zksync/zksync.h b/c/src/pay/zksync/zksync.h index 95fcbff30..7d897bcb5 100644 --- a/c/src/pay/zksync/zksync.h +++ b/c/src/pay/zksync/zksync.h @@ -97,31 +97,44 @@ typedef struct zk_musig_session { bytes_t commitments; /**< all commits */ bytes_t signature_shares; /**< all signatures shares */ void* signer; /**< handle for the signer */ + char* proof_data; /**< the proof needed by the server to verify. This is created by the client and checked in the server. */ struct zk_musig_session* next; /**< next session */ } zk_musig_session_t; +struct pay_criteria; + /** internal configuration-object */ -typedef struct { - char* provider_url; /**< url of the zksync-server */ - uint8_t* account; /**< address of the account */ - uint8_t* main_contract; /**< address of the main zksync contract*/ - uint8_t* gov_contract; /**< address of the government contract */ - uint64_t account_id; /**< the id of the account as used in the messages */ - uint64_t nonce; /**< the current nonce */ - address_t pub_key_hash_set; /**< the pub_key_hash as set in the account*/ - address_t pub_key_hash_pk; /**< the pub_key_hash based on the sync_key*/ - bytes32_t pub_key; /**< the pub_key */ - uint16_t token_len; /**< number of tokens in the tokenlist */ - bytes32_t sync_key; /**< the raw key to sign with*/ - zksync_token_t* tokens; /**< the token-list */ - zk_sign_type_t sign_type; /**< the signature-type to use*/ - uint32_t version; /**< zksync version */ - zk_create2_t* create2; /**< create2 args */ - bytes_t musig_pub_keys; /**< the public keys of all participants of a schnorr musig signature */ - zk_musig_session_t* musig_sessions; /**< linked list of open musig sessions */ - char** musig_urls; /**< urls to get signatureshares, the order must be in the same order as the pub_keys */ +typedef struct zksync_config { + char* provider_url; /**< url of the zksync-server */ + uint8_t* account; /**< address of the account */ + uint8_t* main_contract; /**< address of the main zksync contract*/ + uint8_t* gov_contract; /**< address of the government contract */ + uint64_t account_id; /**< the id of the account as used in the messages */ + uint64_t nonce; /**< the current nonce */ + address_t pub_key_hash_set; /**< the pub_key_hash as set in the account*/ + address_t pub_key_hash_pk; /**< the pub_key_hash based on the sync_key*/ + bytes32_t pub_key; /**< the pub_key */ + uint16_t token_len; /**< number of tokens in the tokenlist */ + bytes32_t sync_key; /**< the raw key to sign with*/ + zksync_token_t* tokens; /**< the token-list */ + zk_sign_type_t sign_type; /**< the signature-type to use*/ + uint32_t version; /**< zksync version */ + zk_create2_t* create2; /**< create2 args */ + bytes_t musig_pub_keys; /**< the public keys of all participants of a schnorr musig signature */ + zk_musig_session_t* musig_sessions; /**< linked list of open musig sessions */ + char** musig_urls; /**< urls to get signatureshares, the order must be in the same order as the pub_keys */ + struct pay_criteria* incentive; /**< incentive payment configuration */ + char* proof_verify_method; /**< the rpc-method used to verify the proof before creating a signature */ + char* proof_create_method; /**< the rpc-method used to create the proof before creating a signature */ } zksync_config_t; +typedef struct pay_criteria { + uint_fast32_t payed_nodes; /**< max number of nodes payed at the same time*/ + uint64_t max_price_per_hundred_igas; /**< the max price per 100 gas units to accept a payment offer */ + char* token; /**< token-name */ + zksync_config_t config; /**< the account configuration */ +} pay_criteria_t; + /** a transaction */ typedef struct { zksync_config_t* conf; /**< the configuration of the zksync-account */ @@ -139,27 +152,30 @@ typedef struct { NONULL in3_ret_t in3_register_zksync(in3_t* c); /** sets a PubKeyHash for the current Account */ -NONULL in3_ret_t zksync_set_key(zksync_config_t* conf, in3_rpc_handle_ctx_t* ctx, d_token_t* params); +NONULL in3_ret_t zksync_set_key(zksync_config_t* conf, in3_rpc_handle_ctx_t* ctx); /** sends a transfer transaction in Layer 2*/ -NONULL in3_ret_t zksync_transfer(zksync_config_t* conf, in3_rpc_handle_ctx_t* ctx, d_token_t* params, zk_msg_type_t type); +NONULL in3_ret_t zksync_transfer(zksync_config_t* conf, in3_rpc_handle_ctx_t* ctx, zk_msg_type_t type); /** sends a deposit transaction in Layer 1*/ -NONULL in3_ret_t zksync_deposit(zksync_config_t* conf, in3_rpc_handle_ctx_t* ctx, d_token_t* params); +NONULL in3_ret_t zksync_deposit(zksync_config_t* conf, in3_rpc_handle_ctx_t* ctx); /** sends a emergency withdraw transaction in Layer 1*/ -NONULL in3_ret_t zksync_emergency_withdraw(zksync_config_t* conf, in3_rpc_handle_ctx_t* ctx, d_token_t* params); +NONULL in3_ret_t zksync_emergency_withdraw(zksync_config_t* conf, in3_rpc_handle_ctx_t* ctx); /** creates message data and signs a transfer-message */ -NONULL in3_ret_t zksync_sign_transfer(sb_t* sb, zksync_tx_data_t* data, in3_ctx_t* ctx, zksync_config_t* conf); +NONULL in3_ret_t zksync_sign_transfer(sb_t* sb, zksync_tx_data_t* data, in3_req_t* req, zksync_config_t* conf); /** creates message data and signs a change_pub_key-message */ -NONULL in3_ret_t zksync_sign_change_pub_key(sb_t* sb, in3_ctx_t* ctx, uint8_t* sync_pub_key, uint32_t nonce, zksync_config_t* conf, zk_fee_t fee, zksync_token_t* token); +NONULL in3_ret_t zksync_sign_change_pub_key(sb_t* sb, in3_req_t* req, uint8_t* sync_pub_key, uint32_t nonce, zksync_config_t* conf, zk_fee_t fee, zksync_token_t* token); -in3_ret_t zksync_musig_sign(zksync_config_t* conf, in3_rpc_handle_ctx_t* ctx, d_token_t* params); +in3_ret_t zksync_musig_sign(zksync_config_t* conf, in3_rpc_handle_ctx_t* ctx); zk_musig_session_t* zk_musig_session_free(zk_musig_session_t* s); -in3_ret_t zksync_sign(zksync_config_t* conf, bytes_t msg, in3_ctx_t* ctx, uint8_t* sig); - +in3_ret_t zksync_sign(zksync_config_t* conf, bytes_t msg, in3_req_t* req, uint8_t* sig); +in3_ret_t zksync_check_payment(zksync_config_t* conf, in3_pay_followup_ctx_t* ctx); +in3_ret_t zksync_add_payload(in3_pay_payload_ctx_t* ctx); +in3_ret_t update_nodelist_from_cache(in3_req_t* req, unsigned int nodelen); +in3_ret_t handle_zksync(void* conf, in3_plugin_act_t action, void* arg); #ifdef __cplusplus } #endif diff --git a/c/src/signer/ledger-nano/signer/ethereum_apdu_client.c b/c/src/signer/ledger-nano/signer/ethereum_apdu_client.c index e6f6aeddc..98f778c84 100644 --- a/c/src/signer/ledger-nano/signer/ethereum_apdu_client.c +++ b/c/src/signer/ledger-nano/signer/ethereum_apdu_client.c @@ -1,5 +1,5 @@ #include "ethereum_apdu_client.h" -#include "../../../core/client/context.h" +#include "../../../core/client/request.h" #include "../../../core/util/log.h" #include "device_apdu_commands.h" #include "ethereum_apdu_client_priv.h" diff --git a/c/src/signer/ledger-nano/signer/ledger_signer.c b/c/src/signer/ledger-nano/signer/ledger_signer.c index 7d7e350e8..efc6d666d 100644 --- a/c/src/signer/ledger-nano/signer/ledger_signer.c +++ b/c/src/signer/ledger-nano/signer/ledger_signer.c @@ -2,7 +2,7 @@ #include #endif -#include "../../../core/client/context.h" +#include "../../../core/client/request.h" #include "../../../core/util/bytes.h" #include "../../../core/util/log.h" #include "device_apdu_commands.h" diff --git a/c/src/signer/multisig/multisig.c b/c/src/signer/multisig/multisig.c index 046b6480d..257aa4a47 100644 --- a/c/src/signer/multisig/multisig.c +++ b/c/src/signer/multisig/multisig.c @@ -34,9 +34,9 @@ #include "multisig.h" #include "../../core/client/client.h" -#include "../../core/client/context.h" -#include "../../core/client/context_internal.h" #include "../../core/client/keys.h" +#include "../../core/client/request.h" +#include "../../core/client/request_internal.h" #include "../../core/util/log.h" #include "../../core/util/mem.h" #include "../../core/util/utils.h" @@ -77,22 +77,22 @@ typedef struct { bytes_t data; } sig_data_t; -static in3_ret_t decode_tx(in3_ctx_t* ctx, bytes_t raw, tx_data_t* result) { - if (rlp_decode_in_list(&raw, 0, &result->nonce) != 1) return ctx_set_error(ctx, "invalid nonce in txdata", IN3_EINVAL); - if (rlp_decode_in_list(&raw, 1, &result->gas_price) != 1) return ctx_set_error(ctx, "invalid gasprice in txdata", IN3_EINVAL); - if (rlp_decode_in_list(&raw, 2, &result->gas) != 1) return ctx_set_error(ctx, "invalid gas in txdata", IN3_EINVAL); - if (rlp_decode_in_list(&raw, 3, &result->to) != 1) return ctx_set_error(ctx, "invalid to in txdata", IN3_EINVAL); - if (rlp_decode_in_list(&raw, 4, &result->value) != 1) return ctx_set_error(ctx, "invalid value in txdata", IN3_EINVAL); - if (rlp_decode_in_list(&raw, 5, &result->data) != 1) return ctx_set_error(ctx, "invalid data in txdata", IN3_EINVAL); - if (rlp_decode_in_list(&raw, 6, &result->v) != 1) return ctx_set_error(ctx, "invalid v in txdata", IN3_EINVAL); +static in3_ret_t decode_tx(in3_req_t* ctx, bytes_t raw, tx_data_t* result) { + if (rlp_decode_in_list(&raw, 0, &result->nonce) != 1) return req_set_error(ctx, "invalid nonce in txdata", IN3_EINVAL); + if (rlp_decode_in_list(&raw, 1, &result->gas_price) != 1) return req_set_error(ctx, "invalid gasprice in txdata", IN3_EINVAL); + if (rlp_decode_in_list(&raw, 2, &result->gas) != 1) return req_set_error(ctx, "invalid gas in txdata", IN3_EINVAL); + if (rlp_decode_in_list(&raw, 3, &result->to) != 1) return req_set_error(ctx, "invalid to in txdata", IN3_EINVAL); + if (rlp_decode_in_list(&raw, 4, &result->value) != 1) return req_set_error(ctx, "invalid value in txdata", IN3_EINVAL); + if (rlp_decode_in_list(&raw, 5, &result->data) != 1) return req_set_error(ctx, "invalid data in txdata", IN3_EINVAL); + if (rlp_decode_in_list(&raw, 6, &result->v) != 1) return req_set_error(ctx, "invalid v in txdata", IN3_EINVAL); return IN3_OK; } -static in3_ret_t call(in3_ctx_t* parent, address_t ms, bytes_t data, bytes_t** result) { +static in3_ret_t call(in3_req_t* parent, address_t ms, bytes_t data, bytes_t** result) { if (!parent) return IN3_EINVAL; - in3_ctx_t* ctx = parent; + in3_req_t* ctx = parent; for (; ctx; ctx = ctx->required) { - if (strcmp(d_get_stringk(ctx->requests[0], K_METHOD), "eth_call")) continue; + if (strcmp(d_get_string(ctx->requests[0], K_METHOD), "eth_call")) continue; d_token_t* t = d_get(ctx->requests[0], K_PARAMS); if (!t || d_type(t) != T_ARRAY || !d_len(t)) continue; t = t + 1; @@ -102,18 +102,18 @@ static in3_ret_t call(in3_ctx_t* parent, address_t ms, bytes_t data, bytes_t** r } if (ctx) - switch (in3_ctx_state(ctx)) { - case CTX_ERROR: - return ctx_set_error(parent, ctx->error, ctx->verification_state ? ctx->verification_state : IN3_ERPC); - case CTX_SUCCESS: - *result = d_get_bytesk(ctx->responses[0], K_RESULT); + switch (in3_req_state(ctx)) { + case REQ_ERROR: + return req_set_error(parent, ctx->error, ctx->verification_state ? ctx->verification_state : IN3_ERPC); + case REQ_SUCCESS: + *result = d_get_bytes(ctx->responses[0], K_RESULT); if (!*result) { - char* s = d_get_stringk(d_get(ctx->responses[0], K_ERROR), K_MESSAGE); - return ctx_set_error(parent, s ? s : "error executing eth_call", IN3_ERPC); + char* s = d_get_string(d_get(ctx->responses[0], K_ERROR), K_MESSAGE); + return req_set_error(parent, s ? s : "error executing eth_call", IN3_ERPC); } return IN3_OK; - case CTX_WAITING_TO_SEND: - case CTX_WAITING_FOR_RESPONSE: + case REQ_WAITING_TO_SEND: + case REQ_WAITING_FOR_RESPONSE: return IN3_WAITING; } @@ -123,7 +123,7 @@ static in3_ret_t call(in3_ctx_t* parent, address_t ms, bytes_t data, bytes_t** r sb_add_bytes(&sb, "{\"method\":\"eth_call\",\"params\":[{\"to\":", &tmp, 1, false); sb_add_bytes(&sb, ",\"data\":", &data, 1, false); sb_add_chars(&sb, "},\"latest\"]}"); - return ctx_add_required(parent, ctx_new(parent->client, sb.data)); + return req_add_required(parent, req_new(parent->client, sb.data)); } static void cpy_right(uint8_t* raw, int index, bytes_t data) { @@ -143,7 +143,7 @@ static bytes_t create_signatures(sig_data_t* signatures, uint32_t sig_count) { return bb.b; } -in3_ret_t get_tx_hash(in3_ctx_t* ctx, multisig_t* ms, tx_data_t* tx_data, bytes32_t result, uint64_t nonce) { +in3_ret_t get_tx_hash(in3_req_t* ctx, multisig_t* ms, tx_data_t* tx_data, bytes32_t result, uint64_t nonce) { /* d8d11f78: getTransactionHash(address,uint256,bytes,uint8,uint256,uint256,uint256,address,address,uint256) ' address to,'+ @@ -174,7 +174,7 @@ in3_ret_t get_tx_hash(in3_ctx_t* ctx, multisig_t* ms, tx_data_t* tx_data, bytes3 long_to_bytes(nonce, raw + 4 + 9 * 32 + 24); TRY(call(ctx, ms->address, bytes(raw, size), &rpc_result)) - if (rpc_result->len != 32) return ctx_set_error(ctx, "invalid getTransactionHash result!", IN3_EINVAL); + if (rpc_result->len != 32) return req_set_error(ctx, "invalid getTransactionHash result!", IN3_EINVAL); memcpy(result, rpc_result->data, 32); return IN3_OK; } @@ -221,7 +221,7 @@ static bool is_valid(sig_data_t* data, multisig_t* ms, address_t new_sig, int si return true; } -static in3_ret_t fill_signature(in3_ctx_t* ctx, bytes_t* signatures, uint32_t* sig_count, multisig_t* ms, sig_data_t* sig_data, bytes32_t tx_hash) { +static in3_ret_t fill_signature(in3_req_t* ctx, bytes_t* signatures, uint32_t* sig_count, multisig_t* ms, sig_data_t* sig_data, bytes32_t tx_hash) { // check passed signatures if (!signatures) return IN3_OK; uint32_t index = *sig_count; @@ -240,19 +240,19 @@ static in3_ret_t fill_signature(in3_ctx_t* ctx, bytes_t* signatures, uint32_t* s sig_data[index].data = bytes(NULL, 0); } else if (v > 26) { - if (!ecrecover_sig(tx_hash, signatures->data + i, sig_data[index].address)) return ctx_set_error(ctx, "could not recover the signature", IN3_EINVAL); + if (!ecrecover_sig(tx_hash, signatures->data + i, sig_data[index].address)) return req_set_error(ctx, "could not recover the signature", IN3_EINVAL); memcpy(sig_data[index].sig, signatures->data + i, 65); sig_data[index].data = bytes(NULL, 0); } else - return ctx_set_error(ctx, "invalid signature (v-value)", IN3_EINVAL); + return req_set_error(ctx, "invalid signature (v-value)", IN3_EINVAL); if (is_valid(sig_data, ms, sig_data[index].address, index)) index++; } *sig_count = index; return IN3_OK; } -static in3_ret_t add_approved(in3_ctx_t* ctx, uint32_t* sig_count, sig_data_t* sig_data, bytes32_t tx_hash, multisig_t* ms) { +static in3_ret_t add_approved(in3_req_t* ctx, uint32_t* sig_count, sig_data_t* sig_data, bytes32_t tx_hash, multisig_t* ms) { // we don't have enough signatures, so we need to check if owners have preapproved for (unsigned int i = 0; i < ms->owners_len && *sig_count < ms->threshold; i++) { if (is_valid(sig_data, ms, (void*) ms->owners + i, *sig_count)) { @@ -264,7 +264,7 @@ static in3_ret_t add_approved(in3_ctx_t* ctx, uint32_t* sig_count, sig_data_t* s memcpy(check_approved + 16, ms->owners + i, 20); memcpy(check_approved + 36, tx_hash, 32); TRY(call(ctx, ms->address, bytes(check_approved, 68), &result)) - if (!result || result->len != 32) return ctx_set_error(ctx, "invalid response for approved check", IN3_EINVAL); + if (!result || result->len != 32) return req_set_error(ctx, "invalid response for approved check", IN3_EINVAL); if (result->data[31]) { memset(sig_data + *sig_count, 0, sizeof(sig_data_t)); memcpy(sig_data[*sig_count].sig + 12, ms->owners + i, 20); @@ -324,31 +324,31 @@ static void approve_hash(bytes_t* target, tx_data_t* tx_data, bytes32_t hash, ad *target = bb.b; } -static in3_ret_t ensure_ms_type(multisig_t* ms, in3_ctx_t* ctx) { +static in3_ret_t ensure_ms_type(multisig_t* ms, in3_req_t* ctx) { if (ms->type == MS_UNKNOWN) { bytes_t* tmp = NULL; TRY(call(ctx, ms->address, bytes((uint8_t*) "\xa3\xf4\xdf\x7e", 4), &tmp)) - if (!tmp || tmp->len < 96) return ctx_set_error(ctx, "invalid MultiSig Name", IN3_ENOTSUP); + if (!tmp || tmp->len < 96) return req_set_error(ctx, "invalid MultiSig Name", IN3_ENOTSUP); char* name = (void*) tmp->data + 64; if (strcmp(name, "Gnosis Safe") == 0) ms->type = MS_GNOSIS_SAFE; else if (strcmp(name, "IAMO Safe") == 0) ms->type = MS_IAMO_SAFE; else - return ctx_set_error(ctx, "unknwon MultiSig TYPE", IN3_ENOTSUP); + return req_set_error(ctx, "unknwon MultiSig TYPE", IN3_ENOTSUP); } return IN3_OK; } -static in3_ret_t ensure_owners(multisig_t* ms, in3_ctx_t* ctx) { +static in3_ret_t ensure_owners(multisig_t* ms, in3_req_t* ctx) { if (ms->owners == NULL) { // init the owners first bytes_t* tmp = NULL; in3_ret_t ret = call(ctx, ms->address, bytes((uint8_t*) "\xa0\xe6\x7e\x2b", 4), &tmp); if (ret == IN3_OK) { - if (!tmp || tmp->len < 64) return ctx_set_error(ctx, "invalid owner result", IN3_ERPC); + if (!tmp || tmp->len < 64) return req_set_error(ctx, "invalid owner result", IN3_ERPC); ms->owners_len = bytes_to_int(tmp->data + 32 + 28, 4); ms->owners = _malloc(sizeof(address_t) * ms->owners_len); - if (tmp->len != 64 + 32 * ms->owners_len) return ctx_set_error(ctx, "invalid owner result length", IN3_ERPC); + if (tmp->len != 64 + 32 * ms->owners_len) return req_set_error(ctx, "invalid owner result length", IN3_ERPC); for (unsigned int i = 0; i < ms->owners_len; i++) memcpy(ms->owners + i, tmp->data + i * 32 + 64 + 12, 20); } else if (ret != IN3_WAITING) @@ -357,7 +357,7 @@ static in3_ret_t ensure_owners(multisig_t* ms, in3_ctx_t* ctx) { // get the threshold in3_ret_t ret2 = call(ctx, ms->address, bytes((uint8_t*) "\xe7\x52\x35\xb8", 4), &tmp); if (ret2 == IN3_OK) { - if (!tmp || tmp->len != 32) return ctx_set_error(ctx, "invalid threshold result", IN3_ERPC); + if (!tmp || tmp->len != 32) return req_set_error(ctx, "invalid threshold result", IN3_ERPC); ms->threshold = bytes_to_int(tmp->data + 28, 4); } @@ -369,7 +369,7 @@ static in3_ret_t ensure_owners(multisig_t* ms, in3_ctx_t* ctx) { in3_ret_t gs_prepare_tx(multisig_t* ms, in3_sign_prepare_ctx_t* prepare_ctx) { bytes_t raw_tx = prepare_ctx->old_tx; bytes_t* new_raw_tx = &prepare_ctx->new_tx; - in3_ctx_t* ctx = prepare_ctx->ctx; + in3_req_t* ctx = prepare_ctx->req; bytes_t* tmp = NULL; uint32_t sig_count = 0; uint64_t nonce = 0; @@ -384,7 +384,7 @@ in3_ret_t gs_prepare_tx(multisig_t* ms, in3_sign_prepare_ctx_t* prepare_ctx) { // get nonce in3_ret_t ret2 = call(ctx, ms->address, bytes((uint8_t*) "\xaf\xfe\xd0\xe0", 4), &tmp); if (ret2 == IN3_OK) { - if (!tmp || tmp->len != 32) return ctx_set_error(ctx, "invalid nonce result", IN3_ERPC); + if (!tmp || tmp->len != 32) return req_set_error(ctx, "invalid nonce result", IN3_ERPC); nonce = bytes_to_long(tmp->data + 24, 8); } else @@ -411,7 +411,7 @@ in3_ret_t gs_prepare_tx(multisig_t* ms, in3_sign_prepare_ctx_t* prepare_ctx) { TRY(get_tx_hash(ctx, ms, &tx_data, tx_hash, nonce)) // verifiy and copy the passed signatures into sig_data - TRY(fill_signature(ctx, d_get_bytes(d_get(ctx->requests[0], K_IN3), "msSigs"), &sig_count, ms, sig_data, tx_hash)) + TRY(fill_signature(ctx, d_get_bytes(d_get(ctx->requests[0], K_IN3), key("msSigs")), &sig_count, ms, sig_data, tx_hash)) // look for already approved messages from owners where we don't have the signature yet. TRY(add_approved(ctx, &sig_count, sig_data, tx_hash, ms)) @@ -423,7 +423,7 @@ in3_ret_t gs_prepare_tx(multisig_t* ms, in3_sign_prepare_ctx_t* prepare_ctx) { // if not we simply approve it approve_hash(new_raw_tx, &tx_data, tx_hash, ms->address); else - return ctx_set_error(ctx, "the account is not an owner and does not have enough signatures to exwecute the transaction!", IN3_EINVAL); + return req_set_error(ctx, "the account is not an owner and does not have enough signatures to exwecute the transaction!", IN3_EINVAL); return IN3_OK; } @@ -433,13 +433,13 @@ in3_ret_t gs_create_contract_signature(multisig_t* ms, in3_sign_ctx_t* ctx) { if (ctx->account.len != 20 || memcmp(ms->address, ctx->account.data, 20)) return IN3_EIGNORE; // make sure we know the type of Multisig - TRY(ensure_ms_type(ms, ctx->ctx)) + TRY(ensure_ms_type(ms, ctx->req)) // calculate the hash bytes32_t hash; switch (ctx->type) { case SIGN_EC_RAW: // already hashed - if (ctx->message.len != 32) return ctx_set_error(ctx->ctx, "invalid message, must be a 256bit hash", IN3_EINVAL); + if (ctx->message.len != 32) return req_set_error(ctx->req, "invalid message, must be a 256bit hash", IN3_EINVAL); if (ms->type == MS_IAMO_SAFE) keccak(ctx->message, hash); else @@ -450,8 +450,8 @@ in3_ret_t gs_create_contract_signature(multisig_t* ms, in3_sign_ctx_t* ctx) { if (memiszero(ms->domain_sep, 32)) { // TODO get it from cache bytes_t* result = NULL; - TRY(call(ctx->ctx, ms->address, bytes((uint8_t*) "\xf6\x98\xda\x25", 4), &result)) - if (!result || result->len != 32) return ctx_set_error(ctx->ctx, "invalid domain_seperator", IN3_EINVAL); + TRY(call(ctx->req, ms->address, bytes((uint8_t*) "\xf6\x98\xda\x25", 4), &result)) + if (!result || result->len != 32) return req_set_error(ctx->req, "invalid domain_seperator", IN3_EINVAL); memcpy(ms->domain_sep, result->data, 32); // TODO put it in cache } @@ -476,15 +476,15 @@ in3_ret_t gs_create_contract_signature(multisig_t* ms, in3_sign_ctx_t* ctx) { } // get Owners - TRY(ensure_owners(ms, ctx->ctx)) + TRY(ensure_owners(ms, ctx->req)) // prepare signatures sig_data_t* sig_data = alloca(sizeof(sig_data_t) * ms->threshold); unsigned int sig_count = 0; // find all available signer-accounts - in3_sign_account_ctx_t sctx = {.ctx = ctx->ctx, .accounts = NULL, .accounts_len = 0}; - for (in3_plugin_t* p = ctx->ctx->client->plugins; p && sig_count < ms->threshold; p = p->next) { + in3_sign_account_ctx_t sctx = {.req = ctx->req, .accounts = NULL, .accounts_len = 0}; + for (in3_plugin_t* p = ctx->req->client->plugins; p && sig_count < ms->threshold; p = p->next) { sctx.accounts = NULL; sctx.accounts_len = 0; if (p->acts & (PLGN_ACT_SIGN_ACCOUNT | PLGN_ACT_SIGN) && p->action_fn(p->data, PLGN_ACT_SIGN_ACCOUNT, &sctx) == IN3_OK && sctx.accounts_len) { @@ -492,7 +492,7 @@ in3_ret_t gs_create_contract_signature(multisig_t* ms, in3_sign_ctx_t* ctx) { uint8_t* account = sctx.accounts + i * 20; if (is_valid(sig_data, ms, account, sig_count)) { bytes_t signature = bytes(NULL, 0); - TRY(ctx_require_signature(ctx->ctx, SIGN_EC_RAW, &signature, bytes(hash, 32), bytes(account, 20))) + TRY(req_require_signature(ctx->req, SIGN_EC_RAW, &signature, bytes(hash, 32), bytes(account, 20))) sig_data[sig_count].address = NULL; for (unsigned int n = 0; n < ms->owners_len; n++) { if (memcmp(ms->owners + n, account, 20) == 0) sig_data[sig_count].address = (void*) (ms->owners + n); @@ -509,12 +509,12 @@ in3_ret_t gs_create_contract_signature(multisig_t* ms, in3_sign_ctx_t* ctx) { } // look for already approved messages from owners where we don't have the signature yet. - TRY(add_approved(ctx->ctx, &sig_count, sig_data, hash, ms)) + TRY(add_approved(ctx->req, &sig_count, sig_data, hash, ms)) if (sig_count >= ms->threshold) ctx->signature = create_signatures(sig_data, sig_count); else - return ctx_set_error(ctx->ctx, "the account is not an owner and does not have enough signatures to sign this messagen!", IN3_EINVAL); + return req_set_error(ctx->req, "the account is not an owner and does not have enough signatures to sign this messagen!", IN3_EINVAL); return IN3_OK; } diff --git a/c/src/signer/pk-signer/signer.c b/c/src/signer/pk-signer/signer.c index 15ce74fb2..e02383b6b 100644 --- a/c/src/signer/pk-signer/signer.c +++ b/c/src/signer/pk-signer/signer.c @@ -33,9 +33,9 @@ *******************************************************************************/ #include "signer.h" -#include "../../core/client/context_internal.h" #include "../../core/client/keys.h" #include "../../core/client/plugin.h" +#include "../../core/client/request_internal.h" #include "../../core/util/mem.h" #include "../../core/util/utils.h" #include "../../third-party/crypto/ecdsa.h" @@ -140,7 +140,7 @@ static in3_ret_t pk_rpc(void* data, in3_plugin_act_t action, void* action_ctx) { in3_configure_ctx_t* ctx = action_ctx; if (ctx->token->key == key("key")) { if (d_type(ctx->token) != T_BYTES || d_len(ctx->token) != 32) { - ctx->error_msg = "invalid key-length, must be 32"; + ctx->error_msg = _strdupn("invalid key-length, must be 32", -1); return IN3_EINVAL; } eth_set_request_signer(ctx->client, ctx->token->data); @@ -149,7 +149,7 @@ static in3_ret_t pk_rpc(void* data, in3_plugin_act_t action, void* action_ctx) { if (ctx->token->key == key("pk")) { if (d_type(ctx->token) == T_BYTES) { if (d_len(ctx->token) != 32) { - ctx->error_msg = "invalid key-length, must be 32"; + ctx->error_msg = _strdupn("invalid key-length, must be 32", -1); return IN3_EINVAL; } add_key(ctx->client, d_bytes(ctx->token)->data); @@ -159,7 +159,7 @@ static in3_ret_t pk_rpc(void* data, in3_plugin_act_t action, void* action_ctx) { for (d_iterator_t iter = d_iter(ctx->token); iter.left; d_iter_next(&iter)) { if (d_type(iter.token) == T_BYTES) { if (d_len(iter.token) != 32) { - ctx->error_msg = "invalid key-length, must be 32"; + ctx->error_msg = _strdupn("invalid key-length, must be 32", -1); return IN3_EINVAL; } add_key(ctx->client, d_bytes(iter.token)->data); @@ -167,29 +167,27 @@ static in3_ret_t pk_rpc(void* data, in3_plugin_act_t action, void* action_ctx) { } return IN3_OK; } - ctx->error_msg = "invalid type for a pk"; + ctx->error_msg = _strdupn("invalid type for a pk", -1); return IN3_EINVAL; } return IN3_EIGNORE; } case PLGN_ACT_RPC_HANDLE: { - in3_rpc_handle_ctx_t* ctx = action_ctx; - char* method = d_get_stringk(ctx->request, K_METHOD); - if (strcmp(method, "in3_addRawKey") == 0) { - d_token_t* t = d_get(ctx->request, K_PARAMS); - if (d_len(t) != 1 || d_type(t + 1) != T_BYTES || d_len(t + 1) != 32) - return ctx_set_error(ctx->ctx, "one argument with 32 bytes is required!", IN3_EINVAL); + in3_rpc_handle_ctx_t* ctx = action_ctx; + if (strcmp(ctx->method, "in3_addRawKey") == 0) { + if (d_len(ctx->params) != 1 || d_type(ctx->params + 1) != T_BYTES || d_len(ctx->params + 1) != 32) + return req_set_error(ctx->req, "one argument with 32 bytes is required!", IN3_EINVAL); address_t adr; - get_address(d_bytes(t + 1)->data, adr); - add_key(ctx->ctx->client, d_bytes(t + 1)->data); + get_address(d_bytes(ctx->params + 1)->data, adr); + add_key(ctx->req->client, d_bytes(ctx->params + 1)->data); return in3_rpc_handle_with_bytes(ctx, bytes(adr, 20)); } - if (strcmp(method, "eth_accounts") == 0) { + if (strcmp(ctx->method, "eth_accounts") == 0) { sb_t* sb = in3_rpc_handle_start(ctx); bool first = true; - in3_sign_account_ctx_t sc = {.ctx = ctx->ctx, .accounts = NULL, .accounts_len = 0, .signer_type = 0}; - for (in3_plugin_t* p = ctx->ctx->client->plugins; p; p = p->next) { + in3_sign_account_ctx_t sc = {.req = ctx->req, .accounts = NULL, .accounts_len = 0, .signer_type = 0}; + for (in3_plugin_t* p = ctx->req->client->plugins; p; p = p->next) { if (p->acts & PLGN_ACT_SIGN_ACCOUNT && p->action_fn(p->data, PLGN_ACT_SIGN_ACCOUNT, &sc) == IN3_OK) { for (int i = 0; i < sc.accounts_len; i++) { sb_add_rawbytes(sb, first ? "[\"0x" : "\",\"0x", bytes(sc.accounts + i * 20, 20), 20); @@ -219,7 +217,23 @@ in3_ret_t eth_sign_req(void* data, in3_plugin_act_t action, void* action_ctx) { switch (action) { case PLGN_ACT_PAY_SIGN_REQ: { in3_pay_sign_req_ctx_t* ctx = action_ctx; - return ec_sign_pk_raw(ctx->request_hash, k->pk, ctx->signature); + in3_ret_t r = ec_sign_pk_raw(ctx->request_hash, k->pk, ctx->signature); + ctx->signature[64] += 27; + return r; + } + case PLGN_ACT_SIGN: { + in3_sign_ctx_t* ctx = action_ctx; + if (ctx->account.len != 20 || memcmp(k->account, ctx->account.data, 20)) return IN3_EIGNORE; + ctx->signature = bytes(_malloc(65), 65); + switch (ctx->type) { + case SIGN_EC_RAW: + return ec_sign_pk_raw(ctx->message.data, k->pk, ctx->signature.data); + case SIGN_EC_HASH: + return ec_sign_pk_hash(ctx->message.data, ctx->message.len, k->pk, hasher_sha3k, ctx->signature.data); + default: + _free(ctx->signature.data); + return IN3_ENOTSUP; + } } case PLGN_ACT_TERM: { @@ -236,7 +250,8 @@ in3_ret_t eth_sign_req(void* data, in3_plugin_act_t action, void* action_ctx) { in3_ret_t eth_set_request_signer(in3_t* in3, bytes32_t pk) { signer_key_t* k = _malloc(sizeof(signer_key_t)); memcpy(k->pk, pk, 32); - return in3_plugin_register(in3, PLGN_ACT_PAY_SIGN_REQ | PLGN_ACT_TERM, eth_sign_req, k, true); + get_address(pk, k->account); + return in3_plugin_register(in3, PLGN_ACT_PAY_SIGN_REQ | PLGN_ACT_TERM | PLGN_ACT_SIGN, eth_sign_req, k, true); } in3_ret_t eth_register_pk_signer(in3_t* in3) { diff --git a/c/src/third-party/zkcrypto/rust/CMakeLists.txt b/c/src/third-party/zkcrypto/rust/CMakeLists.txt index a72d36f49..f66a77a66 100644 --- a/c/src/third-party/zkcrypto/rust/CMakeLists.txt +++ b/c/src/third-party/zkcrypto/rust/CMakeLists.txt @@ -56,5 +56,7 @@ add_static_library( DEPENDS core zk_crypto_rs + dl + m ) diff --git a/c/src/tools/clientdata/client_data.c b/c/src/tools/clientdata/client_data.c index 008480dd3..e97514ff7 100644 --- a/c/src/tools/clientdata/client_data.c +++ b/c/src/tools/clientdata/client_data.c @@ -17,5 +17,5 @@ void* in3_plugin_get_client_data(in3_t* c) { } in3_ret_t in3_register_client_data(in3_t* c, void* data) { - return in3_plugin_register(c, PLGN_ACT_GET_DATA | PLGN_ACT_ADD_PAYLOAD, in3_plugin_client_data, data, true); + return in3_plugin_register(c, PLGN_ACT_GET_DATA, in3_plugin_client_data, data, true); } diff --git a/c/src/tools/recorder/recorder.c b/c/src/tools/recorder/recorder.c index 1bb26d9a1..4cf7ee0af 100644 --- a/c/src/tools/recorder/recorder.c +++ b/c/src/tools/recorder/recorder.c @@ -1,6 +1,6 @@ #include "recorder.h" -#include "../../core/client/context_internal.h" #include "../../core/client/keys.h" +#include "../../core/client/request_internal.h" #include #include #include @@ -120,14 +120,14 @@ static int rand_in(void* s) { static in3_ret_t recorder_transport_in(void* plugin_data, in3_plugin_act_t action, void* plugin_ctx) { UNUSED_VAR(plugin_data); - in3_request_t* req = plugin_ctx; + in3_http_request_t* req = plugin_ctx; if (action == PLGN_ACT_TRANSPORT_SEND) { entry_free(next_entry("request", NULL)); req->cptr = &rec; } if (action != PLGN_ACT_TRANSPORT_CLEAN) { - recorder_entry_t* entry = next_entry("response", d_get_stringk(req->ctx->requests[0], K_METHOD)); - in3_response_t* r = req->ctx->raw_response + atoi(entry->args[1]); + recorder_entry_t* entry = next_entry("response", d_get_string(req->req->requests[0], K_METHOD)); + in3_response_t* r = req->req->raw_response + atoi(entry->args[1]); sb_add_chars(&r->data, entry->content.data); r->state = atoi(entry->args[3]); r->time = atoi(entry->args[4]); @@ -139,12 +139,12 @@ static in3_ret_t recorder_transport_in(void* plugin_data, in3_plugin_act_t actio static in3_ret_t recorder_transport_out(void* plugin_data, in3_plugin_act_t action, void* plugin_ctx) { UNUSED_VAR(plugin_data); - in3_request_t* req = plugin_ctx; - node_match_t* m = req->ctx->nodes; - in3_ret_t res = rec.transport(NULL, action, plugin_ctx); + in3_http_request_t* req = plugin_ctx; + node_match_t* m = req->req->nodes; + in3_ret_t res = rec.transport(NULL, action, plugin_ctx); if (action == PLGN_ACT_TRANSPORT_SEND) { fprintf(rec.f, ":: request "); - char* rpc = d_get_stringk(d_get(req->ctx->requests[0], K_IN3), K_RPC); + char* rpc = d_get_string(d_get(req->req->requests[0], K_IN3), K_RPC); if (rpc) fprintf(rec.f, "%s ", rpc); else { @@ -155,14 +155,14 @@ static in3_ret_t recorder_transport_out(void* plugin_data, in3_plugin_act_t acti fflush(rec.f); } if (action != PLGN_ACT_TRANSPORT_CLEAN) { - m = req->ctx->nodes; - char* rpc = d_get_stringk(d_get(req->ctx->requests[0], K_IN3), K_RPC); - int l = rpc ? 1 : ctx_nodes_len(m); + m = req->req->nodes; + char* rpc = d_get_string(d_get(req->req->requests[0], K_IN3), K_RPC); + int l = rpc ? 1 : req_nodes_len(m); for (int i = 0; i < l; i++, m = m ? m->next : NULL) { - in3_response_t* r = req->ctx->raw_response + i; + in3_response_t* r = req->req->raw_response + i; if (m) rpc = m->url; if (r->time) { - fprintf(rec.f, ":: response %s %i %s %i %i\n", d_get_stringk(req->ctx->requests[0], K_METHOD), i, rpc, r->state, r->time); + fprintf(rec.f, ":: response %s %i %s %i %i\n", d_get_string(req->req->requests[0], K_METHOD), i, rpc, r->state, r->time); char* data = format_json(r->data.data ? r->data.data : ""); fprintf(rec.f, "%s\n\n", data); fflush(rec.f); diff --git a/c/src/tools/sentry/sentry.c b/c/src/tools/sentry/sentry.c index 2473accd7..bc958e44f 100644 --- a/c/src/tools/sentry/sentry.c +++ b/c/src/tools/sentry/sentry.c @@ -25,14 +25,14 @@ static in3_ret_t handle_sentry(void* cptr, in3_plugin_act_t action, void* arg) { char* res = NULL; char* req = NULL; - if (t->ctx->request_context) { - req = t->ctx->request_context->c; + if (t->req->request_context) { + req = t->req->request_context->c; } - if (t->ctx->response_context) { - res = t->ctx->response_context->c; + if (t->req->response_context) { + res = t->req->response_context->c; } - else if (t->ctx->raw_response) { - res = t->ctx->raw_response->data.data; + else if (t->req->raw_response) { + res = t->req->raw_response->data.data; } if (req) { @@ -43,7 +43,7 @@ static in3_ret_t handle_sentry(void* cptr, in3_plugin_act_t action, void* arg) { sentry_value_t crumb_res = sentry_value_new_breadcrumb(0, res); sentry_add_breadcrumb(crumb_res); } - char* conf = in3_get_config(t->ctx->client); + char* conf = in3_get_config(t->req->client); sentry_add_breadcrumb(sentry_value_new_breadcrumb(0, conf)); _free(conf); diff --git a/c/src/transport/curl/in3_curl.c b/c/src/transport/curl/in3_curl.c index 0b30ff981..1ae201fe0 100644 --- a/c/src/transport/curl/in3_curl.c +++ b/c/src/transport/curl/in3_curl.c @@ -64,22 +64,23 @@ static size_t WriteMemoryCallback(void* contents, size_t size, size_t nmemb, voi return size * nmemb; } -static void readDataNonBlocking(CURLM* cm, const char* url, const char* payload, struct curl_slist* headers, in3_response_t* r, uint32_t timeout) { +static void readDataNonBlocking(CURLM* cm, const char* url, const char* payload, uint32_t payload_len, struct curl_slist* headers, in3_response_t* r, uint32_t timeout, char* method) { CURL* curl; CURLMcode res; curl = curl_easy_init(); if (curl) { curl_easy_setopt(curl, CURLOPT_URL, url); - if (payload && *payload) { + if (payload && payload_len) { curl_easy_setopt(curl, CURLOPT_POSTFIELDS, payload); - curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (long) strlen(payload)); + curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (long) payload_len); } curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*) r); curl_easy_setopt(curl, CURLOPT_TIMEOUT, (uint64_t) timeout / 1000L); curl_easy_setopt(curl, CURLOPT_PRIVATE, (void*) r); + curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, method); /* Perform the request, res will get the return code */ res = curl_multi_add_handle(cm, curl); @@ -95,7 +96,7 @@ static void readDataNonBlocking(CURLM* cm, const char* url, const char* payload, } } -in3_ret_t receive_next(in3_request_t* req) { +in3_ret_t receive_next(in3_http_request_t* req) { in3_curl_t* c = req->cptr; CURLMsg* msg; int msgs_left = -1; @@ -120,9 +121,15 @@ in3_ret_t receive_next(in3_request_t* req) { else if (response_code > 100 && response_code < 400) response->state = IN3_OK; else { - if (!response->data.len) - sb_add_chars(&response->data, "returned with invalid status code"); - response->state = IN3_ERPC; + if (!response->data.len) { + sb_add_chars(&response->data, "returned with invalid status code "); + sb_add_int(&response->data, response_code); + } + response->state = -response_code; + } + if (!response->data.data) { + response->data.data = _calloc(1, 1); + response->data.allocted = 1; } curl_multi_remove_handle(c->cm, e); curl_easy_cleanup(e); @@ -146,7 +153,7 @@ in3_ret_t cleanup(in3_curl_t* c) { return IN3_OK; } -in3_ret_t send_curl_nonblocking(in3_request_t* req) { +in3_ret_t send_curl_nonblocking(in3_http_request_t* req) { // init the cptr in3_curl_t* c = _malloc(sizeof(in3_curl_t)); @@ -159,12 +166,13 @@ in3_ret_t send_curl_nonblocking(in3_request_t* req) { struct curl_slist* headers = curl_slist_append(NULL, "Accept: application/json"); if (req->payload && *req->payload) headers = curl_slist_append(headers, "Content-Type: application/json"); - headers = curl_slist_append(headers, "charsets: utf-8"); + headers = curl_slist_append(headers, "charsets: utf-8"); + for (in3_req_header_t* h = req->headers; h; h = h->next) headers = curl_slist_append(headers, h->value); c->headers = curl_slist_append(headers, "User-Agent: in3 curl " IN3_VERSION); // create requests for (unsigned int i = 0; i < req->urls_len; i++) - readDataNonBlocking(c->cm, req->urls[i], req->payload, c->headers, req->ctx->raw_response + i, req->ctx->client->timeout); + readDataNonBlocking(c->cm, req->urls[i], req->payload, req->payload_len, c->headers, req->req->raw_response + i, req->req->client->timeout, req->method); in3_ret_t res = receive_next(req); if (req->urls_len == 1) { @@ -174,38 +182,49 @@ in3_ret_t send_curl_nonblocking(in3_request_t* req) { return res; } -static void readDataBlocking(const char* url, char* payload, in3_response_t* r, uint32_t timeout) { +static void readDataBlocking(const char* url, char* payload, in3_response_t* r, uint32_t timeout, in3_http_request_t* req) { CURL* curl; CURLcode res; curl = curl_easy_init(); if (curl) { curl_easy_setopt(curl, CURLOPT_URL, url); - if (payload && *payload) { + if (payload && req->payload_len) { curl_easy_setopt(curl, CURLOPT_POSTFIELDS, payload); - curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (long) strlen(payload)); + curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (long) req->payload_len); } struct curl_slist* headers = NULL; headers = curl_slist_append(headers, "Accept: application/json"); - if (payload && *payload) + if (payload && req->payload_len) headers = curl_slist_append(headers, "Content-Type: application/json"); headers = curl_slist_append(headers, "charsets: utf-8"); headers = curl_slist_append(headers, "User-Agent: in3 curl " IN3_VERSION); + for (in3_req_header_t* h = req->headers; h; h = h->next) { + if (strchr(h->value, ':')) headers = curl_slist_append(headers, h->value); + } curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*) r); curl_easy_setopt(curl, CURLOPT_TIMEOUT, (uint64_t) timeout / 1000L); + curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, req->method); /* Perform the request, res will get the return code */ res = curl_easy_perform(curl); /* Check for errors */ if (res != CURLE_OK) { + long response_code; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code); + sb_add_chars(&r->data, "Invalid response:"); sb_add_chars(&r->data, (char*) curl_easy_strerror(res)); - r->state = IN3_ERPC; + r->state = -response_code; } else r->state = IN3_OK; + if (!r->data.data) { + r->data.data = _calloc(1, 1); + r->data.allocted = 1; + } curl_slist_free_all(headers); /* always cleanup */ @@ -217,10 +236,10 @@ static void readDataBlocking(const char* url, char* payload, in3_response_t* r, } } -in3_ret_t send_curl_blocking(const char** urls, int urls_len, char* payload, in3_response_t* result, uint32_t timeout) { +in3_ret_t send_curl_blocking(const char** urls, int urls_len, char* payload, in3_response_t* result, uint32_t timeout, in3_http_request_t* req) { int i; for (i = 0; i < urls_len; i++) - readDataBlocking(urls[i], payload, result + i, timeout); + readDataBlocking(urls[i], payload, result + i, timeout, req); for (i = 0; i < urls_len; i++) { if ((result + i)->state) { in3_log_debug("curl: failed for %s\n", urls[i]); @@ -232,14 +251,14 @@ in3_ret_t send_curl_blocking(const char** urls, int urls_len, char* payload, in3 in3_ret_t send_curl(void* plugin_data, in3_plugin_act_t action, void* plugin_ctx) { UNUSED_VAR(plugin_data); - in3_request_t* req = plugin_ctx; + in3_http_request_t* req = plugin_ctx; // set the init-time #ifdef CURL_BLOCKING in3_ret_t res; uint64_t start = current_ms(); - res = send_curl_blocking((const char**) req->urls, req->urls_len, req->payload, req->ctx->raw_response, req->ctx->client->timeout); + res = send_curl_blocking((const char**) req->urls, req->urls_len, req->payload, req->req->raw_response, req->req->client->timeout, req); uint32_t t = (uint32_t)(current_ms() - start); - for (int i = 0; i < req->urls_len; i++) req->ctx->raw_response[i].time = t; + for (int i = 0; i < req->urls_len; i++) req->req->raw_response[i].time = t; return res; #else switch (action) { diff --git a/c/src/transport/http/in3_http.c b/c/src/transport/http/in3_http.c index 9c9cb2490..f12d629d5 100644 --- a/c/src/transport/http/in3_http.c +++ b/c/src/transport/http/in3_http.c @@ -57,7 +57,7 @@ in3_ret_t send_http(void* plugin_data, in3_plugin_act_t action, void* plugin_ctx) { UNUSED_VAR(plugin_data); UNUSED_VAR(action); - in3_request_t* req = plugin_ctx; + in3_http_request_t* req = plugin_ctx; for (unsigned int n = 0; n < req->urls_len; n++) { struct hostent* server; @@ -72,7 +72,7 @@ in3_ret_t send_http(void* plugin_data, in3_plugin_act_t action, void* plugin_ctx // parse url if (strncmp(url, "http://", 7)) { - in3_ctx_add_response(req->ctx, n, true, "invalid url must sart with http", -1, 0); + in3_ctx_add_response(req->req, n, true, "invalid url must sart with http", -1, 0); continue; } @@ -102,13 +102,13 @@ in3_ret_t send_http(void* plugin_data, in3_plugin_act_t action, void* plugin_ctx SOCKET s; if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0) { - in3_ctx_add_response(req->ctx, n, true, "no socket available", -1, 0); + in3_ctx_add_response(req->req, n, true, "no socket available", -1, 0); continue; } //Create a socket if ((s = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) { - in3_ctx_add_response(req->ctx, n, true, "could not create the socket", -1, 0); + in3_ctx_add_response(req->req, n, true, "could not create the socket", -1, 0); continue; } @@ -122,24 +122,24 @@ in3_ret_t send_http(void* plugin_data, in3_plugin_act_t action, void* plugin_ctx memcpy(&serv_addr.sin_addr.s_addr, server->h_addr, server->h_length); //Connect to remote server if (connect(s, (struct sockaddr*) &serv_addr, sizeof(serv_addr)) < 0) { - in3_ctx_add_response(req->ctx, n, true, "Connection failed", -1, 0); + in3_ctx_add_response(req->req, n, true, "Connection failed", -1, 0); continue; } if (send(s, message, strlen(message), 0) < 0) { - in3_ctx_add_response(req->ctx, n, true, "Send failed", -1, 0); + in3_ctx_add_response(req->req, n, true, "Send failed", -1, 0); continue; } //Receive a reply from the server if ((received = recv(s, response, 2000, 0)) == SOCKET_ERROR) { - in3_ctx_add_response(req->ctx, n, true, "Receive failed", -1, 0); + in3_ctx_add_response(req->req, n, true, "Receive failed", -1, 0); continue; } //Add a NULL terminating character to make it a proper string before printing response[received] = '\0'; - in3_ctx_add_response(req->ctx, n, false, response, -1, 0); + in3_ctx_add_response(req->req, n, false, response, -1, 0); closesocket(s); WSACleanup(); @@ -147,12 +147,12 @@ in3_ret_t send_http(void* plugin_data, in3_plugin_act_t action, void* plugin_ctx int sockfd; server = gethostbyname(host); if (server == NULL) { - in3_ctx_add_response(req->ctx, n, true, "no such host", -1, 0); + in3_ctx_add_response(req->req, n, true, "no such host", -1, 0); continue; } sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { - in3_ctx_add_response(req->ctx, n, true, "ERROR opening socket", -1, 0); + in3_ctx_add_response(req->req, n, true, "ERROR opening socket", -1, 0); continue; } /* fill in the structreq->ure */ @@ -162,7 +162,7 @@ in3_ret_t send_http(void* plugin_data, in3_plugin_act_t action, void* plugin_ctx memcpy(&serv_addr.sin_addr.s_addr, server->h_addr_list[0], server->h_length); /* connect the socket */ if (connect(sockfd, (struct sockaddr*) &serv_addr, sizeof(serv_addr)) < 0) { - in3_ctx_add_response(req->ctx, n, true, "ERROR connecting", -1, 0); + in3_ctx_add_response(req->req, n, true, "ERROR connecting", -1, 0); continue; } /* send the request */ @@ -171,7 +171,7 @@ in3_ret_t send_http(void* plugin_data, in3_plugin_act_t action, void* plugin_ctx do { bytes = write(sockfd, message + sent, total - sent); if (bytes < 0) { - in3_ctx_add_response(req->ctx, n, true, "ERROR writing message to socket", -1, 0); + in3_ctx_add_response(req->req, n, true, "ERROR writing message to socket", -1, 0); continue; } if (bytes == 0) @@ -186,17 +186,17 @@ in3_ret_t send_http(void* plugin_data, in3_plugin_act_t action, void* plugin_ctx memset(response, 0, sizeof(response)); bytes = recv(sockfd, response, 1024, 0); if (bytes < 0) { - in3_ctx_add_response(req->ctx, n, true, "ERROR reading response from socket", -1, 0); + in3_ctx_add_response(req->req, n, true, "ERROR reading response from socket", -1, 0); continue; } if (bytes == 0) break; - in3_ctx_add_response(req->ctx, n, false, response, -1, 0); + in3_ctx_add_response(req->req, n, false, response, -1, 0); received += bytes; } while (1); if (received == total) { - in3_ctx_add_response(req->ctx, n, true, "ERROR storing complete response from socket", -1, 0); + in3_ctx_add_response(req->req, n, true, "ERROR storing complete response from socket", -1, 0); continue; } @@ -205,36 +205,36 @@ in3_ret_t send_http(void* plugin_data, in3_plugin_act_t action, void* plugin_ctx #endif - req->ctx->raw_response[n].time = (uint32_t)(current_ms() - start); + req->req->raw_response[n].time = (uint32_t)(current_ms() - start); // now evaluate the response - char *res = req->ctx->raw_response[n].data.data, *header = strstr(res, "\r\n\r\n"), *body = header + 4; + char *res = req->req->raw_response[n].data.data, *header = strstr(res, "\r\n\r\n"), *body = header + 4; if (!header) { - in3_ctx_add_response(req->ctx, n, true, "ERROR invalid response", -1, 0); + in3_ctx_add_response(req->req, n, true, "ERROR invalid response", -1, 0); continue; } *header = 0; header = strstr(res, "\r\n"); if (!header) { - in3_ctx_add_response(req->ctx, n, true, "ERROR invalid response", -1, 0); + in3_ctx_add_response(req->req, n, true, "ERROR invalid response", -1, 0); continue; } *header = 0; header = strtok(res, " "); if (header == NULL || (strcmp(header, "HTTP/1.1") && strcmp(header, "HTTP/1.0"))) { - in3_ctx_add_response(req->ctx, n, true, "ERROR invalid HTTP Version", -1, 0); + in3_ctx_add_response(req->req, n, true, "ERROR invalid HTTP Version", -1, 0); continue; } header = strtok(NULL, " "); int status = header ? atoi(header) : 0; if (status < 200 || status >= 400) { - in3_ctx_add_response(req->ctx, n, true, "ERROR failed request", -1, 0); + in3_ctx_add_response(req->req, n, true, "ERROR failed request", -1, 0); continue; } - memmove(res, body, req->ctx->raw_response[n].data.len - (body - res) + 1); - req->ctx->raw_response[n].data.len -= body - res; + memmove(res, body, req->req->raw_response[n].data.len - (body - res) + 1); + req->req->raw_response[n].data.len -= body - res; } return 0; diff --git a/c/src/transport/winhttp/in3_winhttp.c b/c/src/transport/winhttp/in3_winhttp.c index eb0c5eab6..0c4fa4731 100644 --- a/c/src/transport/winhttp/in3_winhttp.c +++ b/c/src/transport/winhttp/in3_winhttp.c @@ -54,17 +54,17 @@ static inline wchar_t* convert_wstr(const char* src, void* dst) { in3_ret_t send_winhttp(void* plugin_data, in3_plugin_act_t action, void* plugin_ctx) { UNUSED_VAR(plugin_data); - in3_request_t* req = plugin_ctx; + in3_http_request_t* req = plugin_ctx; if (action != PLGN_ACT_TRANSPORT_SEND) return IN3_ENOTSUP; for (unsigned int n = 0; n < req->urls_len; n++) { uint32_t start = current_ms(); - sb_t* sb = &req->ctx->raw_response[n].data; + sb_t* sb = &req->req->raw_response[n].data; HINTERNET hSession = WinHttpOpen(to_wstr("in3 winhttp " IN3_VERSION), WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0); if (!hSession) { - in3_ctx_add_response(req->ctx, n, true, "could not create the session", -1, 0); + in3_ctx_add_response(req->req, n, true, "could not create the session", -1, 0); continue; } @@ -83,7 +83,7 @@ in3_ret_t send_winhttp(void* plugin_data, in3_plugin_act_t action, void* plugin_ HINTERNET connect = WinHttpConnect(hSession, url_components.lpszHostName, url_components.nPort, 0); if (!connect) { - in3_ctx_add_response(req->ctx, n, true, "could not connect to ", -1, 0); + in3_ctx_add_response(req->req, n, true, "could not connect to ", -1, 0); sb_add_chars(sb, req->urls[n]); sb_add_chars(sb, "Error code : "); sb_add_int(sb, GetLastError()); @@ -91,11 +91,11 @@ in3_ret_t send_winhttp(void* plugin_data, in3_plugin_act_t action, void* plugin_ continue; } bool https = strstr(req->urls[n], "https") == req->urls[n]; - HINTERNET request = WinHttpOpenRequest(connect, to_wstr("POST"), + HINTERNET request = WinHttpOpenRequest(connect, to_wstr(req->method), url_components.lpszUrlPath, NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, https ? WINHTTP_FLAG_SECURE : 0); if (!request) { - in3_ctx_add_response(req->ctx, n, true, "could not open the request to ", -1, 0); + in3_ctx_add_response(req->req, n, true, "could not open the request to ", -1, 0); sb_add_chars(sb, req->urls[n]); sb_add_chars(sb, "Error code : "); sb_add_int(sb, GetLastError()); @@ -103,11 +103,17 @@ in3_ret_t send_winhttp(void* plugin_data, in3_plugin_act_t action, void* plugin_ WinHttpCloseHandle(hSession); continue; } - int plen = strlen(req->payload); + sb_t headers = {0}; + sb_add_chars(&headers, "Accept: application/json\r\nContent-Type: application/json\r\ncharsets: utf-8\r\n"); + for (in3_req_header_t* h = req->headers; h; h = h->next) { + sb_add_chars(&headers, h->value); + sb_add_chars(&headers, "\r\n"); + } + int plen = req->payload_len; bool success = plen ? WinHttpSendRequest( request, - to_wstr("Accept: application/json\r\nContent-Type: application/json\r\ncharsets: utf-8\r\n"), + to_wstr(headers.data), (DWORD) -1, (LPVOID) req->payload, (DWORD) plen, (DWORD) plen, 0) @@ -115,6 +121,7 @@ in3_ret_t send_winhttp(void* plugin_data, in3_plugin_act_t action, void* plugin_ request, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0); + _free(headers.data); if (success) { WinHttpReceiveResponse(request, NULL); @@ -127,7 +134,7 @@ in3_ret_t send_winhttp(void* plugin_data, in3_plugin_act_t action, void* plugin_ dwSize = 0; if (!WinHttpQueryDataAvailable(request, &dwSize)) { sb->len = 0; - in3_ctx_add_response(req->ctx, n, true, "could not read the data from ", -1, 0); + in3_ctx_add_response(req->req, n, true, "could not read the data from ", -1, 0); sb_add_chars(sb, req->urls[n]); sb_add_chars(sb, "Error code : "); sb_add_int(sb, GetLastError()); @@ -144,7 +151,7 @@ in3_ret_t send_winhttp(void* plugin_data, in3_plugin_act_t action, void* plugin_ if (!WinHttpReadData(request, (LPVOID) pszOutBuffer, dwSize, &dwDownloaded)) { sb->len = 0; - in3_ctx_add_response(req->ctx, n, true, "could not read the data from ", -1, 0); + in3_ctx_add_response(req->req, n, true, "could not read the data from ", -1, 0); sb_add_chars(sb, req->urls[n]); sb_add_chars(sb, "Error code : "); sb_add_int(sb, GetLastError()); @@ -164,13 +171,13 @@ in3_ret_t send_winhttp(void* plugin_data, in3_plugin_act_t action, void* plugin_ } while (dwSize > 0); - if (req->ctx->raw_response[n].state == IN3_WAITING) { - req->ctx->raw_response[n].state = IN3_OK; - req->ctx->raw_response[n].time = current_ms() - start; + if (req->req->raw_response[n].state == IN3_WAITING) { + req->req->raw_response[n].state = IN3_OK; + req->req->raw_response[n].time = current_ms() - start; } } else { - in3_ctx_add_response(req->ctx, n, true, "could not open send the request to ", -1, 0); + in3_ctx_add_response(req->req, n, true, "could not open send the request to ", -1, 0); sb_add_chars(sb, req->urls[n]); sb_add_chars(sb, "Error code : "); sb_add_int(sb, GetLastError()); diff --git a/c/src/verifier/btc/btc.c b/c/src/verifier/btc/btc.c index 3451c59e1..1871b294e 100644 --- a/c/src/verifier/btc/btc.c +++ b/c/src/verifier/btc/btc.c @@ -1,6 +1,7 @@ #include "btc.h" #include "../../core/client/keys.h" #include "../../core/client/plugin.h" +#include "../../core/client/request_internal.h" #include "../../core/util/mem.h" #include "../../core/util/utils.h" #include "../../verifier/eth1/nano/eth_nano.h" @@ -57,7 +58,7 @@ static in3_ret_t btc_block_number(in3_vctx_t* vc, uint32_t* dst_block_number, d_ btc_tx_in_t tx_in; if (*header.data == 1 && memiszero(header.data + 1, 3)) { - *dst_block_number = (uint32_t) d_get_intk(proof, key("height")); + *dst_block_number = (uint32_t) d_get_int(proof, key("height")); if (!*dst_block_number) return vc_err(vc, "missing height in proof for blocks pre bip34"); #ifdef BTC_PRE_BPI34 return check_pre_bip34(vc, d_to_bytes(d_get(proof, key("final"))), *dst_block_number); @@ -157,7 +158,7 @@ in3_ret_t btc_verify_tx(btc_target_conf_t* conf, in3_vctx_t* vc, uint8_t* tx_id, if (!t || d_type(t) != T_STRING) return vc_err(vc, "missing hex"); data.len = (d_len(t) + 1) >> 1; data.data = _malloc(data.len); - in3_cache_add_ptr(&vc->ctx->cache, data.data); + in3_cache_add_ptr(&vc->req->cache, data.data); hex_to_bytes(d_string(t), d_len(t), data.data, data.len); // parse tx @@ -176,35 +177,35 @@ in3_ret_t btc_verify_tx(btc_target_conf_t* conf, in3_vctx_t* vc, uint8_t* tx_id, hex_to_bytes(d_string(t), d_len(t), expected_block_hash, 32); if (block_hash) { if (memcmp(expected_block_hash, block_hash, 32)) return vc_err(vc, "invalid blockhash"); - in_active_chain = d_get_intk(vc->result, key("in_active_chain")); + in_active_chain = d_get_int(vc->result, key("in_active_chain")); } // check version - if (d_get_intk(vc->result, key("version")) != (int32_t) tx_data.version) return vc_err(vc, "invalid version"); + if (d_get_int(vc->result, key("version")) != (int32_t) tx_data.version) return vc_err(vc, "invalid version"); // check size - if (d_get_intk(vc->result, key("size")) != (int32_t) data.len) return vc_err(vc, "invalid size"); + if (d_get_int(vc->result, key("size")) != (int32_t) data.len) return vc_err(vc, "invalid size"); // check vsize - if (d_get_intk(vc->result, key("vsize")) != (int32_t) btc_vsize(&tx_data)) return vc_err(vc, "invalid vsize"); + if (d_get_int(vc->result, key("vsize")) != (int32_t) btc_vsize(&tx_data)) return vc_err(vc, "invalid vsize"); // weight - if (d_get_intk(vc->result, key("weight")) != (int32_t) btc_weight(&tx_data)) return vc_err(vc, "invalid weight"); + if (d_get_int(vc->result, key("weight")) != (int32_t) btc_weight(&tx_data)) return vc_err(vc, "invalid weight"); // locktime - if (d_get_longk(vc->result, key("locktime")) != tx_data.lock_time) return vc_err(vc, "invalid locktime"); + if (d_get_long(vc->result, key("locktime")) != tx_data.lock_time) return vc_err(vc, "invalid locktime"); // blocktime if (!d_eq(d_get(vc->result, key("time")), d_get(vc->result, key("blocktime")))) return vc_err(vc, "invalid blocktime"); // time tmp = btc_block_get(header, BTC_B_TIMESTAMP); - if (tmp.len == 4 && le_to_int(tmp.data) != (uint32_t) d_get_longk(vc->result, key("time"))) return vc_err(vc, "invalid time"); + if (tmp.len == 4 && le_to_int(tmp.data) != (uint32_t) d_get_long(vc->result, key("time"))) return vc_err(vc, "invalid time"); // check vin uint8_t* p = tx_data.input.data; uint8_t* end = p + tx_data.input.len; - uint32_t tx_index = d_get_intk(vc->proof, key("txIndex")); + uint32_t tx_index = d_get_int(vc->proof, key("txIndex")); btc_tx_in_t tx_in; char* hex; list = d_get(vc->result, key("vin")); @@ -215,23 +216,23 @@ in3_ret_t btc_verify_tx(btc_target_conf_t* conf, in3_vctx_t* vc, uint8_t* tx_id, if (!p) return vc_err(vc, "invalid vin"); // sequence - if (d_get_longk(iter.token, key("sequence")) != tx_in.sequence) return vc_err(vc, "invalid vin.sequence"); + if (d_get_long(iter.token, key("sequence")) != tx_in.sequence) return vc_err(vc, "invalid vin.sequence"); if (tx_index == 0) { // coinbase - hex = d_get_stringk(iter.token, key("coinbase")); + hex = d_get_string(iter.token, key("coinbase")); if (!hex || !equals_hex(tx_in.script, hex)) return vc_err(vc, "invalid coinbase"); } else { // txid - hex = d_get_stringk(iter.token, key("txid")); + hex = d_get_string(iter.token, key("txid")); if (!equals_hex_rev(bytes(tx_in.prev_tx_hash, 32), hex)) return vc_err(vc, "invalid vin.txid"); // vout - if (d_get_intk(iter.token, key("vout")) != (int32_t) tx_in.prev_tx_index) return vc_err(vc, "invalid vin.vout"); + if (d_get_int(iter.token, key("vout")) != (int32_t) tx_in.prev_tx_index) return vc_err(vc, "invalid vin.vout"); // sig.hex - hex = d_get_stringk(d_get(iter.token, key("scriptSig")), key("hex")); + hex = d_get_string(d_get(iter.token, key("scriptSig")), key("hex")); if (!equals_hex(tx_in.script, hex)) return vc_err(vc, "invalid vin.hex"); } } @@ -248,10 +249,10 @@ in3_ret_t btc_verify_tx(btc_target_conf_t* conf, in3_vctx_t* vc, uint8_t* tx_id, if (p > end) return vc_err(vc, "invalid vout"); // n - if (d_get_intk(iter.token, key("n")) != n) return vc_err(vc, "invalid vout.n"); + if (d_get_int(iter.token, key("n")) != n) return vc_err(vc, "invalid vout.n"); // sig.hex - char* hex = d_get_stringk(d_get(iter.token, key("scriptPubKey")), key("hex")); + char* hex = d_get_string(d_get(iter.token, key("scriptPubKey")), key("hex")); if (!equals_hex(tx_out.script, hex)) return vc_err(vc, "invalid vout.hex"); d_token_t* value = d_get(iter.token, K_VALUE); if (!value) return vc_err(vc, "no value found!"); @@ -274,7 +275,7 @@ in3_ret_t btc_verify_tx(btc_target_conf_t* conf, in3_vctx_t* vc, uint8_t* tx_id, if (!vc->result || d_type(vc->result) != T_STRING) return vc_err(vc, "expected hex-data as result"); data.len = (d_len(vc->result) + 1) >> 1; data.data = _malloc(data.len); - in3_cache_add_ptr(&vc->ctx->cache, data.data); + in3_cache_add_ptr(&vc->req->cache, data.data); hex_to_bytes(d_string(vc->result), d_len(vc->result), data.data, data.len); // parse tx @@ -352,7 +353,7 @@ in3_ret_t btc_verify_block(btc_target_conf_t* conf, in3_vctx_t* vc, bytes32_t bl int tx_count = d_len(tx), i = 0; // and count its length bytes32_t* tx_hashes = _malloc(tx_count * sizeof(bytes32_t)); // to reserve hashes-array for (d_iterator_t iter = d_iter(tx); iter.left; d_iter_next(&iter), i++) // iterate through all txs - hex_to_bytes(verbose == 1 ? d_string(iter.token) : d_get_stringk(iter.token, key("txid")), 64, tx_hashes[i], 32); // and copy the hash into the array + hex_to_bytes(verbose == 1 ? d_string(iter.token) : d_get_string(iter.token, key("txid")), 64, tx_hashes[i], 32); // and copy the hash into the array btc_merkle_create_root(tx_hashes, tx_count, tmp); // calculate the merkle root _free(tx_hashes); // cleanup rev_copy(tmp2, tmp); // we need to turn it into little endian be cause ini the header it is store as le. @@ -360,9 +361,9 @@ in3_ret_t btc_verify_block(btc_target_conf_t* conf, in3_vctx_t* vc, bytes32_t bl // btc_target_from_block(bytes(block_header, 80), tmp2); // get current target uint64_t difficulty = 0xFFFF000000000000L / bytes_to_long(tmp2 + 4, 8); // and calc the difficulty - if (difficulty >> 2 != d_get_long(vc->result, "difficulty") >> 2) return vc_err(vc, "Wrong difficulty"); // which must match the one in the json - if (!equals_hex(bytes(block_hash, 32), d_get_string(vc->result, "hash"))) return vc_err(vc, "Wrong blockhash in json"); // check the requested hash - if (d_get_int(vc->result, "nTx") != (int32_t) tx_count) return vc_err(vc, "Wrong nTx"); // check the nuumber of transactions + if (difficulty >> 2 != d_get_long(vc->result, key("difficulty")) >> 2) return vc_err(vc, "Wrong difficulty"); // which must match the one in the json + if (!equals_hex(bytes(block_hash, 32), d_get_string(vc->result, K_HASH))) return vc_err(vc, "Wrong blockhash in json"); // check the requested hash + if (d_get_int(vc->result, key("nTx")) != (int32_t) tx_count) return vc_err(vc, "Wrong nTx"); // check the nuumber of transactions } else { char* block_hex = d_string(vc->result); @@ -395,11 +396,11 @@ in3_ret_t btc_verify_block(btc_target_conf_t* conf, in3_vctx_t* vc, bytes32_t bl // check nextblockhash if (finality_headers.len) { btc_hash(bytes(finality_headers.data, 80), hash); - if (!equals_hex(bytes(hash, 32), d_get_stringk(vc->result, key("nextblockhash")))) + if (!equals_hex(bytes(hash, 32), d_get_string(vc->result, key("nextblockhash")))) return vc_err(vc, "Invalid nextblockhash"); } int32_t v = (block_header[3] << 24) | (block_header[2] << 16) | (block_header[1] << 8) | block_header[0]; - if (v != d_get_intk(vc->result, key("version"))) return vc_err(vc, "Invalid version"); + if (v != d_get_int(vc->result, key("version"))) return vc_err(vc, "Invalid version"); } return IN3_OK; @@ -429,43 +430,46 @@ in3_ret_t btc_verify_target_proof(btc_target_conf_t* conf, in3_vctx_t* vc, d_tok } static in3_ret_t in3_verify_btc(btc_target_conf_t* conf, in3_vctx_t* vc) { - char* method = d_get_stringk(vc->request, K_METHOD); - d_token_t* params = d_get(vc->request, K_PARAMS); - bytes32_t hash; // we only verify BTC if (vc->chain->type != CHAIN_BTC) return IN3_EIGNORE; // make sure we want to verify - if (in3_ctx_get_proof(vc->ctx, vc->index) == PROOF_NONE) return IN3_OK; - - // do we support this request? - if (!method) return vc_err(vc, "No Method in request defined!"); + if (in3_req_get_proof(vc->req, vc->index) == PROOF_NONE) return IN3_OK; // do we have a result? if not it is a vaslid error-response if (!vc->result || d_type(vc->result) == T_NULL) return IN3_OK; // make sure the conf is filled with data from the cache btc_check_conf(vc->client, conf); + d_token_t* params = d_get(vc->request, K_PARAMS); + bytes32_t hash; + + if (strcmp(vc->method, "getblock") == 0) { + // mark zksync as experimental + REQUIRE_EXPERIMENTAL(vc->req, "btc") - if (strcmp(method, "getblock") == 0) { d_token_t* block_hash = d_get_at(params, 0); if (d_len(params) < 1 || d_type(params) != T_ARRAY || d_type(block_hash) != T_STRING || d_len(block_hash) != 64) return vc_err(vc, "Invalid params"); hex_to_bytes(d_string(block_hash), 64, hash, 32); return btc_verify_block(conf, vc, hash, d_len(params) > 1 ? d_get_int_at(params, 1) : 1, true); } - if (strcmp(method, "getblockcount") == 0) { + if (strcmp(vc->method, "getblockcount") == 0) { + REQUIRE_EXPERIMENTAL(vc->req, "btc") return btc_verify_blockcount(conf, vc); } - if (strcmp(method, "getblockheader") == 0) { + if (strcmp(vc->method, "getblockheader") == 0) { + REQUIRE_EXPERIMENTAL(vc->req, "btc") d_token_t* block_hash = d_get_at(params, 0); if (d_len(params) < 1 || d_type(params) != T_ARRAY || d_type(block_hash) != T_STRING || d_len(block_hash) != 64) return vc_err(vc, "Invalid blockhash"); hex_to_bytes(d_string(block_hash), 64, hash, 32); return btc_verify_block(conf, vc, hash, d_len(params) > 1 ? d_get_int_at(params, 1) : 1, false); } - if (strcmp(method, "btc_proofTarget") == 0) { + if (strcmp(vc->method, "btc_proofTarget") == 0) { + REQUIRE_EXPERIMENTAL(vc->req, "btc") return btc_verify_target_proof(conf, vc, params); } - if (strcmp(method, "getrawtransaction") == 0) { + if (strcmp(vc->method, "getrawtransaction") == 0) { + REQUIRE_EXPERIMENTAL(vc->req, "btc") d_token_t* tx_id = d_get_at(params, 0); bool json = d_len(params) < 2 ? d_type(vc->result) == T_OBJECT : d_get_int_at(params, 1); d_token_t* block_hash = d_get_at(params, 2); diff --git a/c/src/verifier/btc/btc_serialize.c b/c/src/verifier/btc/btc_serialize.c index df3b0d1ae..a56d515c4 100644 --- a/c/src/verifier/btc/btc_serialize.c +++ b/c/src/verifier/btc/btc_serialize.c @@ -143,11 +143,11 @@ bytes_t btc_get_txoutput(uint8_t* data) { } in3_ret_t btc_serialize_block_header(d_token_t* data, uint8_t* block_header) { - rev_hex(d_get_string(data, "versionHex"), block_header, 4); - rev_hex(d_get_string(data, "previousblockhash"), block_header + 4, 32); - rev_hex(d_get_string(data, "merkleroot"), block_header + 36, 32); + rev_hex(d_get_string(data, key("versionHex")), block_header, 4); + rev_hex(d_get_string(data, key("previousblockhash")), block_header + 4, 32); + rev_hex(d_get_string(data, key("merkleroot")), block_header + 36, 32); rev_copyl(block_header + 68, d_to_bytes(d_get(data, key("time"))), 4); - rev_hex(d_get_string(data, "bits"), block_header + 72, 4); + rev_hex(d_get_string(data, key("bits")), block_header + 72, 4); rev_copyl(block_header + 76, d_to_bytes(d_get(data, key("nonce"))), 4); return IN3_OK; } diff --git a/c/src/verifier/btc/btc_target.c b/c/src/verifier/btc/btc_target.c index 1d04c69d3..b91367ee3 100644 --- a/c/src/verifier/btc/btc_target.c +++ b/c/src/verifier/btc/btc_target.c @@ -1,9 +1,8 @@ #include "btc_target.h" -#include "../../core/client/context_internal.h" #include "../../core/client/keys.h" #include "../../core/client/plugin.h" +#include "../../core/client/request_internal.h" #include "../../core/util/mem.h" -#include "../../nodeselect/cache.h" #include "btc_serialize.h" in3_ret_t btc_new_target_check(in3_vctx_t* vc, bytes32_t old_target, bytes32_t new_target) { @@ -94,7 +93,7 @@ in3_ret_t btc_check_conf(in3_t* c, btc_target_conf_t* conf) { if (!conf->data.data) { char cache_key[50]; set_cachekey(conf->chain_id, cache_key); - in3_cache_ctx_t cctx = {.ctx = NULL, .content = NULL, .key = cache_key}; + in3_cache_ctx_t cctx = {.req = NULL, .content = NULL, .key = cache_key}; in3_plugin_execute_all(c, PLGN_ACT_CACHE_GET, &cctx); if (cctx.content) { @@ -125,8 +124,8 @@ void btc_set_target(btc_target_conf_t* tc, in3_vctx_t* vc, uint32_t dap, uint8_t // add to cache char cache_key[50]; set_cachekey(vc->chain->chain_id, cache_key); - in3_cache_ctx_t cctx = {.ctx = NULL, .content = &tc->data, .key = cache_key}; - in3_plugin_execute_first_or_none(vc->ctx, PLGN_ACT_CACHE_SET, &cctx); + in3_cache_ctx_t cctx = {.req = NULL, .content = &tc->data, .key = cache_key}; + in3_plugin_execute_first_or_none(vc->req, PLGN_ACT_CACHE_SET, &cctx); } uint32_t btc_get_closest_target(btc_target_conf_t* tc, uint32_t dap, uint8_t* target) { @@ -174,16 +173,16 @@ in3_ret_t btc_check_target(btc_target_conf_t* tc, in3_vctx_t* vc, uint32_t block if (block_number < BIP34_START) return IN3_OK; // for pre bip34, this finalityheader already checked it // is there a required ctx, which we need to clean up? - in3_ctx_t* ctx = ctx_find_required(vc->ctx, "btc_proofTarget"); // do we have an existing required proofTarget-request? + in3_req_t* ctx = req_find_required(vc->req, "btc_proofTarget"); // do we have an existing required proofTarget-request? if (ctx) // yes, we do! - switch (in3_ctx_state(ctx)) { // but what is the state? - case CTX_ERROR: // there was an error, - return ctx_set_error(vc->ctx, "Error verifying the target", ctx_set_error(vc->ctx, ctx->error, IN3_ERPC)); // so we report it! - case CTX_WAITING_FOR_RESPONSE: // for an response - case CTX_WAITING_TO_SEND: + switch (in3_req_state(ctx)) { // but what is the state? + case REQ_ERROR: // there was an error, + return req_set_error(vc->req, "Error verifying the target", req_set_error(vc->req, ctx->error, IN3_ERPC)); // so we report it! + case REQ_WAITING_FOR_RESPONSE: // for an response + case REQ_WAITING_TO_SEND: return IN3_WAITING; // we keep on waiting. - case CTX_SUCCESS: // if it was successful, - if (ctx_remove_required(vc->ctx, ctx, false)) return vc_err(vc, "could not clean up proofTarget-request!"); // we remove it, + case REQ_SUCCESS: // if it was successful, + if (req_remove_required(vc->req, ctx, false)) return vc_err(vc, "could not clean up proofTarget-request!"); // we remove it, break; // since gthe verification already added the verified targets. } @@ -213,5 +212,5 @@ in3_ret_t btc_check_target(btc_target_conf_t* tc, in3_vctx_t* vc, uint32_t block // we need more proof, so we create a request char* req = _malloc(300); sprintf(req, "{\"method\":\"btc_proofTarget\",\"jsonrpc\":\"2.0\",\"params\":[\"%d,%d,%d,%d,%d\"]}", current_dap, found_dap, (int) tc->max_diff, (int) tc->max_daps, (int) tc->dap_limit); - return ctx_add_required(vc->ctx, ctx_new(vc->ctx->client, req)); + return req_add_required(vc->req, req_new(vc->req->client, req)); } diff --git a/c/src/verifier/eth1/basic/eth_account.c b/c/src/verifier/eth1/basic/eth_account.c index 22eaacc09..3e690729c 100644 --- a/c/src/verifier/eth1/basic/eth_account.c +++ b/c/src/verifier/eth1/basic/eth_account.c @@ -32,8 +32,8 @@ * with this program. If not, see . *******************************************************************************/ -#include "../../../core/client/context.h" #include "../../../core/client/keys.h" +#include "../../../core/client/request.h" #include "../../../core/util/data.h" #include "../../../core/util/log.h" #include "../../../core/util/mem.h" @@ -48,7 +48,7 @@ static const uint8_t* EMPTY_HASH = (uint8_t*) "\xc5\xd2\x46\x01\x86\xf7\x23 static const uint8_t* EMPTY_ROOT_HASH = (uint8_t*) "\x56\xe8\x1f\x17\x1b\xcc\x55\xa6\xff\x83\x45\xe6\x92\xc0\xf8\x6e\x5b\x48\xe0\x1b\x99\x6c\xad\xc0\x01\x62\x2f\xb5\xe3\x63\xb4\x21"; static int is_not_existened(d_token_t* account) { d_token_t* t = NULL; - return ((t = d_get(account, K_BALANCE)) && d_type(t) == T_INTEGER && d_int(t) == 0 && (t = d_getl(account, K_CODE_HASH, 32)) && memcmp(t->data, EMPTY_HASH, 32) == 0 && d_get_longk(account, K_NONCE) == 0) && (t = d_getl(account, K_STORAGE_HASH, 32)) && memcmp(t->data, EMPTY_ROOT_HASH, 32) == 0; + return ((t = d_get(account, K_BALANCE)) && d_type(t) == T_INTEGER && d_int(t) == 0 && (t = d_getl(account, K_CODE_HASH, 32)) && memcmp(t->data, EMPTY_HASH, 32) == 0 && d_get_long(account, K_NONCE) == 0) && (t = d_getl(account, K_STORAGE_HASH, 32)) && memcmp(t->data, EMPTY_ROOT_HASH, 32) == 0; } static in3_ret_t verify_proof(in3_vctx_t* vc, bytes_t* header, d_token_t* account) { @@ -138,7 +138,6 @@ static in3_ret_t verify_proof(in3_vctx_t* vc, bytes_t* header, d_token_t* accoun in3_ret_t eth_verify_account_proof(in3_vctx_t* vc) { d_token_t *t, *accounts, *contract = NULL, *proofed_account = NULL; - char* method = d_get_stringk(vc->request, K_METHOD); bytes_t tmp; uint8_t hash[32]; int i; @@ -146,24 +145,24 @@ in3_ret_t eth_verify_account_proof(in3_vctx_t* vc) { // no result -> nothing to verify if (!vc->result) return IN3_OK; if (!vc->proof) { - printf("Missing proof for %s\n", method); + printf("Missing proof for %s\n", vc->method); return vc_err(vc, "no proof"); } // verify header - bytes_t* header = d_get_bytesk(vc->proof, K_BLOCK); + bytes_t* header = d_get_bytes(vc->proof, K_BLOCK); if (!header) return vc_err(vc, "no blockheader"); if (eth_verify_blockheader(vc, header, NULL)) return vc_err(vc, "invalid blockheader"); // make sure we blockheader is based on the right blocknumber (unless it is a nodelist or a 'latest'-string) t = d_get(vc->request, K_PARAMS); - if (strcmp(method, "in3_nodeList") && (t = d_get_at(t, d_len(t) - 1)) && d_type(t) == T_INTEGER && rlp_decode_in_list(header, BLOCKHEADER_NUMBER, &tmp) == 1 && bytes_to_long(tmp.data, tmp.len) != d_long(t)) + if (strcmp(vc->method, "in3_nodeList") && (t = d_get_at(t, d_len(t) - 1)) && d_type(t) == T_INTEGER && rlp_decode_in_list(header, BLOCKHEADER_NUMBER, &tmp) == 1 && bytes_to_long(tmp.data, tmp.len) != d_long(t)) return vc_err(vc, "the blockheader has the wrong blocknumber"); // get the account this proof is based on - if (!(contract = strcmp(method, "in3_nodeList") == 0 ? d_get(vc->result, K_CONTRACT) : d_get_at(d_get(vc->request, K_PARAMS), 0))) + if (!(contract = strcmp(vc->method, "in3_nodeList") == 0 ? d_get(vc->result, K_CONTRACT) : d_get_at(d_get(vc->request, K_PARAMS), 0))) return vc_err(vc, "no account found in request"); - if (strcmp(method, "eth_call") == 0) + if (strcmp(vc->method, "eth_call") == 0) contract = d_getl(d_get_at(d_get(vc->request, K_PARAMS), 0), K_TO, 20); //now check the results @@ -177,15 +176,15 @@ in3_ret_t eth_verify_account_proof(in3_vctx_t* vc) { if (!proofed_account) return vc_err(vc, "the contract this proof is based on was not part of the proof"); - if (strcmp(method, "eth_getBalance") == 0) { + if (strcmp(vc->method, "eth_getBalance") == 0) { if (!d_eq(vc->result, d_get(proofed_account, K_BALANCE))) return vc_err(vc, "the balance in the proof is different"); } - else if (strcmp(method, "eth_getTransactionCount") == 0) { + else if (strcmp(vc->method, "eth_getTransactionCount") == 0) { if (!d_eq(vc->result, d_get(proofed_account, K_NONCE))) return vc_err(vc, "the nonce in the proof is different"); } - else if (strcmp(method, "eth_getCode") == 0) { + else if (strcmp(vc->method, "eth_getCode") == 0) { bytes_t data = d_to_bytes(vc->result); if (data.len) { if (keccak(data, hash) != 0 || memcmp(d_get_byteskl(proofed_account, K_CODE_HASH, 32)->data, hash, 32)) @@ -194,7 +193,7 @@ in3_ret_t eth_verify_account_proof(in3_vctx_t* vc) { else if (memcmp(d_get_byteskl(proofed_account, K_CODE_HASH, 32)->data, EMPTY_HASH, 32)) // must be empty return vc_err(vc, "the code must be empty"); } - else if (strcmp(method, "eth_getStorageAt") == 0) { + else if (strcmp(vc->method, "eth_getStorageAt") == 0) { uint8_t result[32], proofed_result[32]; d_bytes_to(vc->result, result, 32); d_token_t* storage = d_get(proofed_account, K_STORAGE_PROOF); @@ -215,7 +214,7 @@ in3_ret_t eth_verify_account_proof(in3_vctx_t* vc) { } return vc_err(vc, "the storage result does not match"); } - else if (strcmp(method, "eth_call") == 0) { + else if (strcmp(vc->method, "eth_call") == 0) { return IN3_OK; } else diff --git a/c/src/verifier/eth1/basic/eth_basic.c b/c/src/verifier/eth1/basic/eth_basic.c index 91625160b..cc140b018 100644 --- a/c/src/verifier/eth1/basic/eth_basic.c +++ b/c/src/verifier/eth1/basic/eth_basic.c @@ -33,9 +33,10 @@ *******************************************************************************/ #include "eth_basic.h" -#include "../../../core/client/context_internal.h" #include "../../../core/client/keys.h" +#include "../../../core/client/request_internal.h" #include "../../../core/util/data.h" +#include "../../../core/util/debug.h" #include "../../../core/util/mem.h" #include "../../../core/util/utils.h" #include "../../../verifier/eth1/basic/filter.h" @@ -50,48 +51,43 @@ in3_ret_t in3_verify_eth_basic(in3_vctx_t* vc) { if (vc->chain->type != CHAIN_ETH) return IN3_EIGNORE; - char* method = d_get_stringk(vc->request, K_METHOD); // make sure we want to verify - if (in3_ctx_get_proof(vc->ctx, vc->index) == PROOF_NONE) return IN3_OK; + if (in3_req_get_proof(vc->req, vc->index) == PROOF_NONE) return IN3_OK; // do we have a result? if not it is a valid error-response - if (!vc->result) { + if (!vc->result) return IN3_OK; - } else if (d_type(vc->result) == T_NULL) { // check if there's a proof for non-existence - if (!strcmp(method, "eth_getTransactionByBlockHashAndIndex") || !strcmp(method, "eth_getTransactionByBlockNumberAndIndex")) { + if (!strcmp(vc->method, "eth_getTransactionByBlockHashAndIndex") || !strcmp(vc->method, "eth_getTransactionByBlockNumberAndIndex")) { return eth_verify_eth_getTransactionByBlock(vc, d_get_at(d_get(vc->request, K_PARAMS), 0), d_get_int_at(d_get(vc->request, K_PARAMS), 1)); } return IN3_OK; } - // do we support this request? - if (!method) return vc_err(vc, "No Method in request defined!"); - - if (strcmp(method, "eth_getTransactionByHash") == 0) + if (strcmp(vc->method, "eth_getTransactionByHash") == 0) return eth_verify_eth_getTransaction(vc, d_get_bytes_at(d_get(vc->request, K_PARAMS), 0)); - else if (!strcmp(method, "eth_getTransactionByBlockHashAndIndex") || !strcmp(method, "eth_getTransactionByBlockNumberAndIndex")) { + else if (!strcmp(vc->method, "eth_getTransactionByBlockHashAndIndex") || !strcmp(vc->method, "eth_getTransactionByBlockNumberAndIndex")) { return eth_verify_eth_getTransactionByBlock(vc, d_get_at(d_get(vc->request, K_PARAMS), 0), d_get_int_at(d_get(vc->request, K_PARAMS), 1)); } - else if (strcmp(method, "eth_getBlockByNumber") == 0) + else if (strcmp(vc->method, "eth_getBlockByNumber") == 0) return eth_verify_eth_getBlock(vc, NULL, d_get_long_at(d_get(vc->request, K_PARAMS), 0)); - else if (strcmp(method, "eth_getBlockTransactionCountByHash") == 0) + else if (strcmp(vc->method, "eth_getBlockTransactionCountByHash") == 0) return eth_verify_eth_getBlockTransactionCount(vc, d_get_bytes_at(d_get(vc->request, K_PARAMS), 0), 0); - else if (strcmp(method, "eth_getBlockTransactionCountByNumber") == 0) + else if (strcmp(vc->method, "eth_getBlockTransactionCountByNumber") == 0) return eth_verify_eth_getBlockTransactionCount(vc, NULL, d_get_long_at(d_get(vc->request, K_PARAMS), 0)); - else if (strcmp(method, "eth_getBlockByHash") == 0) + else if (strcmp(vc->method, "eth_getBlockByHash") == 0) return eth_verify_eth_getBlock(vc, d_get_bytes_at(d_get(vc->request, K_PARAMS), 0), 0); - else if (strcmp(method, "eth_getBalance") == 0 || strcmp(method, "eth_getCode") == 0 || strcmp(method, "eth_getStorageAt") == 0 || strcmp(method, "eth_getTransactionCount") == 0) + else if (strcmp(vc->method, "eth_getBalance") == 0 || strcmp(vc->method, "eth_getCode") == 0 || strcmp(vc->method, "eth_getStorageAt") == 0 || strcmp(vc->method, "eth_getTransactionCount") == 0) return eth_verify_account_proof(vc); - else if (strcmp(method, "eth_gasPrice") == 0) + else if (strcmp(vc->method, "eth_gasPrice") == 0) return IN3_OK; - else if (!strcmp(method, "eth_newFilter") || !strcmp(method, "eth_newBlockFilter") || !strcmp(method, "eth_newPendingFilter") || !strcmp(method, "eth_uninstallFilter") || !strcmp(method, "eth_getFilterChanges")) + else if (!strcmp(vc->method, "eth_newFilter") || !strcmp(vc->method, "eth_newBlockFilter") || !strcmp(vc->method, "eth_newPendingFilter") || !strcmp(vc->method, "eth_uninstallFilter") || !strcmp(vc->method, "eth_getFilterChanges")) return IN3_OK; - else if (strcmp(method, "eth_getLogs") == 0) // for txReceipt, we need the txhash + else if (strcmp(vc->method, "eth_getLogs") == 0) // for txReceipt, we need the txhash return eth_verify_eth_getLog(vc, d_len(vc->result)); - else if (strcmp(method, "eth_sendRawTransaction") == 0) { + else if (strcmp(vc->method, "eth_sendRawTransaction") == 0) { bytes32_t hash; keccak(d_to_bytes(d_get_at(d_get(vc->request, K_PARAMS), 0)), hash); return bytes_cmp(*d_bytes(vc->result), bytes(hash, 32)) ? IN3_OK : vc_err(vc, "the transactionHash of the response does not match the raw transaction!"); @@ -100,121 +96,139 @@ in3_ret_t in3_verify_eth_basic(in3_vctx_t* vc) { return IN3_EIGNORE; } -/** called to see if we can handle the request internally */ -static in3_ret_t eth_handle_intern(in3_rpc_handle_ctx_t* rctx) { +static in3_ret_t eth_send_transaction_and_wait(in3_rpc_handle_ctx_t* ctx) { + d_token_t * tx_hash, *tx_receipt; + str_range_t r = d_to_json(ctx->params + 1); + char* tx_data = alloca(r.len + 1); + memcpy(tx_data, r.data, r.len); + tx_data[r.len] = 0; + TRY(req_send_sub_request(ctx->req, "eth_sendTransaction", tx_data, NULL, &tx_hash)) + // tx was sent, we have a tx_hash + char tx_hash_hex[69]; + bytes_to_hex(d_bytes(tx_hash)->data, 32, tx_hash_hex + 3); + tx_hash_hex[0] = tx_hash_hex[67] = '"'; + tx_hash_hex[1] = '0'; + tx_hash_hex[2] = 'x'; + tx_hash_hex[68] = 0; + + // get the tx_receipt + TRY(req_send_sub_request(ctx->req, "eth_getTransactionReceipt", tx_hash_hex, NULL, &tx_receipt)) + + if (d_type(tx_receipt) == T_NULL || d_get_long(tx_receipt, K_BLOCK_NUMBER) == 0) { + // no tx yet + // we remove it and try again + in3_req_t* last_r = req_find_required(ctx->req, "eth_getTransactionReceipt"); + uint32_t wait = d_get_int(d_get(last_r->requests[0], K_IN3), K_WAIT); + wait = wait ? wait * 2 : 1000; + req_remove_required(ctx->req, last_r, false); + if (wait > 120000) // more than 2 minutes is too long, so we stop here + return req_set_error(ctx->req, "Waited too long for the transaction to be minded", IN3_ELIMIT); + char in3[20]; + sprintf(in3, "{\"wait\":%d}", wait); + + return req_send_sub_request(ctx->req, "eth_getTransactionReceipt", tx_hash_hex, in3, &tx_receipt); + } + else { + // we have a result and we keep it + str_range_t r = d_to_json(tx_receipt); + sb_add_range(in3_rpc_handle_start(ctx), r.data, 0, r.len); + req_remove_required(ctx->req, req_find_required(ctx->req, "eth_getTransactionReceipt"), false); + req_remove_required(ctx->req, req_find_required(ctx->req, "eth_sendRawTransaction"), false); + return in3_rpc_handle_finish(ctx); + } +} + +static in3_ret_t eth_newFilter(in3_filter_handler_t* filters, in3_rpc_handle_ctx_t* ctx) { + if (!ctx->params || d_type(ctx->params) != T_ARRAY || !d_len(ctx->params) || d_type(ctx->params + 1) != T_OBJECT) + return req_set_error(ctx->req, "invalid type of params, expected object", IN3_EINVAL); + else if (!filter_opt_valid(ctx->params + 1)) + return req_set_error(ctx->req, "filter option parsing failed", IN3_EINVAL); + if (!ctx->params->data) return req_set_error(ctx->req, "binary request are not supported!", IN3_ENOTSUP); + + char* fopt = d_create_json(ctx->req->request_context, ctx->params + 1); + in3_ret_t res = filter_add(filters, ctx->req, FILTER_EVENT, fopt); + if (res < 0) { + _free(fopt); + return req_set_error(ctx->req, "filter creation failed", res); + } - in3_ctx_t* ctx = rctx->ctx; - char* method = d_get_stringk(rctx->request, K_METHOD); - d_token_t* params = d_get(rctx->request, K_PARAMS); + return in3_rpc_handle_with_int(ctx, (uint64_t) res); +} + +static in3_ret_t eth_newBlockFilter(in3_filter_handler_t* filters, in3_rpc_handle_ctx_t* ctx) { + in3_ret_t res = filter_add(filters, ctx->req, FILTER_BLOCK, NULL); + if (res < 0) return req_set_error(ctx->req, "filter creation failed", res); + return in3_rpc_handle_with_int(ctx, (uint64_t) res); +} + +static in3_ret_t eth_getFilterChanges(in3_filter_handler_t* filters, in3_rpc_handle_ctx_t* ctx) { + if (!ctx->params || d_len(ctx->params) == 0 || d_type(ctx->params + 1) != T_INTEGER) + return req_set_error(ctx->req, "invalid type of params, expected filter-id as integer", IN3_EINVAL); + + uint64_t id = d_get_long_at(ctx->params, 0); + sb_t sb = {0}; + in3_ret_t ret = filter_get_changes(filters, ctx->req, id, &sb); + if (ret != IN3_OK) { + if (sb.data) _free(sb.data); + return req_set_error(ctx->req, "failed to get filter changes", ret); + } + in3_rpc_handle_with_string(ctx, sb.data); + _free(sb.data); + return IN3_OK; +} + +/** called to see if we can handle the request internally */ +static in3_ret_t eth_handle_intern(in3_filter_handler_t* filters, in3_rpc_handle_ctx_t* ctx) { // we only support ETH in this module - if (ctx->client->chain.type != CHAIN_ETH) return IN3_EIGNORE; + if (ctx->req->client->chain.type != CHAIN_ETH) return IN3_EIGNORE; // check method to handle internally - if (strcmp(method, "eth_sendTransaction") == 0) - return handle_eth_sendTransaction(ctx, rctx->request); - - else if (strcmp(method, "eth_sendTransactionAndWait") == 0) { - d_token_t * tx_hash, *tx_receipt; - str_range_t r = d_to_json(params + 1); - char* tx_data = alloca(r.len + 1); - memcpy(tx_data, r.data, r.len); - tx_data[r.len] = 0; - TRY(ctx_send_sub_request(ctx, "eth_sendTransaction", tx_data, NULL, &tx_hash)) - // tx was sent, we have a tx_hash - char tx_hash_hex[69]; - bytes_to_hex(d_bytes(tx_hash)->data, 32, tx_hash_hex + 3); - tx_hash_hex[0] = tx_hash_hex[67] = '"'; - tx_hash_hex[1] = '0'; - tx_hash_hex[2] = 'x'; - tx_hash_hex[68] = 0; - - // get the tx_receipt - TRY(ctx_send_sub_request(ctx, "eth_getTransactionReceipt", tx_hash_hex, NULL, &tx_receipt)) - - if (d_type(tx_receipt) == T_NULL || d_get_longk(tx_receipt, K_BLOCK_NUMBER) == 0) { - // no tx yet - // we remove it and try again - in3_ctx_t* last_r = ctx_find_required(ctx, "eth_getTransactionReceipt"); - uint32_t wait = d_get_intk(d_get(last_r->requests[0], K_IN3), K_WAIT); - wait = wait ? wait * 2 : 1000; - ctx_remove_required(ctx, last_r, false); - if (wait > 120000) // more than 2 minutes is too long, so we stop here - return ctx_set_error(ctx, "Waited too long for the transaction to be minded", IN3_ELIMIT); - char in3[20]; - sprintf(in3, "{\"wait\":%d}", wait); - - return ctx_send_sub_request(ctx, "eth_getTransactionReceipt", tx_hash_hex, in3, &tx_receipt); - } - else { - // we have a result and we keep it - str_range_t r = d_to_json(tx_receipt); - sb_add_range(in3_rpc_handle_start(rctx), r.data, 0, r.len); - ctx_remove_required(ctx, ctx_find_required(ctx, "eth_getTransactionReceipt"), false); - ctx_remove_required(ctx, ctx_find_required(ctx, "eth_sendRawTransaction"), false); - return in3_rpc_handle_finish(rctx); - } - } + TRY_RPC("eth_sendTransaction", handle_eth_sendTransaction(ctx->req, ctx->request)) + TRY_RPC("eth_sendTransactionAndWait", eth_send_transaction_and_wait(ctx)) + TRY_RPC("eth_newFilter", eth_newFilter(filters, ctx)) + TRY_RPC("eth_newBlockFilter", eth_newBlockFilter(filters, ctx)) + TRY_RPC("eth_newPendingTransactionFilter", req_set_error(ctx->req, "pending filter not supported", IN3_ENOTSUP)) + TRY_RPC("eth_getFilterChanges", eth_getFilterChanges(filters, ctx)) + TRY_RPC("eth_getFilterLogs", eth_getFilterChanges(filters, ctx)) + TRY_RPC("eth_uninstallFilter", (!ctx->params || d_len(ctx->params) == 0 || d_type(ctx->params + 1) != T_INTEGER) + ? req_set_error(ctx->req, "invalid type of params, expected filter-id as integer", IN3_EINVAL) + : in3_rpc_handle_with_string(ctx, filter_remove(filters, d_get_long_at(ctx->params, 0)) ? "true" : "false")) + + if (strcmp(ctx->method, "eth_chainId") == 0 && ctx->req->client->chain.chain_id != CHAIN_ID_LOCAL) + return in3_rpc_handle_with_int(ctx, ctx->req->client->chain.chain_id); - else if (strcmp(method, "eth_newFilter") == 0) { - if (!params || d_type(params) != T_ARRAY || !d_len(params) || d_type(params + 1) != T_OBJECT) - return ctx_set_error(ctx, "invalid type of params, expected object", IN3_EINVAL); - else if (!filter_opt_valid(params + 1)) - return ctx_set_error(ctx, "filter option parsing failed", IN3_EINVAL); - if (!params->data) return ctx_set_error(ctx, "binary request are not supported!", IN3_ENOTSUP); - - char* fopt = d_create_json(ctx->request_context, params + 1); - in3_ret_t res = filter_add(ctx, FILTER_EVENT, fopt); - if (res < 0) { - _free(fopt); - return ctx_set_error(ctx, "filter creation failed", res); - } + return IN3_EIGNORE; +} - return in3_rpc_handle_with_int(rctx, (uint64_t) res); - } - else if (strcmp(method, "eth_chainId") == 0 && ctx->client->chain.chain_id != CHAIN_ID_LOCAL) - return in3_rpc_handle_with_int(rctx, ctx->client->chain.chain_id); - else if (strcmp(method, "eth_newBlockFilter") == 0) { - in3_ret_t res = filter_add(ctx, FILTER_BLOCK, NULL); - if (res < 0) return ctx_set_error(ctx, "filter creation failed", res); - return in3_rpc_handle_with_int(rctx, (uint64_t) res); +static in3_ret_t free_filters(in3_filter_handler_t* f) { + for (size_t i = 0; i < f->count; i++) { + if (f->array[i]) f->array[i]->release(f->array[i]); } - else if (strcmp(method, "eth_newPendingTransactionFilter") == 0) - return ctx_set_error(ctx, "pending filter not supported", IN3_ENOTSUP); - - else if (strcmp(method, "eth_uninstallFilter") == 0) - return (!params || d_len(params) == 0 || d_type(params + 1) != T_INTEGER) - ? ctx_set_error(ctx, "invalid type of params, expected filter-id as integer", IN3_EINVAL) - : in3_rpc_handle_with_string(rctx, filter_remove(ctx->client, d_get_long_at(params, 0)) ? "true" : "false"); - - else if (strcmp(method, "eth_getFilterChanges") == 0 || strcmp(method, "eth_getFilterLogs") == 0) { - if (!params || d_len(params) == 0 || d_type(params + 1) != T_INTEGER) - return ctx_set_error(ctx, "invalid type of params, expected filter-id as integer", IN3_EINVAL); - - uint64_t id = d_get_long_at(params, 0); - sb_t sb = {0}; - in3_ret_t ret = filter_get_changes(ctx, id, &sb); - if (ret != IN3_OK) { - if (sb.data) _free(sb.data); - return ctx_set_error(ctx, "failed to get filter changes", ret); - } - in3_rpc_handle_with_string(rctx, sb.data); - _free(sb.data); - return IN3_OK; - } - return IN3_EIGNORE; + if (f->array) _free(f->array); + _free(f); + return IN3_OK; } in3_ret_t handle_basic(void* pdata, in3_plugin_act_t action, void* pctx) { UNUSED_VAR(pdata); switch (action) { case PLGN_ACT_RPC_VERIFY: return in3_verify_eth_basic(pctx); - case PLGN_ACT_RPC_HANDLE: return eth_handle_intern(pctx); + case PLGN_ACT_RPC_HANDLE: return eth_handle_intern(pdata, pctx); + case PLGN_ACT_TERM: return free_filters(pdata); default: return IN3_EINVAL; } } +in3_filter_handler_t* eth_basic_get_filters(in3_t* c) { + for (in3_plugin_t* p = c->plugins; p; p = p->next) { + if (p->action_fn == handle_basic) return p->data; + } + return NULL; +} + in3_ret_t in3_register_eth_basic(in3_t* c) { + in3_filter_handler_t* handler = _calloc(1, sizeof(in3_filter_handler_t)); in3_register_eth_nano(c); - return in3_plugin_register(c, PLGN_ACT_RPC_VERIFY | PLGN_ACT_RPC_HANDLE, handle_basic, NULL, false); + return in3_plugin_register(c, PLGN_ACT_TERM | PLGN_ACT_RPC_VERIFY | PLGN_ACT_RPC_HANDLE, handle_basic, handler, false); } diff --git a/c/src/verifier/eth1/basic/eth_basic.h b/c/src/verifier/eth1/basic/eth_basic.h index 6f90e14dd..096b99184 100644 --- a/c/src/verifier/eth1/basic/eth_basic.h +++ b/c/src/verifier/eth1/basic/eth_basic.h @@ -41,6 +41,36 @@ #include "../../../core/client/plugin.h" +/** + * Filter type used internally when managing filters. + */ +typedef enum { + FILTER_EVENT = 0, /**< Event filter */ + FILTER_BLOCK = 1, /**< Block filter */ + FILTER_PENDING = 2, /**< Pending filter (Unsupported) */ +} in3_filter_type_t; + +typedef struct in3_filter_t_ { + bool is_first_usage; /**< if true the filter was not used previously */ + in3_filter_type_t type; /**< filter type: (event, block or pending) */ + uint64_t last_block; /**< block no. when filter was created OR eth_getFilterChanges was called */ + char* options; /**< associated filter options */ + void (*release)(struct in3_filter_t_* f); /**< method to release owned resources */ +} in3_filter_t; + +/** + * Handler which is added to client config in order to handle filter. + */ +typedef struct in3_filter_handler_t_ { + in3_filter_t** array; /** array of filters */ + size_t count; /** counter for filters */ +} in3_filter_handler_t; + +/** + * returns the filters + */ +in3_filter_handler_t* eth_basic_get_filters(in3_t* c); + /** * verifies internal tx-values. */ @@ -85,7 +115,7 @@ in3_ret_t eth_verify_eth_getLog(in3_vctx_t* vc, int l_logs); * prepares a transaction and writes the data to the dst-bytes. In case of success, you MUST free only the data-pointer of the dst. */ in3_ret_t eth_prepare_unsigned_tx(d_token_t* tx, /**< a json-token desribing the transaction */ - in3_ctx_t* ctx, /**< the current context */ + in3_req_t* req, /**< the current context */ bytes_t* dst /**< the bytes to write the result to. */ ); @@ -93,7 +123,7 @@ in3_ret_t eth_prepare_unsigned_tx(d_token_t* tx, /**< a json-token desribing th * signs a unsigned raw transaction and writes the raw data to the dst-bytes. In case of success, you MUST free only the data-pointer of the dst. */ in3_ret_t eth_sign_raw_tx(bytes_t raw_tx, /**< the unsigned raw transaction to sign */ - in3_ctx_t* ctx, /**< the current context */ + in3_req_t* req, /**< the current context */ address_t from, /**< the address of the account to sign with */ bytes_t* dst /**< the bytes to write the result to. */ ); @@ -101,8 +131,8 @@ in3_ret_t eth_sign_raw_tx(bytes_t raw_tx, /**< the unsigned raw transaction t /** * expects a req-object for a transaction and converts it into a sendRawTransaction after signing. */ -in3_ret_t handle_eth_sendTransaction(in3_ctx_t* ctx, /**< the current context */ - d_token_t* req /**< the request */ +in3_ret_t handle_eth_sendTransaction(in3_req_t* req, /**< the current context */ + d_token_t* req_data /**< the request */ ); /** diff --git a/c/src/verifier/eth1/basic/eth_getBlock.c b/c/src/verifier/eth1/basic/eth_getBlock.c index 1ab3e0189..a3cbee71d 100644 --- a/c/src/verifier/eth1/basic/eth_getBlock.c +++ b/c/src/verifier/eth1/basic/eth_getBlock.c @@ -32,8 +32,8 @@ * with this program. If not, see . *******************************************************************************/ -#include "../../../core/client/context.h" #include "../../../core/client/keys.h" +#include "../../../core/client/request.h" #include "../../../core/util/data.h" #include "../../../core/util/mem.h" #include "../../../verifier/eth1/nano/eth_nano.h" @@ -84,7 +84,7 @@ in3_ret_t eth_verify_eth_getBlockTransactionCount(in3_vctx_t* vc, bytes_t* block return vc_err(vc, "Proof is missing!"); // verify the blockdata - bytes_t* header = d_get_bytesk(vc->proof, K_BLOCK); + bytes_t* header = d_get_bytes(vc->proof, K_BLOCK); if (!header) return vc_err(vc, "no blockheader"); if (eth_verify_blockheader(vc, header, block_hash) != IN3_OK) @@ -129,9 +129,10 @@ in3_ret_t eth_verify_eth_getBlock(in3_vctx_t* vc, bytes_t* block_hash, uint64_t in3_ret_t res = IN3_OK; int i; + bytes32_t tmp_hash; d_token_t *transactions, *t, *t2, *tx_hashs = NULL, *txh = NULL; bytes_t tmp, *bhash; - uint64_t bnumber = d_get_longk(vc->result, K_NUMBER); + uint64_t bnumber = d_get_long(vc->result, K_NUMBER); bhash = d_get_byteskl(vc->result, K_HASH, 32); if (block_hash && !b_cmp(block_hash, bhash)) @@ -159,7 +160,7 @@ in3_ret_t eth_verify_eth_getBlock(in3_vctx_t* vc, bytes_t* block_hash, uint64_t if ((t = d_getl(vc->result, K_MIX_HASH, 32)) && (t2 = d_get(vc->result, K_SEAL_FIELDS))) { if (rlp_decode(d_get_bytes_at(t2, 0), 0, &tmp) != 1 || !b_cmp(d_bytes(t), &tmp)) return vc_err(vc, "invalid mixhash"); - if (rlp_decode(d_get_bytes_at(t2, 1), 0, &tmp) != 1 || !b_cmp(d_get_bytesk(vc->result, K_NONCE), &tmp)) + if (rlp_decode(d_get_bytes_at(t2, 1), 0, &tmp) != 1 || !b_cmp(d_get_bytes(vc->result, K_NONCE), &tmp)) return vc_err(vc, "invalid nonce"); } @@ -181,7 +182,9 @@ in3_ret_t eth_verify_eth_getBlock(in3_vctx_t* vc, bytes_t* block_hash, uint64_t bool is_raw_tx = d_type(t) == T_BYTES; bytes_t* path = create_tx_path(i); bytes_t* tx = is_raw_tx ? d_bytes(t) : serialize_tx(t); - bytes_t* h = (full_proof || !include_full_tx) ? sha3(tx) : NULL; + uint8_t* h = (full_proof || !include_full_tx) ? tmp_hash : NULL; + + if (h) keccak(*tx, h); if (!is_raw_tx) { if (eth_verify_tx_values(vc, t, tx)) @@ -198,14 +201,13 @@ in3_ret_t eth_verify_eth_getBlock(in3_vctx_t* vc, bytes_t* block_hash, uint64_t } if (h && txh) { - if (!b_cmp(d_bytes(txh), h)) + if (d_len(txh) != 32 || memcmp(txh->data, h, 32)) res = vc_err(vc, "Wrong Transactionhash"); txh = d_next(txh); } trie_set_value(trie, path, tx); if (!is_raw_tx) b_free(tx); b_free(path); - if (h) b_free(h); } bytes_t t_root = d_to_bytes(d_getl(vc->result, K_TRANSACTIONS_ROOT, 32)); @@ -217,7 +219,7 @@ in3_ret_t eth_verify_eth_getBlock(in3_vctx_t* vc, bytes_t* block_hash, uint64_t // verify uncles if (res == IN3_OK && full_proof) - return eth_verify_uncles(vc, d_get_bytesk(vc->result, K_SHA3_UNCLES)->data, d_get(vc->proof, K_UNCLES), d_get(vc->result, K_UNCLES)); + return eth_verify_uncles(vc, d_get_bytes(vc->result, K_SHA3_UNCLES)->data, d_get(vc->proof, K_UNCLES), d_get(vc->result, K_UNCLES)); } else res = vc_err(vc, "Missing transaction-properties"); diff --git a/c/src/verifier/eth1/basic/eth_getLog.c b/c/src/verifier/eth1/basic/eth_getLog.c index fd448ffa9..cbda3415d 100644 --- a/c/src/verifier/eth1/basic/eth_getLog.c +++ b/c/src/verifier/eth1/basic/eth_getLog.c @@ -32,8 +32,8 @@ * with this program. If not, see . *******************************************************************************/ -#include "../../../core/client/context.h" #include "../../../core/client/keys.h" +#include "../../../core/client/request.h" #include "../../../core/util/data.h" #include "../../../core/util/log.h" #include "../../../core/util/mem.h" @@ -221,7 +221,7 @@ in3_ret_t eth_verify_eth_getLog(in3_vctx_t* vc, int l_logs) { if (d_len(d_get(vc->proof, K_LOG_PROOF)) > l_logs) return vc_err(vc, "too many proofs"); for (d_iterator_t it = d_iter(d_get(vc->proof, K_LOG_PROOF)); it.left; d_iter_next(&it)) { - sprintf(xtmp, "0x%" PRIx64, d_get_longk(it.token, K_NUMBER)); + sprintf(xtmp, "0x%" PRIx64, d_get_long(it.token, K_NUMBER)); if (strlen(xtmp) % 2) { memmove(xtmp + 3, xtmp + 2, strlen(xtmp) - 1); xtmp[2] = '0'; @@ -250,7 +250,7 @@ in3_ret_t eth_verify_eth_getLog(in3_vctx_t* vc, int l_logs) { // verify tx data first r->data = bytes(NULL, 0); - r->transaction_index = d_get_intk(receipt.token, K_TX_INDEX); + r->transaction_index = d_get_int(receipt.token, K_TX_INDEX); bytes_t** proof = d_create_bytes_vec(d_get(receipt.token, K_TX_PROOF)); bytes_t* path = create_tx_path(r->transaction_index); @@ -298,7 +298,7 @@ in3_ret_t eth_verify_eth_getLog(in3_vctx_t* vc, int l_logs) { // verify the log-data if (rlp_decode(&tmp, 3, &logddata) != 2) return vc_err(vc, "invalid log-data"); - if (rlp_decode(&logddata, d_get_intk(it.token, K_TRANSACTION_LOG_INDEX), &logddata) != 2) return vc_err(vc, "invalid log index"); + if (rlp_decode(&logddata, d_get_int(it.token, K_TRANSACTION_LOG_INDEX), &logddata) != 2) return vc_err(vc, "invalid log index"); // check address if (!rlp_decode(&logddata, 0, &tmp) || !bytes_cmp(tmp, d_to_bytes(d_getl(it.token, K_ADDRESS, 20)))) return vc_err(vc, "invalid address"); @@ -310,20 +310,20 @@ in3_ret_t eth_verify_eth_getLog(in3_vctx_t* vc, int l_logs) { if (!rlp_decode(&tops, i++, &tmp) || !bytes_cmp(tmp, *d_bytesl(t.token, 32))) return vc_err(vc, "invalid topic"); } - if (d_get_longk(it.token, K_BLOCK_NUMBER) != bytes_to_long(r->block_number.data, r->block_number.len)) return vc_err(vc, "invalid blocknumber"); + if (d_get_long(it.token, K_BLOCK_NUMBER) != bytes_to_long(r->block_number.data, r->block_number.len)) return vc_err(vc, "invalid blocknumber"); if (!bytes_cmp(d_to_bytes(d_getl(it.token, K_BLOCK_HASH, 32)), bytes(r->block_hash, 32))) return vc_err(vc, "invalid blockhash"); - if (d_get_intk(it.token, K_REMOVED)) return vc_err(vc, "must be removed=false"); - if ((unsigned) d_get_intk(it.token, K_TRANSACTION_INDEX) != r->transaction_index) return vc_err(vc, "wrong transactionIndex"); + if (d_get_int(it.token, K_REMOVED)) return vc_err(vc, "must be removed=false"); + if ((unsigned) d_get_int(it.token, K_TRANSACTION_INDEX) != r->transaction_index) return vc_err(vc, "wrong transactionIndex"); - if (!matches_filter(vc->request, d_to_bytes(d_getl(it.token, K_ADDRESS, 20)), d_get_longk(it.token, K_BLOCK_NUMBER), d_to_bytes(d_getl(it.token, K_BLOCK_HASH, 32)), d_get(it.token, K_TOPICS))) return vc_err(vc, "filter mismatch"); - if (!prev_blk) prev_blk = d_get_longk(it.token, K_BLOCK_NUMBER); - if (filter_from_equals_to(vc->request) && prev_blk != d_get_longk(it.token, K_BLOCK_NUMBER)) return vc_err(vc, "wrong blocknumber"); + if (!matches_filter(vc->request, d_to_bytes(d_getl(it.token, K_ADDRESS, 20)), d_get_long(it.token, K_BLOCK_NUMBER), d_to_bytes(d_getl(it.token, K_BLOCK_HASH, 32)), d_get(it.token, K_TOPICS))) return vc_err(vc, "filter mismatch"); + if (!prev_blk) prev_blk = d_get_long(it.token, K_BLOCK_NUMBER); + if (filter_from_equals_to(vc->request) && prev_blk != d_get_long(it.token, K_BLOCK_NUMBER)) return vc_err(vc, "wrong blocknumber"); // Check for prev_blk > blockNumber is also required for filter_check_latest() to work properly, // this is because we expect the result to be sorted (ascending by blockNumber) and only check // latest toBlock for last log in result. - if (prev_blk > d_get_longk(it.token, K_BLOCK_NUMBER)) return vc_err(vc, "result not sorted"); - if (filter_check_latest(vc->request, d_get_longk(it.token, K_BLOCK_NUMBER), vc->currentBlock, it.left == 1) != IN3_OK) return vc_err(vc, "latest check failed"); + if (prev_blk > d_get_long(it.token, K_BLOCK_NUMBER)) return vc_err(vc, "result not sorted"); + if (filter_check_latest(vc->request, d_get_long(it.token, K_BLOCK_NUMBER), vc->currentBlock, it.left == 1) != IN3_OK) return vc_err(vc, "latest check failed"); } return res; diff --git a/c/src/verifier/eth1/basic/eth_getTransaction.c b/c/src/verifier/eth1/basic/eth_getTransaction.c index df8e885b6..1aa7ca39b 100644 --- a/c/src/verifier/eth1/basic/eth_getTransaction.c +++ b/c/src/verifier/eth1/basic/eth_getTransaction.c @@ -54,7 +54,7 @@ in3_ret_t eth_verify_tx_values(in3_vctx_t* vc, d_token_t* tx, bytes_t* raw) { bytes_t* r = d_get_byteskl(tx, K_R, 32); bytes_t* s = d_get_byteskl(tx, K_S, 32); - uint32_t v = d_get_intk(tx, K_V); + uint32_t v = d_get_int(tx, K_V); uint32_t chain_id = v > 35 ? (v - 35) / 2 : 0; // check transaction hash @@ -89,7 +89,7 @@ in3_ret_t eth_verify_tx_values(in3_vctx_t* vc, d_token_t* tx, bytes_t* raw) { // calculate the messagehash bytes_builder_t* bb = bb_new(); bytes_t raw_list, item; - rlp_decode(raw ? raw : d_get_bytesk(tx, K_RAW), 0, &raw_list); + rlp_decode(raw ? raw : d_get_bytes(tx, K_RAW), 0, &raw_list); rlp_decode(&raw_list, 5, &item); bb_write_raw_bytes(bb, raw_list.data, item.data + item.len - raw_list.data); if (chain_id) { @@ -130,13 +130,13 @@ in3_ret_t eth_verify_eth_getTransaction(in3_vctx_t* vc, bytes_t* tx_hash) { // this means result: null, which is ok, since we can not verify a transaction that does not exists if (!vc->proof) return vc_err(vc, "Proof is missing!"); - bytes_t* blockHeader = d_get_bytesk(vc->proof, K_BLOCK); + bytes_t* blockHeader = d_get_bytes(vc->proof, K_BLOCK); if (!blockHeader) return vc_err(vc, "No Block-Proof!"); res = eth_verify_blockheader(vc, blockHeader, d_get_byteskl(vc->result, K_BLOCK_HASH, 32)); if (res == IN3_OK) { - bytes_t* path = create_tx_path(d_get_intk(vc->proof, K_TX_INDEX)); + bytes_t* path = create_tx_path(d_get_int(vc->proof, K_TX_INDEX)); bytes_t root, raw_transaction = {.len = 0, .data = NULL}; bytes_t** proof = d_create_bytes_vec(d_get(vc->proof, K_MERKLE_PROOF)); @@ -158,7 +158,7 @@ in3_ret_t eth_verify_eth_getTransaction(in3_vctx_t* vc, bytes_t* tx_hash) { if (res == IN3_OK && !d_eq(d_get(vc->result, K_TRANSACTION_INDEX), d_get(vc->proof, K_TX_INDEX))) res = vc_err(vc, "wrong transaction index"); - if (res == IN3_OK && (rlp_decode_in_list(blockHeader, BLOCKHEADER_NUMBER, &root) != 1 || d_get_longk(vc->result, K_BLOCK_NUMBER) != bytes_to_long(root.data, root.len))) + if (res == IN3_OK && (rlp_decode_in_list(blockHeader, BLOCKHEADER_NUMBER, &root) != 1 || d_get_long(vc->result, K_BLOCK_NUMBER) != bytes_to_long(root.data, root.len))) res = vc_err(vc, "wrong block number"); if (proof) _free(proof); @@ -180,7 +180,7 @@ in3_ret_t eth_verify_eth_getTransactionByBlock(in3_vctx_t* vc, d_token_t* blk, u // this means result: null, which is ok, since we can not verify a transaction that does not exists if (!vc->proof) return vc_err(vc, "Proof is missing!"); - bytes_t* blockHeader = d_get_bytesk(vc->proof, K_BLOCK); + bytes_t* blockHeader = d_get_bytes(vc->proof, K_BLOCK); if (!blockHeader) return vc_err(vc, "No Block-Proof!"); // verify that the block matches the block as described in the transaction @@ -200,7 +200,7 @@ in3_ret_t eth_verify_eth_getTransactionByBlock(in3_vctx_t* vc, d_token_t* blk, u bytes_t number_in_header; if (!blk_num) return vc_err(vc, "No block number found"); - else if (d_get(vc->result, K_BLOCK_NUMBER) && blk_num != d_get_longk(vc->result, K_BLOCK_NUMBER)) + else if (d_get(vc->result, K_BLOCK_NUMBER) && blk_num != d_get_long(vc->result, K_BLOCK_NUMBER)) return vc_err(vc, "The block number does not match the required"); else if (rlp_decode_in_list(blockHeader, BLOCKHEADER_NUMBER, &number_in_header) != 1 || bytes_to_long(number_in_header.data, number_in_header.len) != blk_num) return vc_err(vc, "The block number in the header does not match the required"); @@ -212,12 +212,12 @@ in3_ret_t eth_verify_eth_getTransactionByBlock(in3_vctx_t* vc, d_token_t* blk, u return vc_err(vc, "No block hash & number found"); } - if (d_get(vc->result, K_TRANSACTION_INDEX) && tx_idx != (uint32_t) d_get_intk(vc->result, K_TRANSACTION_INDEX)) + if (d_get(vc->result, K_TRANSACTION_INDEX) && tx_idx != (uint32_t) d_get_int(vc->result, K_TRANSACTION_INDEX)) return vc_err(vc, "The transaction index does not match the required"); res = eth_verify_blockheader(vc, blockHeader, d_get_byteskl(vc->result, K_BLOCK_HASH, 32)); if (res == IN3_OK) { - bytes_t* path = create_tx_path(d_get_intk(vc->proof, K_TX_INDEX)); + bytes_t* path = create_tx_path(d_get_int(vc->proof, K_TX_INDEX)); bytes_t root, raw_transaction = {.len = 0, .data = NULL}; bytes_t** proof = d_create_bytes_vec(d_get(vc->proof, K_MERKLE_PROOF)); @@ -245,7 +245,7 @@ in3_ret_t eth_verify_eth_getTransactionByBlock(in3_vctx_t* vc, d_token_t* blk, u if (res == IN3_OK && !d_eq(d_get(vc->result, K_TRANSACTION_INDEX), d_get(vc->proof, K_TX_INDEX))) res = vc_err(vc, "wrong transaction index"); - if (res == IN3_OK && (rlp_decode_in_list(blockHeader, BLOCKHEADER_NUMBER, &root) != 1 || d_get_longk(vc->result, K_BLOCK_NUMBER) != bytes_to_long(root.data, root.len))) + if (res == IN3_OK && (rlp_decode_in_list(blockHeader, BLOCKHEADER_NUMBER, &root) != 1 || d_get_long(vc->result, K_BLOCK_NUMBER) != bytes_to_long(root.data, root.len))) res = vc_err(vc, "wrong block number"); bytes_t* tx_data = serialize_tx(vc->result); diff --git a/c/src/verifier/eth1/basic/filter.c b/c/src/verifier/eth1/basic/filter.c index e5168846e..5b4514c23 100644 --- a/c/src/verifier/eth1/basic/filter.c +++ b/c/src/verifier/eth1/basic/filter.c @@ -33,10 +33,11 @@ *******************************************************************************/ #include "filter.h" -#include "../../../core/client/context_internal.h" #include "../../../core/client/keys.h" +#include "../../../core/client/request_internal.h" #include "../../../core/util/log.h" #include "../../../core/util/mem.h" +#include "eth_basic.h" #include #include @@ -171,7 +172,7 @@ static in3_filter_t* filter_new(in3_filter_type_t ft) { return f; } -in3_ret_t filter_add(in3_ctx_t* ctx, in3_filter_type_t type, char* options) { +in3_ret_t filter_add(in3_filter_handler_t* filters, in3_req_t* ctx, in3_filter_type_t type, char* options) { if (type == FILTER_PENDING) return IN3_ENOTSUP; else if (options == NULL && type != FILTER_BLOCK) @@ -181,21 +182,21 @@ in3_ret_t filter_add(in3_ctx_t* ctx, in3_filter_type_t type, char* options) { in3_ret_t res = IN3_OK; uint64_t current_block = 0; - in3_ctx_t* block_ctx = ctx_find_required(ctx, "eth_blockNumber"); + in3_req_t* block_ctx = req_find_required(ctx, "eth_blockNumber"); if (!block_ctx) - return ctx_add_required(ctx, ctx_new(ctx->client, _strdupn("{\"method\":\"eth_blockNumber\",\"params\":[]}", -1))); + return req_add_required(ctx, req_new(ctx->client, _strdupn("{\"method\":\"eth_blockNumber\",\"params\":[]}", -1))); else { - switch (in3_ctx_state(block_ctx)) { - case CTX_ERROR: - return ctx_set_error(block_ctx, block_ctx->error ? block_ctx->error : "Error fetching the blocknumber", block_ctx->verification_state ? block_ctx->verification_state : IN3_ERPC); - case CTX_WAITING_FOR_RESPONSE: - case CTX_WAITING_TO_SEND: + switch (in3_req_state(block_ctx)) { + case REQ_ERROR: + return req_set_error(block_ctx, block_ctx->error ? block_ctx->error : "Error fetching the blocknumber", block_ctx->verification_state ? block_ctx->verification_state : IN3_ERPC); + case REQ_WAITING_FOR_RESPONSE: + case REQ_WAITING_TO_SEND: return IN3_WAITING; - case CTX_SUCCESS: - if (IN3_OK != (res = ctx_get_error(block_ctx, 0))) - return ctx_set_error(block_ctx, block_ctx->error ? block_ctx->error : "Error fetching the blocknumber", res); - current_block = d_get_longk(block_ctx->responses[0], K_RESULT); - TRY(ctx_remove_required(ctx, block_ctx, false)); + case REQ_SUCCESS: + if (IN3_OK != (res = req_get_error(block_ctx, 0))) + return req_set_error(block_ctx, block_ctx->error ? block_ctx->error : "Error fetching the blocknumber", res); + current_block = d_get_long(block_ctx->responses[0], K_RESULT); + TRY(req_remove_required(ctx, block_ctx, false)); } } @@ -206,85 +207,77 @@ in3_ret_t filter_add(in3_ctx_t* ctx, in3_filter_type_t type, char* options) { // Reuse filter ids that have been uninstalled // Note: filter ids are 1 indexed, and the associated in3_filter_t object is stored // at pos (id - 1) internally in in3->filters->array - if (ctx->client->filters == NULL) - ctx->client->filters = _calloc(1, sizeof *(ctx->client->filters)); - in3_filter_handler_t* fh = ctx->client->filters; - for (size_t i = 0; i < fh->count; i++) { - if (fh->array[i] == NULL) { - fh->array[i] = f; + for (size_t i = 0; i < filters->count; i++) { + if (filters->array[i] == NULL) { + filters->array[i] = f; return i + 1; } } in3_filter_t** arr_; - if (fh->array) - arr_ = _realloc(fh->array, sizeof(in3_filter_t*) * (fh->count + 1), sizeof(in3_filter_t*) * (fh->count)); + if (filters->array) + arr_ = _realloc(filters->array, sizeof(in3_filter_t*) * (filters->count + 1), sizeof(in3_filter_t*) * (filters->count)); else - arr_ = _malloc(sizeof(in3_filter_t*) * (fh->count + 1)); + arr_ = _malloc(sizeof(in3_filter_t*) * (filters->count + 1)); if (arr_ == NULL) { return IN3_ENOMEM; } - fh->array = arr_; - fh->array[fh->count] = f; - fh->count += 1; - return fh->count; + filters->array = arr_; + filters->array[filters->count] = f; + filters->count += 1; + return filters->count; } -bool filter_remove(in3_t* in3, size_t id) { - if (in3->filters == NULL) - return false; - if (id == 0 || id > in3->filters->count) +bool filter_remove(in3_filter_handler_t* filters, size_t id) { + if (id == 0 || id > filters->count) return false; // We don't realloc the array here, instead we simply set this slot to NULL to indicate // that it has been removed and reuse it in add_filter() - in3_filter_t* f = in3->filters->array[id - 1]; + in3_filter_t* f = filters->array[id - 1]; if (!f) return false; f->release(f); - in3->filters->array[id - 1] = NULL; + filters->array[id - 1] = NULL; return true; } -static in3_ctx_t* ctx_find_required_for_block(in3_ctx_t* ctx, uint64_t block_number) { +static in3_req_t* req_find_required_for_block(in3_req_t* ctx, uint64_t block_number) { // find the subctx for the current blocknumber - for (in3_ctx_t* sub_ctx = ctx->required; sub_ctx; sub_ctx = sub_ctx->required) { + for (in3_req_t* sub_ctx = ctx->required; sub_ctx; sub_ctx = sub_ctx->required) { if (!sub_ctx->requests) continue; - const char* required_method = d_get_stringk(sub_ctx->requests[0], K_METHOD); + const char* required_method = d_get_string(sub_ctx->requests[0], K_METHOD); if (required_method && strcmp(required_method, "eth_getBlockByNumber")) continue; if (block_number == d_get_long_at(d_get(sub_ctx->requests[0], K_PARAMS), 0)) return sub_ctx; } return NULL; } -in3_ret_t filter_get_changes(in3_ctx_t* ctx, size_t id, sb_t* result) { +in3_ret_t filter_get_changes(in3_filter_handler_t* filters, in3_req_t* ctx, size_t id, sb_t* result) { in3_ret_t res = IN3_OK; - in3_t* in3 = ctx->client; - if (in3->filters == NULL) - return ctx_set_error(ctx, "no filters found", IN3_EUNKNOWN); - if (id == 0 || id > in3->filters->count) - return ctx_set_error(ctx, "filter with id does not exist", IN3_EUNKNOWN); + if (id == 0 || id > filters->count) + return req_set_error(ctx, "filter with id does not exist", IN3_EUNKNOWN); // fetch the current block number - in3_ctx_t* block_ctx = ctx_find_required(ctx, "eth_blockNumber"); + in3_req_t* block_ctx = req_find_required(ctx, "eth_blockNumber"); if (!block_ctx) - return ctx_add_required(ctx, ctx_new(ctx->client, _strdupn("{\"method\":\"eth_blockNumber\",\"params\":[]}", -1))); + return req_add_required(ctx, req_new(ctx->client, _strdupn("{\"method\":\"eth_blockNumber\",\"params\":[]}", -1))); else { - switch (in3_ctx_state(block_ctx)) { - case CTX_ERROR: - return ctx_set_error(block_ctx, block_ctx->error ? block_ctx->error : "Error fetching the blocknumber", block_ctx->verification_state ? block_ctx->verification_state : IN3_ERPC); - case CTX_WAITING_FOR_RESPONSE: - case CTX_WAITING_TO_SEND: + switch (in3_req_state(block_ctx)) { + case REQ_ERROR: + return req_set_error(block_ctx, block_ctx->error ? block_ctx->error : "Error fetching the blocknumber", block_ctx->verification_state ? block_ctx->verification_state : IN3_ERPC); + case REQ_WAITING_FOR_RESPONSE: + case REQ_WAITING_TO_SEND: return IN3_WAITING; - case CTX_SUCCESS: - if (IN3_OK != (res = ctx_get_error(block_ctx, 0))) - return ctx_set_error(block_ctx, block_ctx->error ? block_ctx->error : "Error fetching the blocknumber", res); + case REQ_SUCCESS: + if (IN3_OK != (res = req_get_error(block_ctx, 0))) + return req_set_error(block_ctx, block_ctx->error ? block_ctx->error : "Error fetching the blocknumber", res); } } - uint64_t blkno = d_get_longk(block_ctx->responses[0], K_RESULT); + uint64_t blkno = d_get_long(block_ctx->responses[0], K_RESULT); - in3_filter_t* f = in3->filters->array[id - 1]; + in3_filter_t* f = filters->array[id - 1]; if (!f) - return ctx_set_error(ctx, "filter with id does not exist", IN3_EUNKNOWN); + return req_set_error(ctx, "filter with id does not exist", IN3_EUNKNOWN); char* fopt = f->options; switch (f->type) { @@ -295,7 +288,7 @@ in3_ret_t filter_get_changes(in3_ctx_t* ctx, size_t id, sb_t* result) { return IN3_OK; } - in3_ctx_t* logs_ctx = ctx_find_required(ctx, "eth_getLogs"); + in3_req_t* logs_ctx = req_find_required(ctx, "eth_getLogs"); if (!logs_ctx) { // create request char* fopt_ = filter_opt_set_fromBlock(fopt, f->last_block, !f->is_first_usage); @@ -305,21 +298,21 @@ in3_ret_t filter_get_changes(in3_ctx_t* ctx, size_t id, sb_t* result) { _free(fopt_); char* req = sb_req->data; _free(sb_req); - return ctx_add_required(ctx, ctx_new(ctx->client, req)); + return req_add_required(ctx, req_new(ctx->client, req)); } // check existing ctx - switch (in3_ctx_state(logs_ctx)) { - case CTX_ERROR: - return ctx_set_error(logs_ctx, logs_ctx->error ? logs_ctx->error : "Error fetching logs", logs_ctx->verification_state ? logs_ctx->verification_state : IN3_ERPC); - case CTX_WAITING_FOR_RESPONSE: - case CTX_WAITING_TO_SEND: + switch (in3_req_state(logs_ctx)) { + case REQ_ERROR: + return req_set_error(logs_ctx, logs_ctx->error ? logs_ctx->error : "Error fetching logs", logs_ctx->verification_state ? logs_ctx->verification_state : IN3_ERPC); + case REQ_WAITING_FOR_RESPONSE: + case REQ_WAITING_TO_SEND: return IN3_WAITING; - case CTX_SUCCESS: - if (IN3_OK != (res = ctx_get_error(logs_ctx, 0))) - return ctx_set_error(logs_ctx, logs_ctx->error ? logs_ctx->error : "Error fetching logs", res); + case REQ_SUCCESS: + if (IN3_OK != (res = req_get_error(logs_ctx, 0))) + return req_set_error(logs_ctx, logs_ctx->error ? logs_ctx->error : "Error fetching logs", res); } d_token_t* r = d_get(logs_ctx->responses[0], K_RESULT); - if (!r) return ctx_set_error(logs_ctx, "no result in filter response", IN3_ERPC); + if (!r) return req_set_error(logs_ctx, "no result in filter response", IN3_ERPC); char* jr = d_create_json(logs_ctx->response_context, r); sb_add_chars(result, jr); _free(jr); @@ -336,24 +329,24 @@ in3_ret_t filter_get_changes(in3_ctx_t* ctx, size_t id, sb_t* result) { else { sb_add_char(result, '['); for (uint64_t i = f->last_block + 1; i <= blkno; i++) { - in3_ctx_t* block_ctx = ctx_find_required_for_block(ctx, i); + in3_req_t* block_ctx = req_find_required_for_block(ctx, i); if (!block_ctx) { char* req = _malloc(150); sprintf(req, "{\"method\":\"eth_getBlockByNumber\",\"params\":[\"0x%" PRIx64 "\", false]}", i); - res = ctx_add_required(ctx, ctx_new(ctx->client, req)); + res = req_add_required(ctx, req_new(ctx->client, req)); } else { // check existing ctx - switch (in3_ctx_state(block_ctx)) { - case CTX_ERROR: - return ctx_set_error(block_ctx, block_ctx->error ? block_ctx->error : "Error fetching blocks", block_ctx->verification_state ? block_ctx->verification_state : IN3_ERPC); - case CTX_WAITING_FOR_RESPONSE: - case CTX_WAITING_TO_SEND: + switch (in3_req_state(block_ctx)) { + case REQ_ERROR: + return req_set_error(block_ctx, block_ctx->error ? block_ctx->error : "Error fetching blocks", block_ctx->verification_state ? block_ctx->verification_state : IN3_ERPC); + case REQ_WAITING_FOR_RESPONSE: + case REQ_WAITING_TO_SEND: return IN3_WAITING; - case CTX_SUCCESS: - if (IN3_OK != (res = ctx_get_error(block_ctx, 0))) - return ctx_set_error(block_ctx, block_ctx->error ? block_ctx->error : "Error fetching blocks", res); + case REQ_SUCCESS: + if (IN3_OK != (res = req_get_error(block_ctx, 0))) + return req_set_error(block_ctx, block_ctx->error ? block_ctx->error : "Error fetching blocks", res); } d_token_t* hash = d_getl(d_get(block_ctx->responses[0], K_RESULT), K_HASH, 32); @@ -369,7 +362,7 @@ in3_ret_t filter_get_changes(in3_ctx_t* ctx, size_t id, sb_t* result) { return IN3_OK; } default: - return ctx_set_error(ctx, "unsupported filter type", IN3_ENOTSUP); + return req_set_error(ctx, "unsupported filter type", IN3_ENOTSUP); } return IN3_OK; } \ No newline at end of file diff --git a/c/src/verifier/eth1/basic/filter.h b/c/src/verifier/eth1/basic/filter.h index 9731a5cd5..2cdeb1cc5 100644 --- a/c/src/verifier/eth1/basic/filter.h +++ b/c/src/verifier/eth1/basic/filter.h @@ -36,11 +36,12 @@ #define FILTER_H #include "../../../core/client/client.h" -#include "../../../core/client/context.h" +#include "../../../core/client/request.h" +#include "eth_basic.h" -in3_ret_t filter_add(in3_ctx_t* ctx, in3_filter_type_t type, char* options); -bool filter_remove(in3_t* in3, size_t id); -in3_ret_t filter_get_changes(in3_ctx_t* ctx, size_t id, sb_t* result); +in3_ret_t filter_add(in3_filter_handler_t* filters, in3_req_t* req, in3_filter_type_t type, char* options); +bool filter_remove(in3_filter_handler_t* filters, size_t id); +in3_ret_t filter_get_changes(in3_filter_handler_t* filters, in3_req_t* req, size_t id, sb_t* result); bool filter_opt_valid(d_token_t* tx_params); char* filter_opt_set_fromBlock(char* fopt, uint64_t toBlock, bool should_overwrite); diff --git a/c/src/verifier/eth1/basic/sign_tx.c b/c/src/verifier/eth1/basic/sign_tx.c index 591f8e27a..1c3bb5c5c 100644 --- a/c/src/verifier/eth1/basic/sign_tx.c +++ b/c/src/verifier/eth1/basic/sign_tx.c @@ -32,8 +32,8 @@ * with this program. If not, see . *******************************************************************************/ -#include "../../../core/client/context_internal.h" #include "../../../core/client/keys.h" +#include "../../../core/client/request_internal.h" #include "../../../core/util/data.h" #include "../../../core/util/mem.h" #include "../../../core/util/utils.h" @@ -60,22 +60,22 @@ static inline bytes_t getl(d_token_t* t, uint16_t key, size_t l) { } /** return data from the client.*/ -static in3_ret_t get_from_nodes(in3_ctx_t* parent, char* method, char* params, bytes_t* dst) { +static in3_ret_t get_from_nodes(in3_req_t* parent, char* method, char* params, bytes_t* dst) { // check if the method is already existing - in3_ctx_t* ctx = ctx_find_required(parent, method); + in3_req_t* ctx = req_find_required(parent, method); if (ctx) { // found one - so we check if it is useable. - switch (in3_ctx_state(ctx)) { + switch (in3_req_state(ctx)) { // in case of an error, we report it back to the parent context - case CTX_ERROR: - return ctx_set_error(parent, ctx->error, IN3_EUNKNOWN); + case REQ_ERROR: + return req_set_error(parent, ctx->error, IN3_EUNKNOWN); // if we are still waiting, we stop here and report it. - case CTX_WAITING_FOR_RESPONSE: - case CTX_WAITING_TO_SEND: + case REQ_WAITING_FOR_RESPONSE: + case REQ_WAITING_TO_SEND: return IN3_WAITING; // if it is useable, we can now handle the result. - case CTX_SUCCESS: { + case REQ_SUCCESS: { d_token_t* r = d_get(ctx->responses[0], K_RESULT); if (r) { // we have a result, so write it back to the dst @@ -84,7 +84,7 @@ static in3_ret_t get_from_nodes(in3_ctx_t* parent, char* method, char* params, b } else // or check the error and report it - return ctx_check_response_error(ctx, 0); + return req_check_response_error(ctx, 0); } } } @@ -97,32 +97,32 @@ static in3_ret_t get_from_nodes(in3_ctx_t* parent, char* method, char* params, b // create it sprintf(req, "{\"method\":\"%s\",\"jsonrpc\":\"2.0\",\"params\":%s}", method, params); // and add the request context to the parent. - return ctx_add_required(parent, ctx_new(parent->client, req)); + return req_add_required(parent, req_new(parent->client, req)); } /** gets the from-fied from the tx or ask the signer */ -static in3_ret_t get_from_address(d_token_t* tx, in3_ctx_t* ctx, address_t res) { +static in3_ret_t get_from_address(d_token_t* tx, in3_req_t* ctx, address_t res) { d_token_t* t = d_get(tx, K_FROM); if (t) { // we only accept valid from addresses which need to be 20 bytes - if (d_type(t) != T_BYTES || d_len(t) != 20) return ctx_set_error(ctx, "invalid from address in tx", IN3_EINVAL); + if (d_type(t) != T_BYTES || d_len(t) != 20) return req_set_error(ctx, "invalid from address in tx", IN3_EINVAL); memcpy(res, d_bytes(t)->data, 20); return IN3_OK; } // if it is not specified, we rely on the from-address of the signer. - if (!in3_plugin_is_registered(ctx->client, PLGN_ACT_SIGN_ACCOUNT)) return ctx_set_error(ctx, "missing from address in tx", IN3_EINVAL); + if (!in3_plugin_is_registered(ctx->client, PLGN_ACT_SIGN_ACCOUNT)) return req_set_error(ctx, "missing from address in tx", IN3_EINVAL); - in3_sign_account_ctx_t actx = {.ctx = ctx, .accounts = NULL, .accounts_len = 0}; + in3_sign_account_ctx_t actx = {.req = ctx, .accounts = NULL, .accounts_len = 0}; TRY(in3_plugin_execute_first(ctx, PLGN_ACT_SIGN_ACCOUNT, &actx)) - if (!actx.accounts) return ctx_set_error(ctx, "no from address found", IN3_EINVAL); + if (!actx.accounts) return req_set_error(ctx, "no from address found", IN3_EINVAL); memcpy(res, actx.accounts, 20); _free(actx.accounts); return IN3_OK; } /** checks if the nonce and gas is set or fetches it from the nodes */ -static in3_ret_t get_nonce_and_gasprice(bytes_t* nonce, bytes_t* gas_price, in3_ctx_t* ctx, address_t from) { +static in3_ret_t get_nonce_and_gasprice(bytes_t* nonce, bytes_t* gas_price, in3_req_t* ctx, address_t from) { in3_ret_t ret = IN3_OK; if (!nonce->data) { bytes_t from_bytes = bytes(from, 20); @@ -146,14 +146,14 @@ static in3_ret_t get_nonce_and_gasprice(bytes_t* nonce, bytes_t* gas_price, in3_ /** gets the v-value from the chain_id */ static inline uint64_t get_v(chain_id_t chain) { uint64_t v = chain; - if (v > 0xFF) v = 0; // this is only valid for ethereum chains. + if (v > 0xFF && v != 1337) v = 0; // this is only valid for ethereum chains. return v; } /** * prepares a transaction and writes the data to the dst-bytes. In case of success, you MUST free only the data-pointer of the dst. */ -in3_ret_t eth_prepare_unsigned_tx(d_token_t* tx, in3_ctx_t* ctx, bytes_t* dst) { +in3_ret_t eth_prepare_unsigned_tx(d_token_t* tx, in3_req_t* ctx, bytes_t* dst) { address_t from; // read the values @@ -168,7 +168,7 @@ in3_ret_t eth_prepare_unsigned_tx(d_token_t* tx, in3_ctx_t* ctx, bytes_t* dst) { chain_id_t chain_id = ctx->client->chain.chain_id; if (chain_id == CHAIN_ID_LOCAL) { d_token_t* r = NULL; - TRY(ctx_send_sub_request(ctx, "eth_chainId", "", NULL, &r)) + TRY(req_send_sub_request(ctx, "eth_chainId", "", NULL, &r)) chain_id = d_long(r); } TRY(get_from_address(tx, ctx, from)) @@ -181,7 +181,7 @@ in3_ret_t eth_prepare_unsigned_tx(d_token_t* tx, in3_ctx_t* ctx, bytes_t* dst) { // do we need to change it? if (in3_plugin_is_registered(ctx->client, PLGN_ACT_SIGN_PREPARE)) { - in3_sign_prepare_ctx_t pctx = {.ctx = ctx, .old_tx = *dst, .new_tx = {0}}; + in3_sign_prepare_ctx_t pctx = {.req = ctx, .old_tx = *dst, .new_tx = {0}}; memcpy(pctx.account, from, 20); in3_ret_t prep_res = in3_plugin_execute_first(ctx, PLGN_ACT_SIGN_PREPARE, &pctx); @@ -197,8 +197,8 @@ in3_ret_t eth_prepare_unsigned_tx(d_token_t* tx, in3_ctx_t* ctx, bytes_t* dst) { } // cleanup subcontexts - TRY(ctx_remove_required(ctx, ctx_find_required(ctx, "eth_getTransactionCount"), false)) - TRY(ctx_remove_required(ctx, ctx_find_required(ctx, "eth_gasPrice"), false)) + TRY(req_remove_required(ctx, req_find_required(ctx, "eth_getTransactionCount"), false)) + TRY(req_remove_required(ctx, req_find_required(ctx, "eth_gasPrice"), false)) return IN3_OK; } @@ -206,19 +206,19 @@ in3_ret_t eth_prepare_unsigned_tx(d_token_t* tx, in3_ctx_t* ctx, bytes_t* dst) { /** * signs a unsigned raw transaction and writes the raw data to the dst-bytes. In case of success, you MUST free only the data-pointer of the dst. */ -in3_ret_t eth_sign_raw_tx(bytes_t raw_tx, in3_ctx_t* ctx, address_t from, bytes_t* dst) { +in3_ret_t eth_sign_raw_tx(bytes_t raw_tx, in3_req_t* ctx, address_t from, bytes_t* dst) { bytes_t signature; // make sure, we have the correct chain_id chain_id_t chain_id = ctx->client->chain.chain_id; if (chain_id == CHAIN_ID_LOCAL) { d_token_t* r = NULL; - TRY(ctx_send_sub_request(ctx, "eth_chainId", "", NULL, &r)) + TRY(req_send_sub_request(ctx, "eth_chainId", "", NULL, &r)) chain_id = d_long(r); } - TRY(ctx_require_signature(ctx, SIGN_EC_HASH, &signature, raw_tx, bytes(from, 20))); - if (signature.len != 65) return ctx_set_error(ctx, "Transaction must be signed by a ECDSA-Signature!", IN3_EINVAL); + TRY(req_require_signature(ctx, SIGN_EC_HASH, &signature, raw_tx, bytes(from, 20))); + if (signature.len != 65) return req_set_error(ctx, "Transaction must be signed by a ECDSA-Signature!", IN3_EINVAL); // get the signature from required @@ -257,18 +257,18 @@ in3_ret_t eth_sign_raw_tx(bytes_t raw_tx, in3_ctx_t* ctx, address_t from, bytes_ } /** handle the sendTransaction internally */ -in3_ret_t handle_eth_sendTransaction(in3_ctx_t* ctx, d_token_t* req) { +in3_ret_t handle_eth_sendTransaction(in3_req_t* ctx, d_token_t* req) { // get the transaction-object d_token_t* tx_params = d_get(req, K_PARAMS); bytes_t unsigned_tx = bytes(NULL, 0), signed_tx = bytes(NULL, 0); address_t from; - if (!tx_params || d_type(tx_params + 1) != T_OBJECT) return ctx_set_error(ctx, "invalid params", IN3_EINVAL); + if (!tx_params || d_type(tx_params + 1) != T_OBJECT) return req_set_error(ctx, "invalid params", IN3_EINVAL); TRY(get_from_address(tx_params + 1, ctx, from)); // is there a pending signature? // we get the raw transaction from this request - in3_ctx_t* sig_ctx = ctx_find_required(ctx, "sign_ec_hash"); + in3_req_t* sig_ctx = req_find_required(ctx, "sign_ec_hash"); if (sig_ctx) { bytes_t raw = *d_get_bytes_at(d_get(sig_ctx->requests[0], K_PARAMS), 0); unsigned_tx = bytes(_malloc(raw.len), raw.len); diff --git a/c/src/verifier/eth1/evm/code.c b/c/src/verifier/eth1/evm/code.c index 52ad61d22..1f4bd520d 100644 --- a/c/src/verifier/eth1/evm/code.c +++ b/c/src/verifier/eth1/evm/code.c @@ -45,8 +45,8 @@ NONULL static in3_ret_t find_code_in_accounts(in3_vctx_t* vc, address_t address, for (d_iterator_t iter = d_iter(accounts); iter.left; d_iter_next(&iter)) { if (memcmp(d_get_byteskl(iter.token, K_ADDRESS, 20)->data, address, 20) == 0) { // even if we don't have a code, we still set the code_hash, since we need it later to verify - *code_hash = d_get_bytesk(iter.token, K_CODE_HASH); - bytes_t* code = d_get_bytesk(iter.token, K_CODE); + *code_hash = d_get_bytes(iter.token, K_CODE_HASH); + bytes_t* code = d_get_bytes(iter.token, K_CODE); if (code) { bytes32_t calculated_hash; keccak(*code, calculated_hash); @@ -62,11 +62,11 @@ NONULL static in3_ret_t find_code_in_accounts(in3_vctx_t* vc, address_t address, return IN3_EFIND; } -NONULL static in3_ctx_t* find_pending_code_request(in3_vctx_t* vc, address_t address) { +NONULL static in3_req_t* find_pending_code_request(in3_vctx_t* vc, address_t address) { // ok, we need a request, do we have a useable? - in3_ctx_t* ctx = vc->ctx->required; + in3_req_t* ctx = vc->req->required; while (ctx) { - if (strcmp(d_get_stringk(ctx->requests[0], K_METHOD), "eth_getCode") == 0) { + if (strcmp(d_get_string(ctx->requests[0], K_METHOD), "eth_getCode") == 0) { // the first param of the eth_getCode is the address bytes_t adr = d_to_bytes(d_get_at(d_get(ctx->requests[0], K_PARAMS), 0)); if (adr.len == 20 && memcmp(adr.data, address, 20) == 0) return ctx; @@ -84,12 +84,12 @@ NONULL static in3_ret_t in3_get_code_from_client(in3_vctx_t* vc, char* cache_key if (res != IN3_EFIND) return res; // ok, we need a request, do we have a useable? - in3_ctx_t* ctx = find_pending_code_request(vc, address); + in3_req_t* ctx = find_pending_code_request(vc, address); // if we have found one, we verify the result and return the bytes. if (ctx) - switch (in3_ctx_state(ctx)) { - case CTX_SUCCESS: { + switch (in3_req_state(ctx)) { + case REQ_SUCCESS: { d_token_t* rpc_result = d_get(ctx->responses[0], K_RESULT); if (!ctx->error && rpc_result) { bytes32_t calculated_code_hash; @@ -97,7 +97,7 @@ NONULL static in3_ret_t in3_get_code_from_client(in3_vctx_t* vc, char* cache_key keccak(code, calculated_code_hash); if (code_hash && memcmp(code_hash->data, calculated_code_hash, 32) != 0) { vc_err(vc, "Wrong codehash"); - ctx_remove_required(vc->ctx, ctx, false); + req_remove_required(vc->req, ctx, false); return IN3_EINVAL; } @@ -110,15 +110,15 @@ NONULL static in3_ret_t in3_get_code_from_client(in3_vctx_t* vc, char* cache_key *must_free = 1; // we always try to cache the code - in3_cache_ctx_t cctx = {.ctx = vc->ctx, .key = cache_key, .content = *target}; - in3_plugin_execute_first_or_none(vc->ctx, PLGN_ACT_CACHE_SET, &cctx); + in3_cache_ctx_t cctx = {.req = vc->req, .key = cache_key, .content = *target}; + in3_plugin_execute_first_or_none(vc->req, PLGN_ACT_CACHE_SET, &cctx); return IN3_OK; } else return vc_err(vc, ctx->error ? ctx->error : "Missing result"); } - case CTX_ERROR: + case REQ_ERROR: return IN3_ERPC; default: return IN3_WAITING; @@ -129,13 +129,13 @@ NONULL static in3_ret_t in3_get_code_from_client(in3_vctx_t* vc, char* cache_key // we can use the cache_key, since it contains the hexencoded string with a "C"-prefix. snprintX(req, 200, "{\"method\":\"eth_getCode\",\"jsonrpc\":\"2.0\",\"params\":[\"0x%s\",\"latest\"],\"in3\":{\"verification\":\"none\"}}", cache_key + 1); - return ctx_add_required(vc->ctx, ctx_new(vc->ctx->client, req)); + return req_add_required(vc->req, req_new(vc->req->client, req)); } } in3_ret_t in3_get_code(in3_vctx_t* vc, address_t address, cache_entry_t** target) { // search in thew cache of the current context - for (cache_entry_t* en = vc->ctx->cache; en; en = en->next) { + for (cache_entry_t* en = vc->req->cache; en; en = en->next) { if (en->key.len == 20 && memcmp(address, en->key.data, 20) == 0) { *target = en; return IN3_OK; @@ -152,8 +152,8 @@ in3_ret_t in3_get_code(in3_vctx_t* vc, address_t address, cache_entry_t** target in3_ret_t res; // not cached yet - in3_cache_ctx_t cctx = {.ctx = vc->ctx, .key = key_str, .content = NULL}; - in3_plugin_execute_all(vc->ctx->client, PLGN_ACT_CACHE_GET, &cctx); + in3_cache_ctx_t cctx = {.req = vc->req, .key = key_str, .content = NULL}; + in3_plugin_execute_all(vc->req->client, PLGN_ACT_CACHE_GET, &cctx); code = cctx.content; in3_log_debug("try to get the code for %s from cache: %p\n", key_str, code); @@ -167,7 +167,7 @@ in3_ret_t in3_get_code(in3_vctx_t* vc, address_t address, cache_entry_t** target if (code) { bytes_t key = bytes(_malloc(20), 20); memcpy(key.data, address, 20); - *target = in3_cache_add_entry(&vc->ctx->cache, key, *code); + *target = in3_cache_add_entry(&vc->req->cache, key, *code); (*target)->props = must_free; // we also store the length into the 4 bytes buffer, so we can reference it later on. diff --git a/c/src/verifier/eth1/evm/env.c b/c/src/verifier/eth1/evm/env.c index 73d90bbd6..07f5ae40e 100644 --- a/c/src/verifier/eth1/evm/env.c +++ b/c/src/verifier/eth1/evm/env.c @@ -81,7 +81,7 @@ int in3_get_env(void* evm_ptr, uint16_t evm_key, uint8_t* in_data, int in_len, u switch (evm_key) { case EVM_ENV_BLOCKHEADER: - if (!(res = d_get_bytesk(vc->proof, K_BLOCK))) + if (!(res = d_get_bytes(vc->proof, K_BLOCK))) INVALID("no blockheader found") *out_data = res->data; return res->len; diff --git a/c/src/verifier/eth1/evm/evm.c b/c/src/verifier/eth1/evm/evm.c index cb2d7e83c..21c1bd9c9 100644 --- a/c/src/verifier/eth1/evm/evm.c +++ b/c/src/verifier/eth1/evm/evm.c @@ -33,7 +33,7 @@ *******************************************************************************/ #include "evm.h" -#include "../../../core/client/context.h" +#include "../../../core/client/request.h" #include "../../../core/util/data.h" #include "../../../core/util/log.h" #include "../../../core/util/mem.h" diff --git a/c/src/verifier/eth1/evm/evm_mem.c b/c/src/verifier/eth1/evm/evm_mem.c index 7482d8f03..e2178fae1 100644 --- a/c/src/verifier/eth1/evm/evm_mem.c +++ b/c/src/verifier/eth1/evm/evm_mem.c @@ -33,7 +33,7 @@ *******************************************************************************/ #include "evm_mem.h" -#include "../../../core/client/context.h" +#include "../../../core/client/request.h" #include "../../../core/util/data.h" #include "../../../core/util/log.h" #include "../../../core/util/mem.h" diff --git a/c/src/verifier/eth1/evm/opcodes.c b/c/src/verifier/eth1/evm/opcodes.c index b524a17a8..8a9aa356a 100644 --- a/c/src/verifier/eth1/evm/opcodes.c +++ b/c/src/verifier/eth1/evm/opcodes.c @@ -33,7 +33,7 @@ *******************************************************************************/ #include "opcodes.h" -#include "../../../core/client/context.h" +#include "../../../core/client/request.h" #include "../../../core/util/data.h" #include "../../../core/util/log.h" #include "../../../core/util/mem.h" diff --git a/c/src/verifier/eth1/full/eth_full.c b/c/src/verifier/eth1/full/eth_full.c index 240ff46b5..1e33787ef 100644 --- a/c/src/verifier/eth1/full/eth_full.c +++ b/c/src/verifier/eth1/full/eth_full.c @@ -33,8 +33,8 @@ *******************************************************************************/ #include "eth_full.h" -#include "../../../core/client/context_internal.h" #include "../../../core/client/keys.h" +#include "../../../core/client/request_internal.h" #include "../../../core/util/data.h" #include "../../../core/util/log.h" #include "../../../core/util/mem.h" @@ -48,20 +48,14 @@ in3_ret_t in3_verify_eth_full(void* pdata, in3_plugin_act_t action, void* pctx) { UNUSED_VAR(pdata); UNUSED_VAR(action); - in3_vctx_t* vc = pctx; - char* method = d_get_stringk(vc->request, K_METHOD); + in3_vctx_t* vc = pctx; if (vc->chain->type != CHAIN_ETH) return IN3_EIGNORE; - if (in3_ctx_get_proof(vc->ctx, vc->index) == PROOF_NONE) return IN3_OK; + if (in3_req_get_proof(vc->req, vc->index) == PROOF_NONE) return IN3_OK; // do we have a result? if not it is a vaslid error-response - if (!vc->result) - return 0; + if (!vc->result) return IN3_OK; - // do we support this request? - if (!method) - return vc_err(vc, "No Method in request defined!"); - - if (strcmp(method, "eth_call") == 0) { + if (strcmp(vc->method, "eth_call") == 0) { if (eth_verify_account_proof(vc) < 0) return vc_err(vc, "proof could not be validated"); d_token_t* tx = d_get_at(d_get(vc->request, K_PARAMS), 0); bytes_t* address = d_get_byteskl(tx, K_TO, 20); @@ -69,8 +63,8 @@ in3_ret_t in3_verify_eth_full(void* pdata, in3_plugin_act_t action, void* pctx) memset(zeros, 0, 20); int res = 0; bytes_t* from = d_get_byteskl(tx, K_FROM, 20); - bytes_t* value = d_get_bytesk(tx, K_VALUE); - bytes_t* data = d_get_bytesk(tx, K_DATA); + bytes_t* value = d_get_bytes(tx, K_VALUE); + bytes_t* data = d_get_bytes(tx, K_DATA); bytes_t gas = d_to_bytes(d_get(tx, K_GAS_LIMIT)); bytes_t* result = NULL; uint64_t gas_limit = bytes_to_long(gas.data, gas.len); @@ -118,12 +112,12 @@ in3_ret_t in3_verify_eth_full(void* pdata, in3_plugin_act_t action, void* pctx) // b_print(result); // b_print(d_bytes(vc->result)); } - if (vc->ctx->error) return IN3_EINVAL; + if (vc->req->error) return IN3_EINVAL; return res ? 0 : vc_err(vc, "The result does not match the proven result"); case IN3_WAITING: return IN3_WAITING; default: - return ctx_set_error(vc->ctx, "General Error during execution", (in3_ret_t) ret); + return req_set_error(vc->req, "General Error during execution", (in3_ret_t) ret); } } else diff --git a/c/src/verifier/eth1/nano/blockheader.c b/c/src/verifier/eth1/nano/blockheader.c index 648dbcf6b..2d059863d 100644 --- a/c/src/verifier/eth1/nano/blockheader.c +++ b/c/src/verifier/eth1/nano/blockheader.c @@ -32,8 +32,8 @@ * with this program. If not, see . *******************************************************************************/ -#include "../../../core/client/context.h" #include "../../../core/client/keys.h" +#include "../../../core/client/request.h" #include "../../../core/util/bitset.h" #include "../../../core/util/mem.h" #include "../../../third-party/crypto/ecdsa.h" @@ -109,21 +109,21 @@ static in3_ret_t add_aura_validators(in3_vctx_t* vc, vhist_t** vhp) { vhist_t* vh = *vhp; // get validators from contract - in3_proof_t proof_ = in3_ctx_get_proof(vc->ctx, vc->index); + in3_proof_t proof_ = in3_req_get_proof(vc->req, vc->index); // TODO we need to make this async and use "in3":{"verification":"none"} - vc->ctx->client->proof = PROOF_NONE; - in3_ctx_t* ctx_ = in3_client_rpc_ctx(vc->ctx->client, "in3_validatorList", "[]"); - vc->ctx->client->proof = proof_; - res = ctx_get_error(ctx_, 0); + vc->req->client->proof = PROOF_NONE; + in3_req_t* ctx_ = in3_client_rpc_ctx(vc->req->client, "in3_validatorList", "[]"); + vc->req->client->proof = proof_; + res = req_get_error(ctx_, 0); if (res != IN3_OK) { - ctx_free(ctx_); + req_free(ctx_); return vc_err(vc, ctx_->error); } // Validate proof d_token_t *ss = d_get(d_get(ctx_->responses[0], K_RESULT), K_STATES), *prf = NULL; for (d_iterator_t sitr = d_iter(ss); sitr.left; d_iter_next(&sitr)) { - blk = d_get_longk(sitr.token, K_BLOCK); + blk = d_get_long(sitr.token, K_BLOCK); if (blk <= vh->last_change_block) continue; prf = d_get(sitr.token, K_PROOF); @@ -131,7 +131,7 @@ static in3_ret_t add_aura_validators(in3_vctx_t* vc, vhist_t** vhp) { return vc_err(vc, "validator list has no proof"); } - bytes_t* prf_blk = d_get_bytesk(prf, K_BLOCK); + bytes_t* prf_blk = d_get_bytes(prf, K_BLOCK); rlp_decode_in_list(prf_blk, BLOCKHEADER_NUMBER, &tmp); uint64_t prf_blkno = bytes_to_long(tmp.data, tmp.len); if (blk != prf_blkno) { @@ -188,7 +188,7 @@ static in3_ret_t add_aura_validators(in3_vctx_t* vc, vhist_t** vhp) { return vc_err(vc, "not enough finality to accept state"); // Verify receipt - bytes_t* path = create_tx_path(d_get_intk(prf, K_TX_INDEX)); + bytes_t* path = create_tx_path(d_get_int(prf, K_TX_INDEX)); // verify the merkle proof for the receipt if (rlp_decode_in_list(prf_blk, BLOCKHEADER_RECEIPT_ROOT, &tmp) != 1) @@ -203,10 +203,10 @@ static in3_ret_t add_aura_validators(in3_vctx_t* vc, vhist_t** vhp) { bytes_t log_data; rlp_decode(&raw_receipt, rlp_decode_len(&raw_receipt) - 1, &log_data); - rlp_decode(&log_data, d_get_intk(prf, K_LOG_INDEX), &log_data); + rlp_decode(&log_data, d_get_int(prf, K_LOG_INDEX), &log_data); rlp_decode(&log_data, 0, &tmp); - if (!b_cmp(&tmp, d_get_bytesk(vc->chain->spec->result, K_VALIDATOR_CONTRACT))) + if (!b_cmp(&tmp, d_get_bytes(vc->chain->spec->result, K_VALIDATOR_CONTRACT))) return vc_err(vc, "Wrong address in log"); rlp_decode(&log_data, 1, &tmp); @@ -246,7 +246,7 @@ static in3_ret_t add_aura_validators(in3_vctx_t* vc, vhist_t** vhp) { vh_free(vh); *vhp = vh_init_nodelist(d_get(ctx_->responses[0], K_RESULT)); - ctx_free(ctx_); + req_free(ctx_); return res; } @@ -254,7 +254,7 @@ static vhist_engine_t eth_get_engine(in3_vctx_t* vc, bytes_t* header, d_token_t* bytes_t b; // try to get from cache - *vh = vh_cache_retrieve(vc->ctx->client); + *vh = vh_cache_retrieve(vc->req->client); // if no validators in cache, get them from spec if (!*vh) { @@ -263,13 +263,13 @@ static vhist_engine_t eth_get_engine(in3_vctx_t* vc, bytes_t* header, d_token_t* vc_err(vc, "Invalid spec"); return ENGINE_UNKNOWN; } - vh_cache_save(*vh, vc->ctx->client); + vh_cache_save(*vh, vc->req->client); } if (vc->last_validator_change > (*vh)->last_change_block) { in3_ret_t res = add_aura_validators(vc, vh); if (res != IN3_OK) return res; - vh_cache_save(*vh, vc->ctx->client); + vh_cache_save(*vh, vc->req->client); } rlp_decode_in_list(header, BLOCKHEADER_NUMBER, &b); @@ -369,13 +369,13 @@ NONULL IN3_EXPORT_TEST void add_verified(in3_t* c, in3_chain_t* chain, uint64_t static void mark_offline(in3_vctx_t* vc, unsigned int missing) { in3_nl_offline_ctx_t octx = {.vctx = vc, .missing = missing}; - in3_plugin_execute_first(vc->ctx, PLGN_ACT_NL_OFFLINE, &octx); + in3_plugin_execute_first(vc->req, PLGN_ACT_NL_OFFLINE, &octx); } static bytes_t compute_msg_hash(uint8_t* msg_data, in3_vctx_t* vc, bytes32_t block_hash, uint64_t header_number) { // get registry_id in3_get_data_ctx_t dctx = {.type = GET_DATA_REGISTRY_ID}; - in3_plugin_execute_first(vc->ctx, PLGN_ACT_GET_DATA, &dctx); + in3_plugin_execute_first(vc->req, PLGN_ACT_GET_DATA, &dctx); bytes_t msg; msg.data = msg_data; @@ -396,7 +396,7 @@ static bytes_t compute_msg_hash(uint8_t* msg_data, in3_vctx_t* vc, bytes32_t blo static bytes_t compute_err_hash(uint8_t* err_data, d_token_t* err) { bytes_builder_t* bb = bb_new(); - bb_write_int(bb, d_get_intk(err, K_CODE)); + bb_write_int(bb, d_get_int(err, K_CODE)); int i = 0; d_token_t* sig = d_get(d_get(err, K_DATA), K_SIGNED_ERR); @@ -433,7 +433,7 @@ static bool is_err_signed(d_token_t* err) { static in3_ret_t validate_err(in3_vctx_t* vc, d_token_t* err, uint64_t header_number) { d_token_t* sig = d_get(d_get(err, K_DATA), K_SIGNED_ERR); - if (d_get_longk(sig, K_BLOCK) != header_number) + if (d_get_long(sig, K_BLOCK) != header_number) return vc_err(vc, "wrong signature blocknumber"); uint8_t err_data[64] = {0}; @@ -442,7 +442,7 @@ static in3_ret_t validate_err(in3_vctx_t* vc, d_token_t* err, uint64_t header_nu } static in3_ret_t validate_sig(in3_vctx_t* vc, d_token_t* sig, uint64_t header_number, bytes32_t block_hash, bytes_t msg) { - if (d_get_longk(sig, K_BLOCK) != header_number) + if (d_get_long(sig, K_BLOCK) != header_number) return vc_err(vc, "wrong signature blocknumber"); bytes_t* sig_hash = d_get_byteskl(sig, K_BLOCK_HASH, 32); @@ -462,22 +462,22 @@ static unsigned int idx_from_bs(unsigned int bs) { static void handle_signed_err(in3_vctx_t* vc, d_token_t* err, unsigned int bs, uint64_t header_number) { // handle errors based on context - if (d_get_intk(err, K_CODE) == JSON_RPC_ERR_FINALITY) { - uint8_t* signer_addr = vc->ctx->signers + (20 * (idx_from_bs(bs) - 1)); + if (d_get_int(err, K_CODE) == JSON_RPC_ERR_FINALITY) { + uint8_t* signer_addr = vc->req->signers + (20 * (idx_from_bs(bs) - 1)); in3_get_data_ctx_t dctx = {.type = GET_DATA_NODE_MIN_BLK_HEIGHT, .data = signer_addr}; ba_print(signer_addr, 20); - in3_plugin_execute_first(vc->ctx, PLGN_ACT_GET_DATA, &dctx); + in3_plugin_execute_first(vc->req, PLGN_ACT_GET_DATA, &dctx); uint32_t* min_blk_height = dctx.data; - if (DIFF_ATMOST(d_get_longk(d_get(d_get(err, K_DATA), K_SIGNED_ERR), K_CURRENT_BLOCK), header_number, *min_blk_height)) { + if (DIFF_ATMOST(d_get_long(d_get(d_get(err, K_DATA), K_SIGNED_ERR), K_CURRENT_BLOCK), header_number, *min_blk_height)) { vc_err(vc, "blacklisting signer (reported wrong min block-height)"); in3_nl_blacklist_ctx_t bctx = {.address = signer_addr, .is_addr = true}; - in3_plugin_execute_first(vc->ctx, PLGN_ACT_NL_BLACKLIST, &bctx); + in3_plugin_execute_first(vc->req, PLGN_ACT_NL_BLACKLIST, &bctx); } - else if (!DIFF_ATMOST(d_get_longk(err, K_CURRENT_BLOCK), vc->currentBlock, 1)) { + else if (!DIFF_ATMOST(d_get_long(err, K_CURRENT_BLOCK), vc->currentBlock, 1)) { vc_err(vc, "blacklisting signer (out-of-sync)"); in3_nl_blacklist_ctx_t bctx = {.address = signer_addr, .is_addr = true}; - in3_plugin_execute_first(vc->ctx, PLGN_ACT_NL_BLACKLIST, &bctx); + in3_plugin_execute_first(vc->req, PLGN_ACT_NL_BLACKLIST, &bctx); } if (dctx.cleanup) dctx.cleanup(dctx.data); } @@ -485,7 +485,7 @@ static void handle_signed_err(in3_vctx_t* vc, d_token_t* err, unsigned int bs, u static uint8_t* get_verified_hash(in3_vctx_t* vc, uint64_t block_number) { if (vc->chain->verified_hashes) - for (uint_fast16_t i = 0; i < vc->ctx->client->max_verified_hashes; i++) + for (uint_fast16_t i = 0; i < vc->req->client->max_verified_hashes; i++) if (vc->chain->verified_hashes[i].block_number == block_number) return vc->chain->verified_hashes[i].hash; return NULL; @@ -523,7 +523,7 @@ in3_ret_t eth_verify_blockheader(in3_vctx_t* vc, bytes_t* header, bytes_t* expec return memcmp(hash, block_hash, 32) ? vc_err(vc, "invalid blockhash") : IN3_OK; // if we expect no signatures ... - if (vc->ctx->signers_length == 0) { + if (vc->req->signers_length == 0) { #ifdef POA vhist_t* vh = NULL; // ... and the chain is a authority chain.... @@ -558,7 +558,7 @@ in3_ret_t eth_verify_blockheader(in3_vctx_t* vc, bytes_t* header, bytes_t* expec for (i = 0, sig = signatures + 1; i < (uint32_t) d_len(signatures); i++, sig = d_next(sig)) { if ((err = d_get(sig, K_ERROR))) { if (!is_err_signed(err)) { - if (d_get_intk(err, K_CODE) != JSON_RPC_ERR_INTERNAL) + if (d_get_int(err, K_CODE) != JSON_RPC_ERR_INTERNAL) return vc_err(vc, "error not signed"); continue; // assume offline } @@ -580,7 +580,7 @@ in3_ret_t eth_verify_blockheader(in3_vctx_t* vc, bytes_t* header, bytes_t* expec } unsigned int signd = (confirmed | erred); - unsigned int all = (1ULL << vc->ctx->signers_length) - 1; + unsigned int all = (1ULL << vc->req->signers_length) - 1; if (signd != all) { mark_offline(vc, all & ~signd); vc->dont_blacklist = true; @@ -591,7 +591,7 @@ in3_ret_t eth_verify_blockheader(in3_vctx_t* vc, bytes_t* header, bytes_t* expec } // ok, it is verified, so we should add it to the verified hashes - add_verified(vc->ctx->client, vc->chain, header_number, block_hash); + add_verified(vc->req->client, vc->chain, header_number, block_hash); return IN3_OK; } diff --git a/c/src/verifier/eth1/nano/chainspec.c b/c/src/verifier/eth1/nano/chainspec.c index f89d0f624..f71a5178a 100644 --- a/c/src/verifier/eth1/nano/chainspec.c +++ b/c/src/verifier/eth1/nano/chainspec.c @@ -138,8 +138,8 @@ chainspec_t* chainspec_create_from_json(json_ctx_t* ctx) { d_token_t* params = d_get(data, ikey(ctx, "params")); if (!params) return log_error("no params-tag in data"); - spec->network_id = d_get_longk(params, ikey(ctx, "networkID")); - spec->account_start_nonce = d_get_longk(params, ikey(ctx, "accountStartNonce")); + spec->network_id = d_get_long(params, ikey(ctx, "networkID")); + spec->account_start_nonce = d_get_long(params, ikey(ctx, "accountStartNonce")); // find all eip transitions unsigned int allocated = 3; @@ -188,7 +188,7 @@ chainspec_t* chainspec_create_from_json(json_ctx_t* ctx) { fill_aura(ctx, params, spec->consensus_transitions, NULL); } else if (d_get(d_get(engine, ikey(ctx, "clique")), ikey(ctx, "params"))) { - bytes_t* extra = d_get_bytesk(genesis, ikey(ctx, "extraData")); + bytes_t* extra = d_get_bytes(genesis, ikey(ctx, "extraData")); if (!extra) return log_error("no extra data in the genesis-block"); spec->consensus_transitions->type = ETH_POA_CLIQUE; spec->consensus_transitions->validators.data = _malloc(extra->len - 32 - 65); diff --git a/c/src/verifier/eth1/nano/eth_nano.c b/c/src/verifier/eth1/nano/eth_nano.c index 0c398c1ad..1d6c80322 100644 --- a/c/src/verifier/eth1/nano/eth_nano.c +++ b/c/src/verifier/eth1/nano/eth_nano.c @@ -33,9 +33,9 @@ *******************************************************************************/ #include "eth_nano.h" -#include "../../../core/client/context.h" #include "../../../core/client/keys.h" #include "../../../core/client/plugin.h" +#include "../../../core/client/request.h" #include "../../../core/util/mem.h" #include "../../../third-party/crypto/ecdsa.h" #include "merkle.h" @@ -49,27 +49,21 @@ char* ALLOWED_METHODS[MAX_METHODS] = {"eth_chainId", "in3_stats", "eth_blockNumb in3_ret_t in3_verify_eth_nano(void* p_data, in3_plugin_act_t action, void* pctx) { UNUSED_VAR(p_data); UNUSED_VAR(action); - in3_vctx_t* vc = pctx; - char* method = NULL; - d_token_t* params = d_get(vc->request, K_PARAMS); - int i; + in3_vctx_t* vc = pctx; // do we support this request? - if (!(method = d_get_stringk(vc->request, K_METHOD))) - return vc_err(vc, "No Method in request defined!"); - if (in3_ctx_get_proof(vc->ctx, vc->index) == PROOF_NONE) return IN3_OK; + if (in3_req_get_proof(vc->req, vc->index) == PROOF_NONE) return IN3_OK; // do we have a result? if not it is a vaslid error-response - if (!vc->result) - return IN3_OK; + if (!vc->result) return IN3_OK; // check if this call is part of the not verifieable calls - for (i = 0; i < MAX_METHODS; i++) { - if (strcmp(ALLOWED_METHODS[i], method) == 0) + for (int i = 0; i < MAX_METHODS; i++) { + if (strcmp(ALLOWED_METHODS[i], vc->method) == 0) return IN3_OK; } - if (strcmp(method, "eth_getTransactionReceipt") == 0) + if (strcmp(vc->method, "eth_getTransactionReceipt") == 0) // for txReceipt, we need the txhash - return eth_verify_eth_getTransactionReceipt(vc, d_get_bytes_at(params, 0)); + return eth_verify_eth_getTransactionReceipt(vc, d_get_bytes_at(d_get(vc->request, K_PARAMS), 0)); else return IN3_EIGNORE; } diff --git a/c/src/verifier/eth1/nano/serialize.c b/c/src/verifier/eth1/nano/serialize.c index df3000229..dc05b95b4 100644 --- a/c/src/verifier/eth1/nano/serialize.c +++ b/c/src/verifier/eth1/nano/serialize.c @@ -33,9 +33,9 @@ *******************************************************************************/ #include "serialize.h" -#include "../../../core/client/context.h" #include "../../../core/client/keys.h" #include "../../../core/client/plugin.h" +#include "../../../core/client/request.h" #include "../../../core/util/bytes.h" #include "../../../core/util/data.h" #include "../../../core/util/mem.h" diff --git a/c/src/verifier/eth1/nano/signature.c b/c/src/verifier/eth1/nano/signature.c index c47b8fa84..f84afc227 100644 --- a/c/src/verifier/eth1/nano/signature.c +++ b/c/src/verifier/eth1/nano/signature.c @@ -32,8 +32,8 @@ * with this program. If not, see . *******************************************************************************/ -#include "../../../core/client/context.h" #include "../../../core/client/keys.h" +#include "../../../core/client/request.h" #include "../../../core/util/data.h" #include "../../../core/util/mem.h" #include "../../../third-party/crypto/ecdsa.h" @@ -50,7 +50,7 @@ bytes_t* ecrecover_signature(bytes_t* msg_hash, d_token_t* sig) { uint8_t pubkey[65], sdata[64]; bytes_t* r = d_get_byteskl(sig, K_R, 32); bytes_t* s = d_get_byteskl(sig, K_S, 32); - int v = d_get_intk(sig, K_V); + int v = d_get_int(sig, K_V); // correct v if (v >= 27) v -= 27; @@ -78,8 +78,8 @@ unsigned int eth_verify_signature(in3_vctx_t* vc, bytes_t* msg_hash, d_token_t* if (addr == NULL) return 0 * vc_err(vc, "could not recover the signature"); // try to find the signature requested - for (i = 0; i < vc->ctx->signers_length; i++) { - if (memcmp(vc->ctx->signers + i * 20, addr->data, 20) == 0) { + for (i = 0; i < vc->req->signers_length; i++) { + if (memcmp(vc->req->signers + i * 20, addr->data, 20) == 0) { // adn set the bit depending on the index. res = 1 << i; break; diff --git a/c/src/verifier/eth1/nano/txreceipt.c b/c/src/verifier/eth1/nano/txreceipt.c index 35255f3cf..6b865ba92 100644 --- a/c/src/verifier/eth1/nano/txreceipt.c +++ b/c/src/verifier/eth1/nano/txreceipt.c @@ -32,8 +32,8 @@ * with this program. If not, see . *******************************************************************************/ -#include "../../../core/client/context.h" #include "../../../core/client/keys.h" +#include "../../../core/client/request.h" #include "../../../core/util/data.h" #include "../../../core/util/mem.h" #include "../../../third-party/crypto/ecdsa.h" @@ -78,7 +78,7 @@ in3_ret_t eth_verify_eth_getTransactionReceipt(in3_vctx_t* vc, bytes_t* tx_hash) if (!vc->proof) return vc_err(vc, "Proof is missing!"); - bytes_t* blockHeader = d_get_bytesk(vc->proof, K_BLOCK); + bytes_t* blockHeader = d_get_bytes(vc->proof, K_BLOCK); if (!blockHeader) return vc_err(vc, "No Block-Proof!"); @@ -86,12 +86,12 @@ in3_ret_t eth_verify_eth_getTransactionReceipt(in3_vctx_t* vc, bytes_t* tx_hash) res = eth_verify_blockheader(vc, blockHeader, d_bytes(block_hash)); // make sure the blocknumner on the receipt is correct - if (res == IN3_OK && (rlp_decode_in_list(blockHeader, BLOCKHEADER_NUMBER, &root) != 1 || bytes_to_long(root.data, root.len) != d_get_longk(vc->result, K_BLOCK_NUMBER))) + if (res == IN3_OK && (rlp_decode_in_list(blockHeader, BLOCKHEADER_NUMBER, &root) != 1 || bytes_to_long(root.data, root.len) != d_get_long(vc->result, K_BLOCK_NUMBER))) res = vc_err(vc, "wrong blocknumber in the result"); if (res == IN3_OK) { // encode the tx_path - bytes_t* path = create_tx_path(d_get_intk(vc->proof, K_TX_INDEX)); + bytes_t* path = create_tx_path(d_get_int(vc->proof, K_TX_INDEX)); // verify the merkle proof for the receipt if (rlp_decode_in_list(blockHeader, BLOCKHEADER_RECEIPT_ROOT, &root) != 1) @@ -139,7 +139,7 @@ in3_ret_t eth_verify_eth_getTransactionReceipt(in3_vctx_t* vc, bytes_t* tx_hash) // check rest of the values if (!d_eq(d_get(vc->proof, K_TX_INDEX), d_get(vc->result, K_TRANSACTION_INDEX))) return vc_err(vc, "wrong transactionIndex"); - if (!b_cmp(tx_hash, d_get_bytesk(vc->result, K_TRANSACTION_HASH))) + if (!b_cmp(tx_hash, d_get_bytes(vc->result, K_TRANSACTION_HASH))) return vc_err(vc, "wrong transactionHash"); d_token_t *l, *logs = d_get(vc->result, K_LOGS), *block_number = d_get(vc->result, K_BLOCK_NUMBER); @@ -148,9 +148,9 @@ in3_ret_t eth_verify_eth_getTransactionReceipt(in3_vctx_t* vc, bytes_t* tx_hash) return vc_err(vc, "wrong block number in log"); if (!d_eq(block_hash, d_getl(l, K_BLOCK_HASH, 32))) return vc_err(vc, "wrong block hash in log"); - if (in3_ctx_get_proof(vc->ctx, vc->index) == PROOF_FULL && d_get_intk(l, K_LOG_INDEX) != i) + if (in3_req_get_proof(vc->req, vc->index) == PROOF_FULL && d_get_int(l, K_LOG_INDEX) != i) return vc_err(vc, "wrong log index"); - if (!b_cmp(d_get_bytesk(l, K_TRANSACTION_HASH), tx_hash)) + if (!b_cmp(d_get_bytes(l, K_TRANSACTION_HASH), tx_hash)) return vc_err(vc, "wrong tx Hash"); if (!d_eq(d_get(vc->proof, K_TX_INDEX), d_get(l, K_TRANSACTION_INDEX))) return vc_err(vc, "wrong tx index"); diff --git a/c/src/verifier/eth1/nano/vhist.c b/c/src/verifier/eth1/nano/vhist.c index 6473991e4..c11b20683 100644 --- a/c/src/verifier/eth1/nano/vhist.c +++ b/c/src/verifier/eth1/nano/vhist.c @@ -84,7 +84,7 @@ vhist_t* vh_init_spec(d_token_t* spec) { d_iterator_t sitr; for (sitr = d_iter(spec); sitr.left; d_iter_next(&sitr)) { - vh->last_change_block = d_get_longk(sitr.token, K_BLOCK); + vh->last_change_block = d_get_long(sitr.token, K_BLOCK); vh_add_state(vh, sitr.token, true); } return vh; @@ -100,7 +100,7 @@ vhist_t* vh_init_nodelist(d_token_t* nodelist) { d_iterator_t sitr; for (sitr = d_iter(ss); sitr.left; d_iter_next(&sitr)) { - vh->last_change_block = d_get_longk(sitr.token, K_BLOCK); + vh->last_change_block = d_get_long(sitr.token, K_BLOCK); vh_add_state(vh, sitr.token, false); } return vh; @@ -167,7 +167,7 @@ void vh_add_state(vhist_t* vh, d_token_t* state, bool is_spec) { vhist_engine_t engine = ENGINE_UNKNOWN; vs = d_get(state, is_spec ? K_LIST : K_VALIDATORS); - engine = stoengine(d_get_stringk(state, K_ENGINE)); + engine = stoengine(d_get_string(state, K_ENGINE)); d_token_t* tmp; if ((tmp = d_get(state, K_BYPASS_FINALITY))) { @@ -179,7 +179,7 @@ void vh_add_state(vhist_t* vh, d_token_t* state, bool is_spec) { blk = bytes_to_long(b->data, b->len); } else - blk = d_get_longk(state, K_BLOCK); + blk = d_get_long(state, K_BLOCK); bb_write_long(vh->diffs, blk); bb_write_raw_bytes(vh->diffs, &engine, sizeof(engine)); diff --git a/c/src/verifier/ipfs/ipfs.c b/c/src/verifier/ipfs/ipfs.c index 9e1079bf6..7c27a7ca4 100644 --- a/c/src/verifier/ipfs/ipfs.c +++ b/c/src/verifier/ipfs/ipfs.c @@ -140,31 +140,25 @@ in3_ret_t ipfs_verify_hash(const char* content, const char* encoding, const char in3_ret_t in3_verify_ipfs(void* pdata, in3_plugin_act_t action, void* pctx) { UNUSED_VAR(pdata); UNUSED_VAR(action); - in3_vctx_t* vc = pctx; - char* method = NULL; - d_token_t* params = d_get(vc->request, K_PARAMS); + in3_vctx_t* vc = pctx; if (vc->chain->type != CHAIN_IPFS) return IN3_EIGNORE; - - if (in3_ctx_get_proof(vc->ctx, vc->index) == PROOF_NONE) return IN3_OK; + if (in3_req_get_proof(vc->req, vc->index) == PROOF_NONE) return IN3_OK; // do we have a result? if not it is a vaslid error-response - if (!vc->result) - return IN3_OK; + if (!vc->result) return IN3_OK; + d_token_t* params = d_get(vc->request, K_PARAMS); // do we support this request? - if (!(method = d_get_stringk(vc->request, K_METHOD))) - return vc_err(vc, "No Method in request defined!"); - - if (strcmp(method, "in3_nodeList") && d_type(vc->result) != T_STRING) + if (strcmp(vc->method, "in3_nodeList") && d_type(vc->result) != T_STRING) return vc_err(vc, "Invalid response!"); - if (strcmp(method, "in3_nodeList") == 0) + if (strcmp(vc->method, "in3_nodeList") == 0) return true; - else if (strcmp(method, "ipfs_get") == 0) + else if (strcmp(vc->method, "ipfs_get") == 0) return ipfs_verify_hash(d_string(vc->result), d_get_string_at(params, 1) ? d_get_string_at(params, 1) : "base64", d_get_string_at(params, 0)); - else if (strcmp(method, "ipfs_put") == 0) + else if (strcmp(vc->method, "ipfs_put") == 0) return ipfs_verify_hash(d_get_string_at(params, 0), d_get_string_at(params, 1) ? d_get_string_at(params, 1) : "base64", d_string(vc->result)); diff --git a/c/test/qemu/esp32/main/CMakeLists.txt b/c/test/qemu/esp32/main/CMakeLists.txt index 14388c1c6..ca59e5e76 100644 --- a/c/test/qemu/esp32/main/CMakeLists.txt +++ b/c/test/qemu/esp32/main/CMakeLists.txt @@ -10,6 +10,10 @@ ADD_DEFINITIONS(-DEVM_GAS) ADD_DEFINITIONS(-DLOGGING) ADD_DEFINITIONS(-DNODESELECT_DEF) ADD_DEFINITIONS(-DNODESELECT_DEF_WL) +ADD_DEFINITIONS(-DNO_BOOT_NODES_MAINNET) +ADD_DEFINITIONS(-DNO_BOOT_NODES_BTC) +ADD_DEFINITIONS(-DNO_BOOT_NODES_IPFS) +ADD_DEFINITIONS(-DNO_BOOT_NODES_EWC) ADD_DEFINITIONS(-DIN3_EXPORT_TEST=static) ADD_DEFINITIONS(-DIN3_IMPORT_TEST=) ADD_DEFINITIONS(-DESP_IDF) @@ -17,11 +21,12 @@ OPTION(ESP_IDF "Esp-idf framework" ON) ADD_DEFINITIONS(-DIN3_MATH_LITE) set(IN3_SRC ../../../..) add_subdirectory(${IN3_SRC}/src/core build_core) +add_subdirectory(${IN3_SRC}/src/init build_init) add_subdirectory(${IN3_SRC}/src/third-party/tommath build_tommath) add_subdirectory(${IN3_SRC}/src/third-party/crypto build_crypto) add_subdirectory(${IN3_SRC}/src/signer/pk-signer build_signer) -add_subdirectory(${IN3_SRC}/src/nodeselect build_nodeselect) +add_subdirectory(${IN3_SRC}/src/nodeselect/full build_nodeselect) add_subdirectory(${IN3_SRC}/src/verifier/eth1/basic build_basic) add_subdirectory(${IN3_SRC}/src/verifier/eth1/nano build_nano) add_subdirectory(${IN3_SRC}/src/verifier/eth1/full build_full) diff --git a/c/test/qemu/esp32/main/in3_main.c b/c/test/qemu/esp32/main/in3_main.c index e5efe737a..25157c917 100644 --- a/c/test/qemu/esp32/main/in3_main.c +++ b/c/test/qemu/esp32/main/in3_main.c @@ -82,8 +82,8 @@ in3_ret_t local_transport_func(char** urls, int urls_len, char* payload, in3_res return IN3_OK; } in3_ret_t transport_mock(void* plugin_data, in3_plugin_act_t action, void* plugin_ctx) { - in3_request_t* req = plugin_ctx; - return local_transport_func((char**) req->urls, req->urls_len, req->payload, req->ctx->raw_response); + in3_http_request_t* req = plugin_ctx; + return local_transport_func((char**) req->urls, req->urls_len, req->payload, req->req->raw_response); } /* Setup and init in3 */ void init_in3(void) { diff --git a/c/test/qemu/zephyr-arm3/CMakeLists.txt b/c/test/qemu/zephyr-arm3/CMakeLists.txt index 3d559f3bb..f1c7d46f5 100644 --- a/c/test/qemu/zephyr-arm3/CMakeLists.txt +++ b/c/test/qemu/zephyr-arm3/CMakeLists.txt @@ -26,6 +26,7 @@ ADD_DEFINITIONS(-DIN3_MATH_LITE) set(IN3_SRC ../../..) set(IN3_DEPS ${IN3_SRC}/src/core +${IN3_SRC}/src/init ${IN3_SRC}/src/verifier/eth1/basic ${IN3_SRC}/src/verifier/eth1/nano ${IN3_SRC}/src/signer/pk-signer @@ -33,7 +34,7 @@ ${IN3_SRC}/src/api/eth1 ${IN3_SRC}/src/api/utils ${IN3_SRC}/src/third-party/crypto ${IN3_SRC}/src/third-party/tommath -${IN3_SRC}/src/nodeselect +${IN3_SRC}/src/nodeselect/full ) foreach(dep ${IN3_DEPS}) diff --git a/c/test/qemu/zephyr-arm3/src/main.c b/c/test/qemu/zephyr-arm3/src/main.c index 0516b4a24..e0bec953b 100644 --- a/c/test/qemu/zephyr-arm3/src/main.c +++ b/c/test/qemu/zephyr-arm3/src/main.c @@ -64,8 +64,8 @@ in3_ret_t local_transport_func(char** urls, int urls_len, char* payload, in3_res } in3_ret_t transport_mock(void* plugin_data, in3_plugin_act_t action, void* plugin_ctx) { - in3_request_t* req = plugin_ctx; - return local_transport_func((char**) req->urls, req->urls_len, req->payload, req->ctx->raw_response); + in3_http_request_t* req = plugin_ctx; + return local_transport_func((char**) req->urls, req->urls_len, req->payload, req->req->raw_response); } in3_t* init_in3_goerli(in3_plugin_act_fn custom_transport) { diff --git a/c/test/runner.c b/c/test/runner.c index 9daa38eb0..ab0dfacda 100644 --- a/c/test/runner.c +++ b/c/test/runner.c @@ -43,8 +43,8 @@ #include "../src/verifier/btc/btc.h" #include "../src/verifier/eth1/full/eth_full.h" #include "../src/verifier/ipfs/ipfs.h" -#include -#include +#include +#include #include #include #include @@ -176,13 +176,13 @@ static void prepare_response(int count, d_token_t* response_array, int as_bin, i _tmp_pos = 0; } static in3_ret_t send_mock(void* plugin_data, in3_plugin_act_t action, void* plugin_ctx) { - in3_request_t* req = plugin_ctx; - int i; - bytes_t response; + in3_http_request_t* req = plugin_ctx; + int i; + bytes_t response; if (d_len(_tmp_responses) <= _tmp_pos) { for (i = 0; i < req->urls_len; i++) { - req->ctx->raw_response[i].state = IN3_ECONFIG; - sb_add_chars(&(req->ctx->raw_response + i)->data, "Reached end of available responses!"); + req->req->raw_response[i].state = IN3_ECONFIG; + sb_add_chars(&(req->req->raw_response + i)->data, "Reached end of available responses!"); } return IN3_EINVAL; } @@ -208,8 +208,8 @@ static in3_ret_t send_mock(void* plugin_data, in3_plugin_act_t action, void* plu // printf("payload: %s\n",payload); for (i = 0; i < req->urls_len; i++) { - sb_add_range(&(req->ctx->raw_response + i)->data, (char*) response.data, 0, response.len); - req->ctx->raw_response[i].state = IN3_OK; + sb_add_range(&(req->req->raw_response + i)->data, (char*) response.data, 0, response.len); + req->req->raw_response[i].state = IN3_OK; } _free(response.data); @@ -226,9 +226,10 @@ int execRequest(in3_t* c, d_token_t* test, int must_fail, int counter, char* des char params[10000]; // configure in3 - c->request_count = (t = d_get(config, key("requestCount"))) ? d_int(t) : 1; - method = d_get_string(request, "method"); - bool intern = d_get_int(test, "intern"); + sprintf(params, "{\"requestCount\":%d}", (t = d_get(config, key("requestCount"))) ? d_int(t) : 1); + in3_configure(c, params); + method = d_get_string(request, key("method")); + bool intern = d_get_int(test, key("intern")); str_range_t s = d_to_json(d_get(request, key("params"))); if (!method) { @@ -243,11 +244,11 @@ int execRequest(in3_t* c, d_token_t* test, int must_fail, int counter, char* des params[s.len] = 0; char *res = NULL, *err = NULL; - int success = must_fail ? 0 : d_get_intkd(test, key("success"), 1); + int success = must_fail ? 0 : d_get_intd(test, key("success"), 1); if (intern) _tmp_pos++; // if this is a intern, then the first response is the expected, while the all other come after this. // _tmp_response = response; - int is_bin = d_get_int(test, "binaryFormat"); + int is_bin = d_get_int(test, key("binaryFormat")); in3_client_rpc_raw(c, d_string(request), is_bin ? NULL : &res, &err); fflush(stdout); @@ -313,7 +314,7 @@ int run_test(d_token_t* test, int counter, char* fuzz_prop, in3_proof_t proof) { int i; in3_log_set_prefix(""); - if ((descr = d_get_string(test, "descr"))) { + if ((descr = d_get_string(test, key("descr")))) { if (fuzz_prop) sprintf(temp, " ... manipulate #%s", fuzz_prop); else @@ -322,13 +323,13 @@ int run_test(d_token_t* test, int counter, char* fuzz_prop, in3_proof_t proof) { else sprintf(temp, "Request #%i", counter); - in3_t* c = in3_for_chain(d_get_intkd(test, key("chainId"), 1)); + in3_t* c = in3_for_chain(d_get_intd(test, key("chainId"), 1)); in3_plugin_register(c, PLGN_ACT_TRANSPORT, send_mock, NULL, true); int j; c->max_attempts = 1; - c->flags = FLAGS_STATS | FLAGS_INCLUDE_CODE | FLAGS_AUTO_UPDATE_LIST; - c->finality = d_get_intkd(test, key("finality"), 0); + c->flags = FLAGS_STATS | FLAGS_INCLUDE_CODE | FLAGS_AUTO_UPDATE_LIST | FLAGS_ALLOW_EXPERIMENTAL; + c->finality = d_get_intd(test, key("finality"), 0); d_token_t* first_res = d_get(d_get_at(d_get(test, key("response")), 0), key("result")); d_token_t* registry_id = d_type(first_res) == T_OBJECT ? d_get(first_res, key("registryId")) : NULL; @@ -358,23 +359,18 @@ int run_test(d_token_t* test, int counter, char* fuzz_prop, in3_proof_t proof) { int fail = execRequest(c, test, fuzz_prop != NULL, counter, temp); in3_free(c); - if (mem_get_memleak_cnt()) { - printf(" -- Memory Leak detected by malloc #%i!", mem_get_memleak_cnt()); - if (!fail) fail = 1; - } d_token_t* response = d_get(test, key("response")); - size_t max_heap = mem_get_max_heap(); str_range_t res_size = d_to_json(response); bytes_builder_t* bb = bb_new(); d_serialize_binary(bb, response); - printf(" ( heap: %zu json: %lu bin: %u) ", max_heap, res_size.len, bb->b.len); + printf(" ( json: %lu bin: %u) ", res_size.len, bb->b.len); bb_free(bb); return fail; } -int runRequests(char** names, int test_index, int mem_track) { +int runRequests(char** names, int test_index) { int res = 0, n = 0; char* name = names[n]; int failed = 0, total = 0, count = 0; @@ -405,7 +401,7 @@ int runRequests(char** names, int test_index, int mem_track) { fuzz_pos = -1; in3_proof_t proof = PROOF_STANDARD; - if ((str_proof = d_get_string(test, "proof"))) { + if ((str_proof = d_get_string(test, key("proof")))) { if (strcmp(str_proof, "none") == 0) proof = PROOF_NONE; if (strcmp(str_proof, "standard") == 0) proof = PROOF_STANDARD; if (strcmp(str_proof, "full") == 0) proof = PROOF_FULL; @@ -414,12 +410,12 @@ int runRequests(char** names, int test_index, int mem_track) { count++; if (test_index < 0 || count == test_index) { total++; - prepare_response(1, d_get(test, key("response")), d_get_int(test, "binaryFormat"), -1); - mem_reset(mem_track); + prepare_response(1, d_get(test, key("response")), d_get_int(test, key("binaryFormat")), -1); + mem_reset(); if (run_test(test, count, NULL, proof)) failed++; } - if (d_get_int(test, "fuzzer")) { + if (d_get_int(test, key("fuzzer"))) { str_range_t resp = d_to_json(d_get_at(d_get(test, key("response")), 0)); while ((fuzz_pos = find_hex(resp.data, fuzz_pos + 1, resp.len)) > 0) { str_range_t prop = find_prop_name(resp.data + fuzz_pos, resp.data); @@ -432,8 +428,8 @@ int runRequests(char** names, int test_index, int mem_track) { count++; if (test_index > 0 && count != test_index) continue; total++; - prepare_response(1, d_get(test, key("response")), d_get_int(test, "binaryFormat"), fuzz_pos); - mem_reset(mem_track); + prepare_response(1, d_get(test, key("response")), d_get_int(test, key("binaryFormat")), fuzz_pos); + mem_reset(); if (run_test(test, count, tmp, proof)) failed++; } } @@ -465,9 +461,9 @@ int main(int argc, char* argv[]) { in3_register_default(in3_register_nodeselect_def); int i = 0, size = 1; - int testIndex = -1, membrk = -1; - char** names = malloc(sizeof(char*)); - names[0] = NULL; + int testIndex = -1; + char** names = malloc(sizeof(char*)); + names[0] = NULL; for (i = 1; i < argc; i++) { if (strcmp(argv[i], "-t") == 0) testIndex = atoi(argv[++i]); @@ -475,8 +471,6 @@ int main(int argc, char* argv[]) { in3_log_set_level(LOG_TRACE); in3_log_set_quiet(false); } - else if (strcmp(argv[i], "-m") == 0) - membrk = atoi(argv[++i]); else { char** t = malloc((size + 1) * sizeof(char*)); memmove(t, names, size * sizeof(char*)); @@ -487,7 +481,7 @@ int main(int argc, char* argv[]) { } } - int res = runRequests(names, testIndex, membrk); + int res = runRequests(names, testIndex); free(names); return res; } \ No newline at end of file diff --git a/c/test/test_evm.c b/c/test/test_evm.c index abfe53056..a079012c8 100644 --- a/c/test/test_evm.c +++ b/c/test/test_evm.c @@ -37,8 +37,8 @@ #ifndef TEST #define TEST #endif -#include "../src/core/client/context.h" #include "../src/core/client/keys.h" +#include "../src/core/client/request.h" #include "../src/core/util/data.h" #include "../src/core/util/log.h" #include "../src/core/util/mem.h" @@ -419,20 +419,20 @@ static void read_accounts(evm_t* evm, d_token_t* accounts) { static d_token_t* get_test_val(d_token_t* root, char* name, d_token_t* indexes) { d_token_t* array = d_get(root, ikey(jc, name)); if (!array) return NULL; - return d_get_at(array, d_get_intk(indexes, ikey(jc, strcmp(name, "gasLimit") == 0 ? "gas" : name))); + return d_get_at(array, d_get_int(indexes, ikey(jc, strcmp(name, "gasLimit") == 0 ? "gas" : name))); } int run_evm(json_ctx_t* jctx, d_token_t* test, uint32_t props, uint64_t* ms, char* fork_name, int test_index) { jc = jctx; uint8_t caller[32]; - d_token_t* exec = d_get(test, ikey(jc, "exec")); - d_token_t* transaction = d_get(test, ikey(jc, "transaction")); - d_token_t* post = d_get(test, ikey(jc, "post")); - d_token_t* indexes = NULL; - uint64_t total_gas = 0; - bool has_enough_gas = true; + d_token_t* exec = d_get(test, ikey(jc, "exec")); + d_token_t* transaction = d_get(test, ikey(jc, "transaction")); + d_token_t* post = d_get(test, ikey(jc, "post")); + d_token_t* indexes = NULL; + uint64_t total_gas = 0; + bool has_enough_gas = true; - address_t _to; + address_t _to; memset(_to, 0, 20); // create vm @@ -470,14 +470,14 @@ int run_evm(json_ctx_t* jctx, d_token_t* test, uint32_t props, uint64_t* ms, cha evm.call_data = d_to_bytes(d_get(exec, ikey(jc, "data"))); evm.call_value = d_to_bytes(d_get(exec, ikey(jc, "value"))); - evm.caller = d_get_bytesk(exec, ikey(jc, "caller"))->data; - evm.origin = d_get_bytesk(exec, ikey(jc, "origin"))->data; - evm.address = d_get_bytesk(exec, ikey(jc, "address"))->data; - evm.account = d_get_bytesk(exec, ikey(jc, "address"))->data; + evm.caller = d_get_bytes(exec, ikey(jc, "caller"))->data; + evm.origin = d_get_bytes(exec, ikey(jc, "origin"))->data; + evm.address = d_get_bytes(exec, ikey(jc, "address"))->data; + evm.account = d_get_bytes(exec, ikey(jc, "address"))->data; #ifdef EVM_GAS evm.accounts = NULL; - evm.gas = d_get_longk(exec, ikey(jc, "gas")); + evm.gas = d_get_long(exec, ikey(jc, "gas")); evm.code = d_to_bytes(d_get(exec, ikey(jc, "code"))); evm.parent = NULL; evm.logs = NULL; @@ -490,7 +490,7 @@ int run_evm(json_ctx_t* jctx, d_token_t* test, uint32_t props, uint64_t* ms, cha evm.call_data = d_to_bytes(get_test_val(transaction, "data", indexes)); evm.call_value = d_to_bytes(get_test_val(transaction, "value", indexes)); - uint8_t *pk = d_get_bytesk(transaction, ikey(jc, "secretKey"))->data, public_key[65], sdata[32]; + uint8_t *pk = d_get_bytes(transaction, ikey(jc, "secretKey"))->data, public_key[65], sdata[32]; ecdsa_get_public_key65(&secp256k1, pk, public_key); // hash it and return the last 20 bytes as address if (keccak(bytes(public_key + 1, 64), sdata) == 0) @@ -508,7 +508,7 @@ int run_evm(json_ctx_t* jctx, d_token_t* test, uint32_t props, uint64_t* ms, cha evm.account = evm.address; if (d_getl(transaction, ikey(jc, "to"), 20) && d_len(d_getl(transaction, ikey(jc, "to"), 20))) - evm.code = d_to_bytes(d_get(vm_get_account(test, d_get_bytesk(transaction, ikey(jc, "to"))->data), ikey(jc, "code"))); + evm.code = d_to_bytes(d_get(vm_get_account(test, d_get_bytes(transaction, ikey(jc, "to"))->data), ikey(jc, "code"))); else evm.code = evm.call_data; @@ -525,7 +525,7 @@ int run_evm(json_ctx_t* jctx, d_token_t* test, uint32_t props, uint64_t* ms, cha // -- add the cost for transaction data for (int i = 0; i < evm.call_data.len; i++) { tx_intrinsic_gas += evm.call_data.data[i] ? G_TXDATA_NONZERO : G_TXDATA_ZERO; - } + } // -- check if we are executing a creation transaction if (transaction && !d_len(d_get(transaction, ikey(jc, "to")))) { tx_intrinsic_gas += G_TXCREATE; @@ -534,7 +534,7 @@ int run_evm(json_ctx_t* jctx, d_token_t* test, uint32_t props, uint64_t* ms, cha has_enough_gas = (tx_intrinsic_gas < evm.init_gas); // execution should only continue if gasLimit is enough to pay for the transaction - if(has_enough_gas) { + if (has_enough_gas) { // prepare all accounts read_accounts(&evm, d_get(test, ikey(jc, "pre"))); @@ -601,12 +601,12 @@ int run_evm(json_ctx_t* jctx, d_token_t* test, uint32_t props, uint64_t* ms, cha prepare_header(d_get(test, ikey(jc, "env"))); uint64_t start = clock(), gas_before = evm.gas; - int fail = has_enough_gas ? evm_run(&evm, evm.account) : 0; - *ms = (clock() - start) / 1000; + int fail = has_enough_gas ? evm_run(&evm, evm.account) : 0; + *ms = (clock() - start) / 1000; if (transaction) { #ifdef EVM_GAS - if(has_enough_gas) { + if (has_enough_gas) { total_gas += gas_before - evm.gas; if (fail) { // it failed, so the transaction used up all the gas and we reverse all accounts @@ -656,7 +656,7 @@ int run_evm(json_ctx_t* jctx, d_token_t* test, uint32_t props, uint64_t* ms, cha } // pay the miner the total gas - account_t* miner = evm_get_account(&evm, d_get_bytesk(d_get(test, ikey(jc, "env")), ikey(jc, "currentCoinbase"))->data, 1); + account_t* miner = evm_get_account(&evm, d_get_bytes(d_get(test, ikey(jc, "env")), ikey(jc, "currentCoinbase"))->data, 1); // increase balance of the miner long_to_bytes(total_gas, tmp); @@ -695,9 +695,9 @@ int run_evm(json_ctx_t* jctx, d_token_t* test, uint32_t props, uint64_t* ms, cha // check post state fail = check_post_state(&evm, post); #ifdef EVM_GAS - if (!fail && d_get_longk(test, ikey(jc, "gas")) != evm.gas) { + if (!fail && d_get_long(test, ikey(jc, "gas")) != evm.gas) { print_error("Wrong Gas"); - printf(" (expected : %" PRIu64 ", but got %" PRIu64 "", d_get_longk(test, ikey(jc, "gas")), evm.gas); + printf(" (expected : %" PRIu64 ", but got %" PRIu64 "", d_get_long(test, ikey(jc, "gas")), evm.gas); fail = 1; } #endif diff --git a/c/test/test_trie.c b/c/test/test_trie.c index ce6cf3aae..0e381de49 100644 --- a/c/test/test_trie.c +++ b/c/test/test_trie.c @@ -73,7 +73,7 @@ int test_trie(json_ctx_t* jc, d_token_t* test, uint32_t props, uint64_t* ms) { uint64_t start = clock(); trie_t* trie = trie_new(); d_token_t *in = d_get(test, ikey(jc, "in")), *t, *el; - uint8_t is_hex = d_get_intk(test, ikey(jc, "hexEncoded")), i, tmp[64], tmp2[64], tmp3[32], res = 0; + uint8_t is_hex = d_get_int(test, ikey(jc, "hexEncoded")), i, tmp[64], tmp2[64], tmp3[32], res = 0; if (d_type(in) == T_ARRAY) { for (i = 0, t = in + 1; i < d_len(in); i++, t = d_next(t)) { diff --git a/c/test/testdata/cmd/btc_bip34.txt b/c/test/testdata/cmd/btc_bip34.txt index 1ee375890..57e7c3a41 100644 --- a/c/test/testdata/cmd/btc_bip34.txt +++ b/c/test/testdata/cmd/btc_bip34.txt @@ -1,17 +1,198 @@ -:: cmd ./bin/in3 -fi ../c/test/testdata/cmd/btc_bip34.txt -c btc -nl http://localhost:8500 -f 5 getblockheader 000000002afcaf0e0d78e698e71c26fdd5f87b7703c18ed48e27ab133dc3d4bb true -debug -rc 1 -a 1make +:: cmd ./bin/in3 -x -fi ../c/test/testdata/cmd/btc_bip34.txt -c btc -nl http://localhost:8500 -f 5 getblockheader 000000002afcaf0e0d78e698e71c26fdd5f87b7703c18ed48e27ab133dc3d4bb true -debug -rc 1 -a 1 -:: time 1607435056 +:: time 1612516368 + +:: rand 1138659513 + +:: rand 1223656574 + +:: rand 1692635546 + +:: rand 409749813 + +:: rand 1832534809 + +:: rand 202069589 + +:: rand 1011936416 + +:: rand 1692343119 + +:: request http://localhost:8500 + [{"id":2,"jsonrpc":"2.0","method":"in3_nodeList","params":[0,"0x43de90b948ef847e64e3919a186c49356d3a43190c0b56553c50eca064df1b4f",[],true],"in3":{"verification":"proof","version": "2.1.0","chainId":"0x99","finality":5,"preBIP34":true}}] + +:: response in3_nodeList 0 http://localhost:8500 0 6 +[{ + "id":2, + "result":{ + "nodes":[{ + "url":"https://in3-v2.slock.it/btc/nd-1", + "address":"0x45d45e6ff99e6c34a235d263965910298985fcfe", + "index":0, + "deposit":"0x2386f26fc10000", + "props":"0x2000001dd", + "timeout":3456000, + "registerTime":1593440588, + "weight":2000, + "performance":{ + "count":1, + "total":198, + "last_failed":0 + } + }, + { + "url":"https://in3-v2.slock.it/btc/nd-2", + "address":"0x1fe2e9bf29aa1938859af64c413361227d04059a", + "index":1, + "deposit":"0x2386f26fc10000", + "props":"0x2000001dd", + "timeout":3456000, + "registerTime":1593440633, + "weight":2000, + "performance":{ + "count":1, + "total":3201, + "last_failed":1612516223542 + } + }, + { + "url":"https://in3-v2.slock.it/btc/nd-3", + "address":"0x945f75c0408c0026a3cd204d36f5e47745182fd4", + "index":2, + "deposit":"0x2386f26fc10000", + "props":"0x2000001dd", + "timeout":3456000, + "registerTime":1593440648, + "weight":2000, + "performance":{ + "count":1, + "total":195, + "last_failed":0 + } + }, + { + "url":"https://in3-v2.slock.it/btc/nd-4", + "address":"0xc513a534de5a9d3f413152c41b09bd8116237fc8", + "index":3, + "deposit":"0x2386f26fc10000", + "props":"0x2000001dd", + "timeout":3456000, + "registerTime":1593440678, + "weight":2000, + "performance":{ + "count":1, + "total":3326, + "last_failed":1612516223542 + } + }, + { + "url":"https://in3-v2.slock.it/btc/nd-5", + "address":"0xbcdf4e3e90cc7288b578329efd7bcc90655148d2", + "index":4, + "deposit":"0x2386f26fc10000", + "props":"0x2000001dd", + "timeout":3456000, + "registerTime":1593440708, + "weight":2000, + "performance":{ + "count":1, + "total":3220, + "last_failed":1612516223542 + } + }], + "contract":"0xc2c05fbfe76ee7748ae5f5b61b57a46cc4061c32", + "registryId":"0x53786c93e54c21d9852d093c394eee9df8d714d8f2534cdf92f9c9998c528d19", + "lastBlockNumber":4229185, + "totalServers":5 + }, + "jsonrpc":"2.0", + "in3":{ + "execTime":0, + "proof":{ + "type":"accountProof", + "block":"0xf9025ca076d3a4a758090c66b136b2b719a94d2823bc0be8d1172b23fbfda179bebcc96aa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a0b5d5f066b66d451b5d5cf3395150122568c66c865766b17f3a83e2e4a211586fa04dbdc0f0e921e2e95988a8c725af395cc3d25314ade9ad412f809fd96af1be45a03fcc60c369a34f1fbf6611e71daa0d11f25e66a09c26237087d65c38a0719a79b90100008000000000000000000000008001000000800000000800008000000000000004000000000000040000008000004000000000000800000400000000000000000000000000001020000000090000008042014000000000000000200000000010000000000210000000000000000008040000000000000000000000100000104000000000000000000000400000000000000000000000000000000000010000001000020000000000000000000000000000000001000800000000000000000000000000020010000010000000200000000000200000000000000000000000200000000000000000100000000000000400000000000000000000000000000000000283408841837a1200831aae9884601d0b7cb861000000000000436f6e73656e5379732048797065726c65646765722042657375a93e60140d01945fb8a233a4eedab42b61e0e5c4e7ec25267ec0fd74b481351f5a397679d36ddbc97fd85abd7286ceb63b656bcdd83ebc7e7c8672faa53e541700a00000000000000000000000000000000000000000000000000000000000000000880000000000000000", + "accounts":{ + "0xc2c05fbfe76ee7748ae5f5b61b57a46cc4061c32":{ + "accountProof":["0xf90211a02176c129dbc42e25c8d1162dc0edf92c2e65bee045d0c7560934438153406a6fa0e118fb12921b790d5a9ee1ad345c260ee3276cf850561658e1abe616baf40286a032517df96c207ceb6964b516f7cf7f54594ed433b0b5f032e362a550b38ad1ffa044b91c7c42e59fa635337b00d381c672bd2945c951e68cd1365ea485d4f37ec6a0e2d2af55418b8ef4f8d9c47f8a53f19b526294b9a97905c340b9cc6f620da301a00bceffcc6073b6cb383dca8d4f7f6abfe605b5e9f40838adc58105da6819319da01305e8d89582149cb08147b4a60bf98863b23c2708960782c29d986482faa388a024ba45083e5850966c3e760f95aec7d4004738f427c25a56c18439348dba9a23a0c40609f42e985bf7c1df75b26786528c4e4ea09a275f01f8704d720a7284e038a03989be34cb23145de7bbdfa095868575dd527202ce41a256b5c84e5582080be9a05f22ae2af2734025efc73c0b5c60329126733cefe03c9f57b0e9170da2264f43a0a86f752f84985ae46c715dd6de83cadeb8491a05442c1c2a490564e496adf8a1a09ba64dbea55976d707883e43c019cc6d94c49b8f6ae65099bda01c84c3888e4fa09296cf138f05ea04341e823d682a7cda889a3f80270725479b40733701db7f0ba0139fdc9eed3c2d025283d6dd4afaddde0919161f51a4ca7e0f2c8495017b7733a0543a55b212f31fa4009ae14c9008a142fd9629442a1dbb886a97c6a9e709b9fc80", + "0xf90211a0ed9c0ff9ae751d881c84a357918739f10525eed27b43de0f9296e5baaf9bb1fda0e0128203a2f634bd2bc3bedfd6bcf164f69f5fbe94c87c05d4908a37a1f81d46a08f3fd424a0c6719514dbef79e1e849c24f39f4239ecdf665c73116c152e09050a0979a57a7ecbc9018043f0d9edeacf3965f5cb9487aa243a016eaabff06740189a0b21b702577cd8579103422d551d85efb638172bc54fc55a75693b5a2fdfdc54fa09b6d19191d8d09916c9fbd3f819173caa43709c5b7041998bef417b2b7515ceda0b210d6ba8e1162dde71877ae2c8a5c9c16137efa662cec3e627d6a9645c0cd44a0acf80531cc4b674c58a4c9faf0fa63034e861b85c8613947da582fec5f1dee68a019cc0bc1c987814d96d15898ef1ec3dfff19b10fb41bbdc7f39eb39182833672a0926bf31e6b8575ca40a55b33717965ccee9500be55c525586d17138bc3d1e43fa0b35f96a10bf3126d6ed21b8cf400e9b1d94ee828dcfce3544462ab21d0c2d6aea00676b7047bfe5e74da9f04b0e58ac0624b60160496dd79f1530d2beb4a6e5350a09c5f723923cdc360a9f7e0e1200fe8f82967e6c1ecac06b94f2d9252204d6caea08799003a84ec35a486ec5d520bc160b57c62c6eb4f8117e0c69ca5cd1ac23440a0a3bfea660692e188e4cf88d78efc21868418c58b43aa51d15afbeaeb5a30ea90a0327f99800e8d4d5146898d0eb401ee4f967f0c62b98014a96efd248d71cb273f80", + "0xf90211a0c52b7d7c9faa8fc42e3843e59b0c7102188d918840b8b5cf5649197b13942a94a067f59108675f198f0b1f14273b4fbb3ba4c9ac61ecaa83900e37154881990941a08407f24415d4b1971faa2f1e53d2cfbb4fae100d135486236834036b94d129fca0cdf5918e749c6ed171d0e1db4a39df01763c7a2e7b0429b304f5de22d16195e8a01efdf7379329d0d371efabd4fa76401f1984fcbca64471ebe2c74475845f0a85a0a28daa09319d9b64e5967130cdd21a099b54869ddf92dff7cc080bbb25279364a0cea9a3f62b9e510d5508f3ca8323dd519cae9c320f99dc172193d07f0c6317b3a0369809678111f01bbcdcd5df6c6a2841e85077206e3b650db6eb2ec037e13a2da0e7511971b817dd5f0241d0309cd6f8e8e9ad35aba0807204884e840c16f4471ca06d6da5d6f453b1ea3dc911431e9a26abc197b409538aa40d46da259e6c08729aa0a5edc7f66811fa983d4e2d61c09fbc50bdefb4d77c487eb1ac533ceab3bcaf09a06e6f4a8927f13aadfb9c772b0715bcfe313f02b6034b0d6f2b59f56e0b9c9c3ba0763f63c10c5e3334c7b3af8f419f8add4e1f85f7cfcedea3f06912d66840c1fda05286d33d2797793fca9d99ece2f764da00716ac9536c635c83c695ed84a0e4d3a0079a7452891f1b97eccbb9bd876353da6732910c99194953c3e392265a6a0712a0d729c7014af2776b688d09d312623bb74cb092c92aafa099bdac3c6a1f53e39980", + "0xf90211a037a3337f0005db74a91f0f96ff9fbacbbc0521a8784b3ff8c9d8444d81e20456a075183b26afb188dcbbeee102e53d7ecf7f9b82c92c0d6efce4ff73c2fc9427eea0fe890d643ed692fa36be93853f94be950f7c57367fc9a3fd19fdfa76fbcd084ea06335914313fc71923c429c0a768c0584f2486976aaf5ae6e939cc0c1819c678fa0cc46707e8dab2140eabb4c2af2c8ae392674ac306f8608037e5afecd026b76b1a0910c8d52ee6bafc81d8033360f056cd845e15a87fbfd52d58daa576b58e9e39aa0db792420e982fc3088994c2fecc5271dae872a7743d8e9509b211c5d4e47bc8ca05eaa1847e192dda347bb7f272485e67f55925df2ad747e9faacc02ba12dd9d2da0a4437a739941a0a53d690f63cf5154030f1786944b7db70b224ad3bc3185725da0cd2436f554561a620f05eccc2cf101540161a3e3f5cd0b850602ece78b39e70da0ea6d47e623b880d04163a1976acd454e44ae57cfacda98a3757ae4350eead60ca0b696d8434f73dce704ab08de53ff772e86f50cfcc1a752002d1e0e5726308679a0a25b9334ba25fbd904b35fdc0063cca2be2817ce508108687a48c9020ff3aa5aa051ffa5e10005f382bbc6b388e200037bb41bbef652137761d8a317ffabaf2b3aa0abb3708f4efc71f63d4d3c45fdfb616da97646b412d79c134f58e64795cebde0a09b81a3cbbf7eeefcafae4f0163f51303c2708f20870dc23edf905da4aa8e522280", + "0xf90131808080a0615059ed3d0c135089a399e39e1108e5f58fc040d20bb1594d327d565f6530dfa0cca3258088afed6e4228125045d2813d736c800bc9551b38e99a228fb4985334a0b8609eb04093c8652ac25cf5d412d366616c55d78e769d0133a4e11baaf51c9480a071319005086e17af8200acfdcdaaac0d39b3a30daafb102cb1e81787a5671246a0d623ac3203b39d02c36962fae8246e75cfc6eb03d9ec358115794e0ef967b7d8a0005374980c9eb696e134af89e55bec93767d19fbc7eacdfb423865e28fb853d98080a0a7f8317e21a74ea5c5ade1f3cfe5b019caf1e5df49c0e6063fe477a7a3e7e79c80a05adcf071a5adcb1c99f67df461650b2ba62d3f48600f4b97e6b1201194288702a05db46c9db1409a03378debec1d3daf79a6365672e7ca0b1902e158d3b18355ea80", + "0xf8679e3dfa35139af4f993370c1dc5c729942db777d38a285fb227906c1bc93854b846f8440180a04d736bfa42e5592b521061863e73c096fb378444a82b1a057e240b863c90666ea029140efcd5358d1dd75badfaa179e3df0dd53f17a883a30152d82903305697a1"], + "address":"0xc2c05fbfe76ee7748ae5f5b61b57a46cc4061c32", + "balance":"0x0", + "codeHash":"0x29140efcd5358d1dd75badfaa179e3df0dd53f17a883a30152d82903305697a1", + "nonce":"0x1", + "storageHash":"0x4d736bfa42e5592b521061863e73c096fb378444a82b1a057e240b863c90666e", + "storageProof":[{ + "key":"0x0", + "proof":["0xf90211a0c1d22c4f4f1cc6ad83407a19b0bf3b129206880b89a580d09ec7151ad9886095a053147b12a82ecbbf958ea21eaaa2b4b5e676963a1753f0e1c817c7cfe8ea48ada0076fff6235c18f210b8221a89fed3f6722f69f20f36341bae5e8da877284000fa0551e4cfb868bba75b151be76c2da75e52824e15c501c0000ba044250a971176fa012a4969e387686fc86af25c07f72fbd658df39b133002d50a19ada8a8c005b9da0e2665b2ac7f21c0d77a88b8ffe7eb97fc247c768d77f8e49e518f7ef949d3989a00916ff25b14411517799d32a46128fd65ee9c90208563ffc6ca52e654673f1b6a07f67f5182dfcdcd333dbe5418dd1372f57ef648defa506aa4b8939d9e87b8fd8a0cee9a05be79629c249555cca89bead566bbf2a791de2729a3f37c4795b0ef3b2a0e07263f33741ea2779a238a95b43c60fe85c1f5c55ccfbe71202a5270e8d4b6ba05f03c75d89c4a70dfe72980c3c740155d12bc07edaca4300153d9f74b6b3624aa0be3f6a3c5587a2e321d2e6a766518c8966e311f921e1936906920fed463ec8b1a078dc7aa0d2de98f73391cda3066e6c4dec84c1ffa840b234b7081ca5ddebd4fea01d8b2a194aeacedef6268d6bf81d351fd0e2177ae007c5201ff7c10e9716d5c4a0f09b315bf02379572d599d47a7610f96feb1b72dd98123a1f47ac8e9750862c2a01d6cc819b88e2433c90c9990aed9dc37c67c80729c88d583c96832b368b76d9b80", + "0xf891a0f881becd1a54ec2ac129979fbb7cc851f4245d372d588056b040ccae152793e8808080808080a0f229214dba34c16ca65b1e0df175282a07b3ea9453d97f5b9e9e78762fe279fd80a081b7693d9ef9dea4b83b27e12fd4a86cfd861c266865545c3602ec6a1e43039da0aa7f3523263242a60b36be40eabda7dae87817cbb0cdbf6948564d446d43cae0808080808080", + "0xe2a0200decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e56305"], + "value":"0x5" + }, + { + "key":"0x1", + "proof":["0xf90211a0c1d22c4f4f1cc6ad83407a19b0bf3b129206880b89a580d09ec7151ad9886095a053147b12a82ecbbf958ea21eaaa2b4b5e676963a1753f0e1c817c7cfe8ea48ada0076fff6235c18f210b8221a89fed3f6722f69f20f36341bae5e8da877284000fa0551e4cfb868bba75b151be76c2da75e52824e15c501c0000ba044250a971176fa012a4969e387686fc86af25c07f72fbd658df39b133002d50a19ada8a8c005b9da0e2665b2ac7f21c0d77a88b8ffe7eb97fc247c768d77f8e49e518f7ef949d3989a00916ff25b14411517799d32a46128fd65ee9c90208563ffc6ca52e654673f1b6a07f67f5182dfcdcd333dbe5418dd1372f57ef648defa506aa4b8939d9e87b8fd8a0cee9a05be79629c249555cca89bead566bbf2a791de2729a3f37c4795b0ef3b2a0e07263f33741ea2779a238a95b43c60fe85c1f5c55ccfbe71202a5270e8d4b6ba05f03c75d89c4a70dfe72980c3c740155d12bc07edaca4300153d9f74b6b3624aa0be3f6a3c5587a2e321d2e6a766518c8966e311f921e1936906920fed463ec8b1a078dc7aa0d2de98f73391cda3066e6c4dec84c1ffa840b234b7081ca5ddebd4fea01d8b2a194aeacedef6268d6bf81d351fd0e2177ae007c5201ff7c10e9716d5c4a0f09b315bf02379572d599d47a7610f96feb1b72dd98123a1f47ac8e9750862c2a01d6cc819b88e2433c90c9990aed9dc37c67c80729c88d583c96832b368b76d9b80", + "0xf85180a083500cde7f6fd365be906592de84b1d7b3bbb1fc02e2129051371bf3adb79eed808080808080808080808080a008ce5962e734b12d09863c498b32a8f4b2078bf5b414ae7ee0fa3a57e2b6b3a48080", + "0xf843a0200e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6a1a053786c93e54c21d9852d093c394eee9df8d714d8f2534cdf92f9c9998c528d19"], + "value":"0x53786c93e54c21d9852d093c394eee9df8d714d8f2534cdf92f9c9998c528d19" + }, + { + "key":"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e567", + "proof":["0xf90211a0c1d22c4f4f1cc6ad83407a19b0bf3b129206880b89a580d09ec7151ad9886095a053147b12a82ecbbf958ea21eaaa2b4b5e676963a1753f0e1c817c7cfe8ea48ada0076fff6235c18f210b8221a89fed3f6722f69f20f36341bae5e8da877284000fa0551e4cfb868bba75b151be76c2da75e52824e15c501c0000ba044250a971176fa012a4969e387686fc86af25c07f72fbd658df39b133002d50a19ada8a8c005b9da0e2665b2ac7f21c0d77a88b8ffe7eb97fc247c768d77f8e49e518f7ef949d3989a00916ff25b14411517799d32a46128fd65ee9c90208563ffc6ca52e654673f1b6a07f67f5182dfcdcd333dbe5418dd1372f57ef648defa506aa4b8939d9e87b8fd8a0cee9a05be79629c249555cca89bead566bbf2a791de2729a3f37c4795b0ef3b2a0e07263f33741ea2779a238a95b43c60fe85c1f5c55ccfbe71202a5270e8d4b6ba05f03c75d89c4a70dfe72980c3c740155d12bc07edaca4300153d9f74b6b3624aa0be3f6a3c5587a2e321d2e6a766518c8966e311f921e1936906920fed463ec8b1a078dc7aa0d2de98f73391cda3066e6c4dec84c1ffa840b234b7081ca5ddebd4fea01d8b2a194aeacedef6268d6bf81d351fd0e2177ae007c5201ff7c10e9716d5c4a0f09b315bf02379572d599d47a7610f96feb1b72dd98123a1f47ac8e9750862c2a01d6cc819b88e2433c90c9990aed9dc37c67c80729c88d583c96832b368b76d9b80", + "0xf871a0a28c08659e018bd7c2c18c6275f97881c4d7c045943c5caecfea71e41474cc9e8080808080808080808080a0407e55e9a8f7681ee1a46fd778e03ffd2fa7507952c81308e60239bbaba3875a80a0a3e90ff33462c5a993a90a3387e5c9c2d7aad2f327ff5c69cbfab2e5ce6c3a798080", + "0xf843a020418048a637d1641c6d732dd38174732bbf7b47a1cf6d5f65895384518b07d9a1a013218ee8dd11494c58f119748f198ad3c24a0024746f3a5896f51dc1e008821f"], + "value":"0x13218ee8dd11494c58f119748f198ad3c24a0024746f3a5896f51dc1e008821f" + }, + { + "key":"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e56c", + "proof":["0xf90211a0c1d22c4f4f1cc6ad83407a19b0bf3b129206880b89a580d09ec7151ad9886095a053147b12a82ecbbf958ea21eaaa2b4b5e676963a1753f0e1c817c7cfe8ea48ada0076fff6235c18f210b8221a89fed3f6722f69f20f36341bae5e8da877284000fa0551e4cfb868bba75b151be76c2da75e52824e15c501c0000ba044250a971176fa012a4969e387686fc86af25c07f72fbd658df39b133002d50a19ada8a8c005b9da0e2665b2ac7f21c0d77a88b8ffe7eb97fc247c768d77f8e49e518f7ef949d3989a00916ff25b14411517799d32a46128fd65ee9c90208563ffc6ca52e654673f1b6a07f67f5182dfcdcd333dbe5418dd1372f57ef648defa506aa4b8939d9e87b8fd8a0cee9a05be79629c249555cca89bead566bbf2a791de2729a3f37c4795b0ef3b2a0e07263f33741ea2779a238a95b43c60fe85c1f5c55ccfbe71202a5270e8d4b6ba05f03c75d89c4a70dfe72980c3c740155d12bc07edaca4300153d9f74b6b3624aa0be3f6a3c5587a2e321d2e6a766518c8966e311f921e1936906920fed463ec8b1a078dc7aa0d2de98f73391cda3066e6c4dec84c1ffa840b234b7081ca5ddebd4fea01d8b2a194aeacedef6268d6bf81d351fd0e2177ae007c5201ff7c10e9716d5c4a0f09b315bf02379572d599d47a7610f96feb1b72dd98123a1f47ac8e9750862c2a01d6cc819b88e2433c90c9990aed9dc37c67c80729c88d583c96832b368b76d9b80", + "0xf8718080a004086d122b3bd8d29156e97aacb81408ae87858145b9749f8f6c7bbf653d6ce38080808080808080a0db8ab81a65a81b2ff2c25e14082cc52fa19e16339b5d616a4a7749e830bf136780a03f40fdc942ec4a9b8cf72f3599a83e4b40cf9f76905977c6e9cf1d93e3485a7b808080", + "0xf843a0205fcc8f73196524ea5f04c38888c2f09c6cbef411cb31e259d35b56e3d0047ba1a091605b26d5a69917787d9bcac74f808951039567c0db700da087a92a4e9a6072"], + "value":"0x91605b26d5a69917787d9bcac74f808951039567c0db700da087a92a4e9a6072" + }, + { + "key":"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e571", + "proof":["0xf90211a0c1d22c4f4f1cc6ad83407a19b0bf3b129206880b89a580d09ec7151ad9886095a053147b12a82ecbbf958ea21eaaa2b4b5e676963a1753f0e1c817c7cfe8ea48ada0076fff6235c18f210b8221a89fed3f6722f69f20f36341bae5e8da877284000fa0551e4cfb868bba75b151be76c2da75e52824e15c501c0000ba044250a971176fa012a4969e387686fc86af25c07f72fbd658df39b133002d50a19ada8a8c005b9da0e2665b2ac7f21c0d77a88b8ffe7eb97fc247c768d77f8e49e518f7ef949d3989a00916ff25b14411517799d32a46128fd65ee9c90208563ffc6ca52e654673f1b6a07f67f5182dfcdcd333dbe5418dd1372f57ef648defa506aa4b8939d9e87b8fd8a0cee9a05be79629c249555cca89bead566bbf2a791de2729a3f37c4795b0ef3b2a0e07263f33741ea2779a238a95b43c60fe85c1f5c55ccfbe71202a5270e8d4b6ba05f03c75d89c4a70dfe72980c3c740155d12bc07edaca4300153d9f74b6b3624aa0be3f6a3c5587a2e321d2e6a766518c8966e311f921e1936906920fed463ec8b1a078dc7aa0d2de98f73391cda3066e6c4dec84c1ffa840b234b7081ca5ddebd4fea01d8b2a194aeacedef6268d6bf81d351fd0e2177ae007c5201ff7c10e9716d5c4a0f09b315bf02379572d599d47a7610f96feb1b72dd98123a1f47ac8e9750862c2a01d6cc819b88e2433c90c9990aed9dc37c67c80729c88d583c96832b368b76d9b80", + "0xf871a0d3b9189299e575e9b50d9e6113d15c202e7dd53942477ff21ac5a62e5b5fcd018080a08a0a0e6297b603d3e5577d7e849031cfba639f44aa9f27a34b6e4b950c6c073a808080808080a04a5be21f4f0c0f5e1fcccb140e7cb5b1ff2ce45bce977d8e23cc7320e8c7bdd0808080808080", + "0xf843a0206695c256a4a4a1b8ed004dc824e330f1747032632c0e6d88c1d84c330c1c5ca1a0855e7bdf0b02683e5ab1cdc096c6101085b4c7fe69fe218bffa7dff912490a9b"], + "value":"0x855e7bdf0b02683e5ab1cdc096c6101085b4c7fe69fe218bffa7dff912490a9b" + }, + { + "key":"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e576", + "proof":["0xf90211a0c1d22c4f4f1cc6ad83407a19b0bf3b129206880b89a580d09ec7151ad9886095a053147b12a82ecbbf958ea21eaaa2b4b5e676963a1753f0e1c817c7cfe8ea48ada0076fff6235c18f210b8221a89fed3f6722f69f20f36341bae5e8da877284000fa0551e4cfb868bba75b151be76c2da75e52824e15c501c0000ba044250a971176fa012a4969e387686fc86af25c07f72fbd658df39b133002d50a19ada8a8c005b9da0e2665b2ac7f21c0d77a88b8ffe7eb97fc247c768d77f8e49e518f7ef949d3989a00916ff25b14411517799d32a46128fd65ee9c90208563ffc6ca52e654673f1b6a07f67f5182dfcdcd333dbe5418dd1372f57ef648defa506aa4b8939d9e87b8fd8a0cee9a05be79629c249555cca89bead566bbf2a791de2729a3f37c4795b0ef3b2a0e07263f33741ea2779a238a95b43c60fe85c1f5c55ccfbe71202a5270e8d4b6ba05f03c75d89c4a70dfe72980c3c740155d12bc07edaca4300153d9f74b6b3624aa0be3f6a3c5587a2e321d2e6a766518c8966e311f921e1936906920fed463ec8b1a078dc7aa0d2de98f73391cda3066e6c4dec84c1ffa840b234b7081ca5ddebd4fea01d8b2a194aeacedef6268d6bf81d351fd0e2177ae007c5201ff7c10e9716d5c4a0f09b315bf02379572d599d47a7610f96feb1b72dd98123a1f47ac8e9750862c2a01d6cc819b88e2433c90c9990aed9dc37c67c80729c88d583c96832b368b76d9b80", + "0xf85180a083500cde7f6fd365be906592de84b1d7b3bbb1fc02e2129051371bf3adb79eed808080808080808080808080a008ce5962e734b12d09863c498b32a8f4b2078bf5b414ae7ee0fa3a57e2b6b3a48080", + "0xf843a020257165ee8c7eae64faf81e97823d50dba1b6a2be88bccea1ac5d01256f0590a1a0b28786a66e4e84e2b7e236efb9fb0a82053e342cbf26d41af8c4cae4836d56e8"], + "value":"0xb28786a66e4e84e2b7e236efb9fb0a82053e342cbf26d41af8c4cae4836d56e8" + }, + { + "key":"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e57b", + "proof":["0xf90211a0c1d22c4f4f1cc6ad83407a19b0bf3b129206880b89a580d09ec7151ad9886095a053147b12a82ecbbf958ea21eaaa2b4b5e676963a1753f0e1c817c7cfe8ea48ada0076fff6235c18f210b8221a89fed3f6722f69f20f36341bae5e8da877284000fa0551e4cfb868bba75b151be76c2da75e52824e15c501c0000ba044250a971176fa012a4969e387686fc86af25c07f72fbd658df39b133002d50a19ada8a8c005b9da0e2665b2ac7f21c0d77a88b8ffe7eb97fc247c768d77f8e49e518f7ef949d3989a00916ff25b14411517799d32a46128fd65ee9c90208563ffc6ca52e654673f1b6a07f67f5182dfcdcd333dbe5418dd1372f57ef648defa506aa4b8939d9e87b8fd8a0cee9a05be79629c249555cca89bead566bbf2a791de2729a3f37c4795b0ef3b2a0e07263f33741ea2779a238a95b43c60fe85c1f5c55ccfbe71202a5270e8d4b6ba05f03c75d89c4a70dfe72980c3c740155d12bc07edaca4300153d9f74b6b3624aa0be3f6a3c5587a2e321d2e6a766518c8966e311f921e1936906920fed463ec8b1a078dc7aa0d2de98f73391cda3066e6c4dec84c1ffa840b234b7081ca5ddebd4fea01d8b2a194aeacedef6268d6bf81d351fd0e2177ae007c5201ff7c10e9716d5c4a0f09b315bf02379572d599d47a7610f96feb1b72dd98123a1f47ac8e9750862c2a01d6cc819b88e2433c90c9990aed9dc37c67c80729c88d583c96832b368b76d9b80", + "0xf871a0a28c08659e018bd7c2c18c6275f97881c4d7c045943c5caecfea71e41474cc9e8080808080808080808080a0407e55e9a8f7681ee1a46fd778e03ffd2fa7507952c81308e60239bbaba3875a80a0a3e90ff33462c5a993a90a3387e5c9c2d7aad2f327ff5c69cbfab2e5ce6c3a798080", + "0xf85180808080a02ae042c128229c068ee987ed30164a035d10da3ba96f25b04b7e56e6fc2c12fb808080808080808080a04083c8127572e64ae53476470e7a632258565a37b7f2066cb22ef228e679c24e8080", + "0xf8429f3d807394a26a5623e844d859daa1940d13cb7bda091582294562d688f4de00a1a0986891b6cd760bac247ed5d7dbc574b1c07425bc49a44d54b9900dc485329218"], + "value":"0x986891b6cd760bac247ed5d7dbc574b1c07425bc49a44d54b9900dc485329218" + }] + } + } + } + } +}] + +:: cache btc_target_153 1 +000affff001d000fffff001d00145746651c0019a7bc201c001e64ba0e1c00235a0c011c0028ed66471b002d56720e1b0032cb04041b0037cd2d011b003cfa98001b00418521131a0046864a091a004bcaf00d1a0050d7690d1a005587320b1a005a5f8b0a1a005fc93c081a0064087e051a006962fa041a006e5c98041a007394de011a007815de001a007d328754190082cab01619008742120619008c2cf50119009199db0019009642286918009ba2ae3a1800a093b81f1800a5747b1b1800aa87bb181800aff017171800b48e41161800b9c14d131800be89b2101800c31bb3091800c8c3a4061800cd3684051800d22872051800d7c440041800dc858b031800e1937e021800e63e1b021800eb308d011800f00b31011800f54bce001800fa8c577e1700ff494a51170104495a411701097b4f2f17010e91c125170113f41e37170118505b2e17011d38ff291701229b0d1f170127f5ab1717012c3eb215170131ff3212170136bc2013170135413b1417 :: request http://localhost:8500 [{"id":1,"jsonrpc":"2.0","method":"getblockheader","params":["000000002afcaf0e0d78e698e71c26fdd5f87b7703c18ed48e27ab133dc3d4bb",true],"in3":{"verification":"proof","version": "2.1.0","chainId":"0x99","finality":5,"preBIP34":true}}] -:: response getblockheader 0 http://localhost:8500 0 1316 +:: response getblockheader 0 http://localhost:8500 0 129 [{ "id":1, "jsonrpc":"2.0", "result":{ "hash":"000000002afcaf0e0d78e698e71c26fdd5f87b7703c18ed48e27ab133dc3d4bb", - "confirmations":637709, + "confirmations":646406, "height":22790, "version":1, "versionHex":"00000001", @@ -31,16 +212,14 @@ "final":"0x01000000bbd4c33d13ab278ed48ec103777bf8d5fd261ce798e6780d0eaffc2a00000000d661462f180562c74d25efb0c007d6b4b20fe10b61adecad7484c3c53fde0e41c3dfac4affff001dba4db74d01000000fcdbcd016be8773a777ba924c6468a2c1cc4d020fdbdf13aec9f43c80000000014104745e906313add5762734b11a44e64ea7a35fce3b448365ae3e4e3161d1988e5ac4affff001d149df3dd01000000ceda3913875fad030d3ab752a2c95893e66958fa34c164cffe6e73da00000000b2d841452e2a7117753c423f049cbbe0d13dacdb99266880407e26282ea53d3d3aeaac4affff001d16343a420100000032b5d55ed9667e77bc11c7f3e16503ea184e146cdb3bd290cbd85e83000000003177ded1cce03952f1fc214b3930d6de33186d5a72a5c8c0c9e38ed608fac76f88f0ac4affff001d20e3ad500100000023c81d5fa8eb67ceccc8d42262c900ecb60b2c080865d3eb6e2bdf44000000007120278a4a79ccc46a29f6ec819485c6d04f20c721c0a4e0d1364f1e007eae505af2ac4affff001d0031144a01000000e8b8406cadca24f4be8feac6c2cd1ec21e0c134504e4874807092b6c00000000aa7fbe13f0d870c298a54dc0624375d728557b7f8f6a6c88f58b71a056dc90c542f8ac4affff001d08ffb3d001000000ffe8566bb6808828e251ec3dc6081c335f3a039f6ed4e7143d509ea500000000c2f7dfa0221a15512cb99ea2c193eb39c5c181c840204b623ffde6e17c4e5e47aefaac4affff001dc2bdcc11010000000a77bb0ff642c5c568a7f5440c11f0ddd04fd801d2a66a3325f5ce25000000003b846ebf084baa6a1dbd88ce761c793d21afb86588a1e285d050c3b6f1e8fc657bfcac4affff001d2080bb670100000030ff49d95072dcc9f78301ceeaf43e13c84d8250cb07229c61be5ef20000000005abf988b99ad4199b5122701452117f2328f3c1051678090fc452d8d319ec710404ad4affff001d1fec09660100000079ff834d61ea4c6264612c58d5853fc0392a5c4ded52c797e033a2d9000000008aea365a64ae3664861ed730c087d263d28273ae70c086fc55c211fed8e64d78310dad4affff001d176d900c", "height":22790 }, - "lastNodeList":3890668, - "execTime":1311, + "lastNodeList":4229185, + "execTime":125, "rpcTime":0, "rpcCount":0, - "currentBlock":3890833, + "currentBlock":4229194, "version":"2.1.0" } }] -:: cache btc_target_153 0 - :: result -{"hash":"000000002afcaf0e0d78e698e71c26fdd5f87b7703c18ed48e27ab133dc3d4bb","confirmations":637709,"height":22790,"version":1,"versionHex":"00000001","merkleroot":"a2d99d38724cfb8bc7bf25b69278be0511dcc8229280b3d28144ed61c312a542","time":1252839569,"mediantime":1252834756,"nonce":231526776,"bits":"1d00ffff","difficulty":1,"chainwork":"0000000000000000000000000000000000000000000000000000590759075907","nTx":1,"previousblockhash":"0000000081a33fec1ece434279ddc7c59a00c7a4ec2f08db452bade37d50be75","nextblockhash":"00000000c8439fec3af1bdfd20d0c41c2c8a46c624a97b773a77e86b01cddbfc"} +{"hash":"000000002afcaf0e0d78e698e71c26fdd5f87b7703c18ed48e27ab133dc3d4bb","confirmations":646406,"height":22790,"version":1,"versionHex":"00000001","merkleroot":"a2d99d38724cfb8bc7bf25b69278be0511dcc8229280b3d28144ed61c312a542","time":1252839569,"mediantime":1252834756,"nonce":231526776,"bits":"1d00ffff","difficulty":1,"chainwork":"0000000000000000000000000000000000000000000000000000590759075907","nTx":1,"previousblockhash":"0000000081a33fec1ece434279ddc7c59a00c7a4ec2f08db452bade37d50be75","nextblockhash":"00000000c8439fec3af1bdfd20d0c41c2c8a46c624a97b773a77e86b01cddbfc"} diff --git a/c/test/testdata/cmd/zksync_account_eip1271.txt b/c/test/testdata/cmd/zksync_account_eip1271.txt index 13ddff56a..cf0e35638 100644 --- a/c/test/testdata/cmd/zksync_account_eip1271.txt +++ b/c/test/testdata/cmd/zksync_account_eip1271.txt @@ -1,4 +1,4 @@ -:: cmd in3 -zks http://localhost:3030 -pk 0xe20eb92b34a3c5bd2ef0802a4bc443a90e73fc4a0edc4781446d7b22a44cc5d8 -c http://localhost:8545 -fi zksync_account_eip1271.txt -ms 0x7ff5c6fab254833c037ad23ca32e2b2b2c6083a4 -zka 0x7ff5c6fab254833c037ad23ca32e2b2b2c6083a4 -zkat contract zksync_account_info 0x7ff5c6fab254833c037ad23ca32e2b2b2c6083a4 +:: cmd in3 -x -zks http://localhost:3030 -pk 0xe20eb92b34a3c5bd2ef0802a4bc443a90e73fc4a0edc4781446d7b22a44cc5d8 -c http://localhost:8545 -fi zksync_account_eip1271.txt -ms 0x7ff5c6fab254833c037ad23ca32e2b2b2c6083a4 -zka 0x7ff5c6fab254833c037ad23ca32e2b2b2c6083a4 -zkat contract zksync_account_info 0x7ff5c6fab254833c037ad23ca32e2b2b2c6083a4 :: time 1610970655 diff --git a/c/test/testdata/cmd/zksync_deposit.txt b/c/test/testdata/cmd/zksync_deposit.txt index ef3d3d0e4..876627185 100644 --- a/c/test/testdata/cmd/zksync_deposit.txt +++ b/c/test/testdata/cmd/zksync_deposit.txt @@ -1,4 +1,4 @@ -:: cmd ./in3 -fi ../../c/test/testdata/cmd/zksync_deposit.txt -zks http://localhost:3030 -c http://localhost:8545 -pk 0xe20eb92b34a3c5bd2ef0802a4bc443a90e73fc4a0edc4781446d7b22a44cc5d8 zksync_deposit 0xDE0B6B3A7640000 ETH false -debug +:: cmd ./in3 -x -fi ../../c/test/testdata/cmd/zksync_deposit.txt -zks http://localhost:3030 -c http://localhost:8545 -pk 0xe20eb92b34a3c5bd2ef0802a4bc443a90e73fc4a0edc4781446d7b22a44cc5d8 zksync_deposit 0xDE0B6B3A7640000 ETH false -debug :: time 1601026236 diff --git a/c/test/testdata/cmd/zksync_deposit_c2.txt b/c/test/testdata/cmd/zksync_deposit_c2.txt index 7cb74af15..22d2b2890 100644 --- a/c/test/testdata/cmd/zksync_deposit_c2.txt +++ b/c/test/testdata/cmd/zksync_deposit_c2.txt @@ -1,4 +1,4 @@ -:: cmd in3 -zks http://localhost:3030 -pk 0xe20eb92b34a3c5bd2ef0802a4bc443a90e73fc4a0edc4781446d7b22a44cc5d8 -c http://localhost:8545 -fi zksync_deposit_c2.txt -zkat contract zksync_deposit 10.0eth ETH false 0x89eb15687f7b55be70ac2faffcc5a52589c42d1e +:: cmd in3 -x -zks http://localhost:3030 -pk 0xe20eb92b34a3c5bd2ef0802a4bc443a90e73fc4a0edc4781446d7b22a44cc5d8 -c http://localhost:8545 -fi zksync_deposit_c2.txt -zkat contract zksync_deposit 10.0eth ETH false 0x89eb15687f7b55be70ac2faffcc5a52589c42d1e :: time 1611138822 diff --git a/c/test/testdata/cmd/zksync_deposit_eip1271.txt b/c/test/testdata/cmd/zksync_deposit_eip1271.txt index 3ae365aea..60aa371bb 100644 --- a/c/test/testdata/cmd/zksync_deposit_eip1271.txt +++ b/c/test/testdata/cmd/zksync_deposit_eip1271.txt @@ -1,4 +1,4 @@ -:: cmd in3 -zks http://localhost:3030 -pk 0xe20eb92b34a3c5bd2ef0802a4bc443a90e73fc4a0edc4781446d7b22a44cc5d8 -c http://localhost:8545 -fi zksync_deposit_eip1271.txt -ms 0x7ff5c6fab254833c037ad23ca32e2b2b2c6083a4 -zka 0x7ff5c6fab254833c037ad23ca32e2b2b2c6083a4 -zkat contract zksync_deposit 4000000000000000000 ETH false +:: cmd in3 -x -zks http://localhost:3030 -pk 0xe20eb92b34a3c5bd2ef0802a4bc443a90e73fc4a0edc4781446d7b22a44cc5d8 -c http://localhost:8545 -fi zksync_deposit_eip1271.txt -ms 0x7ff5c6fab254833c037ad23ca32e2b2b2c6083a4 -zka 0x7ff5c6fab254833c037ad23ca32e2b2b2c6083a4 -zkat contract zksync_deposit 4000000000000000000 ETH false :: time 1610970423 diff --git a/c/test/testdata/cmd/zksync_deposit_pk.txt b/c/test/testdata/cmd/zksync_deposit_pk.txt index def033225..2592631b6 100644 --- a/c/test/testdata/cmd/zksync_deposit_pk.txt +++ b/c/test/testdata/cmd/zksync_deposit_pk.txt @@ -1,4 +1,4 @@ -:: cmd in3 -zks http://localhost:3030 -pk 0xc073624ce79d35f60581134500771cecf21c34e07f5f599033cabaceeb187fef -c http://localhost:8545 -fi zksync_deposit_pk.txt zksync_deposit 1990493664000000000 ETH +:: cmd in3 -x -zks http://localhost:3030 -pk 0xc073624ce79d35f60581134500771cecf21c34e07f5f599033cabaceeb187fef -c http://localhost:8545 -fi zksync_deposit_pk.txt zksync_deposit 1990493664000000000 ETH :: time 1610972368 diff --git a/c/test/testdata/cmd/zksync_emergencyWithdraw.txt b/c/test/testdata/cmd/zksync_emergencyWithdraw.txt index fd2a0f80c..a87f8a3e6 100644 --- a/c/test/testdata/cmd/zksync_emergencyWithdraw.txt +++ b/c/test/testdata/cmd/zksync_emergencyWithdraw.txt @@ -1,4 +1,4 @@ -:: cmd ./in3 -fi ../../c/test/testdata/cmd/zksync_emergency_withdraw.txt -zks http://localhost:3030 -c http://localhost:8545 -pk 0xe20eb92b34a3c5bd2ef0802a4bc443a90e73fc4a0edc4781446d7b22a44cc5d8 zksync_emergency_withdraw ETH -debug +:: cmd ./in3 -x -fi ../../c/test/testdata/cmd/zksync_emergency_withdraw.txt -zks http://localhost:3030 -c http://localhost:8545 -pk 0xe20eb92b34a3c5bd2ef0802a4bc443a90e73fc4a0edc4781446d7b22a44cc5d8 zksync_emergency_withdraw ETH -debug :: time 1601030219 diff --git a/c/test/testdata/cmd/zksync_getPubKeyHash.txt b/c/test/testdata/cmd/zksync_getPubKeyHash.txt index 8d6cfd492..6732bbd38 100644 --- a/c/test/testdata/cmd/zksync_getPubKeyHash.txt +++ b/c/test/testdata/cmd/zksync_getPubKeyHash.txt @@ -1,4 +1,4 @@ -:: cmd build/bin/in3 -pk 0xe41d2489571d322189246dafa5ebde1f4699f498000000000000000000000000 zksync_pubkeyhash +:: cmd build/bin/in3 -x -pk 0xe41d2489571d322189246dafa5ebde1f4699f498000000000000000000000000 zksync_pubkeyhash :: time 1610550157 diff --git a/c/test/testdata/cmd/zksync_setKey.txt b/c/test/testdata/cmd/zksync_setKey.txt index 3efcf69df..6100068f2 100644 --- a/c/test/testdata/cmd/zksync_setKey.txt +++ b/c/test/testdata/cmd/zksync_setKey.txt @@ -1,4 +1,4 @@ -:: cmd ./in3 -fi ../../c/test/testdata/cmd/zksync_set_key.txt -zks http://localhost:3030 -c http://localhost:8545 -pk 0xe20eb92b34a3c5bd2ef0802a4bc443a90e73fc4a0edc4781446d7b22a44cc5d8 zksync_set_key ETH -debug +:: cmd ./in3 -x -fi ../../c/test/testdata/cmd/zksync_set_key.txt -zks http://localhost:3030 -c http://localhost:8545 -pk 0xe20eb92b34a3c5bd2ef0802a4bc443a90e73fc4a0edc4781446d7b22a44cc5d8 zksync_set_key ETH -debug :: time 1608290665 diff --git a/c/test/testdata/cmd/zksync_setkey_eip1271.txt b/c/test/testdata/cmd/zksync_setkey_eip1271.txt index b9350be86..e45d9fafb 100644 --- a/c/test/testdata/cmd/zksync_setkey_eip1271.txt +++ b/c/test/testdata/cmd/zksync_setkey_eip1271.txt @@ -1,4 +1,4 @@ -:: cmd in3 -zks http://localhost:3030 -pk 0xe20eb92b34a3c5bd2ef0802a4bc443a90e73fc4a0edc4781446d7b22a44cc5d8 -c http://localhost:8545 -fi zksync_setkey_eip1271.txt -ms 0x7ff5c6fab254833c037ad23ca32e2b2b2c6083a4 -zka 0x7ff5c6fab254833c037ad23ca32e2b2b2c6083a4 -zkat contract zksync_set_key ETH +:: cmd in3 -x -zks http://localhost:3030 -pk 0xe20eb92b34a3c5bd2ef0802a4bc443a90e73fc4a0edc4781446d7b22a44cc5d8 -c http://localhost:8545 -fi zksync_setkey_eip1271.txt -ms 0x7ff5c6fab254833c037ad23ca32e2b2b2c6083a4 -zka 0x7ff5c6fab254833c037ad23ca32e2b2b2c6083a4 -zkat contract zksync_set_key ETH :: time 1610970472 diff --git a/c/test/testdata/cmd/zksync_setkey_pk.txt b/c/test/testdata/cmd/zksync_setkey_pk.txt index 8970ac0ec..cee40c904 100644 --- a/c/test/testdata/cmd/zksync_setkey_pk.txt +++ b/c/test/testdata/cmd/zksync_setkey_pk.txt @@ -1,4 +1,4 @@ -:: cmd in3 -zks http://localhost:3030 -pk 0xc073624ce79d35f60581134500771cecf21c34e07f5f599033cabaceeb187fef -c http://localhost:8545 -fi zksync_setkey_pk.txt zksync_set_key ETH -debug +:: cmd in3 -x -zks http://localhost:3030 -pk 0xc073624ce79d35f60581134500771cecf21c34e07f5f599033cabaceeb187fef -c http://localhost:8545 -fi zksync_setkey_pk.txt zksync_set_key ETH -debug :: time 1610972402 diff --git a/c/test/testdata/cmd/zksync_setkey_pk_again.txt b/c/test/testdata/cmd/zksync_setkey_pk_again.txt index 6b7ae39e8..50757415c 100644 --- a/c/test/testdata/cmd/zksync_setkey_pk_again.txt +++ b/c/test/testdata/cmd/zksync_setkey_pk_again.txt @@ -1,4 +1,4 @@ -:: cmd in3 -zks http://localhost:3030 -pk 0xc073624ce79d35f60581134500771cecf21c34e07f5f599033cabaceeb187fef -c http://localhost:8545 -fi zksync_setkey_pk_again.txt zksync_set_key ETH -debug +:: cmd in3 -x -zks http://localhost:3030 -pk 0xc073624ce79d35f60581134500771cecf21c34e07f5f599033cabaceeb187fef -c http://localhost:8545 -fi zksync_setkey_pk_again.txt zksync_set_key ETH -debug :: time 1610972451 diff --git a/c/test/testdata/cmd/zksync_transfer_c2.txt b/c/test/testdata/cmd/zksync_transfer_c2.txt index a7a18c443..40d9f118c 100644 --- a/c/test/testdata/cmd/zksync_transfer_c2.txt +++ b/c/test/testdata/cmd/zksync_transfer_c2.txt @@ -1,4 +1,4 @@ -:: cmd in3 -zks http://localhost:3030 -c http://localhost:8545 -fi zksync_transfer_c2.txt -zka 0x8f6883b78d71ac2871f4b01d6fc5e047ccecfd02 -zkat create2 -zsk 0xd818beb367732ed0bc2ada1750fcce827040edf96ea3cdacf420b5c3cb1456df zksync_transfer 0xce93a4561fe6445653a8f6e4ff73c971ce1e9eec 0.1eth ETH +:: cmd in3 -x -zks http://localhost:3030 -c http://localhost:8545 -fi zksync_transfer_c2.txt -zka 0x8f6883b78d71ac2871f4b01d6fc5e047ccecfd02 -zkat create2 -zsk 0xd818beb367732ed0bc2ada1750fcce827040edf96ea3cdacf420b5c3cb1456df zksync_transfer 0xce93a4561fe6445653a8f6e4ff73c971ce1e9eec 0.1eth ETH :: time 1611139221 diff --git a/c/test/testdata/cmd/zksync_transfer_eip1271.txt b/c/test/testdata/cmd/zksync_transfer_eip1271.txt index 1dd381502..4454f9dc8 100644 --- a/c/test/testdata/cmd/zksync_transfer_eip1271.txt +++ b/c/test/testdata/cmd/zksync_transfer_eip1271.txt @@ -1,4 +1,4 @@ -:: cmd in3 -zks http://localhost:3030 -pk 0xe20eb92b34a3c5bd2ef0802a4bc443a90e73fc4a0edc4781446d7b22a44cc5d8 -c http://localhost:8545 -fi zksync_transfer_eip1271.txt -ms 0x7ff5c6fab254833c037ad23ca32e2b2b2c6083a4 -zka 0x7ff5c6fab254833c037ad23ca32e2b2b2c6083a4 -zkat contract zksync_transfer 0xab6ff744cf1276a78460e93972d22725abd3e095 9433236000000000 ETH +:: cmd in3 -x -zks http://localhost:3030 -pk 0xe20eb92b34a3c5bd2ef0802a4bc443a90e73fc4a0edc4781446d7b22a44cc5d8 -c http://localhost:8545 -fi zksync_transfer_eip1271.txt -ms 0x7ff5c6fab254833c037ad23ca32e2b2b2c6083a4 -zka 0x7ff5c6fab254833c037ad23ca32e2b2b2c6083a4 -zkat contract zksync_transfer 0xab6ff744cf1276a78460e93972d22725abd3e095 9433236000000000 ETH :: time 1610970586 diff --git a/c/test/testdata/cmd/zksync_transfer_pk.txt b/c/test/testdata/cmd/zksync_transfer_pk.txt index f8215fca1..a13a880cf 100644 --- a/c/test/testdata/cmd/zksync_transfer_pk.txt +++ b/c/test/testdata/cmd/zksync_transfer_pk.txt @@ -1,4 +1,4 @@ -:: cmd in3 -zks http://localhost:3030 -pk 0xc073624ce79d35f60581134500771cecf21c34e07f5f599033cabaceeb187fef -c http://localhost:8545 -fi zksync_transfer_pk.txt zksync_transfer 0x8a91dc2d28b689474298d91899f0c1baf62cb85b 990493664000000000 ETH +:: cmd in3 -x -zks http://localhost:3030 -pk 0xc073624ce79d35f60581134500771cecf21c34e07f5f599033cabaceeb187fef -c http://localhost:8545 -fi zksync_transfer_pk.txt zksync_transfer 0x8a91dc2d28b689474298d91899f0c1baf62cb85b 990493664000000000 ETH :: time 1610972571 diff --git a/c/test/testdata/cmd/zksync_withdraw_c2.txt b/c/test/testdata/cmd/zksync_withdraw_c2.txt index 2380764a8..6af2a6169 100644 --- a/c/test/testdata/cmd/zksync_withdraw_c2.txt +++ b/c/test/testdata/cmd/zksync_withdraw_c2.txt @@ -1,4 +1,4 @@ -:: cmd in3 -zks http://localhost:3030 -c http://localhost:8545 -fi zksync_withdraw_c2.txt -zka 0x8f6883b78d71ac2871f4b01d6fc5e047ccecfd02 -zkat create2 -zsk 0xd818beb367732ed0bc2ada1750fcce827040edf96ea3cdacf420b5c3cb1456df zksync_withdraw 0xce93a4561fe6445653a8f6e4ff73c971ce1e9eec 0.05eth ETH +:: cmd in3 -x -zks http://localhost:3030 -c http://localhost:8545 -fi zksync_withdraw_c2.txt -zka 0x8f6883b78d71ac2871f4b01d6fc5e047ccecfd02 -zkat create2 -zsk 0xd818beb367732ed0bc2ada1750fcce827040edf96ea3cdacf420b5c3cb1456df zksync_withdraw 0xce93a4561fe6445653a8f6e4ff73c971ce1e9eec 0.05eth ETH :: time 1611139373 diff --git a/c/test/testdata/cmd/zksync_withdraw_eip1271.txt b/c/test/testdata/cmd/zksync_withdraw_eip1271.txt index 3f25268ae..40261189d 100644 --- a/c/test/testdata/cmd/zksync_withdraw_eip1271.txt +++ b/c/test/testdata/cmd/zksync_withdraw_eip1271.txt @@ -1,4 +1,4 @@ -:: cmd in3 -zks http://localhost:3030 -pk 0xe20eb92b34a3c5bd2ef0802a4bc443a90e73fc4a0edc4781446d7b22a44cc5d8 -c http://localhost:8545 -fi zksync_withdraw_eip1271.txt -ms 0x7ff5c6fab254833c037ad23ca32e2b2b2c6083a4 -zka 0x7ff5c6fab254833c037ad23ca32e2b2b2c6083a4 -zkat contract zksync_withdraw 0xab6ff744cf1276a78460e93972d22725abd3e095 1990493664000000000 ETH +:: cmd in3 -x -zks http://localhost:3030 -pk 0xe20eb92b34a3c5bd2ef0802a4bc443a90e73fc4a0edc4781446d7b22a44cc5d8 -c http://localhost:8545 -fi zksync_withdraw_eip1271.txt -ms 0x7ff5c6fab254833c037ad23ca32e2b2b2c6083a4 -zka 0x7ff5c6fab254833c037ad23ca32e2b2b2c6083a4 -zkat contract zksync_withdraw 0xab6ff744cf1276a78460e93972d22725abd3e095 1990493664000000000 ETH :: time 1610970705 diff --git a/c/test/testdata/cmd/zksync_withdraw_pk.txt b/c/test/testdata/cmd/zksync_withdraw_pk.txt index b49736cb8..4270413c2 100644 --- a/c/test/testdata/cmd/zksync_withdraw_pk.txt +++ b/c/test/testdata/cmd/zksync_withdraw_pk.txt @@ -1,4 +1,4 @@ -:: cmd in3 -zks http://localhost:3030 -pk 0xc073624ce79d35f60581134500771cecf21c34e07f5f599033cabaceeb187fef -c http://localhost:8545 -fi zksync_withdraw_pk.txt zksync_withdraw 0xec8b8b4e05f647b36fa31d76273a7dc2860d0e73 90493664000000000 ETH +:: cmd in3 -x -zks http://localhost:3030 -pk 0xc073624ce79d35f60581134500771cecf21c34e07f5f599033cabaceeb187fef -c http://localhost:8545 -fi zksync_withdraw_pk.txt zksync_withdraw 0xec8b8b4e05f647b36fa31d76273a7dc2860d0e73 90493664000000000 ETH :: time 1610972724 diff --git a/c/test/testdata/requests/in3_nodeList_partial.json b/c/test/testdata/requests/in3_nodeList_partial.json index 31564c304..74b995e0b 100644 --- a/c/test/testdata/requests/in3_nodeList_partial.json +++ b/c/test/testdata/requests/in3_nodeList_partial.json @@ -9,11 +9,11 @@ "params": [ "0x2", "0xd355433cb98bdc18c5a1a28a04e218650e349d47bc0bc15cb51f71a53d12620e", - [ ] + [] ], "in3": { "signerNodes": [ - "0x1fe2e9bf29aa1938859af64c413361227d04059a" + "0x2e333ec090f1028df0a3c39a918063443be82b2b" ] } }, @@ -21,28 +21,28 @@ { "id": 1, "result": { - "totalServers": 24, + "totalServers": 25, "contract": "0xac1b824795e1eb1f6e609fe0da9b9af8beaab60f", - "lastBlockNumber": 9591025, + "lastBlockNumber": 11980954, "nodes": [ { - "url": "https://in3-v2.slock.it/mainnet/nd-3", - "address": "0x945f75c0408c0026a3cd204d36f5e47745182fd4", - "index": 2, - "deposit": "0x45871874b4b50000", - "props": "0x6000001dd", + "url": "https://in3-node-from.space", + "address": "0x792cc04f89b012ac1f98c19b7281fbda8a3e1a92", + "index": 7, + "deposit": "0x2386f26fc10000", + "props": "0xa000001d9", "timeout": 3456000, - "registerTime": 1576224604, - "weight": 2000 + "registerTime": 1579088618, + "weight": 1 }, { - "url": "http://eth-mainnet-01.incubed-node.de:8500", - "address": "0xe9a1f583c6591566b0cda30dd2a647126d1ce0c2", - "index": 5, - "deposit": "0x3782dace9d90000", - "props": "0x6000001dd", + "url": "https://incubed.online", + "address": "0x77a4a0e80d7786dec85e3087cc1c6ac3802af9cd", + "index": 9, + "deposit": "0x2386f26fc10000", + "props": "0xf000001d9", "timeout": 3456000, - "registerTime": 1578987329, + "registerTime": 1579247282, "weight": 2000 } ], @@ -50,79 +50,81 @@ }, "jsonrpc": "2.0", "in3": { - "execTime": 92, + "execTime": 99, "lastValidatorChange": 0, "proof": { "type": "accountProof", - "block": "0xf90215a0f6231cece95377c85968402a97c3660cd2437adae565c29f01ce823c548a596aa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d4934794ea674fdde714fd979de3edf0f56aa9716b898ec8a0ae71cd14a9513817ccbba4ef77588b9def8f354795ee61a0948804993d43d278a0674fe651f24d712f4e3ce46f27087635a81a936b90e78066fbeda89c8b76f2b6a02cdc8f441b15da7e0a83a8e4ad8dd45d42be6461a2d87dd1d5900c5f18ccc49fb9010000044888000020210008000020020414100002802a020000022a0340030000410443003202000e002000840000908900b811044000000410002030a080240330006800800408460804220c48204a00042a204940004c0005000001100a818010492010402b2441b5008100010040080040a0012a24041a0c4a140451c002022c524130d0000000004002801000480c000021000000d1040821441994021c2113e600185830a004047204008200a008002800009c200240100000090400a020012204288214004200080a04500104008400243000820880904100007004082080001419a08004100700001420a007080002003201030001280000c00400122c008707dfefae230528839258f183989677839879d8845e5cdb0094505059452d65746865726d696e652d6575312d31a0960ad883869b308fea67ec39dd9f448bb8cb910382188c24b507339d6bfda48f88f4b7840000e4ee7c", + "block": "0xf90210a0fae361e858f24035878b240925ccfc0bc56b10abe31b923c0809813dbd1f84e0a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347941b50e8779040b182cc2322079144d225b0361b75a02a3cb51bd601280d8f9d215ea297aa646a89bb5863c48fb610580271321a3b3ca0397e08b413b2cfc301d5e27e3316c4b9aa0ecbe96a645b3ec62e6ea06f21928aa0b073204dab3176f2858ba931816c857afa85f6e4a0664c2fb8f7b2a501c4777db90100997658004513a0b9ff8405e0c5497685415baa8030143e44ecadd108a0f155625814a71acc41302060409a2faa0c37d70b58c0102debed85c2558e6b26711039dd04208109022d60de1302e8acb4dd62f28e150744e6701c148e364992d51801194284c6bec50000f1244188292c39d15a9959ea9d68b6980623c1b89600c8020823acc8fa32d240b9c04960cd0508468a285481458014bc85a901e0609ce763039c081d41dd2143221fc39859942250c0700319208246323a9107e859dabbc71c910446458a1262780016f3e4926e5db5b0fe02e58042b6584f608e96f26e214b7c67099aad224ef164468202084fa63da820b1a884107418a487a5147091168713969aff7628d383b6d09a83be2a5e83bdff6c846042ab798f535a30322f48756f42692f000b9915a044df240839d91e247e136177255038586ef72c87f1391912c74e89300725f8f288b4716b075a52f452", "accounts": { "0xac1b824795e1eb1f6e609fe0da9b9af8beaab60f": { + "address": "0xac1b824795e1eb1f6e609fe0da9b9af8beaab60f", "accountProof": [ - "0xf90211a024583159940136761fdf101a830370eb8717a7fa8613c0c58a6b8f2452b181d0a07ba17cc99af9b83e8150a7e3d5b13ab904cfeff9bba482d4605b86d1f3be3ab3a0ba7776909926548d2b0603cb6a83d71d574efb0932ab3191838b118e404a71a1a001976d41aec1879e5c9b2918127fbcc85f810f7822bc609e0669c232b74e89c5a02db613c8dbf22b4977434065dc97ac6bafe850689674a9c83124f1a3e93243d1a07636c3fffd0d5b8a25cd1668d632fce992017ea4c823aa7befe5793e57ef8bcca0053f2e87496e030cbe309bfdb31056887c6042d6056defc693200bb758ff165da043cf1b80b62133c21ae0b44f612ab711957ab49a292a8794676740f1f8df1baca0113bac93d54b1158f5354a309659e7694efe414af1dd08932e3977655d00b8fda012b182bf9517ad41f95faea93836267ecc9caac8be34d3734ac57eedd3ebaeb7a0cea71e27f0ec24c433203239bafcd011a2b42f6a42e96c9b18246ca46e2457b5a07683ce81a71025949e77a0d5fb1470492af3be2564af04842e75ceac16c7d936a01aa89ab5cc7b3b8d243809452e273d251f94bb3aaf9dccbb7a7bb180fc66ecf6a0c27eeba276def79f62fc0603544b924a232f30551e148902554ea6bbae524a40a0742f609e8910d5c5aa09b81ebd704c3ebd62677ae5d51c2b04e9c62f9b86b28ca00daf54759d2eea008f9af623099cf3d8b3fa839e9af1b6cfd47a32ad91c1ecda80", - "0xf90211a00971e7167f621d028e1f97ddfd74404cc3362787e8939beb48830c44b4863ecaa0ab82512b7c373684340fd63efd0007abee47cce20df7d86f4aeeb881da324e93a0e5806da01379d23cf07686c02c6dfeb902944adb2d6c071f1e5ccf3d5432b847a03fe41ae0a918a32ee9106e3212ca76d388833ad76e64d6ca4e7a4da04490c91ea01576bfe55d8ac777c98a8705bf81a81adcffc7ec63e68c1bd031b7a775518cd7a0fb3becb4551539140482cdbae629b5141989c4b3d6d844e3896249b0681f58a7a0e10a137e3abf2e91443cdc62d2f89ccf7792a227b95be17a1e8a6f18f7b5fa80a01aea68d8c0de6ab9a3a24447114400a68f5c782cd3dfde661bd01970fb61c0d0a02f0245617e50cb9270eda2cbb53914c9894e232d88792a2cc8f5dbe61ee8f0bea0e8190880c6a683694019a8f805b8ed1e747ab10e10e6b4b9fb41a914333d473ba0ef639592a6552d32e030d4699b1c537316d6873ce8b3b4f2c479d5ffa580be25a07be019d168148456835ea3c471898e865a631e78997eabebc8b8ad999451e268a0ed4552bb48fa721b9c60e3254d35428c5e8f6d75c988c77df69e8aa0fe9b816aa00e2c83914bc654da013d025262301ec53d82e05b86566b3f14a6291d4213fbf8a0274153e4752a0721d5b63de41d74b50f3cee49c854a71e92f5af7b7d4d58c590a067f4dcf9b6d572cc203ed7e6d11897ff5e2f82963f0042519a9cb8b18001e11980", - "0xf90211a0b7894845fd50c14786a99e6efd1419ae8233a52ca40ce4a1efd1387b948f98a7a0f10828e7d0592e5b7f380767fc8fbd829ff68a829a9326f8f3e07b05aac6e358a0418163db70ba5ef09bf2bab4e534f55f9df69152d995d65e2bda299b4266f93da0bf003104cc2e71a71c8e83f56cf32c3845bc681fa8e9a3714116e6a9791e9330a00e9ae9ad41b6802f662624bb8ef9feee93e1cf501af922193f2a0aaf0b6fa6a3a08a34e7cb4efad2353ae65116ac318bcece1e71aa9de1606f23fe74e1e94c272ca07e9dc7dcfb139c1123e821ef01400a108a0f72830092a891702213a44cd451f6a0a60f9aef38604d768437a0a3619225008ac834a704ec1498d77527158cb5fe7da0b4f63a4f09066004323c2c99f63b2c524df5eaff17494e2a0d09a0c969e19af9a08e41936d4c73db7e51583c58ecd207ffcbaa6996b32ea71908c3c89a3a78ed27a010689a7c738d8448d4bba85caed1eee3d76f12b056c755d9d466ed7023b9ee66a0ffd4351e2fb03b9438aa40b45a46a8d37a705a3937a6c017dea43784cf3a9e06a067fccd5ffebfa7dd3f6d04445d092ea73b026c84aa532aa4c8004596444432d9a0ec548048e263086cd891606235f96a6cfb94cef5ae916809ebc33e1d6cebc95da02deada398fd3533d2f7e351b29198b000c1f99b2724aa1e20b253cd60d6cb776a0e2ac81d4f362bb69bf28f3466cac67b4a501819c8544837894ab509258b7ba6480", - "0xf90211a0aecbfde2fd93d54de9d9e22363e3778a747641af38e2a7ce04ee3b446eb50690a05782ebbc21dcf76fd1f1c35c5d82bc7b4bd25343097a31c3c7298394d25c83b0a0b5770af278ca9328d52eeee0e52d0b91f64f6b9cf2d186b7c67d07d71cbdb8a2a0791fc463a46e831460ddc777213daead09c3d5cf6f3861cd6173dd4aca1e150da0b95367476ffb38abaacfb01e10d09596424b63083d8620d010c7baabef5e3e6ca051c83eb0e2334958b7085f1e18cffcb37d95a4caa3a2677f77fe12ea9a9fb1dda07758af7921c950b475972b82353026408b1442d2b74c0c0b3d99e7ede5b306f2a0178db1449a90d2fa46e06507e57225a8f42f5ed57bf9416387b62e22447fff9ba00201459c7f74b0a69dc3954868706c9b94f51ebc5937bea00f50f5325cf19c58a0dd4dcf242b02bc46c9bb121f5139d421fe183afd2997723c0ee0df566c888dc2a04d012287da24cc8ab6b0614f2dd966405065bfb96294266e856de0e1a520ee23a06f9c030cb75b1a513bc28a348c2daa0f3d21b03a7b21e93ab56601c48d746a99a04c37000b2c16645b8b65a2811e13c30b6f1a70d1b708bb5f2b3fe9de626637b2a059eb78cae44436149d36dfc0be4ed5e73b2593f57148f58e5cad37e3da72d134a05a0f5319579784976a94c99d33a3be1e94adf08c23f84c8801b74312e3b934bfa0f49121527a4b200bf92c7ab413dd3941c6a2d528b8c7e1a0ed7179b20cbfc9c580", - "0xf90211a0849a8d374df06edf8b38ca90acf91b3c8780c0c0ac682bf1c38ae39b6ae3b10ba0e0305cac35c98f9cb58af4e64127328247617e0d7f3b8eef445ff6cbeb89a846a0ba1779542a01190ad446a7107078961708b2fdb6c7823aa598f46cba83143b32a05682f587daef701ae28b361aa663347df487076d31958f0b9e40eef6917c01a6a04c0d2ad4c899731377e35cf80431fc3eddf35e86ddb27906bc73a03b3680f1cea0aa9ab43823660142d4109b7acd1a9f4422c4d26d330d2c46831dfa546a083645a07ec1b026ce57226db459f594939faaa14a921e8fa33b1853e4295c74000481f9a0f97feabdf3596c9d0e235db09c464569ffd21d7025863701da1e6e72c52318c9a044205a58a2630a0a4f15b968a4b50d253f66b3843c2f48f67a04c7948932d1b1a0dd579ba870e8be680609fe8e2596c526c5d43c65ef50fa7987db8239a992a81ca0505eaa35fc46616608eaea2cc8e6d47a83c719bb5cf64c3b49154e9a904eb12ca0ad9435516b10e42a8921f6d937558b73a5d9ebedccd1be330fca6f293e466e4aa0b2ec359076e0c0868432fe6ac30f659d446883163e43f43a7bc8b1b1bdc62089a05e63a9bba822e4f73aa25270d8692299731191dea773dc5162397f76b976703aa046ef598497ff8f489f17d37f26c767fc39db4e878d23623661f7d720b5cbbbc7a0e408bb60fdd4d3330fd330cb7e69a4c03b3cf2882db3fc22399ba343dced9e0580", - "0xf90211a0beab0b1e832468563994acb78058d76b9b8d7f3ef71aaaf05959f38aae21edcaa0f1a510919c07d8539a9e7611453ac3f4b64e575355b8f0a1c58f3c54dc1531a8a05058a380b065612ea7cb9a7b45174068b6f71665fc21ebb73dafbd4570b6fa14a0161a8b092e0de3bde9575afc5165d50e6d79efe224c409b3814afee7368c6c28a0dccf7318665d89412fdffaa5a6741d11b9cb529afe504f770eb6c0c748a608d3a08b71dd67c9ff6ea323b5ec1302bd2d6437816d0a68bf4b29a48e162c8c61f7efa060636537ffefd8e54031e7ae9200135a5ed7eb0b9984db03e14a51cbad677d8fa03c139dbd4ecbdca97e442ae535d642d7dd3f6d12ff1878d84f5d8375d3a8e517a03412ecb9bc8acdb503195da735e1ab9918d67638ce321eed7568a33f934d3677a062c5adc422d6393b0e5d69b4c313ee3cc342173e89ee610f8341aaef66b226a7a09ba8172f914aea9d85e552cf9db59247e4a9caeb9056bd0e1e09052c07f9d154a0f2cabb17d69bfb117c719ac9c0d0d83015bb8e7ae30a468097ebf31cd09b6b43a08543c8513396f35bfa383806ced4d41dd189a0bceb7e28f8cd630fadef56cb68a0399cd0904ea2242055795b194f1bff9450adc03241c9d55d8b15c322b047efd0a076fb23883502dc6328a20a5343f8f3c1595e702e176988d99fbe7d820d198090a0daaf0b307f1086d29fff4d31e3866d2a3068f7ccf79acf5c36fe38c5976919ea80", - "0xf8d18080a01a27c49a5a77e292b591767f76ddf2bfbdf1752a5b53c7f07c519d0868760d2ea0ad6cb523f73649d74c1213abb948c10037a7a342ede5cd373b6060061d79faf7808080808080a0d8825f40f808fd1d368ffd5381e2926d2263bbbcee3fee5a1aa7401328da3402a02dca1cd7f04d0fd9625b649903883a2faa52ea6cfcbda738e61f6ea6322328cd80a099fec790aed90a5f7cba13d2cb2d22c79c6e737b5673133796cb831629ac3cbba0d327ffd4270f97c978c638645dc59c0a8ed42fc09bc538c9ad91eea990f543fd8080", - "0xf8669d3ad8a871b31cb3552080711d61fda45242133e0695c60218a95533aa2cb846f8440180a08af15fe9c3fb8fbeb9952e1f0a3ca415821af2225ba7ce0a31c2d2f85cf53a28a029140efcd5358d1dd75badfaa179e3df0dd53f17a883a30152d82903305697a1" + "0xf90211a03367f2b80dd230a014af0c4e25f8e0ec222fbddf73a0406e514361870443ad76a01128ebd58f80613887e3e6860ccc73b944eb8e57cfd4aa16694b5dad520f181ea006e9a76740e675ad60feca9adcf7383921befb7a8b7848f9b3a2a3572ec79823a0ce76f7d51430f6d48f2e28669e0505d35e928c9ed9923696aa4b7636bc42b35da03ba247e76690cdcfa7de19b4cf04dda97be0803e7bc1657a670d422424401b22a09bbb6e9f380bc6fb92ebd1acb7e3f9fcff3777c1c681dc8e9dfb13ee87c937b9a031da57ce0b5b82d526568c92ff16e601e04d29cbe4aceb2d20b2a6d0e27c7aeba012978910d8c74e4101f7c03dda6a19af4a95df6eb2e91c58b589993017da15e1a01922879a18e5a85525c48ee4edbebadbb5ead7f32e953f643f1c83bf66d9727fa0cbd0a2326b68f413183d0793be5c494b9bca32497629627862010cfc3d7c94d4a0e1ead34db658b1b4c93490f871e648bc36a31d2b91b735f906946c820207a13ea0b291ad584bd655bcbe413281d1d8c7c3ae465a7401dc06a4c6f20f5cff75033ca0ff029f6561b5a465fbdfccce7ad3f430834240941b985cd0d767944aa6dc7021a09f42fd0bc1caec947cac5ef3d6a670ff9ce5a70a1fade467150a842abc37916da0b7d5125ae3a18ff5ca4f06d023ca217978ac835e104d23ef01e26a4522841fc9a0367b00ac08cd0dff356394a1f402dbba2cdfff5c05dded5f096a6d00ed8b414780", + "0xf90211a0151f3edd0b4908f401993043b684ce057354d73740438bf86695bc7cead99607a0760bfb6a5c6afb74b5a721aa06bd8618338044b1217bb6736e5cfba3d17611d2a0c87dada391d571fd921e127f85f047561e78b3440670176cff1469b53edc12b2a0048bae74b09ca77e5ee401c4bc13adcc5014b61506940cb0c55660fad509951fa0faf970567ea1ce35b3dc3da89d1167e11035d7f7252cde7df89a7d294d33c528a06b88cb9d98711031316203717ad9eef377854509811d631e1e43c9666222c6c8a00a7fe62c637cc25f16236ce92b2f5ad8e85f34ee88e2abfbcc41693041ec1458a00036915b8c4b2dd0c99c80448f10994927e83d53cfb369990f60f9cee3d52203a0214c7f00d57d6b1a3370a1b8e00a4516a101066f8a192d8255398b2c8b39c9b4a0ce9a035eaa42d43c1ee0eab1c8933c5018b4f28aa1d0fbaeb3ee6684e3f30373a03fd6fe1c1f772759538412641cabe620401d91af234ecf317dc580e1bdcb6895a0d555a3e94fbae30893b318502473463054fe4006ec38a14c5ed98995794263c4a010397164528bd24379e0d72ef1850ef74455dac7225d5edc31ec705620e1abafa0a7a98b09cd4e5e5d4fa46c31f022e6d79f6beb92ce8692d7378caca7d66cd1f9a0f782aa02483fb62c10c636c832a2785163214a8f285ad637795117b22c76e300a05bd3c2f9f80def01d6bf25962d436c0f74c687076b2966594c7ac61992e5038480", + "0xf90211a012fa7ba424f9caaba301d5a700c0d2a40d5f12c0cd42371ff7f2f8830c673e77a0657aefb5f1f5e0d33333f2681dd108b288d2f8fd0447913c14453402ae6c2ad3a01b9e6621ede0aad03e682f7972714f74af93c579bb02e32ae376edbe044d44f7a0902cf8361261b731ab4118108cc3b046a38036cb318b98eb1c8943dac8749ff4a06e07f41c63fe6e778702fd500be20078d4f65bc37fd75c31c0ffe9ee6b74b591a0e8840fb8f7de4d8479cfeb3710219b6905b5028e7712df262a342f90d5920bd7a0312ff0ab6e82e50ba3da1bbff376a8f57d5891ffd8dcad43a9cc25be3de1d075a02eb0b4cb9d74d0388baad4c3bbb997e325848c5e08ec21cd22310c04b7ba6067a0c9e3f9b0f2e5daec7281f9bed462bbf0280675bf55ef4a25d5f4ad295125bad0a01b16eb7cf79775df900dcb4dcddb743b5a00e15a8495856054c22eaf94544f46a0145dd08a5dad41885a1e8f980da45dcd0f217da96ac4ae31ce8cd8116ceeaa7ba05a02caa88bb9eaa716625a8aa60ef5030d351c780ca7400124b1da3282feafb9a0ebe2f9e486bb958c04b5467305542ce33e699f26366841d50274a03ecb005752a01272fbb6f0f3a04504cb85a71b047cf62d30092aa5439427fb155a6e3e25aaa3a03d02ab51ade40151f227b304edd21be08b9e4a00c50ffc11b1e1dcc48ef56231a01a1926ca65ec74f6d3336cbb35eb38119baa111bbb5bd98dbf5e108828cc7dfe80", + "0xf90211a04621e0861cbd359cc0cab3dc71ef313df89b5f3f95b17fcccbe888be9d37ba6aa0288353ef505f7540b39c1595f43e41331076dd5a394b413e915fd38af0a2cfffa06ef04e5891c5af052d9e4845d31ed102e7e8cbce64a178e760390ea0abffff55a0cb64c669e87ded02683eb925ddb0bbfde900fbbc2c7d08c27e654d0669afdbbfa032129c0a5e52a6cb2e5f4144a58fac74a8a65fb754f13f8aac0334cc94500502a09b4fe797a214534f827b3dbc70f05bdf18f6b00177f3f12a79bb9cb09ab72e4ca08450cbab7a7a5b8773666aabf9f3341090d5a5a1014e3be39f7ea2eed4e2765aa0ec584aa97e73a6dad786c62baeaff2dc15dd6a249897b9f9ecd4a20246a8b470a0439ff74d34ce0a5fd981a93c01dd75a6e62790bde6808103c2ae5dc99758b79da03d51d7cc23864a2099048f6bf84eb5ed83c421999a938c35dc36b3d7dd029d45a0567e1d7ad83c2c40b5f6d89379d249f2bdc61be0efda28db08f6373891183fc8a043d8bb581cbd1ce589f1de57167db463843e131737e668559fe1427e1d331953a08d3831ba79b9e66a7fa5ab676b530eeff035effd297b867ec74315a3043376bba098cea86f644e4cc2424eaf30993ce3c34ba96cee256bc247c29765280d1fbbf9a07abc088fbd93bd7c0f44936a695259b8a3c5f1390f395c60785dfe2e814bc355a05df8837c2410a2712e982140f6ac0c107ce212dd4af2f08c2bdb1b61e15c793780", + "0xf90211a01cf88a16e4515848d13027dd38791076299bb27a1c30c96bdd8a9b5958f215e7a0104dcf4c957cb44f28b47fe4cf9fe269d7b096329db2928caec538778d77ff1fa06cb0893ab32f9b08e181cb97e80dd82b1595294c4e6b2fa4ec983d6747c9739da0c41fbfaa6b52390345c17403de84779c0ed717758d7961677aed0f93dc549feca0c0205bc683a9336e30a17a736ca222a3073a3bf67111d428970150d2e83d64d9a0c6378bef184cf3a3a7fcd71a1b1a8ec5e3da827c7ef65cd81cf1e3ba710f5963a093578bf4d211c8d0f366839acd8afc226b64a5719f92f08a0cf4b92074b7db7ea0725afa4d8fd1b47092a9decd5b31f4e36b981d5e4a48a7698bb78e8164d825eea0d4662e867406e627911edc7eb27700acd26443eda011d5d144f5cd15cb20e0baa087e502c380415d80ad15a514fe4c5d73fdbf5a748cf05d117c9c2bbbfe41f214a09d525463f0b852fba44be3012accdb26577b91551426f9e498b28b50aa427996a02c523f40893a4b37c6d20c2b6226fac86073659489f29b6e5dd86b12411d6598a0a404a13f10677197ced01a53e44bd75fec0865446c1467b00b80f3c4d8722973a0b59c0dedb4f40f55ca7f3ef6f2428bb7e2e7eeeb95b40d7d0c5c6575b57c455aa04580d210817f3a62898df05b31ca0668c93d6a666082a85c1949d088de9bdd6ca0beeab37a779cfff14373a83764cd6e262aae4a7416bd9115b08cfd54c3ba74c680", + "0xf90211a0f9c66e24bb2bbde07d6b75f5200a37640f265a6c3be3a81901025c15832d996fa05545c74b0e07b50c7f95e4460b80641a50aec7555f7e1d6e0a141331a78a8452a041e7d801236654e46a202acff8c407847e42f1b11aa975f35883b52b53181f23a0dc14112f696b1096cf0b0cbf1df04e978ccf542abe3d264727b5827bcc4ae238a0fbb7950ebedb94ff21526de50b63a4584718c0de7b50c64412bb8dba83428cbda036240075ae536773e26e3261882dbb93681d45180bc3c85a9edb0b220c738441a0a405ee90216163b18bbf497d92f6345031d1f8eba781f421bce49bcbfbc7bf35a0d6e70be759dae3b1676c1f0a601c2a26d0dfed1dc0e2ff63ab07798eb8c47323a094b7072e1b7c5d1aa86bbeb181559ccf568343abfab72cfc52e0827992df3499a06f3b3f317c6581b0b35a29a6745cbf5e0f8092e08f870cad0df120adde62706fa04f4e01fe0fafd4d6a847444b5d93640de161b5d315dbd5be650e52e2dfe8dfe4a00e8803305ad73f37c01c53849a453e17385908182b3ddeb1b3d94bdc1cd72ae8a08b65015c9c0f26122d2e5604e5184531d4b95ec66b39120d46710f9e4dff1d5ca02849dfbc7c21dbee02d4f142bf27b036bf6447279128051c7516db2452146bf7a0a3c1d24ca8b0fc5b5cbe9c409d23ed1eff0ea0bcfd1fddc6276cdac8a047d81ca0331b78398972f837a06ba19096cd1c139140ecc807ccce25c368f6cc1e11875180", + "0xf8f18080a01a27c49a5a77e292b591767f76ddf2bfbdf1752a5b53c7f07c519d0868760d2ea0cbab1565fdf1098bc2ccc55688eeda4dfb11d4ebe9cc31329ed376e27b0061448080808080a0aad04ee32acd485a0137d6ea4b198f735cabc4645d6ffd34d7925011374430b7a0d8825f40f808fd1d368ffd5381e2926d2263bbbcee3fee5a1aa7401328da3402a0496ab143dbfe1b5c4a707f686e7cfa79828214fc0e64b7436ed5731223880cb080a0a5602b305d4ce5a7e60db35e14ff89b2dff2b19d96a902b0faa189d2a44b7113a0da089350002ec5c6193e79ceb6b6db7474f573406a8d96fcdfe84cafe05823be8080", + "0xf8669d3ad8a871b31cb3552080711d61fda45242133e0695c60218a95533aa2cb846f8440180a04d6c5972bcc0c8229c8b041df4aa70879e37e9f7eb47530e4232b317438524eda029140efcd5358d1dd75badfaa179e3df0dd53f17a883a30152d82903305697a1" ], - "address": "0xac1b824795e1eb1f6e609fe0da9b9af8beaab60f", "balance": "0x0", "codeHash": "0x29140efcd5358d1dd75badfaa179e3df0dd53f17a883a30152d82903305697a1", "nonce": "0x1", - "storageHash": "0x8af15fe9c3fb8fbeb9952e1f0a3ca415821af2225ba7ce0a31c2d2f85cf53a28", + "storageHash": "0x4d6c5972bcc0c8229c8b041df4aa70879e37e9f7eb47530e4232b317438524ed", "storageProof": [ { "key": "0x0", + "value": "0x19", "proof": [ - "0xf90211a0385ced5243cdf2896972bb9308e46e495cb2c03722aa10ab9391a01982a68969a061a54bf87d397f38ac356fd3cb5f95e043726e6b899da8d4cf82051fac6d5bb5a060009bef28f7e27a059c616ffb65b40952d1ef3da33a703b881408165b0d9d6ea06f38996fb3c789470e6ff6b4ba6a575d20e2fb7f604de607a4d5f9e416e95958a0884356315041d41798f53558a3d2b292b05e2a477632a1488337ab9f85a9781fa092cc1cc9804c55a1c254de5e327ecf3443db9ded678fab119e879748913c6ccda01cb4108edb3b23a09b5d9c61cd7740a915429b38ec76f398f562396625d4b045a088b23a9a79e1d944430302fb910575a76309d52e99eb5f78716e4d9cc91c4b98a0292456129fb7878da212fb91cee5248fdd8d54a747f3e7dba644351d5a541650a09a5bc559d679edda76ee1041a535354b507cdc763bb9c3f0d4ee2faf379790bfa0b03a80929005d5d7f1e5f93cb15e853d35582a6d0eb0c35030f7eb95000c4e1fa0580bcab639a165c7d8e463fe59d001e1595de288b18f822f8079635f39bae05aa007bd7fb0f32e306bfe70b62b27820d7e8c41836b689776d9fa958fec3c0b3b2fa06ff4ed4fb54b258464e426a03131f8f65c2a5d2368c61317ba9ca2ff2b35ea89a0aec7de8f376d67aca9c7a478b6f19eefaeea4075c5ebd6859b53cccb98c7ac08a063054e722a9091aa337f7ff8d717a60af0198e5a2103b31488fb498c83eab22a80", - "0xf90191a0625f8d33fc0be884a044b72b5d1e5540c8438ba229cfd1b3cb580012dcbfbf96a04cc155a7733da13a4178ac150af3aae5a546d5e852b88c7b2348995d26614cfd80a05873c62aaf91429469acbd060af360a0f8858aede4e7554e3289f171f2a79e158080a0905337c7334612fdb0e2bd6f5bbbe7844a5b2e68121bad742e449cc0b26c8bd2a0f229214dba34c16ca65b1e0df175282a07b3ea9453d97f5b9e9e78762fe279fda06ce2fb704d930c53524fbf883e483d598b6869cd479598391d8d9974b5bcdf97a0dfa06820b792d37d80969f0f46bf43fb698d499a92c3bb90f7df86da00456ab2a026056fdebd58e774617d2b76dfb0bd14f7863bf6abcf25ba1c76e8527d4d79c3a088606f96a26074bc1ddd07d867f6611662a0a90809339d57d25635382ac9dfeda01a803446fd04d71dca9cccbce730f278d71629c08a92b173b3f67806eed94121a0bed418af7fb2c79b05d23d46e280a7e6da507bc02babb0437bc8a8bedd76d32580a02ed77de2ba88f0af119aac155e22c23dd35fd1e6d35afb3a90ff6e0788855d2780", - "0xf851a07857fa9fae1428bc873b55cd9278c7389972f3a3e4be1b7ec97126ded1666be9808080a0a02d6b52757f7816acf5f459d06658b3af5d944bcadceaf803769ed1ab55fe63808080808080808080808080", - "0xe19f3decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e56318" - ], - "value": "0x18" + "0xf90211a084b9482cc629c5c15315b54e0c0cb90fc95d8117f796e5ebca386107066b38d6a05cb2558a9912c6bb590825e9da5510ab838ef5812f76cf9218a273955d510cf0a0a3fe70dcdf9a109605d24665f7e14c3a0292832d77ff036ea61cea4df1776892a038b5edb2345d68bf33498f19b158f8b4e3e566163ecfdd33ffe111dfab68e1f8a01d205ff147cf2d2b60462b4dff349bc1be5a127cdb9b298e739bbb306bf6c05ca0163f60336744b6ac4ac157b9232c6e82c2e5dac0982ca0131913aa802103425da016e48baa9fb248fda998f6119e41d75d2ef0e48aaf019e17996fdbe6297ec743a066cfc3f8208ca850992ca5b966fbe2c0af4e294c7f65fe49b71a7d8b14856010a0d95612054d5d9d90874d9d6d390b97d75a92c6775fecc7064e2d4f30d2c2df18a0a9d6680a2a5113fd81065721fadcd0e8b067f0e527fa375dcde64eff5cf1ee1ca0eee388de7e3924ba91eb8c52b4283dd29efe6f954b490eb97c27b7aad64efa62a01dc077a55b9e7602c307b1a777b7f5d88b88b37c84601049a47ab2cb90230128a0c0f4a4cd9a9e8cf1d0fc9b36a852835bc6e870a7a9c4a67686af8f7903024f2ba09dc1f680c6b28667e3973ebee5f5b8463221d652e6449642e4d24629467e3988a0811704f9e8dc824705dd759c2c53b204563cc7bd5bc9dacba31d692fdac44e3fa0b7db1e8202f5304cdf4907645770e6d54309e86195bc836978071ad85a4f2f1680", + "0xf901b1a0625f8d33fc0be884a044b72b5d1e5540c8438ba229cfd1b3cb580012dcbfbf96a04cc155a7733da13a4178ac150af3aae5a546d5e852b88c7b2348995d26614cfda08f022d7db632666ff9d9fb60bfefa427aa8a23870a0bfc796de958d62604a1b3a05873c62aaf91429469acbd060af360a0f8858aede4e7554e3289f171f2a79e158080a09638013e8296d7275f9d4aeac5e1d3ddda8fe102281e29a70003fdf4fdd0bdd1a0f229214dba34c16ca65b1e0df175282a07b3ea9453d97f5b9e9e78762fe279fda0ea64a0171e2dc732422b4ace80942f39ef1060bd0b1285022340e7caf24686f0a07eb06d79ae367589806c6e6f2bfcedd1bcca1018e823c0c57b47abf984813f1aa06e5c5748bd4f9a08127d2e6b02a67941a3bc444c6f9a54e3e7d46da2e27d8a43a088606f96a26074bc1ddd07d867f6611662a0a90809339d57d25635382ac9dfeda079f01f013985b0f342a8c89addcc24b5f1c2dde7abe131a892b82aaabbffad84a0bed418af7fb2c79b05d23d46e280a7e6da507bc02babb0437bc8a8bedd76d32580a02ed77de2ba88f0af119aac155e22c23dd35fd1e6d35afb3a90ff6e0788855d2780", + "0xf851a08a14eff77681ba39cb65a45ad9339bdc867e7df44a9ae385f9bdf4cce68acd6f808080a0a02d6b52757f7816acf5f459d06658b3af5d944bcadceaf803769ed1ab55fe63808080808080808080808080", + "0xe19f3decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e56319" + ] }, { "key": "0x1", + "value": "0x23d5345c5c13180a8080bd5ddbe7cde64683755dcce6e734d95b7b573845facb", "proof": [ - "0xf90211a0385ced5243cdf2896972bb9308e46e495cb2c03722aa10ab9391a01982a68969a061a54bf87d397f38ac356fd3cb5f95e043726e6b899da8d4cf82051fac6d5bb5a060009bef28f7e27a059c616ffb65b40952d1ef3da33a703b881408165b0d9d6ea06f38996fb3c789470e6ff6b4ba6a575d20e2fb7f604de607a4d5f9e416e95958a0884356315041d41798f53558a3d2b292b05e2a477632a1488337ab9f85a9781fa092cc1cc9804c55a1c254de5e327ecf3443db9ded678fab119e879748913c6ccda01cb4108edb3b23a09b5d9c61cd7740a915429b38ec76f398f562396625d4b045a088b23a9a79e1d944430302fb910575a76309d52e99eb5f78716e4d9cc91c4b98a0292456129fb7878da212fb91cee5248fdd8d54a747f3e7dba644351d5a541650a09a5bc559d679edda76ee1041a535354b507cdc763bb9c3f0d4ee2faf379790bfa0b03a80929005d5d7f1e5f93cb15e853d35582a6d0eb0c35030f7eb95000c4e1fa0580bcab639a165c7d8e463fe59d001e1595de288b18f822f8079635f39bae05aa007bd7fb0f32e306bfe70b62b27820d7e8c41836b689776d9fa958fec3c0b3b2fa06ff4ed4fb54b258464e426a03131f8f65c2a5d2368c61317ba9ca2ff2b35ea89a0aec7de8f376d67aca9c7a478b6f19eefaeea4075c5ebd6859b53cccb98c7ac08a063054e722a9091aa337f7ff8d717a60af0198e5a2103b31488fb498c83eab22a80", - "0xf90151a0e96607228720bed234b27bb0c37e50e491a8938bb805526555881c355488fff8a0cf1bb0975c1421732acd6e4355d4be5a5cabef4b1abd7ad1567c30acd41ab25ba0c8ddf6cc85a6db42ef4c698c4fafeba56c74bc420e7faebffc427f8629af5bbe80a0e48ac1fb66db5420c7589d28982875f6b00a01bf2550410419f57b1d5b2b8f5a80a093cfad45cd604cf4106e82ba40a6b52b55d97e5adcd18cce5cb2b2ce0e96edc8a00b70e702a028a1c36668a44a5737e4233057f7ad89cf96b20aad4dfb02c47db280a0be908080ee7e1bf33568ad4544dbacb39ca16330d86404c93ff9a2325842b633a0ba4f73ad2d3895debec7bffa1d095b66b3f86037d903e77fd3d6d09c601a73ffa0bd4e347cf4e458ce6fcfda1400aad6be52bf24776122cec6b81565875f7efa318080a089e93950ee646c6303858c03da4f679895f38946ddfecd12750b072b785d5b6c8080", + "0xf90211a084b9482cc629c5c15315b54e0c0cb90fc95d8117f796e5ebca386107066b38d6a05cb2558a9912c6bb590825e9da5510ab838ef5812f76cf9218a273955d510cf0a0a3fe70dcdf9a109605d24665f7e14c3a0292832d77ff036ea61cea4df1776892a038b5edb2345d68bf33498f19b158f8b4e3e566163ecfdd33ffe111dfab68e1f8a01d205ff147cf2d2b60462b4dff349bc1be5a127cdb9b298e739bbb306bf6c05ca0163f60336744b6ac4ac157b9232c6e82c2e5dac0982ca0131913aa802103425da016e48baa9fb248fda998f6119e41d75d2ef0e48aaf019e17996fdbe6297ec743a066cfc3f8208ca850992ca5b966fbe2c0af4e294c7f65fe49b71a7d8b14856010a0d95612054d5d9d90874d9d6d390b97d75a92c6775fecc7064e2d4f30d2c2df18a0a9d6680a2a5113fd81065721fadcd0e8b067f0e527fa375dcde64eff5cf1ee1ca0eee388de7e3924ba91eb8c52b4283dd29efe6f954b490eb97c27b7aad64efa62a01dc077a55b9e7602c307b1a777b7f5d88b88b37c84601049a47ab2cb90230128a0c0f4a4cd9a9e8cf1d0fc9b36a852835bc6e870a7a9c4a67686af8f7903024f2ba09dc1f680c6b28667e3973ebee5f5b8463221d652e6449642e4d24629467e3988a0811704f9e8dc824705dd759c2c53b204563cc7bd5bc9dacba31d692fdac44e3fa0b7db1e8202f5304cdf4907645770e6d54309e86195bc836978071ad85a4f2f1680", + "0xf90151a0e96607228720bed234b27bb0c37e50e491a8938bb805526555881c355488fff8a0cf1bb0975c1421732acd6e4355d4be5a5cabef4b1abd7ad1567c30acd41ab25ba0e8b1e354cec00ebc550914459c251516dc0a82073d79200897f8c2941359f97480a0e48ac1fb66db5420c7589d28982875f6b00a01bf2550410419f57b1d5b2b8f5a80a093cfad45cd604cf4106e82ba40a6b52b55d97e5adcd18cce5cb2b2ce0e96edc8a00b70e702a028a1c36668a44a5737e4233057f7ad89cf96b20aad4dfb02c47db28080a0ba4f73ad2d3895debec7bffa1d095b66b3f86037d903e77fd3d6d09c601a73ffa0bd4e347cf4e458ce6fcfda1400aad6be52bf24776122cec6b81565875f7efa3180a0db3c950ea0de552af7bc1bb046a59d914c17c775557062609bf84e8f15b7f6ffa089e93950ee646c6303858c03da4f679895f38946ddfecd12750b072b785d5b6c8080", "0xf843a0200e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6a1a023d5345c5c13180a8080bd5ddbe7cde64683755dcce6e734d95b7b573845facb" - ], - "value": "0x23d5345c5c13180a8080bd5ddbe7cde64683755dcce6e734d95b7b573845facb" + ] }, { - "key": "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e571", + "key": "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e58a", + "value": "0x28240fd8b95647d56a04b62c86bc4e5a78203ff5c3393fe86482de080d0e90a6", "proof": [ - "0xf90211a0385ced5243cdf2896972bb9308e46e495cb2c03722aa10ab9391a01982a68969a061a54bf87d397f38ac356fd3cb5f95e043726e6b899da8d4cf82051fac6d5bb5a060009bef28f7e27a059c616ffb65b40952d1ef3da33a703b881408165b0d9d6ea06f38996fb3c789470e6ff6b4ba6a575d20e2fb7f604de607a4d5f9e416e95958a0884356315041d41798f53558a3d2b292b05e2a477632a1488337ab9f85a9781fa092cc1cc9804c55a1c254de5e327ecf3443db9ded678fab119e879748913c6ccda01cb4108edb3b23a09b5d9c61cd7740a915429b38ec76f398f562396625d4b045a088b23a9a79e1d944430302fb910575a76309d52e99eb5f78716e4d9cc91c4b98a0292456129fb7878da212fb91cee5248fdd8d54a747f3e7dba644351d5a541650a09a5bc559d679edda76ee1041a535354b507cdc763bb9c3f0d4ee2faf379790bfa0b03a80929005d5d7f1e5f93cb15e853d35582a6d0eb0c35030f7eb95000c4e1fa0580bcab639a165c7d8e463fe59d001e1595de288b18f822f8079635f39bae05aa007bd7fb0f32e306bfe70b62b27820d7e8c41836b689776d9fa958fec3c0b3b2fa06ff4ed4fb54b258464e426a03131f8f65c2a5d2368c61317ba9ca2ff2b35ea89a0aec7de8f376d67aca9c7a478b6f19eefaeea4075c5ebd6859b53cccb98c7ac08a063054e722a9091aa337f7ff8d717a60af0198e5a2103b31488fb498c83eab22a80", - "0xf90151a007c522ccc7cec8771c7e60104825e57a88fca9ef833a368cdfa592ddd17db1978080a0a3431507a80e92ed617c99a803bb36ab27f6d1085ad26fa4672ce91b5c81947ba00bb934ce449a830b198be4cc1fbb3efb43aaa12dfd15df18581e07a33fd2592da0dfec69d15bd73b0b06344b84e6e9cba847c7e2b1c2f19ea42f96563668661ca98080a0c046a31a3a76fb07795fec6bce8ee2d58d6da9e053eb196e6d99f0871dbb32c180a0d64c5137b3bf612119e481de1f286855ab03b5a89205e847295cbf7ece0943bfa0880ad135a503864e143431baf513e4da174b3827a1eea4ace002be0d4c15715aa01064dbbc60b97bb3006c07aa9e92982aac85f33b477863f2bffe3ec701fb981ea0e5e159a9aaa234f1b61d05b54844f17d3f28de3e8cbbf4f78bbe80ee5828c9e3a08ed0b40704167fb82194ea0cf45739a72b0f84f0f3e6c7be89ed220eafffd6ac8080", - "0xf851808080808080a04dd88bb04fac169bbf3c4a222c80b687a630117edaf83e52e13ca6cbbcefe1b980808080a0433788bc4a7a09b0d2faeb9c2d44f28b8124825722a7f23444f114f30ee369938080808080", - "0xf8429f3695c256a4a4a1b8ed004dc824e330f1747032632c0e6d88c1d84c330c1c5ca1a039b1cdf063f1c717d4a5450f1dbbc5683dc242cc8600ad7ec5ba0f7ddff664bd" - ], - "value": "0x39b1cdf063f1c717d4a5450f1dbbc5683dc242cc8600ad7ec5ba0f7ddff664bd" + "0xf90211a084b9482cc629c5c15315b54e0c0cb90fc95d8117f796e5ebca386107066b38d6a05cb2558a9912c6bb590825e9da5510ab838ef5812f76cf9218a273955d510cf0a0a3fe70dcdf9a109605d24665f7e14c3a0292832d77ff036ea61cea4df1776892a038b5edb2345d68bf33498f19b158f8b4e3e566163ecfdd33ffe111dfab68e1f8a01d205ff147cf2d2b60462b4dff349bc1be5a127cdb9b298e739bbb306bf6c05ca0163f60336744b6ac4ac157b9232c6e82c2e5dac0982ca0131913aa802103425da016e48baa9fb248fda998f6119e41d75d2ef0e48aaf019e17996fdbe6297ec743a066cfc3f8208ca850992ca5b966fbe2c0af4e294c7f65fe49b71a7d8b14856010a0d95612054d5d9d90874d9d6d390b97d75a92c6775fecc7064e2d4f30d2c2df18a0a9d6680a2a5113fd81065721fadcd0e8b067f0e527fa375dcde64eff5cf1ee1ca0eee388de7e3924ba91eb8c52b4283dd29efe6f954b490eb97c27b7aad64efa62a01dc077a55b9e7602c307b1a777b7f5d88b88b37c84601049a47ab2cb90230128a0c0f4a4cd9a9e8cf1d0fc9b36a852835bc6e870a7a9c4a67686af8f7903024f2ba09dc1f680c6b28667e3973ebee5f5b8463221d652e6449642e4d24629467e3988a0811704f9e8dc824705dd759c2c53b204563cc7bd5bc9dacba31d692fdac44e3fa0b7db1e8202f5304cdf4907645770e6d54309e86195bc836978071ad85a4f2f1680", + "0xf90151a0c10be40210eaeafb7affb37be1cf73a8d79ab6fa11811f92ef9b383b5c28ec3c80a0268940e99b915692f0d70fc16d7913eb67200da8170a5246eccc8e99413e35f080a0dc430d4af5cd2ee1b45c3ccbd3dd056d439593455787b501d60329693c1960e2a017e5b7ec0b1e27255728acb3ba13a3a7d97db3543a86e26f020e7314fce5af3ea0edf9ef32d52c49dcabca1e53c61adb441ee2e51c9d56c32ad54e77c5b1ea4d0580a02798c2f932bdccab80dcb582b53e5790453c8a2da25b14bf87b4d2826caf8fc480a0ce1e04072f90d7a1e3da7fa8f38a01770f4f3f42283c600ae9b823b8e5353a31a07bd910420f36d6c755cd335380197d7b8f6bc6680901cbd967fd7700a1425eb7a0424a41de56b820d7c5bd231be063b86a6f94a67a7aec4b592b37abe768886ca280a0d370dc8aa939bf4b8b29d1cee7ba493bc77f9b1e876133880c080bb0c8353aa08080", + "0xf8b180a018235be78684e641db774248330c6d069c014248394e2e05d8ef170a3430bf9aa0d015c8e57b24dbee103560df45cfd8362e487b63c8dd8bb0d9067b17b2a322a7a0f0cbfe7fa273cfbbcfa9c3439d44db08d99b6f8c511c84a9e0bde7a10c2f34248080a008a98a5e6c395d0392a114ce84d56d94fa31649c4b81ae9d544db634674fbfd980808080a099b1d48d6d8d9ccb1a75e184ea5e013e7cf5c7c5ff1edd72a0a343bb44c231db8080808080", + "0xe216a0047ac7de0d120fd6480927bfd9740c37ed9e6b562a9190b9e6f6f3a6dd120c34", + "0xf851808080808080808080a0fe9a758713c23aa4184f64c749e72340046c9bbeda80b5232df250e76f1d35c68080808080a0d1d8219af8b8ac923c57c310ff1d1c21b53e47b06592d6d529261f0abe70819a80", + "0xf8419e3ad336e69b72e50a4cec1eff1aac27f3fe4a9e50ec468c2897f8dff1de35a1a028240fd8b95647d56a04b62c86bc4e5a78203ff5c3393fe86482de080d0e90a6" + ] }, { - "key": "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e580", + "key": "0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e594", + "value": "0x32800a926a5b9a99a6d483c673abde97967bc214e83b82f1fb9cb4068c72474f", "proof": [ - "0xf90211a0385ced5243cdf2896972bb9308e46e495cb2c03722aa10ab9391a01982a68969a061a54bf87d397f38ac356fd3cb5f95e043726e6b899da8d4cf82051fac6d5bb5a060009bef28f7e27a059c616ffb65b40952d1ef3da33a703b881408165b0d9d6ea06f38996fb3c789470e6ff6b4ba6a575d20e2fb7f604de607a4d5f9e416e95958a0884356315041d41798f53558a3d2b292b05e2a477632a1488337ab9f85a9781fa092cc1cc9804c55a1c254de5e327ecf3443db9ded678fab119e879748913c6ccda01cb4108edb3b23a09b5d9c61cd7740a915429b38ec76f398f562396625d4b045a088b23a9a79e1d944430302fb910575a76309d52e99eb5f78716e4d9cc91c4b98a0292456129fb7878da212fb91cee5248fdd8d54a747f3e7dba644351d5a541650a09a5bc559d679edda76ee1041a535354b507cdc763bb9c3f0d4ee2faf379790bfa0b03a80929005d5d7f1e5f93cb15e853d35582a6d0eb0c35030f7eb95000c4e1fa0580bcab639a165c7d8e463fe59d001e1595de288b18f822f8079635f39bae05aa007bd7fb0f32e306bfe70b62b27820d7e8c41836b689776d9fa958fec3c0b3b2fa06ff4ed4fb54b258464e426a03131f8f65c2a5d2368c61317ba9ca2ff2b35ea89a0aec7de8f376d67aca9c7a478b6f19eefaeea4075c5ebd6859b53cccb98c7ac08a063054e722a9091aa337f7ff8d717a60af0198e5a2103b31488fb498c83eab22a80", - "0xf90191a0625f8d33fc0be884a044b72b5d1e5540c8438ba229cfd1b3cb580012dcbfbf96a04cc155a7733da13a4178ac150af3aae5a546d5e852b88c7b2348995d26614cfd80a05873c62aaf91429469acbd060af360a0f8858aede4e7554e3289f171f2a79e158080a0905337c7334612fdb0e2bd6f5bbbe7844a5b2e68121bad742e449cc0b26c8bd2a0f229214dba34c16ca65b1e0df175282a07b3ea9453d97f5b9e9e78762fe279fda06ce2fb704d930c53524fbf883e483d598b6869cd479598391d8d9974b5bcdf97a0dfa06820b792d37d80969f0f46bf43fb698d499a92c3bb90f7df86da00456ab2a026056fdebd58e774617d2b76dfb0bd14f7863bf6abcf25ba1c76e8527d4d79c3a088606f96a26074bc1ddd07d867f6611662a0a90809339d57d25635382ac9dfeda01a803446fd04d71dca9cccbce730f278d71629c08a92b173b3f67806eed94121a0bed418af7fb2c79b05d23d46e280a7e6da507bc02babb0437bc8a8bedd76d32580a02ed77de2ba88f0af119aac155e22c23dd35fd1e6d35afb3a90ff6e0788855d2780", - "0xf8518080a0cddb6195608409ce1e3af7bcafb1438332c340b7ca526661a0cff52f7acab826808080808080a09a1a77e2ad05e8178da178bf660822cefdb0572bf5dd9dfda7caa1266003d84a80808080808080", - "0xf8429f3f0f7a7af9ed4f160d1c425f37d148d10bddb9c828e99d4145b150485711cea1a0a78b8e772e2235c3777d75526957ecb08bb0681b47f5ac2582bf0add4c004185" - ], - "value": "0xa78b8e772e2235c3777d75526957ecb08bb0681b47f5ac2582bf0add4c004185" + "0xf90211a084b9482cc629c5c15315b54e0c0cb90fc95d8117f796e5ebca386107066b38d6a05cb2558a9912c6bb590825e9da5510ab838ef5812f76cf9218a273955d510cf0a0a3fe70dcdf9a109605d24665f7e14c3a0292832d77ff036ea61cea4df1776892a038b5edb2345d68bf33498f19b158f8b4e3e566163ecfdd33ffe111dfab68e1f8a01d205ff147cf2d2b60462b4dff349bc1be5a127cdb9b298e739bbb306bf6c05ca0163f60336744b6ac4ac157b9232c6e82c2e5dac0982ca0131913aa802103425da016e48baa9fb248fda998f6119e41d75d2ef0e48aaf019e17996fdbe6297ec743a066cfc3f8208ca850992ca5b966fbe2c0af4e294c7f65fe49b71a7d8b14856010a0d95612054d5d9d90874d9d6d390b97d75a92c6775fecc7064e2d4f30d2c2df18a0a9d6680a2a5113fd81065721fadcd0e8b067f0e527fa375dcde64eff5cf1ee1ca0eee388de7e3924ba91eb8c52b4283dd29efe6f954b490eb97c27b7aad64efa62a01dc077a55b9e7602c307b1a777b7f5d88b88b37c84601049a47ab2cb90230128a0c0f4a4cd9a9e8cf1d0fc9b36a852835bc6e870a7a9c4a67686af8f7903024f2ba09dc1f680c6b28667e3973ebee5f5b8463221d652e6449642e4d24629467e3988a0811704f9e8dc824705dd759c2c53b204563cc7bd5bc9dacba31d692fdac44e3fa0b7db1e8202f5304cdf4907645770e6d54309e86195bc836978071ad85a4f2f1680", + "0xf9017180a0c5c4d600e8237c5f052e7a4fc9aec09c22884401dec59443694deb4b9418324780a02a6f27850ba820ca67089d13837414acd6bbc1acc82e094f45fa1c2c00406eeda0b690356c47be2fa80c4de9e607ddd934440540a4210015873189a42cc00cabad80a0e2a57e168b71096b928357bb9350ebc53dc31ecea2cbe5f6eeda70ee63e7feeea0bb0c8623a00fbe57b61cbf26a353088a0d5c78bca40e81697579b59416e5cac1a023cf38f358412e2975c90da2a25647a4739ea853ce1c178e05b9e8d5bc07d51ea05100b51ce8cf50451300450adcdbb8eebe935afa2b283e69a4a48ac80ef45c7ba0e3b3cd35c91710546ba23f317d666e416ce399489c752a0e59f58b7a9d23a41180a0a7df0f5c2008e7b9cd9daac967ee2823014f018659a4e0162e2a6616752fd4eca09e4ae5889ccad33ec1ce0fd116c0b05b30cd4e5584f0ea00c69f3ca10a9b967d80a0045a12dd55288ab5b29b9fdaff9f9442eb5a09b0a1dcd715901c651b60e2329d80", + "0xf85180808080808080a004420e11ae357a6902c99daad0cb70dde57bd374f6d2d4804d3e2dd70180a63b80808080808080a0b2b3100e55edcdd3c5a8998b2a73751b4353fb1ab58bd79d8e96550aaa8f552980", + "0xf8429f396013ec5db4774639d8122f0250855863bdf6ebef9b8684e35a974ac0d691a1a032800a926a5b9a99a6d483c673abde97967bc214e83b82f1fb9cb4068c72474f" + ] } ] } }, "signatures": [ { - "blockHash": "0xc397545c6d161d2ec2d30d4a94376930de0b12de224056f51df5cab6c048af59", - "block": 9591025, - "r": "0xdcbad7d30a54cb7ebd9aa4c20a0615495588ad13535f3bdd57599bd8fc6dc41d", - "s": "0x3579f6eb0a600ee33614dbcf85d9fdaf0703761c6af48b35f3eda5c7379c1997", + "blockHash": "0x9d6e0ee46007d90fd1fdbbaa0c14e8193c67c8ebb82c85a62e2a5e45842d921e", + "block": 11980954, + "r": "0x31b76aff7e35bd40287f0158bdf1f7177d18d7c32291a6ad46ffc4cff1d770ee", + "s": "0x286470bbcfbf2e9bbab1ac8117ba8d1ccee276e7d47ee1c639a894ad23e4e2cb", "v": 27, - "msgHash": "0xdbaaa3d1df151b9d8079416e41ba3d5e30ce575e1cbee0a1b9fc0671ff185de1" + "msgHash": "0xb36ed3002ec9811bd623115e1fcd3f9d7f8533dc7d870319c0639108836aac8e" } ] } diff --git a/c/test/unit_tests/test_abi.c b/c/test/unit_tests/test_abi.c index 3ef9e73c7..afccc38b6 100644 --- a/c/test/unit_tests/test_abi.c +++ b/c/test/unit_tests/test_abi.c @@ -219,7 +219,7 @@ static void test_json() { for (d_iterator_t iter = d_iter(jctx->result); iter.left; d_iter_next(&iter)) { count++; char* error = NULL; - char* sig = d_get_string(iter.token, "sig"); + char* sig = d_get_string(iter.token, key("sig")); d_token_t* values = d_get(iter.token, key("values")); d_token_t* rev_values = d_get(iter.token, key("revValues")); // printf("%02i ## %s : %s\n", count, d_get_string(iter.token, "name"), sig); diff --git a/c/test/unit_tests/test_binary_encoding.c b/c/test/unit_tests/test_binary_encoding.c index 1ff9d0cfc..da3aff4b1 100644 --- a/c/test/unit_tests/test_binary_encoding.c +++ b/c/test/unit_tests/test_binary_encoding.c @@ -79,8 +79,8 @@ static void test_binary_primitives() { bytes_t* d = d_bytes(d_get(ctx->result, k_result)); char* str_result = malloc(d->len * 2 + 2); bytes_to_hex(d->data, d->len, str_result); - char* jsonrpc = d_get_stringk(ctx->result, k_jsonrpc); - int32_t id_ = d_get_intk(ctx->result, k_id); + char* jsonrpc = d_get_string(ctx->result, k_jsonrpc); + int32_t id_ = d_get_int(ctx->result, k_id); TEST_ASSERT_EQUAL_STRING(str_result, "0000000000000000000000000000000000000000000000000000000000000001"); TEST_ASSERT_EQUAL_STRING(jsonrpc, "2.0"); TEST_ASSERT_EQUAL_INT32(id_, 1); diff --git a/c/test/unit_tests/test_btc_api.c b/c/test/unit_tests/test_btc_api.c index 4a8ed544d..1c128660e 100644 --- a/c/test/unit_tests/test_btc_api.c +++ b/c/test/unit_tests/test_btc_api.c @@ -45,12 +45,12 @@ #include "../test_utils.h" #include "../util/transport.h" #include -#include +#include static in3_t* in3_init_test() { in3_t* in3 = in3_for_chain(CHAIN_ID_BTC); register_transport(in3, mock_transport); - in3_configure(in3, "{\"autoUpdateList\":false,\"maxAttempts\":1,\"nodeRegistry\":{\"needsUpdate\":false}}"); + in3_configure(in3, "{\"autoUpdateList\":false,\"maxAttempts\":1,\"experimental\":true,\"nodeRegistry\":{\"needsUpdate\":false}}"); return in3; } diff --git a/c/test/unit_tests/test_bulk.c b/c/test/unit_tests/test_bulk.c index 8b2302dfe..48a5be73e 100644 --- a/c/test/unit_tests/test_bulk.c +++ b/c/test/unit_tests/test_bulk.c @@ -44,15 +44,15 @@ #include "../../src/core/util/log.h" #include "../../src/verifier/eth1/full/eth_full.h" #include "../test_utils.h" -#include "nodeselect/nodeselect_def.h" +#include "nodeselect/full/nodeselect_def.h" #include #include static in3_ret_t test_bulk_transport(void* plugin_data, in3_plugin_act_t action, void* plugin_ctx) { - in3_request_t* req = plugin_ctx; - char* buffer = NULL; - long length; - FILE* f = fopen("../c/test/testdata/mock/get_blocks.json", "r"); + in3_http_request_t* req = plugin_ctx; + char* buffer = NULL; + long length; + FILE* f = fopen("../c/test/testdata/mock/get_blocks.json", "r"); if (f) { fseek(f, 0, SEEK_END); length = ftell(f); @@ -78,7 +78,7 @@ static in3_ret_t test_bulk_transport(void* plugin_data, in3_plugin_act_t action, // now parse the json json_ctx_t* res = parse_json(buffer); str_range_t json = d_to_json(d_get(d_get_at(res->result, 0), key("response"))); - in3_ctx_add_response(req->ctx, 0, false, json.data, json.len, 0); + in3_ctx_add_response(req->req, 0, false, json.data, json.len, 0); json_free(res); if (buffer) _free(buffer); @@ -101,8 +101,8 @@ static void test_context_bulk() { sb_add_chars(req, ","); } sb_add_chars(req, "]"); - in3_ctx_t* block_ctx = ctx_new(in3, req->data); - in3_ret_t ret = in3_send_ctx(block_ctx); + in3_req_t* block_ctx = req_new(in3, req->data); + in3_ret_t ret = in3_send_req(block_ctx); for (uint64_t i = 0; i < blkno; i++) { d_token_t* hash = d_getl(d_get(block_ctx->responses[i], K_RESULT), K_HASH, 32); TEST_ASSERT_NOT_NULL(hash); @@ -110,7 +110,7 @@ static void test_context_bulk() { bytes_to_hex(d_bytes(hash)->data, 32, h + 2); in3_log_trace("HASH %s\n", h); } - ctx_free(block_ctx); + req_free(block_ctx); _free(req); in3_free(in3); } diff --git a/c/test/unit_tests/test_cache.c b/c/test/unit_tests/test_cache.c index 5335853f0..37d36526b 100644 --- a/c/test/unit_tests/test_cache.c +++ b/c/test/unit_tests/test_cache.c @@ -45,10 +45,10 @@ #include "../../src/core/util/scache.h" #include "../../src/verifier/eth1/nano/eth_nano.h" #include "../test_utils.h" -#include "nodeselect/cache.h" -#include "nodeselect/nodelist.h" +#include "nodeselect/full/cache.h" +#include "nodeselect/full/nodelist.h" #include -#include +#include #include #include @@ -57,10 +57,10 @@ #define WHITELIST_CONTRACT_ADDRS "0xdd80249a0631cf0f1593c7a9c9f9b8545e6c88ab" static in3_ret_t test_transport(void* plugin_data, in3_plugin_act_t action, void* plugin_ctx) { - in3_request_t* req = plugin_ctx; - char* buffer = NULL; - long length; - FILE* f = fopen("../c/test/testdata/requests/in3_nodeList.json", "r"); + in3_http_request_t* req = plugin_ctx; + char* buffer = NULL; + long length; + FILE* f = fopen("../c/test/testdata/requests/in3_nodeList.json", "r"); if (f) { fseek(f, 0, SEEK_END); length = ftell(f); @@ -86,7 +86,7 @@ static in3_ret_t test_transport(void* plugin_data, in3_plugin_act_t action, void // now parse the json json_ctx_t* res = parse_json(buffer); str_range_t json = d_to_json(d_get_at(d_get(d_get_at(res->result, 0), key("response")), 0)); - in3_ctx_add_response(req->ctx, 0, false, json.data, json.len, 0); + in3_ctx_add_response(req->req, 0, false, json.data, json.len, 0); json_free(res); if (buffer) _free(buffer); return IN3_OK; @@ -173,10 +173,10 @@ static void test_cache() { TEST_ASSERT_EQUAL_INT32(7, nl2->nodelist_length); // test request - in3_ctx_t* ctx = in3_client_rpc_ctx(c2, "in3_nodeList", "[]"); + in3_req_t* ctx = in3_client_rpc_ctx(c2, "in3_nodeList", "[]"); if (ctx->error) printf("ERROR : %s\n", ctx->error); TEST_ASSERT(ctx && ctx->error == NULL); - ctx_free(ctx); + req_free(ctx); in3_free(c); in3_free(c2); } @@ -306,7 +306,7 @@ static void test_whitelist_cache() { in3_nodeselect_def_t* nl = in3_nodeselect_def_data(c); hex_to_bytes(WHITELIST_CONTRACT_ADDRS, -1, wlc, 20); TEST_ASSERT_EQUAL_MEMORY(nl->whitelist->contract, wlc, 20); - in3_ctx_t* ctx = ctx_new(c, "{\"method\":\"eth_getBlockByNumber\",\"params\":[\"latest\",false]}"); + in3_req_t* ctx = req_new(c, "{\"method\":\"eth_getBlockByNumber\",\"params\":[\"latest\",false]}"); TEST_ASSERT_EQUAL(IN3_OK, in3_cache_store_whitelist(ctx->client, nl)); // fixme: nl_sep @@ -320,7 +320,7 @@ static void test_whitelist_cache() { // TEST_ASSERT_TRUE(b_cmp(&nl2->whitelist->addresses, &nl2->whitelist->addresses)); // in3_free(c2); - ctx_free(ctx); + req_free(ctx); in3_free(c); } @@ -338,8 +338,8 @@ int main() { // now run tests TESTS_BEGIN(); RUN_TEST(test_scache); - RUN_TEST(test_cache); - RUN_TEST(test_newchain); + // RUN_TEST(test_cache); + // RUN_TEST(test_newchain); RUN_TEST(test_whitelist_cache); return TESTS_END(); } diff --git a/c/test/unit_tests/test_config.c b/c/test/unit_tests/test_config.c index 0bb235514..c87b72a9e 100644 --- a/c/test/unit_tests/test_config.c +++ b/c/test/unit_tests/test_config.c @@ -46,9 +46,9 @@ #include "../../src/core/util/utils.h" #include "../../src/verifier/eth1/nano/eth_nano.h" #include "../test_utils.h" -#include "nodeselect/cache.h" -#include "nodeselect/nodelist.h" -#include +#include "nodeselect/full/cache.h" +#include "nodeselect/full/nodelist.h" +#include #include #include @@ -63,7 +63,7 @@ void test_get_config() { if (error) printf("ERROR: %s\n", error); TEST_ASSERT_NULL(error); TEST_ASSERT_EQUAL_STRING(result, - "{\"autoUpdateList\":true,\"chainId\":5,\"signatureCount\":0,\"finality\":0,\"includeCode\":false,\"bootWeights\":true,\"maxAttempts\":7,\"keepIn3\":false,\"stats\":true,\"useBinary\":false,\"useHttp\":false,\"maxVerifiedHashes\":5,\"timeout\":10000,\"minDeposit\":0,\"nodeProps\":0,\"nodeLimit\":0,\"proof\":\"standard\",\"requestCount\":1,\"nodeRegistry\":{\"contract\":\"0x5f51e413581dd76759e9eed51e63d14c8d1379c8\",\"registryId\":\"0x67c02e5e272f9d6b4a33716614061dd298283f86351079ef903bf0d4410a44ea\",\"needsUpdate\":true,\"avgBlockTime\":15}}"); + "{\"autoUpdateList\":true,\"chainId\":5,\"signatureCount\":0,\"finality\":0,\"includeCode\":false,\"bootWeights\":true,\"maxAttempts\":7,\"keepIn3\":false,\"stats\":true,\"useBinary\":false,\"useHttp\":false,\"experimental\":false,\"maxVerifiedHashes\":5,\"timeout\":10000,\"proof\":\"standard\",\"requestCount\":1,\"minDeposit\":0,\"nodeProps\":0,\"nodeLimit\":0,\"nodeRegistry\":{\"contract\":\"0x5f51e413581dd76759e9eed51e63d14c8d1379c8\",\"registryId\":\"0x67c02e5e272f9d6b4a33716614061dd298283f86351079ef903bf0d4410a44ea\",\"needsUpdate\":true,\"avgBlockTime\":15}}"); _free(result); in3_free(c); } diff --git a/c/test/unit_tests/test_core.c b/c/test/unit_tests/test_core.c index dc46ac2f7..e543948db 100644 --- a/c/test/unit_tests/test_core.c +++ b/c/test/unit_tests/test_core.c @@ -39,14 +39,14 @@ #define DEBUG #endif -#include "../../src/core/client/context.h" +#include "../../src/core/client/request.h" #include "../../src/core/util/data.h" #include "../../src/core/util/debug.h" #include "../../src/core/util/utils.h" #include "../../src/verifier/eth1/nano/eth_nano.h" #include "../test_utils.h" -#include "nodeselect/cache.h" -#include "nodeselect/nodelist.h" +#include "nodeselect/full/cache.h" +#include "nodeselect/full/nodelist.h" #include #include diff --git a/c/test/unit_tests/test_ethapi.c b/c/test/unit_tests/test_ethapi.c index dcaa4f396..a8361ca60 100644 --- a/c/test/unit_tests/test_ethapi.c +++ b/c/test/unit_tests/test_ethapi.c @@ -39,8 +39,8 @@ #endif #include "../../src/api/eth1/eth_api.h" -#include "../../src/core/client/context.h" #include "../../src/core/client/keys.h" +#include "../../src/core/client/request.h" #include "../../src/core/util/data.h" #include "../../src/core/util/log.h" #include "../../src/core/util/scache.h" @@ -49,9 +49,9 @@ #include "../../src/verifier/eth1/nano/eth_nano.h" #include "../test_utils.h" #include "../util/transport.h" -#include "nodeselect/cache.h" -#include "nodeselect/nodelist.h" -#include "nodeselect/nodeselect_def.h" +#include "nodeselect/full/cache.h" +#include "nodeselect/full/nodelist.h" +#include "nodeselect/full/nodeselect_def.h" #include #include @@ -187,7 +187,7 @@ static void test_get_filter_changes() { _free(hashes); // Test with non-existent filter id - TEST_ASSERT_EQUAL(IN3_EINVAL, eth_getFilterChanges(in3, 1234, NULL, NULL)); + TEST_ASSERT_EQUAL(IN3_EFIND, eth_getFilterChanges(in3, 1234, NULL, NULL)); // Test with all filters uninstalled TEST_ASSERT_TRUE(eth_uninstallFilter(in3, fid)); @@ -224,7 +224,7 @@ static void test_get_logs() { json_free(jopt); // Test with non-existent filter id - TEST_ASSERT_EQUAL(IN3_EINVAL, eth_getFilterLogs(in3, 1234, NULL)); + TEST_ASSERT_EQUAL(IN3_EFIND, eth_getFilterLogs(in3, 1234, NULL)); // Test with all filters uninstalled TEST_ASSERT_EQUAL(IN3_EFIND, eth_getFilterLogs(in3, fid, NULL)); diff --git a/c/test/unit_tests/test_filter.c b/c/test/unit_tests/test_filter.c index e0d6c988e..f64a6387d 100644 --- a/c/test/unit_tests/test_filter.c +++ b/c/test/unit_tests/test_filter.c @@ -40,16 +40,16 @@ #endif #include "../../src/api/eth1/eth_api.h" -#include "../../src/core/client/context.h" +#include "../../src/core/client/request.h" #include "../../src/core/util/data.h" #include "../../src/core/util/log.h" #include "../../src/verifier/eth1/basic/eth_basic.h" #include "../../src/verifier/eth1/basic/filter.h" #include "../test_utils.h" #include "../util/transport.h" -#include "nodeselect/cache.h" -#include "nodeselect/nodelist.h" -#include "nodeselect/nodeselect_def.h" +#include "nodeselect/full/cache.h" +#include "nodeselect/full/nodelist.h" +#include "nodeselect/full/nodeselect_def.h" #include #include @@ -179,23 +179,24 @@ static void test_filter_from_block_manip() { } static void test_filter_creation() { - in3_t* c = in3_for_chain(CHAIN_ID_MAINNET); - c->flags = FLAGS_STATS; + in3_t* c = in3_for_chain(CHAIN_ID_MAINNET); + in3_filter_handler_t* filters = eth_basic_get_filters(c); + c->flags = FLAGS_STATS; TEST_ASSERT_NULL(in3_configure(c, "{\"autoUpdateList\":false,\"proof\":\"none\",\"signatureCount\":0,\"nodeRegistry\":{\"needsUpdate\":false}}")); register_transport(c, test_transport); - TEST_ASSERT_FALSE(filter_remove(c, 1)); + TEST_ASSERT_FALSE(filter_remove(filters, 1)); TEST_ASSERT_EQUAL(0, eth_newFilter(c, NULL)); add_response("eth_blockNumber", "[]", "\"0x84cf59\"", NULL, NULL); TEST_ASSERT_GREATER_THAN(0, eth_newBlockFilter(c)); add_response("eth_blockNumber", "[]", "\"0x84cf5a\"", NULL, NULL); TEST_ASSERT_GREATER_THAN(0, eth_newBlockFilter(c)); - TEST_ASSERT_TRUE(filter_remove(c, 1)); + TEST_ASSERT_TRUE(filter_remove(filters, 1)); add_response("eth_blockNumber", "[]", "\"0x84cf5f\"", NULL, NULL); TEST_ASSERT_GREATER_THAN(0, eth_newBlockFilter(c)); - TEST_ASSERT_EQUAL(2, c->filters->count); - TEST_ASSERT_FALSE(filter_remove(c, 10)); - TEST_ASSERT_FALSE(filter_remove(c, 0)); + TEST_ASSERT_EQUAL(2, filters->count); + TEST_ASSERT_FALSE(filter_remove(filters, 10)); + TEST_ASSERT_FALSE(filter_remove(filters, 0)); TEST_ASSERT_FALSE(0); in3_free(c); } @@ -256,7 +257,7 @@ static void test_filter_changes() { TEST_ASSERT_EQUAL_STRING("[]", result); _free(result); - TEST_ASSERT_TRUE(filter_remove(c, 1)); + TEST_ASSERT_TRUE(filter_remove(eth_basic_get_filters(c), 1)); in3_free(c); } diff --git a/c/test/unit_tests/test_ipfs_api.c b/c/test/unit_tests/test_ipfs_api.c index 5f8cc5c13..ce5d3e3e8 100644 --- a/c/test/unit_tests/test_ipfs_api.c +++ b/c/test/unit_tests/test_ipfs_api.c @@ -44,9 +44,9 @@ #include "../test_utils.h" #include "../util/transport.h" #include -#include +#include -#define LOREM_IPSUM "Lorem ipsum dolor sit amet" +#define LOREM_IPSUM "Lorem ipsum dolor sit amet" #define LOREM_IPSUM_LONG "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation " \ "ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint " \ "occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." diff --git a/c/test/unit_tests/test_key_hash.c b/c/test/unit_tests/test_key_hash.c index a2f3fc137..cdc50459d 100644 --- a/c/test/unit_tests/test_key_hash.c +++ b/c/test/unit_tests/test_key_hash.c @@ -74,7 +74,10 @@ static int compare(const void* a, const void* b) { static bool is_allowed(char* a, char* b) { // this function may contains exceptions which are ok + if (strcmp(b, "provider_url") == 0 && strcmp(a, "nodeRegistry") == 0) return true; // params and autoupdateList will not appear in the same object + if (strcmp(b, "nodeRegistry") == 0 && strcmp(a, "provider_url") == 0) return true; // params and autoupdateList will not appear in the same object + if (strcmp(b, "autoUpdateList") == 0 && strcmp(a, "params") == 0) return true; // params and autoupdateList will not appear in the same object if (strcmp(a, "autoUpdateList") == 0 && strcmp(b, "params") == 0) return true; // params and autoupdateList will not appear in the same object return false; } diff --git a/c/test/unit_tests/test_nanoledger.c b/c/test/unit_tests/test_nanoledger.c index 4710f1c17..9582f8ffe 100644 --- a/c/test/unit_tests/test_nanoledger.c +++ b/c/test/unit_tests/test_nanoledger.c @@ -41,8 +41,8 @@ #include "../../include/in3/error.h" #include "../../src/api/eth1/eth_api.h" -#include "../../src/core/client/context.h" #include "../../src/core/client/keys.h" +#include "../../src/core/client/request.h" #include "../../src/core/util/bytes.h" #include "../../src/core/util/data.h" #include "../../src/core/util/log.h" @@ -50,8 +50,8 @@ #include "../../src/core/util/scache.h" #include "../../src/verifier/eth1/full/eth_full.h" #include "../../src/verifier/eth1/nano/eth_nano.h" -#include "nodeselect/cache.h" -#include "nodeselect/nodelist.h" +#include "nodeselect/full/cache.h" +#include "nodeselect/full/nodelist.h" #if defined(LEDGER_NANO) #include "../../src/signer/ledger-nano/signer/ethereum_apdu_client.h" @@ -113,7 +113,7 @@ static void test_signer() { in3_t* c = in3_for_chain(CHAIN_ID_MAINNET); eth_ledger_set_signer_txn(c, bip_path); - in3_ctx_t* ctx = ctx_new(c, "{\"method\":\"eth_getBlockByNumber\",\"params\":[\"latest\",false]}"); + in3_req_t* ctx = req_new(c, "{\"method\":\"eth_getBlockByNumber\",\"params\":[\"latest\",false]}"); char* data_str = "msgABCDEF"; // prefixing messages with msg to differentiate between transaction and message signing bytes_t* data = b_new((uint8_t*) data_str, strlen(data_str)); @@ -122,7 +122,7 @@ static void test_signer() { sc.message = *data; sc.account = bytes(NULL, 0); sc.wallet = c->signer->wallet; - sc.ctx = ctx; + sc.req = ctx; TEST_ASSERT_EQUAL(IN3_OK, eth_ledger_sign_txn(&sc)); TEST_ASSERT_FALSE(memiszero(sc.signature.data, 65)); diff --git a/c/test/unit_tests/test_nodelist.c b/c/test/unit_tests/test_nodelist.c index ee6455714..28cece8c9 100644 --- a/c/test/unit_tests/test_nodelist.c +++ b/c/test/unit_tests/test_nodelist.c @@ -42,8 +42,8 @@ #include "../src/core/util/log.h" #include "../test_utils.h" #include "../util/transport.h" -#include "nodeselect/nodelist.h" -#include "nodeselect/nodeselect_def.h" +#include "nodeselect/full/nodelist.h" +#include "nodeselect/full/nodeselect_def.h" #define ADD_RESPONSE_NODELIST_3(last_block) add_response("in3_nodeList", \ "[0,\"0x0000000100000002000000030000000400000005000000060000000700000008\",[]]", \ @@ -696,42 +696,43 @@ static void test_nodelist_update_8() { static void test_nodelist_pick_signer_exclusions() { in3_t* in3 = in3_for_chain(0x34ff); - in3_configure(in3, "{\"chainId\":\"0x34ff\",\"chainType\":0,\"autoUpdateList\":false,\"signatureCount\":1,\"requestCount\":1,\"maxAttempts\":1,\"maxVerifiedHashes\":0," - "\"nodeRegistry\":{" - " \"needsUpdate\":false," - " \"contract\": \"0x5f51e413581dd76759e9eed51e63d14c8d1379c8\"," - " \"registryId\": \"0x67c02e5e272f9d6b4a33716614061dd298283f86351079ef903bf0d4410a44ea\"," - " \"nodeList\": [{" - " \"url\":\"https://in3-v2.slock.it/priv/nd-1\"," - " \"address\":\"0x45d45e6ff99e6c34a235d263965910298985fcfe\"," - " \"props\":\"0x1dd\"" - " }," - " {" - " \"url\":\"https://in3-v2.slock.it/priv/nd-2\"," - " \"address\":\"0x1fe2e9bf29aa1938859af64c413361227d04059a\"," - " \"props\":\"0x1dd\"" - " }," - " {" - " \"url\":\"https://in3-v2.slock.it/goerli/nd-3\"," - " \"address\":\"0x945f75c0408c0026a3cd204d36f5e47745182fd4\"," - " \"props\":\"0x1dd\"" - " }]" - "}}"); + char* err = in3_configure(in3, "{\"chainId\":\"0x34ff\",\"chainType\":0,\"autoUpdateList\":false,\"signatureCount\":1,\"requestCount\":1,\"maxAttempts\":1,\"maxVerifiedHashes\":0," + "\"nodeRegistry\":{" + " \"needsUpdate\":false," + " \"contract\": \"0x5f51e413581dd76759e9eed51e63d14c8d1379c8\"," + " \"registryId\": \"0x67c02e5e272f9d6b4a33716614061dd298283f86351079ef903bf0d4410a44ea\"," + " \"nodeList\": [{" + " \"url\":\"https://in3-v2.slock.it/priv/nd-1\"," + " \"address\":\"0x45d45e6ff99e6c34a235d263965910298985fcfe\"," + " \"props\":\"0x1dd\"" + " }," + " {" + " \"url\":\"https://in3-v2.slock.it/priv/nd-2\"," + " \"address\":\"0x1fe2e9bf29aa1938859af64c413361227d04059a\"," + " \"props\":\"0x1dd\"" + " }," + " {" + " \"url\":\"https://in3-v2.slock.it/goerli/nd-3\"," + " \"address\":\"0x945f75c0408c0026a3cd204d36f5e47745182fd4\"," + " \"props\":\"0x1dd\"" + " }]" + "}}"); + TEST_ASSERT_NULL_MESSAGE(err, err); register_transport(in3, test_transport); size_t test_count = 100; /* we should surely hit a collision by then (unless the code is handling exclusions correctly) */ for (size_t i = 0; i < test_count; i++) { - in3_ctx_t* ctx = ctx_new(in3, "{\"jsonrpc\":\"2.0\"," + in3_req_t* ctx = req_new(in3, "{\"jsonrpc\":\"2.0\"," "\"method\":\"eth_getTransactionByHash\"," "\"params\":[\"0x715ece6967d0dc6aa6e8e4ee83937d3d4a79fdc644b64f07aa72f877df156be7\"]}"); - in3_nl_pick_ctx_t pctx = {.type = NL_DATA, .ctx = ctx}; + in3_nl_pick_ctx_t pctx = {.type = NL_DATA, .req = ctx}; TEST_ASSERT_EQUAL(IN3_OK, in3_plugin_execute_first(ctx, PLGN_ACT_NL_PICK, &pctx)); pctx.type = NL_SIGNER; TEST_ASSERT_EQUAL(IN3_OK, in3_plugin_execute_first(ctx, PLGN_ACT_NL_PICK, &pctx)); TEST_ASSERT_NOT_NULL(ctx->nodes); TEST_ASSERT_EQUAL(1, ctx->signers_length); TEST_ASSERT(memcmp(ctx->nodes->address, ctx->signers, 20) != 0); - ctx_free(ctx); + req_free(ctx); } in3_free(in3); @@ -746,6 +747,7 @@ int main() { in3_register_default(in3_register_nodeselect_def); in3_set_func_time(mock_time); in3_set_func_rand(mock_rand); + RUN_TEST(test_nodelist_pick_signer_exclusions); RUN_TEST(test_capabilities); RUN_TEST(test_nodelist_update_1); RUN_TEST(test_nodelist_update_2); @@ -755,6 +757,5 @@ int main() { RUN_TEST(test_nodelist_update_6); RUN_TEST(test_nodelist_update_7); RUN_TEST(test_nodelist_update_8); - RUN_TEST(test_nodelist_pick_signer_exclusions); return TESTS_END(); } diff --git a/c/test/unit_tests/test_recorder.c b/c/test/unit_tests/test_recorder.c index fd6a0a635..d40979e95 100644 --- a/c/test/unit_tests/test_recorder.c +++ b/c/test/unit_tests/test_recorder.c @@ -45,7 +45,7 @@ #include "../../src/verifier/eth1/full/eth_full.h" #include "../test_utils.h" #include "../util/transport.h" -#include +#include #include in3_t* init_in3(in3_plugin_act_fn custom_transport, chain_id_t chain) { diff --git a/c/test/unit_tests/test_request.c b/c/test/unit_tests/test_request.c index f42f1cfac..704cbebfb 100644 --- a/c/test/unit_tests/test_request.c +++ b/c/test/unit_tests/test_request.c @@ -40,8 +40,8 @@ #endif #include "../../src/api/eth1/eth_api.h" -#include "../../src/core/client/context_internal.h" #include "../../src/core/client/keys.h" +#include "../../src/core/client/request_internal.h" #include "../../src/core/util/bitset.h" #include "../../src/core/util/data.h" #include "../../src/core/util/log.h" @@ -49,9 +49,9 @@ #include "../../src/verifier/eth1/basic/eth_basic.h" #include "../test_utils.h" #include "../util/transport.h" -#include "nodeselect/cache.h" -#include "nodeselect/nodelist.h" -#include "nodeselect/nodeselect_def.h" +#include "nodeselect/full/cache.h" +#include "nodeselect/full/nodelist.h" +#include "nodeselect/full/nodeselect_def.h" #define TEST_ASSERT_CONFIGURE_FAIL(desc, in3, config, err_slice) \ do { \ @@ -76,23 +76,23 @@ static void test_configure_request() { c->flags = FLAGS_INCLUDE_CODE | FLAGS_BINARY | FLAGS_HTTP; c->replace_latest_block = 6; - in3_ctx_t* ctx = ctx_new(c, "{\"method\":\"eth_getBlockByNumber\",\"params\":[\"latest\",false]}"); - TEST_ASSERT_EQUAL(IN3_WAITING, in3_ctx_execute(ctx)); - in3_request_t* request = in3_create_request(ctx); - json_ctx_t* json = parse_json(request->payload); - d_token_t* in3 = d_get(d_get_at(json->result, 0), K_IN3); + in3_req_t* ctx = req_new(c, "{\"method\":\"eth_getBlockByNumber\",\"params\":[\"latest\",false]}"); + TEST_ASSERT_EQUAL(IN3_WAITING, in3_req_execute(ctx)); + in3_http_request_t* request = in3_create_request(ctx); + json_ctx_t* json = parse_json(request->payload); + d_token_t* in3 = d_get(d_get_at(json->result, 0), K_IN3); TEST_ASSERT_NOT_NULL(in3); - TEST_ASSERT_EQUAL(1, d_get_int(in3, "useFullProof")); - TEST_ASSERT_EQUAL(1, d_get_int(in3, "useBinary")); - TEST_ASSERT_EQUAL(10, d_get_int(in3, "finality")); - TEST_ASSERT_EQUAL(6, d_get_int(in3, "latestBlock")); + TEST_ASSERT_EQUAL(1, d_get_int(in3, key("useFullProof"))); + TEST_ASSERT_EQUAL(1, d_get_int(in3, key("useBinary"))); + TEST_ASSERT_EQUAL(10, d_get_int(in3, key("finality"))); + TEST_ASSERT_EQUAL(6, d_get_int(in3, key("latestBlock"))); d_token_t* signers = d_get(in3, key("signers")); TEST_ASSERT_NOT_NULL(signers); TEST_ASSERT_EQUAL(2, d_len(signers)); request_free(request); json_free(json); - // ctx_free(ctx); - ctx_free(ctx); + // req_free(ctx); + req_free(ctx); in3_free(c); } @@ -103,22 +103,22 @@ static void test_bulk_response() { c->flags = 0; // add_response("eth_blockNumber", "[]", "0x2", NULL, NULL); - in3_ctx_t* ctx = ctx_new(c, "[{\"method\":\"eth_blockNumber\",\"params\":[]},{\"method\":\"eth_blockNumber\",\"params\":[]}]"); - TEST_ASSERT_EQUAL(CTX_WAITING_TO_SEND, in3_ctx_exec_state(ctx)); - in3_request_t* req = in3_create_request(ctx); + in3_req_t* ctx = req_new(c, "[{\"method\":\"eth_blockNumber\",\"params\":[]},{\"method\":\"eth_blockNumber\",\"params\":[]}]"); + TEST_ASSERT_EQUAL(REQ_WAITING_TO_SEND, in3_req_exec_state(ctx)); + in3_http_request_t* req = in3_create_request(ctx); // first response is an error we expect a waiting since the transport has not passed all responses yet - in3_ctx_add_response(req->ctx, 0, true, "500 from server", -1, 0); - TEST_ASSERT_EQUAL(CTX_WAITING_FOR_RESPONSE, in3_ctx_exec_state(ctx)); - in3_ctx_add_response(req->ctx, 1, false, "[{\"result\":\"0x1\"},{\"result\":\"0x2\",\"in3\":{\"currentBlock\":\"0x1\"}}]", -1, 0); + in3_ctx_add_response(req->req, 0, true, "500 from server", -1, 0); + TEST_ASSERT_EQUAL(REQ_WAITING_FOR_RESPONSE, in3_req_exec_state(ctx)); + in3_ctx_add_response(req->req, 1, false, "[{\"result\":\"0x1\"},{\"result\":\"0x2\",\"in3\":{\"currentBlock\":\"0x1\"}}]", -1, 0); request_free(req); - TEST_ASSERT_EQUAL(CTX_SUCCESS, in3_ctx_exec_state(ctx)); + TEST_ASSERT_EQUAL(REQ_SUCCESS, in3_req_exec_state(ctx)); - char* res = ctx_get_response_data(ctx); + char* res = req_get_response_data(ctx); TEST_ASSERT_EQUAL_STRING("[{\"result\":\"0x1\"},{\"result\":\"0x2\"}]", res); _free(res); - ctx_free(ctx); + req_free(ctx); in3_free(c); } @@ -130,21 +130,21 @@ static void test_configure_signed_request() { TEST_ASSERT_NULL_MESSAGE(err, err); c->flags = FLAGS_INCLUDE_CODE; - in3_ctx_t* ctx = ctx_new(c, "{\"id\":2,\"method\":\"eth_blockNumber\",\"params\":[]}"); - TEST_ASSERT_EQUAL(IN3_WAITING, in3_ctx_execute(ctx)); - in3_request_t* request = in3_create_request(ctx); - json_ctx_t* json = parse_json(request->payload); - d_token_t* in3 = d_get(d_get_at(json->result, 0), K_IN3); + in3_req_t* ctx = req_new(c, "{\"id\":2,\"method\":\"eth_blockNumber\",\"params\":[]}"); + TEST_ASSERT_EQUAL(IN3_WAITING, in3_req_execute(ctx)); + in3_http_request_t* request = in3_create_request(ctx); + json_ctx_t* json = parse_json(request->payload); + d_token_t* in3 = d_get(d_get_at(json->result, 0), K_IN3); TEST_ASSERT_NOT_NULL(in3); - bytes_t* sig = d_get_bytes(in3, "sig"); + bytes_t* sig = d_get_bytes(in3, key("sig")); TEST_ASSERT_NOT_NULL(sig); TEST_ASSERT_EQUAL(65, sig->len); char hex[150]; TEST_ASSERT_EQUAL(65 * 2, bytes_to_hex(sig->data, sig->len, hex)); // 65bytes *2 - TEST_ASSERT_EQUAL_STRING("8e39d2066cf9d1898e6bc9fbbfaa8fd6b9e5a86515e643f537c831982718866d0903e91f5f8824363dd3754fe550b37aa1e6eeb3742f13ad36d3321972e959a701", hex); + TEST_ASSERT_EQUAL_STRING("8e39d2066cf9d1898e6bc9fbbfaa8fd6b9e5a86515e643f537c831982718866d0903e91f5f8824363dd3754fe550b37aa1e6eeb3742f13ad36d3321972e959a71c", hex); request_free(request); json_free(json); - ctx_free(ctx); + req_free(ctx); in3_free(c); } @@ -175,23 +175,23 @@ static void test_partial_response() { c->flags = 0; // add_response("eth_blockNumber", "[]", "0x2", NULL, NULL); - in3_ctx_t* ctx = ctx_new(c, "{\"method\":\"eth_blockNumber\",\"params\":[]}"); - TEST_ASSERT_EQUAL(IN3_WAITING, in3_ctx_execute(ctx)); - in3_request_t* req = in3_create_request(ctx); + in3_req_t* ctx = req_new(c, "{\"method\":\"eth_blockNumber\",\"params\":[]}"); + TEST_ASSERT_EQUAL(IN3_WAITING, in3_req_execute(ctx)); + in3_http_request_t* req = in3_create_request(ctx); // first response is an error we expect a waiting since the transport has not passed all responses yet - in3_ctx_add_response(req->ctx, 0, true, "500 from server", -1, 0); - TEST_ASSERT_EQUAL(IN3_WAITING, in3_ctx_execute(ctx)); - TEST_ASSERT_EQUAL(IN3_WAITING, in3_ctx_execute(ctx)); // calling twice will give the same result + in3_ctx_add_response(req->req, 0, true, "500 from server", -1, 0); + TEST_ASSERT_EQUAL(IN3_WAITING, in3_req_execute(ctx)); + TEST_ASSERT_EQUAL(IN3_WAITING, in3_req_execute(ctx)); // calling twice will give the same result TEST_ASSERT_TRUE(get_node(in3_nodeselect_def_data(c), ctx->nodes)->blocked); // first node is blacklisted TEST_ASSERT_FALSE(get_node(in3_nodeselect_def_data(c), ctx->nodes->next)->blocked); // second node is not blacklisted // now we have a valid response and should get a accaptable response - in3_ctx_add_response(req->ctx, 2, false, "{\"result\":\"0x100\"}", -1, 0); - TEST_ASSERT_EQUAL(IN3_OK, in3_ctx_execute(ctx)); + in3_ctx_add_response(req->req, 2, false, "{\"result\":\"0x100\"}", -1, 0); + TEST_ASSERT_EQUAL(IN3_OK, in3_req_execute(ctx)); request_free(req); - ctx_free(ctx); + req_free(ctx); in3_free(c); } @@ -201,19 +201,19 @@ static void test_retry_response() { c->flags = 0; // add_response("eth_blockNumber", "[]", "0x2", NULL, NULL); - in3_ctx_t* ctx = ctx_new(c, "{\"method\":\"eth_blockNumber\",\"params\":[]}"); - TEST_ASSERT_EQUAL(IN3_WAITING, in3_ctx_execute(ctx)); - in3_request_t* req = in3_create_request(ctx); + in3_req_t* ctx = req_new(c, "{\"method\":\"eth_blockNumber\",\"params\":[]}"); + TEST_ASSERT_EQUAL(IN3_WAITING, in3_req_execute(ctx)); + in3_http_request_t* req = in3_create_request(ctx); // first response is an error we expect a waiting since the transport has not passed all responses yet - in3_ctx_add_response(req->ctx, 0, true, "500 from server", -1, 0); - TEST_ASSERT_EQUAL(IN3_WAITING, in3_ctx_execute(ctx)); // calling twice will give the same result + in3_ctx_add_response(req->req, 0, true, "500 from server", -1, 0); + TEST_ASSERT_EQUAL(IN3_WAITING, in3_req_execute(ctx)); // calling twice will give the same result TEST_ASSERT_TRUE(get_node(in3_nodeselect_def_data(c), ctx->nodes)->blocked); // first node is blacklisted TEST_ASSERT_FALSE(get_node(in3_nodeselect_def_data(c), ctx->nodes->next)->blocked); // second node is not blacklisted TEST_ASSERT_NOT_NULL(ctx->raw_response); // we still keep the raw response - in3_ctx_add_response(req->ctx, 1, false, "{\"error\":\"Error:no internet\"}", -1, 0); - TEST_ASSERT_EQUAL(IN3_WAITING, in3_ctx_execute(ctx)); + in3_ctx_add_response(req->req, 1, false, "{\"error\":\"Error:no internet\"}", -1, 0); + TEST_ASSERT_EQUAL(IN3_WAITING, in3_req_execute(ctx)); TEST_ASSERT_NULL(ctx->raw_response); request_free(req); @@ -222,11 +222,11 @@ static void test_retry_response() { req = in3_create_request(ctx); TEST_ASSERT_NOT_NULL(ctx->raw_response); // now the raw response is set - in3_ctx_add_response(req->ctx, 0, false, "{\"result\":\"0x100\"}", -1, 0); - TEST_ASSERT_EQUAL(IN3_OK, in3_ctx_execute(ctx)); + in3_ctx_add_response(req->req, 0, false, "{\"result\":\"0x100\"}", -1, 0); + TEST_ASSERT_EQUAL(IN3_OK, in3_req_execute(ctx)); request_free(req); - ctx_free(ctx); + req_free(ctx); in3_free(c); } @@ -243,7 +243,7 @@ static void test_configure() { tmp = in3_configure(c, "{\"rpc\":\"http://rpc.slock.it\"}"); TEST_ASSERT_EQUAL(PROOF_NONE, c->proof); TEST_ASSERT_EQUAL(CHAIN_ID_LOCAL, c->chain.chain_id); - TEST_ASSERT_EQUAL(1, c->request_count); + TEST_ASSERT_EQUAL(1, in3_get_nodelist(c)->request_count); TEST_ASSERT_EQUAL_STRING("http://rpc.slock.it", in3_nodeselect_def_data(c)->nodelist->url); free(tmp); @@ -259,7 +259,8 @@ static void test_configure() { } static void test_configure_validation() { - in3_t* c = in3_for_chain(CHAIN_ID_MAINNET); + in3_t* c = in3_for_chain(CHAIN_ID_MAINNET); + in3_nodeselect_config_t* w = in3_get_nodelist(c); eth_register_pk_signer(c); TEST_ASSERT_CONFIGURE_FAIL("invalid JSON in config", c, "{\"\"}", "parse error"); @@ -387,14 +388,14 @@ static void test_configure_validation() { TEST_ASSERT_CONFIGURE_FAIL("mismatched type: minDeposit", c, "{\"minDeposit\":false}", "expected uint64"); TEST_ASSERT_CONFIGURE_FAIL("mismatched type: minDeposit", c, "{\"minDeposit\":\"0x012345678901234567\"}", "expected uint64"); TEST_ASSERT_CONFIGURE_PASS(c, "{\"minDeposit\":1}"); - TEST_ASSERT_EQUAL(c->min_deposit, 1); + TEST_ASSERT_EQUAL(w->min_deposit, 1); TEST_ASSERT_CONFIGURE_PASS(c, "{\"minDeposit\":0}"); - TEST_ASSERT_EQUAL(c->min_deposit, 0); + TEST_ASSERT_EQUAL(w->min_deposit, 0); // fixme: // TEST_ASSERT_CONFIGURE_PASS(c, "{\"minDeposit\":18446744073709551615}"); // UINT64_MAX // TEST_ASSERT_EQUAL(c->min_deposit, 18446744073709551615ULL); TEST_ASSERT_CONFIGURE_PASS(c, "{\"minDeposit\":\"0xffffffffffffffff\"}"); // UINT64_MAX - TEST_ASSERT_EQUAL(c->min_deposit, 0xffffffffffffffff); + TEST_ASSERT_EQUAL(w->min_deposit, 0xffffffffffffffff); TEST_ASSERT_CONFIGURE_FAIL("mismatched type: nodeProps", c, "{\"nodeProps\":\"-1\"}", "expected uint64"); TEST_ASSERT_CONFIGURE_FAIL("mismatched type: nodeProps", c, "{\"nodeProps\":\"\"}", "expected uint64"); @@ -402,14 +403,14 @@ static void test_configure_validation() { TEST_ASSERT_CONFIGURE_FAIL("mismatched type: nodeProps", c, "{\"nodeProps\":false}", "expected uint64"); TEST_ASSERT_CONFIGURE_FAIL("mismatched type: nodeProps", c, "{\"nodeProps\":\"0x012345678901234567\"}", "expected uint64"); TEST_ASSERT_CONFIGURE_PASS(c, "{\"nodeProps\":1}"); - TEST_ASSERT_EQUAL(c->node_props, 1); + TEST_ASSERT_EQUAL(w->node_props, 1); TEST_ASSERT_CONFIGURE_PASS(c, "{\"nodeProps\":0}"); - TEST_ASSERT_EQUAL(c->node_props, 0); + TEST_ASSERT_EQUAL(w->node_props, 0); // fixme: // TEST_ASSERT_CONFIGURE_PASS(c, "{\"nodeProps\":18446744073709551615}"); // UINT64_MAX // TEST_ASSERT_EQUAL(c->node_props, 18446744073709551615ULL); TEST_ASSERT_CONFIGURE_PASS(c, "{\"nodeProps\":\"0xffffffffffffffff\"}"); // UINT64_MAX - TEST_ASSERT_EQUAL(c->node_props, 0xffffffffffffffff); + TEST_ASSERT_EQUAL(w->node_props, 0xffffffffffffffff); TEST_ASSERT_CONFIGURE_FAIL("mismatched type: nodeLimit", c, "{\"nodeLimit\":\"-1\"}", "expected uint16"); TEST_ASSERT_CONFIGURE_FAIL("mismatched type: nodeLimit", c, "{\"nodeLimit\":\"0x123412341234\"}", "expected uint16"); @@ -440,7 +441,7 @@ static void test_configure_validation() { TEST_ASSERT_CONFIGURE_PASS(c, "{\"replaceLatestBlock\":255}"); TEST_ASSERT_CONFIGURE_PASS(c, "{\"replaceLatestBlock\":\"0xff\"}"); TEST_ASSERT_EQUAL(c->replace_latest_block, 255); - TEST_ASSERT_EQUAL(in3_node_props_get(c->node_props, NODE_PROP_MIN_BLOCK_HEIGHT), c->replace_latest_block); + TEST_ASSERT_EQUAL(in3_node_props_get(w->node_props, NODE_PROP_MIN_BLOCK_HEIGHT), c->replace_latest_block); TEST_ASSERT_CONFIGURE_FAIL("mismatched type: requestCount", c, "{\"requestCount\":\"-1\"}", "expected uint8"); TEST_ASSERT_CONFIGURE_FAIL("mismatched type: requestCount", c, "{\"requestCount\":\"0x123412341234\"}", "expected uint8"); @@ -450,7 +451,7 @@ static void test_configure_validation() { TEST_ASSERT_CONFIGURE_PASS(c, "{\"requestCount\":1}"); TEST_ASSERT_CONFIGURE_PASS(c, "{\"requestCount\":255}"); TEST_ASSERT_CONFIGURE_PASS(c, "{\"requestCount\":\"0xff\"}"); - TEST_ASSERT_EQUAL(c->request_count, 255); + TEST_ASSERT_EQUAL(w->request_count, 255); TEST_ASSERT_CONFIGURE_FAIL("mismatched type: rpc", c, "{\"rpc\":false}", "expected string"); TEST_ASSERT_CONFIGURE_FAIL("mismatched type: rpc", c, "{\"rpc\":\"0x123412341234\"}", "expected string"); @@ -458,8 +459,8 @@ static void test_configure_validation() { TEST_ASSERT_CONFIGURE_PASS(c, "{\"rpc\":\"rpc.local\"}"); TEST_ASSERT_EQUAL(c->proof, PROOF_NONE); TEST_ASSERT_EQUAL(c->chain.chain_id, CHAIN_ID_LOCAL); - TEST_ASSERT_EQUAL(c->request_count, 1); - TEST_ASSERT_EQUAL_STRING(in3_nodeselect_def_data(c)->nodelist[0].url, "rpc.local"); + TEST_ASSERT_EQUAL(w->request_count, 1); + TEST_ASSERT_EQUAL_STRING(w->data->nodelist[0].url, "rpc.local"); TEST_ASSERT_CONFIGURE_FAIL("mismatched type: nodeRegistry", c, "{\"nodeRegistry\":false}", "expected object"); TEST_ASSERT_CONFIGURE_FAIL("mismatched type: nodeRegistry", c, "{\"nodeRegistry\":\"0x123412341234\"}", "expected object"); @@ -697,7 +698,7 @@ static void test_parallel_signatures() { // we ask nd-1 and nd-5 for signatures of 3 nodes - nd-2, nd-3 & nd-4. // nd-1's response is missing a signature from nd-4, therefore we mark nd-4 as offline. // nd-5's response however has all 3 signatures, so we accept this response. - in3_ctx_t* ctx = in3_client_rpc_ctx_raw(in3, "{\"jsonrpc\":\"2.0\"," + in3_req_t* ctx = in3_client_rpc_ctx_raw(in3, "{\"jsonrpc\":\"2.0\"," "\"method\":\"eth_getTransactionByHash\"," "\"params\":[\"0x715ece6967d0dc6aa6e8e4ee83937d3d4a79fdc644b64f07aa72f877df156be7\"]," "\"in3\":{\"dataNodes\":[\"0x45d45e6ff99e6c34a235d263965910298985fcfe\", \"0xbcdf4e3e90cc7288b578329efd7bcc90655148d2\"]," @@ -713,7 +714,7 @@ static void test_parallel_signatures() { address = hex_to_new_bytes("c513a534de5a9d3f413152c41b09bd8116237fc8", 40); TEST_ASSERT_EQUAL_MEMORY(nl->offlines->offline->address, address->data, 20); b_free(address); - ctx_free(ctx); + req_free(ctx); ADD_RESPONSE_SIGS("[{" " \"blockHash\": \"0x3b1d2d185af8856ae03743b632ce1ed2c949e5d857870b7dae15f5b0601efff7\"," @@ -742,7 +743,7 @@ static void test_parallel_signatures() { nl = in3_nodeselect_def_data(in3); TEST_ASSERT_TRUE(is_blacklisted(&nl->nodelist[3])); TEST_ASSERT_NULL(nl->offlines); - ctx_free(ctx); + req_free(ctx); in3_free(in3); } @@ -846,7 +847,7 @@ static void test_sigs() { // we ask nd-1 and nd-5 for signatures of 3 nodes - nd-2, nd-3 & nd-4. // nd-1's response is missing a signature from nd-4, therefore we mark nd-4 as offline. // nd-5's response however has all 3 signatures, so we accept this response. - in3_ctx_t* ctx = in3_client_rpc_ctx_raw(in3, "{\"jsonrpc\":\"2.0\"," + in3_req_t* ctx = in3_client_rpc_ctx_raw(in3, "{\"jsonrpc\":\"2.0\"," "\"method\":\"eth_getTransactionByHash\"," "\"params\":[\"0x715ece6967d0dc6aa6e8e4ee83937d3d4a79fdc644b64f07aa72f877df156be7\"]," "\"in3\":{\"dataNodes\":[\"0x45d45e6ff99e6c34a235d263965910298985fcfe\", \"0xbcdf4e3e90cc7288b578329efd7bcc90655148d2\"]," @@ -862,7 +863,7 @@ static void test_sigs() { address = hex_to_new_bytes("c513a534de5a9d3f413152c41b09bd8116237fc8", 40); TEST_ASSERT_EQUAL_MEMORY(nl->offlines->offline->address, address->data, 20); b_free(address); - ctx_free(ctx); + req_free(ctx); ADD_RESPONSE_SIGS("[{" " \"blockHash\": \"0x3b1d2d185af8856ae03743b632ce1ed2c949e5d857870b7dae15f5b0601efff7\"," @@ -908,7 +909,7 @@ static void test_sigs() { nl = in3_nodeselect_def_data(in3); TEST_ASSERT_TRUE(is_blacklisted(&nl->nodelist[7])); - ctx_free(ctx); + req_free(ctx); in3_free(in3); } diff --git a/c/test/unit_tests/test_rpc_api.c b/c/test/unit_tests/test_rpc_api.c index 7f2d6e673..d9feb0372 100644 --- a/c/test/unit_tests/test_rpc_api.c +++ b/c/test/unit_tests/test_rpc_api.c @@ -40,16 +40,16 @@ #endif #include "../../src/api/eth1/abi.h" #include "../../src/api/eth1/eth_api.h" -#include "../../src/core/client/context_internal.h" #include "../../src/core/client/keys.h" +#include "../../src/core/client/request_internal.h" #include "../../src/core/util/bitset.h" #include "../../src/core/util/data.h" #include "../../src/core/util/log.h" #include "../../src/verifier/eth1/full/eth_full.h" #include "../test_utils.h" #include "../util/transport.h" -#include "nodeselect/nodelist.h" -#include "nodeselect/nodeselect_def.h" +#include "nodeselect/full/nodelist.h" +#include "nodeselect/full/nodeselect_def.h" #include #define err_string(msg) ("Error:" msg) @@ -61,8 +61,8 @@ static void test_in3_config() { c->proof = PROOF_NONE; c->signature_count = 0; register_transport(c, test_transport); - - in3_ctx_t* ctx = in3_client_rpc_ctx(c, "in3_config", "[{\ + in3_nodeselect_config_t* w = in3_get_nodelist(c); + in3_req_t* ctx = in3_client_rpc_ctx(c, "in3_config", "[{\ \"chainId\":7,\ \"autoUpdateList\":true,\ \"finality\":50,\ @@ -90,19 +90,19 @@ static void test_in3_config() { }]"); TEST_ASSERT_NULL(ctx->error); - TEST_ASSERT_EQUAL(1, d_get_intk(ctx->responses[0], K_RESULT)); - ctx_free(ctx); + TEST_ASSERT_EQUAL(1, d_get_int(ctx->responses[0], K_RESULT)); + req_free(ctx); TEST_ASSERT_EQUAL(7, c->chain.chain_id); TEST_ASSERT_EQUAL(FLAGS_AUTO_UPDATE_LIST, c->flags & FLAGS_AUTO_UPDATE_LIST); TEST_ASSERT_EQUAL(50, c->finality); TEST_ASSERT_EQUAL(FLAGS_INCLUDE_CODE, c->flags & FLAGS_INCLUDE_CODE); TEST_ASSERT_EQUAL(99, c->max_attempts); - TEST_ASSERT_EQUAL(96, c->min_deposit); + TEST_ASSERT_EQUAL(96, w->min_deposit); TEST_ASSERT_EQUAL(PROOF_FULL, c->proof); - TEST_ASSERT_EQUAL(95, c->node_limit); + TEST_ASSERT_EQUAL(95, w->node_limit); TEST_ASSERT_EQUAL(94, c->replace_latest_block); - TEST_ASSERT_EQUAL(93, c->request_count); + TEST_ASSERT_EQUAL(93, w->request_count); TEST_ASSERT_EQUAL(92, c->signature_count); TEST_ASSERT_EQUAL(FLAGS_KEEP_IN3, c->flags & FLAGS_KEEP_IN3); @@ -165,9 +165,9 @@ static void test_in3_client_rpc() { TEST_ASSERT_EQUAL(IN3_EINVAL, in3_client_rpc(c, "eth_blockNumber", "[]", NULL, NULL)); // Invalid calls to in3_client_rpc_ctx() - in3_ctx_t* ctx = in3_client_rpc_ctx(c, "eth_blockNumber", "[\"]"); + in3_req_t* ctx = in3_client_rpc_ctx(c, "eth_blockNumber", "[\"]"); TEST_ASSERT_NOT_NULL(ctx->error); - ctx_free(ctx); + req_free(ctx); // test in3_client_exec_req() with keep_in3 set to true c->flags |= FLAGS_KEEP_IN3; @@ -226,44 +226,44 @@ static void test_in3_checksum_rpc() { static void test_in3_client_context() { in3_t* c = in3_for_chain(CHAIN_ID_MAINNET); - in3_ctx_t* ctx = ctx_new(c, "[{\"id\":1,\"jsonrpc\":\"2.0\"," + in3_req_t* ctx = req_new(c, "[{\"id\":1,\"jsonrpc\":\"2.0\"," "\"method\":\"eth_getBlockByHash\"," "\"params\":[\"0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331\", false]," "\"in3\":{\"version\": \"" IN3_PROTO_VER "\",\"chainId\":\"0x1\"}}]"); - TEST_ASSERT_EQUAL(IN3_EINVAL, ctx_get_error(ctx, 1)); - TEST_ASSERT_EQUAL(IN3_ERPCNRES, ctx_get_error(ctx, 0)); + TEST_ASSERT_EQUAL(IN3_EINVAL, req_get_error(ctx, 1)); + TEST_ASSERT_EQUAL(IN3_ERPCNRES, req_get_error(ctx, 0)); // null maybe a valid result json_ctx_t* json = parse_json("{\"result\":null}"); ctx->responses = malloc(sizeof(d_token_t*)); ctx->responses[0] = json->result; - TEST_ASSERT_EQUAL(IN3_OK, ctx_get_error(ctx, 0)); + TEST_ASSERT_EQUAL(IN3_OK, req_get_error(ctx, 0)); json_free(json); // Test with error json = parse_json("{\"error\":\"Unknown\"}"); ctx->responses[0] = json->result; - TEST_ASSERT_EQUAL(IN3_EINVALDT, ctx_get_error(ctx, 0)); - // Test ctx_check_response_error() which internally also calls ctx_set_error() - TEST_ASSERT_EQUAL(IN3_ERPC, ctx_check_response_error(ctx, 0)); + TEST_ASSERT_EQUAL(IN3_EINVALDT, req_get_error(ctx, 0)); + // Test req_check_response_error() which internally also calls req_set_error() + TEST_ASSERT_EQUAL(IN3_ERPC, req_check_response_error(ctx, 0)); TEST_ASSERT_EQUAL_STRING("Unknown", ctx->error); json_free(json); // Test with error obj json = parse_json("{\"error\":{\"msg\":\"Unknown\",\"id\":\"0xf1\"}}"); ctx->responses[0] = json->result; - TEST_ASSERT_EQUAL(IN3_ERPC, ctx_check_response_error(ctx, 0)); + TEST_ASSERT_EQUAL(IN3_ERPC, req_check_response_error(ctx, 0)); TEST_ASSERT_EQUAL_STRING("{\"msg\":\"Unknown\",\"id\":\"0xf1\"}:Unknown", ctx->error); json_free(json); free(ctx->responses); ctx->responses = NULL; // Test getter/setter - TEST_ASSERT_EQUAL(IN3_ERPC, ctx_set_error(ctx, "RPC failure", IN3_ERPC)); - TEST_ASSERT_EQUAL(IN3_ERPC, ctx_get_error(ctx, 0)); + TEST_ASSERT_EQUAL(IN3_ERPC, req_set_error(ctx, "RPC failure", IN3_ERPC)); + TEST_ASSERT_EQUAL(IN3_ERPC, req_get_error(ctx, 0)); TEST_ASSERT_EQUAL_STRING("RPC failure:{\"msg\":\"Unknown\",\"id\":\"0xf1\"}:Unknown", ctx->error); - ctx_free(ctx); + req_free(ctx); in3_free(c); } diff --git a/c/test/unit_tests/test_sign.c b/c/test/unit_tests/test_sign.c index d9afcee41..c98fc5317 100644 --- a/c/test/unit_tests/test_sign.c +++ b/c/test/unit_tests/test_sign.c @@ -41,8 +41,8 @@ #include "../../include/in3/error.h" #include "../../src/api/eth1/eth_api.h" -#include "../../src/core/client/context.h" #include "../../src/core/client/keys.h" +#include "../../src/core/client/request.h" #include "../../src/core/util/bytes.h" #include "../../src/core/util/data.h" #include "../../src/core/util/log.h" @@ -50,8 +50,8 @@ #include "../../src/core/util/scache.h" #include "../../src/verifier/eth1/full/eth_full.h" #include "../../src/verifier/eth1/nano/eth_nano.h" -#include "nodeselect/cache.h" -#include "nodeselect/nodelist.h" +#include "nodeselect/full/cache.h" +#include "nodeselect/full/nodelist.h" #include "../../src/signer/pk-signer/signer.h" #include "../../src/third-party/crypto/ecdsa.h" @@ -59,7 +59,7 @@ #include "../../src/verifier/eth1/basic/eth_basic.h" #include "../test_utils.h" #include "../util/transport.h" -#include +#include #include #include #define ETH_PRIVATE_KEY "0x8da4ef21b864d2cc526dbdb2a120bd2874c36c9d0a1fb7f8c63d7f7a8b41de8f" @@ -78,10 +78,10 @@ static void test_sign() { add_response("eth_gasPrice", "[]", "\"0xffff\"", NULL, NULL); add_response("eth_getTransactionCount", "[\"0xb91bd1b8624d7a0a13f1f6ccb1ae3f254d3888ba\",\"latest\"]", "\"0x1\"", NULL, NULL); - in3_ctx_t* ctx = in3_client_rpc_ctx(c, "eth_sendTransaction", "[{\"to\":\"0x45d45e6ff99e6c34a235d263965910298985fcfe\", \"value\":\"0xff\" }]"); - TEST_ASSERT_EQUAL(IN3_OK, ctx_check_response_error(ctx, 0)); - TEST_ASSERT_TRUE(ctx && ctx_get_error(ctx, 0) == IN3_OK); - ctx_free(ctx); + in3_req_t* ctx = in3_client_rpc_ctx(c, "eth_sendTransaction", "[{\"to\":\"0x45d45e6ff99e6c34a235d263965910298985fcfe\", \"value\":\"0xff\" }]"); + TEST_ASSERT_EQUAL(IN3_OK, req_check_response_error(ctx, 0)); + TEST_ASSERT_TRUE(ctx && req_get_error(ctx, 0) == IN3_OK); + req_free(ctx); in3_free(c); } @@ -143,18 +143,18 @@ static void test_sign_hex() { add_response("eth_gasPrice", "[]", "\"0xffff\"", NULL, NULL); add_response("eth_getTransactionCount", "[\"0xb91bd1b8624d7a0a13f1f6ccb1ae3f254d3888ba\",\"latest\"]", "\"0x1\"", NULL, NULL); - in3_ctx_t* ctx = in3_client_rpc_ctx(c, "eth_sendTransaction", "[{\"to\":\"0x45d45e6ff99e6c34a235d263965910298985fcfe\", \"value\":\"0xff\" }]"); - TEST_ASSERT_EQUAL(IN3_OK, ctx_check_response_error(ctx, 0)); - TEST_ASSERT_TRUE(ctx && ctx_get_error(ctx, 0) == IN3_OK); - ctx_free(ctx); + in3_req_t* ctx = in3_client_rpc_ctx(c, "eth_sendTransaction", "[{\"to\":\"0x45d45e6ff99e6c34a235d263965910298985fcfe\", \"value\":\"0xff\" }]"); + TEST_ASSERT_EQUAL(IN3_OK, req_check_response_error(ctx, 0)); + TEST_ASSERT_TRUE(ctx && req_get_error(ctx, 0) == IN3_OK); + req_free(ctx); in3_free(c); } static void test_sign_sans_signer_and_from() { in3_t* c = in3_for_chain(CHAIN_ID_MAINNET); - in3_ctx_t* ctx = in3_client_rpc_ctx(c, "eth_sendTransaction", "[{\"to\":\"0x45d45e6ff99e6c34a235d263965910298985fcfe\", \"value\":\"0xff\" }]"); + in3_req_t* ctx = in3_client_rpc_ctx(c, "eth_sendTransaction", "[{\"to\":\"0x45d45e6ff99e6c34a235d263965910298985fcfe\", \"value\":\"0xff\" }]"); TEST_ASSERT_NOT_NULL(ctx->error); - ctx_free(ctx); + req_free(ctx); in3_free(c); } @@ -163,11 +163,11 @@ static void test_signer() { bytes32_t pk; hex_to_bytes("0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8", -1, pk, 32); eth_set_pk_signer(c, pk); - in3_ctx_t* ctx = ctx_new(c, "{\"method\":\"eth_getBlockByNumber\",\"params\":[\"latest\",false]}"); + in3_req_t* ctx = req_new(c, "{\"method\":\"eth_getBlockByNumber\",\"params\":[\"latest\",false]}"); char* data_str = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"; bytes_t* data = hex_to_new_bytes(data_str, strlen(data_str)); in3_sign_ctx_t sc = {0}; - sc.ctx = ctx; + sc.req = ctx; sc.message = *data; sc.type = SIGN_EC_RAW; sc.account = bytes(NULL, 0); @@ -175,12 +175,12 @@ static void test_signer() { TEST_ASSERT_FALSE(memiszero(sc.signature.data, 65)); _free(sc.signature.data); b_free(data); - ctx_free(ctx); + req_free(ctx); in3_free(c); } static in3_ret_t prep_tx(void* ctx, d_token_t* old_tx, json_ctx_t** new_tx) { - if (d_get_int(old_tx, "success")) { + if (d_get_int(old_tx, key("success"))) { *new_tx = parse_json("{\"from\": \"0xb60e8dd61c5d32be8058bb8eb970870f07233155\"," "\"to\": \"0xd46e8dd67c5d32be8058bb8eb970870f07244567\"," "\"gas\": \"0x76c0\"," @@ -201,27 +201,27 @@ static void test_signer_prepare_tx() { eth_set_pk_signer(c, pk); // prepare request - in3_ctx_t* ctx = ctx_new(c, "{\"method\":\"eth_getBlockByNumber\",\"params\":[\"latest\",false]}"); + in3_req_t* ctx = req_new(c, "{\"method\":\"eth_getBlockByNumber\",\"params\":[\"latest\",false]}"); c->signer->prepare_tx = prep_tx; json_ctx_t* jtx = parse_json("{\"success\":false}"); bytes_t raw_tx = sign_tx(jtx->result, ctx); TEST_ASSERT_FALSE(raw_tx.data && raw_tx.len); - TEST_ASSERT_NOT_EQUAL(IN3_OK, ctx_get_error(ctx, 0)); + TEST_ASSERT_NOT_EQUAL(IN3_OK, req_get_error(ctx, 0)); json_free(jtx); - ctx_free(ctx); + req_free(ctx); - ctx = ctx_new(c, "{\"method\":\"eth_getBlockByNumber\",\"params\":[\"latest\",false]}"); + ctx = req_new(c, "{\"method\":\"eth_getBlockByNumber\",\"params\":[\"latest\",false]}"); jtx = parse_json("{\"success\":true}"); raw_tx = sign_tx(jtx->result, ctx); - TEST_ASSERT_TRUE(ctx->type == CT_RPC && ctx->verification_state == IN3_WAITING && ctx->required); - TEST_ASSERT_EQUAL(IN3_OK, in3_send_ctx(ctx->required)); + TEST_ASSERT_TRUE(ctx->type == RT_RPC && ctx->verification_state == IN3_WAITING && ctx->required); + TEST_ASSERT_EQUAL(IN3_OK, in3_send_req(ctx->required)); raw_tx = sign_tx(jtx->result, ctx); TEST_ASSERT_NOT_NULL(raw_tx.data); - TEST_ASSERT_NOT_EQUAL(IN3_OK, ctx_get_error(ctx, 0)); + TEST_ASSERT_NOT_EQUAL(IN3_OK, req_get_error(ctx, 0)); _free(raw_tx.data); - ctx_free(ctx); + req_free(ctx); json_free(jtx); in3_free(c); } diff --git a/c/test/util/transport.c b/c/test/util/transport.c index a063c4454..c491d6fa4 100644 --- a/c/test/util/transport.c +++ b/c/test/util/transport.c @@ -1,8 +1,9 @@ #include "transport.h" +#include "../../src/core/client/keys.h" #include "../../src/core/util/data.h" #include "../test_utils.h" -#include "nodeselect/cache.h" -#include "nodeselect/nodelist.h" +#include "nodeselect/full/cache.h" +#include "nodeselect/full/nodelist.h" #include #include #define MOCK_PATH "../c/test/testdata/mock/%s.json" @@ -117,7 +118,7 @@ int add_response_test(char* test, char* needed_params) { clean_json_str(params); response_buffer = _calloc(1, sizeof(response_t)); - response_buffer->request_method = _strdupn(d_get_stringk(req, key("method")), -1); + response_buffer->request_method = _strdupn(d_get_string(req, key("method")), -1); response_buffer->request_params = params; response_buffer->response = _strdupn(res.data, res.len); } @@ -130,12 +131,12 @@ in3_ret_t test_transport(void* plugin_data, in3_plugin_act_t action, void* plugi UNUSED_VAR(plugin_data); UNUSED_VAR(action); - in3_request_t* req = plugin_ctx; + in3_http_request_t* req = plugin_ctx; TEST_ASSERT_NOT_NULL_MESSAGE(responses, "no request registered"); json_ctx_t* r = parse_json(req->payload); TEST_ASSERT_NOT_NULL_MESSAGE(r, "payload not parseable"); d_token_t* request = d_type(r->result) == T_ARRAY ? r->result + 1 : r->result; - char* method = d_get_string(request, "method"); + char* method = d_get_string(request, K_METHOD); str_range_t params = d_to_json(d_get(request, key("params"))); char* p = alloca(params.len + 1); strncpy(p, params.data, params.len); @@ -146,7 +147,7 @@ in3_ret_t test_transport(void* plugin_data, in3_plugin_act_t action, void* plugi for (int i = 0; i < req->urls_len; ++i) { TEST_ASSERT_EQUAL_STRING(resp->request_method, method); TEST_ASSERT_EQUAL_STRING(resp->request_params, p); - in3_ctx_add_response(req->ctx, i, false, resp->response, -1, 0); + in3_ctx_add_response(req->req, i, false, resp->response, -1, 0); _free(resp->response); responses = resp->next; _free(resp); @@ -161,14 +162,14 @@ in3_ret_t mock_transport(void* plugin_data, in3_plugin_act_t action, void* plugi UNUSED_VAR(plugin_data); UNUSED_VAR(action); - in3_request_t* req = plugin_ctx; - json_ctx_t* r = parse_json(req->payload); - d_token_t* request = d_type(r->result) == T_ARRAY ? r->result + 1 : r->result; - char* method = d_get_string(request, "method"); - str_range_t params = d_to_json(d_get(request, key("params"))); - char* p = alloca(params.len + 1); - sb_t* filename = sb_new(method); - for (d_iterator_t iter = d_iter(d_get(request, key("params"))); iter.left; d_iter_next(&iter)) { + in3_http_request_t* req = plugin_ctx; + json_ctx_t* r = parse_json(req->payload); + d_token_t* request = d_type(r->result) == T_ARRAY ? r->result + 1 : r->result; + char* method = d_get_string(request, K_METHOD); + str_range_t params = d_to_json(d_get(request, K_PARAMS)); + char* p = alloca(params.len + 1); + sb_t* filename = sb_new(method); + for (d_iterator_t iter = d_iter(d_get(request, K_PARAMS)); iter.left; d_iter_next(&iter)) { switch (d_type(iter.token)) { case T_BOOLEAN: case T_INTEGER: @@ -199,8 +200,8 @@ in3_ret_t mock_transport(void* plugin_data, in3_plugin_act_t action, void* plugi TEST_ASSERT_EQUAL_STRING(response_buffer->request_params, p); json_free(r); - sb_add_chars(&req->ctx->raw_response->data, response_buffer->response); - req->ctx->raw_response->state = IN3_OK; + sb_add_chars(&req->req->raw_response->data, response_buffer->response); + req->req->raw_response->state = IN3_OK; clean_last_response(); return IN3_OK; } diff --git a/c/test/vm_runner.c b/c/test/vm_runner.c index b990c328d..58319f89c 100644 --- a/c/test/vm_runner.c +++ b/c/test/vm_runner.c @@ -36,8 +36,8 @@ #define TEST #endif #include "vm_runner.h" -#include "../src/core/client/context.h" #include "../src/core/client/keys.h" +#include "../src/core/client/request.h" #include "../src/core/util/data.h" #include "../src/core/util/log.h" #include "../src/core/util/mem.h" @@ -134,12 +134,12 @@ int run_test(json_ctx_t* jc, d_token_t* test, int counter, char* name, uint32_t } if (!fail) print_success("OK"); - in3_log_debug(" ( heap: %zu, %" PRIu64 " ms) ", mem_get_max_heap(), ms); + in3_log_debug(" ( %" PRIu64 " ms) ", ms); return fail; } -int runRequests(char** names, int test_index, int mem_track, uint32_t props) { +int runRequests(char** names, int test_index, uint32_t props) { int res = 0, n = 0; char* name = names[n]; int failed = 0, total = 0, count = 0; @@ -168,7 +168,7 @@ int runRequests(char** names, int test_index, int mem_track, uint32_t props) { count++; if (test_index < 0 || count == test_index) { total++; - mem_reset(mem_track); + mem_reset(); if (run_test(parsed, test, count, name, props)) failed++; } } @@ -191,7 +191,7 @@ int runRequests(char** names, int test_index, int mem_track, uint32_t props) { int main(int argc, char* argv[]) { int i = 0, size = 1; - int testIndex = -1, membrk = -1; + int testIndex = -1; char** names = malloc(sizeof(char*)); names[0] = NULL; uint32_t props = 0; @@ -214,8 +214,6 @@ int main(int argc, char* argv[]) { for (i = 1; i < argc; i++) { if (strcmp(argv[i], "-t") == 0) testIndex = atoi(argv[++i]); - else if (strcmp(argv[i], "-m") == 0) - membrk = atoi(argv[++i]); else if (strcmp(argv[i], "-d") == 0) in3_log_set_level(LOG_TRACE); else if (strcmp(argv[i], "-c") == 0) @@ -235,7 +233,7 @@ int main(int argc, char* argv[]) { } } - int ret = runRequests(names, testIndex, membrk, props); + int ret = runRequests(names, testIndex, props); free(names); return ret; } \ No newline at end of file diff --git a/dotnet/Examples/README.md b/dotnet/Examples/README.md index b2ee451ff..cfc259842 100644 --- a/dotnet/Examples/README.md +++ b/dotnet/Examples/README.md @@ -64,7 +64,7 @@ namespace ConnectToEthereum Console.Out.WriteLine($"Latest Block Number: {mainnetLatest}"); Console.Out.WriteLine($"Gas Price: {mainnetCurrentGasPrice} Wei"); - Console.Out.WriteLine("Ethereum Ewc Test Network"); + Console.Out.WriteLine("Ethereum EWC Network"); IN3 ewcClient = IN3.ForChain(Chain.Ewc); BigInteger ewcLatest = await ewcClient.Eth1.BlockNumber(); BigInteger ewcCurrentGasPrice = await ewcClient.Eth1.GetGasPrice(); diff --git a/dotnet/In3/Configuration/ClientConfiguration.cs b/dotnet/In3/Configuration/ClientConfiguration.cs index 523771886..c0383b955 100644 --- a/dotnet/In3/Configuration/ClientConfiguration.cs +++ b/dotnet/In3/Configuration/ClientConfiguration.cs @@ -132,6 +132,17 @@ public bool UseHttp set => SetState("useHttp", value); } + /// + /// allow experimental features to be used. + /// + /// If the client will not throw Excewptions, if a experimental feature is used. + [JsonPropertyName("experimental")] + public bool Experimental + { + get => (bool)GetState("experimental"); + set => SetState("experimental", value); + } + /// /// Milliseconds before a request times out. /// diff --git a/dotnet/In3/Context/Context.cs b/dotnet/In3/Context/Context.cs index 12e51f952..58ab0f203 100644 --- a/dotnet/In3/Context/Context.cs +++ b/dotnet/In3/Context/Context.cs @@ -47,23 +47,23 @@ public static Context FromRpc(NativeClient wrapper, string rpc) private static IntPtr CreateNativeCtx(IntPtr nativeIn3Ptr, string rpc) { IntPtr rpcPtr = Marshal.StringToHGlobalAnsi(rpc); - IntPtr context = ctx_new(nativeIn3Ptr, rpcPtr); - string err = ctx_get_error_data(context); + IntPtr context = req_new(nativeIn3Ptr, rpcPtr); + string err = req_get_error_data(context); if (!String.IsNullOrEmpty(err)) { - ctx_free(context); + req_free(context); throw new ContextException(err); } return context; } /// - /// Proxy to in3_ctx_execute, every invocation generates a new state. + /// Proxy to in3_req_execute, every invocation generates a new state. /// - /// The state as computed by in3_ctx_execute. + /// The state as computed by in3_req_execute. public async Task Execute() { - return await new StateMachine(in3_ctx_exec_state(this._nativeCtx)) + return await new StateMachine(in3_req_exec_state(this._nativeCtx)) .HandleChange(this); } @@ -73,7 +73,7 @@ public async Task Execute() /// A context object. public Context GetLastWaiting() { - return new Context(in3_ctx_last_waiting(_nativeCtx), _wrapper); + return new Context(in3_req_last_waiting(_nativeCtx), _wrapper); } @@ -92,7 +92,7 @@ public bool IsValid() /// The final result. public string GetResponse() { - IntPtr rspPtr = ctx_get_response_data(_nativeCtx); + IntPtr rspPtr = req_get_response_data(_nativeCtx); string msg = Marshal.PtrToStringUTF8(rspPtr); // This needs to be freed since it is a copy of the response context. Native.Utils._free_(rspPtr); @@ -106,7 +106,7 @@ public string GetResponse() /// The final result. public new CtxType GetType() { - uint type = ctx_get_type(_nativeCtx); + uint type = req_get_type(_nativeCtx); return (CtxType)type; } @@ -115,7 +115,7 @@ public string GetResponse() /// public void Dispose() { - ctx_free(_nativeCtx); + req_free(_nativeCtx); } /// @@ -140,7 +140,7 @@ public async Task HandleSign() public void ReportError(string errorMessage) { IntPtr rpcPtr = Marshal.StringToHGlobalAnsi(errorMessage); - ctx_set_error_intern(_nativeCtx, rpcPtr, (int)In3Code.IN3_ERPC); + req_set_error_intern(_nativeCtx, rpcPtr, (int)In3Code.IN3_ERPC); // This needs to be freed since our pointer is copied into the context by the function and needs to be freed this way else it will lead to Heap Corruption and its platform independent. Marshal.FreeHGlobal(rpcPtr); } @@ -151,22 +151,22 @@ public void ReportError(string errorMessage) /// A string describing the encountered error. public string GetErrorMessage() { - IntPtr msgPtr = ctx_get_error_rpc(_nativeCtx, 0); + IntPtr msgPtr = req_get_error_rpc(_nativeCtx, 0); string msg = Marshal.PtrToStringUTF8(msgPtr); // This needs to be freed since it is a copy of the error context. Native.Utils._free_(msgPtr); return msg; } - [DllImport("libin3", CharSet = CharSet.Ansi)] private static extern IntPtr ctx_get_error_rpc(IntPtr ctx, int ret); - [DllImport("libin3", CharSet = CharSet.Ansi)] private static extern void ctx_set_error_intern(IntPtr ctx, IntPtr message, int errnumber); - [DllImport("libin3", CharSet = CharSet.Ansi)] private static extern uint ctx_get_type(IntPtr ctx); - [DllImport("libin3", CharSet = CharSet.Ansi)] private static extern IntPtr ctx_new(IntPtr client, IntPtr req_data); - [DllImport("libin3", CharSet = CharSet.Ansi)] private static extern string ctx_get_error_data(IntPtr ctx); - [DllImport("libin3", CharSet = CharSet.Ansi)] private static extern void ctx_free(IntPtr ctx); - [DllImport("libin3", CharSet = CharSet.Ansi)] private static extern int in3_ctx_exec_state(IntPtr ctx); - [DllImport("libin3", CharSet = CharSet.Ansi)] private static extern IntPtr in3_ctx_last_waiting(IntPtr ctx); - [DllImport("libin3", CharSet = CharSet.Ansi)] private static extern IntPtr ctx_get_response_data(IntPtr ctx); + [DllImport("libin3", CharSet = CharSet.Ansi)] private static extern IntPtr req_get_error_rpc(IntPtr ctx, int ret); + [DllImport("libin3", CharSet = CharSet.Ansi)] private static extern void req_set_error_intern(IntPtr ctx, IntPtr message, int errnumber); + [DllImport("libin3", CharSet = CharSet.Ansi)] private static extern uint req_get_type(IntPtr ctx); + [DllImport("libin3", CharSet = CharSet.Ansi)] private static extern IntPtr req_new(IntPtr client, IntPtr req_data); + [DllImport("libin3", CharSet = CharSet.Ansi)] private static extern string req_get_error_data(IntPtr ctx); + [DllImport("libin3", CharSet = CharSet.Ansi)] private static extern void req_free(IntPtr ctx); + [DllImport("libin3", CharSet = CharSet.Ansi)] private static extern int in3_req_exec_state(IntPtr ctx); + [DllImport("libin3", CharSet = CharSet.Ansi)] private static extern IntPtr in3_req_last_waiting(IntPtr ctx); + [DllImport("libin3", CharSet = CharSet.Ansi)] private static extern IntPtr req_get_response_data(IntPtr ctx); } } \ No newline at end of file diff --git a/dotnet/In3/Context/ContextState.cs b/dotnet/In3/Context/ContextState.cs index b7f041951..6070f28d6 100644 --- a/dotnet/In3/Context/ContextState.cs +++ b/dotnet/In3/Context/ContextState.cs @@ -1,9 +1,9 @@ internal enum ContextState { - CTX_SUCCESS = 0, - CTX_WAITING_TO_SEND = 1, - CTX_WAITING_FOR_RESPONSE = 2, - CTX_ERROR = -1, + REQ_SUCCESS = 0, + REQ_WAITING_TO_SEND = 1, + REQ_WAITING_FOR_RESPONSE = 2, + REQ_ERROR = -1, } diff --git a/dotnet/In3/Context/State/StateMachine.cs b/dotnet/In3/Context/State/StateMachine.cs index 0a4a7c9a2..7282e8652 100644 --- a/dotnet/In3/Context/State/StateMachine.cs +++ b/dotnet/In3/Context/State/StateMachine.cs @@ -11,12 +11,12 @@ public StateMachine(int code) { Dictionary actions = new Dictionary { - {ContextState.CTX_SUCCESS, new OkState()}, - {ContextState.CTX_WAITING_TO_SEND, new WaitingState()}, - // TODO as long as we fetch all responses (as we do now), CTX_WAITING_FOR_RESPONSE will never happen. + {ContextState.REQ_SUCCESS, new OkState()}, + {ContextState.REQ_WAITING_TO_SEND, new WaitingState()}, + // TODO as long as we fetch all responses (as we do now), REQ_WAITING_FOR_RESPONSE will never happen. // so we might be able to skip it for now -// {ContextState.CTX_WAITING_FOR_RESPONSE, new WaitingState()}, - {ContextState.CTX_ERROR, new ErrorState()} +// {ContextState.REQ_WAITING_FOR_RESPONSE, new WaitingState()}, + {ContextState.REQ_ERROR, new ErrorState()} }; _state = actions[(ContextState)code]; diff --git a/dotnet/In3/Native/AsyncRequestHandler.cs b/dotnet/In3/Native/AsyncRequestHandler.cs index e3efb5b04..8dd06f79a 100644 --- a/dotnet/In3/Native/AsyncRequestHandler.cs +++ b/dotnet/In3/Native/AsyncRequestHandler.cs @@ -19,16 +19,22 @@ public async Task Handle(IntPtr ctx) { IntPtr reqPtr = in3_create_request(ctx); int urlsLength = in3_get_request_urls_len(reqPtr); + int payloadLength = in3_get_request_payload_len(reqPtr); // This is marshaled in a non-declarative way to prevent double freeing of the string (sometimes necessary when the string is declared as a char*). - string payload = Marshal.PtrToStringAnsi(in3_get_request_payload(reqPtr)); + byte[] payload = new byte[payloadLength]; + Marshal.Copy(in3_get_request_payload(reqPtr), payload, 0, payloadLength); + string method = Marshal.PtrToStringAnsi(in3_get_request_method(reqPtr)); string[] urls = Utils.GetAllStrings(in3_get_request_urls(reqPtr), urlsLength); + string[] headers = new string[in3_get_request_headers_len(reqPtr)]; + for (int i=0;i requestsTasks = urls.Select(async (url, i) => { try { - string result = await NativeClient.Client.Transport.Handle(urls[i], payload); + string result = await NativeClient.Client.Transport.Handle(method, urls[i], payload, headers); // This is freed here (by the declartive marshall) and it works because internally this is an sb_add which copies the string (same with error). in3_req_add_response(reqPtr, i, false, result, result.Length,0); } @@ -42,9 +48,13 @@ public async Task Handle(IntPtr ctx) request_free(reqPtr, NativeClient.Pointer, false); } + [DllImport("libin3", CharSet = CharSet.Ansi)] private static extern IntPtr in3_get_request_method(IntPtr request); [DllImport("libin3", CharSet = CharSet.Ansi)] private static extern IntPtr in3_get_request_payload(IntPtr request); + [DllImport("libin3", CharSet = CharSet.Ansi)] private static extern int in3_get_request_payload_len(IntPtr request); [DllImport("libin3", CharSet = CharSet.Ansi)] private static extern IntPtr in3_get_request_urls(IntPtr request); [DllImport("libin3", CharSet = CharSet.Ansi)] private static extern int in3_get_request_urls_len(IntPtr request); + [DllImport("libin3", CharSet = CharSet.Ansi)] private static extern int in3_get_request_headers_len(IntPtr request); + [DllImport("libin3", CharSet = CharSet.Ansi)] private static extern IntPtr in3_get_request_headers_at(IntPtr request, int index); [DllImport("libin3", CharSet = CharSet.Ansi)] private static extern void in3_req_add_response(IntPtr req, int index, bool is_error, string data, int data_len, int time); [DllImport("libin3", CharSet = CharSet.Ansi)] private static extern void request_free(IntPtr req, IntPtr ctx, bool free_response); [DllImport("libin3", CharSet = CharSet.Ansi)] private static extern IntPtr in3_create_request(IntPtr ctx); diff --git a/dotnet/In3/Transport/DefaultTransport.cs b/dotnet/In3/Transport/DefaultTransport.cs index b380eafab..1d87e01cc 100644 --- a/dotnet/In3/Transport/DefaultTransport.cs +++ b/dotnet/In3/Transport/DefaultTransport.cs @@ -27,18 +27,19 @@ public DefaultTransport() /// The url of the node. /// Json for the body of the POST request to the node. /// The http json response. - public async Task Handle(string url, string payload) + public async Task Handle(string method, string url, byte[] payload, string[] headers) { var httpWebRequest = (HttpWebRequest)WebRequest.Create(url); httpWebRequest.ContentType = "application/json"; - httpWebRequest.Method = "POST"; + httpWebRequest.Method = method; ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls13 | SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls; + foreach (var header in headers) httpWebRequest.Headers.Add(header); - using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream())) + using (var stream = httpWebRequest.GetRequestStream()) { - streamWriter.Write(payload); - streamWriter.Flush(); - streamWriter.Close(); + stream.Write(payload,0,payload.Length); + stream.Flush(); + stream.Close(); } var httpResponse = (HttpWebResponse) await httpWebRequest.GetResponseAsync(); diff --git a/dotnet/In3/Transport/Transport.cs b/dotnet/In3/Transport/Transport.cs index 412a3c83b..0d722c0d6 100644 --- a/dotnet/In3/Transport/Transport.cs +++ b/dotnet/In3/Transport/Transport.cs @@ -13,6 +13,6 @@ public interface Transport /// Url of the node. /// Content for the RPC request. /// The rpc response. - public Task Handle(string url, string payload); + public Task Handle(string method, string url, byte[] payload, string[] headers); } } \ No newline at end of file diff --git a/dotnet/Test/ProoflessClientFactory.cs b/dotnet/Test/ProoflessClientFactory.cs index 0bb4f8966..643a49216 100644 --- a/dotnet/Test/ProoflessClientFactory.cs +++ b/dotnet/Test/ProoflessClientFactory.cs @@ -23,6 +23,7 @@ protected override void CreateConfig() clientConfig.Proof = Proof.None; clientConfig.MaxAttempts = 10; clientConfig.SignatureCount = 0; + clientConfig.Experimental = true; } } } \ No newline at end of file diff --git a/dotnet/Test/StandardProofClientFactory.cs b/dotnet/Test/StandardProofClientFactory.cs index e9852a2b1..436476c64 100644 --- a/dotnet/Test/StandardProofClientFactory.cs +++ b/dotnet/Test/StandardProofClientFactory.cs @@ -23,6 +23,7 @@ protected override void CreateConfig() clientConfig.Proof = Proof.Standard; clientConfig.MaxAttempts = 10; clientConfig.SignatureCount = 0; + clientConfig.Experimental = true; } } } \ No newline at end of file diff --git a/dotnet/Test/StubTransport.cs b/dotnet/Test/StubTransport.cs index d7dfde462..6b437f106 100644 --- a/dotnet/Test/StubTransport.cs +++ b/dotnet/Test/StubTransport.cs @@ -17,9 +17,9 @@ public StubTransport() Responses = new Dictionary(); } - public Task Handle(string url, string payload) + public Task Handle(string method,string url, byte[] payload, string[] headers) { - return Task.Run(() => Responses[GetMethod(payload)]); + return Task.Run(() => Responses[GetMethod(System.Text.Encoding.UTF8.GetString(payload))]); } public void AddMockedresponse(string methodName, string filename) diff --git a/dotnet/docs/api-dotnet.md b/dotnet/docs/api-dotnet.md index d4fbeadd1..823d3f935 100644 --- a/dotnet/docs/api-dotnet.md +++ b/dotnet/docs/api-dotnet.md @@ -2110,11 +2110,11 @@ This method has no parameters. #### Execute() `method` -Proxy to in3_ctx_execute, every invocation generates a new state. +Proxy to in3_req_execute, every invocation generates a new state. ###### Returns -The state as computed by in3_ctx_execute. +The state as computed by in3_req_execute. ###### Parameters diff --git a/dotnet/docs/examples.md b/dotnet/docs/examples.md index a8659324d..eba20e86d 100644 --- a/dotnet/docs/examples.md +++ b/dotnet/docs/examples.md @@ -4,6 +4,8 @@ source : [in3-c/dotnet/Examples/CallSmartContractFunction//CallSmartContractFunction](https://github.com/blockchainsllc/in3/blob/master/dotnet/Examples/CallSmartContractFunction//CallSmartContractFunction/Program.cs) + + ```c# using System; using System.Numerics; @@ -59,40 +61,42 @@ namespace CallSmartContractFunction source : [in3-c/dotnet/Examples/ConnectToEthereum//ConnectToEthereum](https://github.com/blockchainsllc/in3/blob/master/dotnet/Examples/ConnectToEthereum//ConnectToEthereum/Program.cs) -```c# -using System; -using System.Numerics; -using System.Threading.Tasks; -using In3; -namespace ConnectToEthereum -{ - class Program - { - static async Task Main() - { - Console.Out.WriteLine("Ethereum Main Network"); - IN3 mainnetClient = IN3.ForChain(Chain.Mainnet); - BigInteger mainnetLatest = await mainnetClient.Eth1.BlockNumber(); - BigInteger mainnetCurrentGasPrice = await mainnetClient.Eth1.GetGasPrice(); - Console.Out.WriteLine($"Latest Block Number: {mainnetLatest}"); - Console.Out.WriteLine($"Gas Price: {mainnetCurrentGasPrice} Wei"); - - Console.Out.WriteLine("Ethereum Ewc Test Network"); - IN3 ewcClient = IN3.ForChain(Chain.Ewc); - BigInteger ewcLatest = await ewcClient.Eth1.BlockNumber(); - BigInteger ewcCurrentGasPrice = await ewcClient.Eth1.GetGasPrice(); - Console.Out.WriteLine($"Latest Block Number: {ewcLatest}"); - Console.Out.WriteLine($"Gas Price: {ewcCurrentGasPrice} Wei"); - - Console.Out.WriteLine("Ethereum Goerli Test Network"); - IN3 goerliClient = IN3.ForChain(Chain.Goerli); - BigInteger goerliLatest = await goerliClient.Eth1.BlockNumber(); - BigInteger clientCurrentGasPrice = await goerliClient.Eth1.GetGasPrice(); - Console.Out.WriteLine($"Latest Block Number: {goerliLatest}"); - Console.Out.WriteLine($"Gas Price: {clientCurrentGasPrice} Wei"); - } - } + +```c# +using System; +using System.Numerics; +using System.Threading.Tasks; +using In3; + +namespace ConnectToEthereum +{ + class Program + { + static async Task Main() + { + Console.Out.WriteLine("Ethereum Main Network"); + IN3 mainnetClient = IN3.ForChain(Chain.Mainnet); + BigInteger mainnetLatest = await mainnetClient.Eth1.BlockNumber(); + BigInteger mainnetCurrentGasPrice = await mainnetClient.Eth1.GetGasPrice(); + Console.Out.WriteLine($"Latest Block Number: {mainnetLatest}"); + Console.Out.WriteLine($"Gas Price: {mainnetCurrentGasPrice} Wei"); + + Console.Out.WriteLine("Ethereum EWC Network"); + IN3 ewcClient = IN3.ForChain(Chain.Ewc); + BigInteger ewcLatest = await ewcClient.Eth1.BlockNumber(); + BigInteger ewcCurrentGasPrice = await ewcClient.Eth1.GetGasPrice(); + Console.Out.WriteLine($"Latest Block Number: {ewcLatest}"); + Console.Out.WriteLine($"Gas Price: {ewcCurrentGasPrice} Wei"); + + Console.Out.WriteLine("Ethereum Goerli Test Network"); + IN3 goerliClient = IN3.ForChain(Chain.Goerli); + BigInteger goerliLatest = await goerliClient.Eth1.BlockNumber(); + BigInteger clientCurrentGasPrice = await goerliClient.Eth1.GetGasPrice(); + Console.Out.WriteLine($"Latest Block Number: {goerliLatest}"); + Console.Out.WriteLine($"Gas Price: {clientCurrentGasPrice} Wei"); + } + } } ``` @@ -100,6 +104,8 @@ namespace ConnectToEthereum source : [in3-c/dotnet/Examples/EnsResolver//EnsResolver](https://github.com/blockchainsllc/in3/blob/master/dotnet/Examples/EnsResolver//EnsResolver/Program.cs) + + ```c# using System; using System.Threading.Tasks; @@ -127,34 +133,36 @@ namespace EnsResolver source : [in3-c/dotnet/Examples/Ipfs//Ipfs](https://github.com/blockchainsllc/in3/blob/master/dotnet/Examples/Ipfs//Ipfs/Program.cs) -```c# -using System; -using System.Text; -using System.Threading.Tasks; -using In3; - -namespace Ipfs -{ - class Program - { - static async Task Main() - { - // Content to be stored - string toStore = "LOREM_IPSUM"; - - // Connect to ipfs. - IN3 ipfsClient = IN3.ForChain(Chain.Ipfs); - // Store the hash since it will be needed to fetch the content back. - string hash = await ipfsClient.Ipfs.Put(toStore); - // - byte[] storedBytes = await ipfsClient.Ipfs.Get(hash); - string storedStging = Encoding.UTF8.GetString(storedBytes, 0, storedBytes.Length); - Console.Out.WriteLine($"The stored string is: {storedStging}"); - } - } -} +```c# +using System; +using System.Text; +using System.Threading.Tasks; +using In3; + +namespace Ipfs +{ + class Program + { + static async Task Main() + { + // Content to be stored + string toStore = "LOREM_IPSUM"; + + // Connect to ipfs. + IN3 ipfsClient = IN3.ForChain(Chain.Ipfs); + + // Store the hash since it will be needed to fetch the content back. + string hash = await ipfsClient.Ipfs.Put(toStore); + + // + byte[] storedBytes = await ipfsClient.Ipfs.Get(hash); + string storedStging = Encoding.UTF8.GetString(storedBytes, 0, storedBytes.Length); + Console.Out.WriteLine($"The stored string is: {storedStging}"); + } + } +} ``` @@ -162,49 +170,51 @@ namespace Ipfs source : [in3-c/dotnet/Examples/Logs//Logs](https://github.com/blockchainsllc/in3/blob/master/dotnet/Examples/Logs//Logs/Program.cs) -```c# -using System; -using System.Threading; -using System.Threading.Tasks; -using In3; -using In3.Eth1; -namespace Logs -{ - class Program - { - static async Task Main() - { - // Define an upper limit for poll since we dont want our application potentially running forever. - int maxIterations = 500; - int oneSecond = 1000; // in ms - // Connect to mainnet. - IN3 mainnetClient = IN3.ForChain(Chain.Mainnet); - - // Create a filter object pointing, in this case, to an "eventful" contract address. - LogFilter tetherUsFilter = new LogFilter {Address = "0xdAC17F958D2ee523a2206206994597C13D831ec7"}; - - // Create the filter to be polled for logs. - long filterId = await mainnetClient.Eth1.NewLogFilter(tetherUsFilter); - - // Loop to initiate the poll for the logs. - for (int i = 0; i < maxIterations; i++) - { - // Query for the log events since the creation of the filter or the previous poll (this method in NOT idempotent as it retrieves a diff). - Log[] tetherLogs = await mainnetClient.Eth1.GetFilterChangesFromLogs(filterId); - if (tetherLogs.Length > 0) - { - Console.Out.WriteLine("Logs found: " + tetherLogs.Length); - break; - } - - // Wait before next query. - Thread.Sleep(oneSecond); - } - } - } -} +```c# +using System; +using System.Threading; +using System.Threading.Tasks; +using In3; +using In3.Eth1; + +namespace Logs +{ + class Program + { + static async Task Main() + { + // Define an upper limit for poll since we dont want our application potentially running forever. + int maxIterations = 500; + int oneSecond = 1000; // in ms + + // Connect to mainnet. + IN3 mainnetClient = IN3.ForChain(Chain.Mainnet); + + // Create a filter object pointing, in this case, to an "eventful" contract address. + LogFilter tetherUsFilter = new LogFilter {Address = "0xdAC17F958D2ee523a2206206994597C13D831ec7"}; + + // Create the filter to be polled for logs. + long filterId = await mainnetClient.Eth1.NewLogFilter(tetherUsFilter); + + // Loop to initiate the poll for the logs. + for (int i = 0; i < maxIterations; i++) + { + // Query for the log events since the creation of the filter or the previous poll (this method in NOT idempotent as it retrieves a diff). + Log[] tetherLogs = await mainnetClient.Eth1.GetFilterChangesFromLogs(filterId); + if (tetherLogs.Length > 0) + { + Console.Out.WriteLine("Logs found: " + tetherLogs.Length); + break; + } + + // Wait before next query. + Thread.Sleep(oneSecond); + } + } + } +} ``` @@ -212,6 +222,8 @@ namespace Logs source : [in3-c/dotnet/Examples/SendTransaction//SendTransaction](https://github.com/blockchainsllc/in3/blob/master/dotnet/Examples/SendTransaction//SendTransaction/Program.cs) + + ```c# using System; using System.Threading; @@ -262,6 +274,7 @@ namespace SendTransaction ### Build Examples + To setup and run the example projects, simply run on the respective project folder: ```sh @@ -273,3 +286,4 @@ To build all of them, on the solution folder, run: ```sh dotnet build ``` + diff --git a/java/build.gradle b/java/build.gradle index 0d88ff5e8..7f0bb9d69 100644 --- a/java/build.gradle +++ b/java/build.gradle @@ -100,4 +100,4 @@ consoleReporter { test.dependsOn 'createLibDir' test.dependsOn 'copyJarToBindings' test.finalizedBy jacocoTestReport -jacocoTestReport.finalizedBy reportCoverage \ No newline at end of file +jacocoTestReport.finalizedBy reportCoverage diff --git a/java/ci.yml b/java/ci.yml index dbd9d0e73..4054a17b4 100644 --- a/java/ci.yml +++ b/java/ci.yml @@ -54,8 +54,8 @@ test_android: - .gradle/wrapper - .gradle/caches script: - - wget https://services.gradle.org/distributions/gradle-6.8.1-bin.zip ; unzip gradle-6.8.1-bin.zip ; export PATH=`pwd`/gradle-6.8.1/bin:$PATH - - git clone https://github.com/blockchainsllc/in3-example-android.git + - wget https://services.gradle.org/distributions/gradle-6.8.1-bin.zip && unzip gradle-6.8.1-bin.zip && export PATH=`pwd`/gradle-6.8.1/bin:$PATH + - git clone https://github.com/slockit/in3-example-android.git - cd in3-example-android - mkdir in3 - mv ../c ../CMakeLists.txt ../java in3/ @@ -82,7 +82,7 @@ java_linux: script: - mv java_build build - cd java - - ./gradlew test + - ./gradlew --info test tags: - short-jobs artifacts: @@ -108,7 +108,7 @@ java_arm: script: - mv java_build build - cd java - - ./gradlew test + - ./gradlew --info test tags: - arm artifacts: @@ -132,7 +132,7 @@ java_macos: script: - mv java_build build - cd java; cp test/build_test.gradle build.gradle - - ./gradlew test + - ./gradlew --info test tags: - mac-os @@ -145,9 +145,11 @@ java_win: script: - mv java_build build - cd java; cp test/build_test.gradle build.gradle - - ./gradlew test + - ./gradlew --info test tags: - windows + variables: + GRADLE_OPTS: "-Dorg.gradle.daemon=false" # artifacts: # reports: # junit: java/build/test-results/test/TEST-*.xml diff --git a/java/docs/1_install.md b/java/docs/1_install.md index 274d39eeb..c31a88321 100644 --- a/java/docs/1_install.md +++ b/java/docs/1_install.md @@ -62,7 +62,7 @@ fi ```js externalNativeBuild { cmake { - path file('in3/CMakeLists.txt') + path file('../in3/CMakeLists.txt') } } sourceSets { diff --git a/java/docs/2_examples.md b/java/docs/2_examples.md index ac5254dbe..61fc9cc43 100644 --- a/java/docs/2_examples.md +++ b/java/docs/2_examples.md @@ -6,6 +6,7 @@ source : [in3-c/java/examples/CallFunction.java](https://github.com/blockchainsl Calling Functions of Contracts + ```java /// Calling Functions of Contracts @@ -41,6 +42,7 @@ source : [in3-c/java/examples/Configure.java](https://github.com/blockchainsllc/ Changing the default configuration + ```java /// Changing the default configuration @@ -66,13 +68,11 @@ public class Configure { clientConfig.setProof(Proof.none); // does not require proof (not recommended) // Setup the ChainConfiguration object for the nodes on a certain chain - ChainConfiguration chainConfiguration = new ChainConfiguration(Chain.GOERLI, clientConfig); + NodeRegistryConfiguration chainConfiguration = clientConfig.getNodeRegistry(); chainConfiguration.setNeedsUpdate(false); chainConfiguration.setContract("0xac1b824795e1eb1f6e609fe0da9b9af8beaab60f"); chainConfiguration.setRegistryId("0x23d5345c5c13180a8080bd5ddbe7cde64683755dcce6e734d95b7b573845facb"); - in3.setConfig(clientConfig); - Block block = in3.getEth1API().getBlockByNumber(Block.LATEST, true); System.out.println(block.getHash()); } @@ -85,6 +85,7 @@ source : [in3-c/java/examples/GetBalance.java](https://github.com/blockchainsllc getting the Balance with or without API + ```java /// getting the Balance with or without API @@ -123,6 +124,7 @@ source : [in3-c/java/examples/GetBlockAPI.java](https://github.com/blockchainsll getting a block with API + ```java /// getting a block with API @@ -162,6 +164,7 @@ source : [in3-c/java/examples/GetBlockRPC.java](https://github.com/blockchainsll getting a block without API + ```java /// getting a block without API @@ -191,6 +194,7 @@ source : [in3-c/java/examples/GetTransaction.java](https://github.com/blockchain getting a Transaction with or without API + ```java /// getting a Transaction with or without API @@ -229,6 +233,7 @@ source : [in3-c/java/examples/GetTransactionReceipt.java](https://github.com/blo getting a TransactionReceipt with or without API + ```java /// getting a TransactionReceipt with or without API @@ -268,6 +273,7 @@ source : [in3-c/java/examples/SendTransaction.java](https://github.com/blockchai Sending Transactions + ```java /// Sending Transactions @@ -323,7 +329,8 @@ public class SendTransaction { ``` -### Building + +### Building In order to run those examples, you only need a Java SDK installed. @@ -338,3 +345,4 @@ In order to run a example use ``` java -cp $IN3/build/lib/in3.jar:. GetBlockAPI ``` + diff --git a/java/src/CMakeLists.txt b/java/src/CMakeLists.txt index ab2de8887..e7d16af5e 100644 --- a/java/src/CMakeLists.txt +++ b/java/src/CMakeLists.txt @@ -73,6 +73,13 @@ IF (NOT DEFINED ANDROID_ABI) in3/eth1/TransactionReceipt.java in3/eth1/TransactionRequest.java in3/ipfs/API.java + in3/zksync/API.java + in3/zksync/Account.java + in3/zksync/AccountState.java + in3/zksync/Token.java + in3/zksync/EthOp.java + in3/zksync/TxFee.java + in3/zksync/Tx.java in3/utils/Account.java in3/utils/Crypto.java in3/utils/JSON.java @@ -81,6 +88,7 @@ IF (NOT DEFINED ANDROID_ABI) in3/utils/Signer.java in3/utils/StorageProvider.java in3/utils/TempStorageProvider.java + in3/utils/TransportException.java ) if(JAVA_MULTI_LIBS) diff --git a/java/src/in3/IN3.java b/java/src/in3/IN3.java index 538cc7c69..bcfc03e7e 100644 --- a/java/src/in3/IN3.java +++ b/java/src/in3/IN3.java @@ -39,6 +39,7 @@ import in3.utils.JSON; import in3.utils.Signer; import in3.utils.StorageProvider; +import in3.utils.TransportException; /** * This is the main class creating the incubed client. The client can then be @@ -124,6 +125,13 @@ public in3.ipfs.API getIpfs() { return new in3.ipfs.API(this); } + /** + * gets the zksync-api + */ + public in3.zksync.API getZksync() { + return new in3.zksync.API(this); + } + /** * gets the btc-api */ @@ -206,21 +214,30 @@ public Object sendobject(String request) { private native Object sendobjectinternal(String request); private String toRPC(String method, Object[] params) { - String p = ""; + StringBuilder p = new StringBuilder(); for (int i = 0; i < params.length; i++) { if (p.length() > 0) - p += ","; + p.append(","); if (params[i] == null) - p += "null"; + p.append("null"); + else if (params[i] instanceof byte[]) { + byte[] b = (byte[]) params[i]; + p.append("\"0x"); + for (int j = 0; j < b.length; j++) { + p.append(Character.forDigit((b[j] >> 4) & 0xF, 16)); + p.append(Character.forDigit(b[j] & 0xF, 16)); + } + p.append("\""); + } else if (params[i] instanceof String) { String s = (String) params[i]; if (s.charAt(0) == '{' || s.equals("true") || s.equals("false")) - p += s; + p.append(s); else - p += "\"" + s + "\""; + p.append("\"" + s + "\""); } else - p += JSON.toJson(params[i]); + p.append(JSON.toJson(params[i])); } return "{\"method\":\"" + method + "\", \"params\":[" + p + "]}"; } @@ -272,8 +289,8 @@ public Object sendRPCasObject(String method, Object[] params) { } /** internal function to handle the internal requests */ - static byte[][] sendRequest(String[] urls, byte[] payload) { - return IN3.transport.handle(urls, payload); + static byte[][] sendRequest(String method, String[] urls, byte[] payload, String[] headers) throws TransportException { + return IN3.transport.handle(method, urls, payload, headers); } private native void free(); diff --git a/java/src/in3/IN3DefaultTransport.java b/java/src/in3/IN3DefaultTransport.java index fe4d37110..899c99a42 100644 --- a/java/src/in3/IN3DefaultTransport.java +++ b/java/src/in3/IN3DefaultTransport.java @@ -1,5 +1,6 @@ package in3; +import in3.utils.TransportException; import java.io.*; import java.net.*; @@ -9,7 +10,7 @@ class IN3DefaultTransport implements IN3Transport { @Override - public byte[][] handle(String[] urls, byte[] payload) { + public byte[][] handle(String method, String[] urls, byte[] payload, String[] headers) throws TransportException { byte[][] result = new byte[urls.length][]; for (int i = 0; i < urls.length; i++) { @@ -17,13 +18,17 @@ public byte[][] handle(String[] urls, byte[] payload) { URL url = new URL(urls[i]); URLConnection con = url.openConnection(); HttpURLConnection http = (HttpURLConnection) con; - http.setRequestMethod("POST"); + http.setRequestMethod(method); http.setUseCaches(false); http.setDoOutput(true); http.setRequestProperty("Content-Type", "application/json"); http.setRequestProperty("Accept", "application/json"); http.setRequestProperty("charsets", "utf-8"); http.setRequestProperty("User-Agent", "in3 java " + IN3.getVersion()); + for (int n = 0; n < headers.length; n++) { + int p = headers[n].indexOf(':'); + if (p > 0) http.setRequestProperty(headers[n].substring(0, p).trim(), headers[n].substring(p + 1).trim()); + } http.connect(); OutputStream os = http.getOutputStream(); os.write(payload); @@ -35,11 +40,15 @@ public byte[][] handle(String[] urls, byte[] payload) { while ((nRead = is.read(data, 0, data.length)) != -1) buffer.write(data, 0, nRead); + int status = http.getResponseCode(); buffer.flush(); is.close(); - result[i] = buffer.toByteArray(); + if (status > 300) + throw new TransportException(buffer.toString().replaceAll("\"", " "), status, i); + else + result[i] = buffer.toByteArray(); } catch (Exception ex) { - result[i] = null; + throw new TransportException("Error during request transport:" + ex.getMessage(), 11, 0); } } return result; diff --git a/java/src/in3/IN3Transport.java b/java/src/in3/IN3Transport.java index 2d4a1ecfc..95d595147 100644 --- a/java/src/in3/IN3Transport.java +++ b/java/src/in3/IN3Transport.java @@ -1,8 +1,10 @@ package in3; +import in3.utils.TransportException; + /* * Interface for the IN3 transport. */ -interface IN3Transport { - byte[][] handle(String[] urls, byte[] payload); +public interface IN3Transport { + byte[][] handle(String method, String[] urls, byte[] payload, String[] headers) throws TransportException; } \ No newline at end of file diff --git a/java/src/in3/config/ClientConfiguration.java b/java/src/in3/config/ClientConfiguration.java index c043391c4..4f7308e74 100644 --- a/java/src/in3/config/ClientConfiguration.java +++ b/java/src/in3/config/ClientConfiguration.java @@ -129,6 +129,16 @@ public void setUseHttp(boolean useHttp) { data.put("useHttp", useHttp); } + public Boolean isExperimental() { + return data.getBoolean("experimental"); + } + + /* allow experimental features to be used */ + public void setExperimental(boolean val) { + setDirty(val != isExperimental()); + data.put("experimental", val); + } + public Long getTimeout() { return data.getLong("timeout"); } @@ -244,6 +254,9 @@ public String toString() { if (isUseHttp() != null) { JSON.appendKey(sb, "useHttp", isUseHttp()); } + if (isExperimental() != null) { + JSON.appendKey(sb, "experimental", isExperimental()); + } if (getTimeout() != null) { JSON.appendKey(sb, "timeout", getTimeout()); } diff --git a/java/src/in3/utils/TransportException.java b/java/src/in3/utils/TransportException.java new file mode 100644 index 000000000..2318cea95 --- /dev/null +++ b/java/src/in3/utils/TransportException.java @@ -0,0 +1,32 @@ +package in3.utils; +/** + * Exception to be thrown in case of failed request. + * + */ +public class TransportException extends Exception { + private int status; + private int index; + + /** + * constrcutor + * @param message + * @param status + */ + public TransportException(String message, int status, int index) { + super(message); + this.status = status; + this.index = index; + } + + public int getIndex() { + return index; + } + + /** + * the http-status + * @return + */ + public int getStatus() { + return status; + } +} diff --git a/java/src/in3/zksync/API.java b/java/src/in3/zksync/API.java new file mode 100644 index 000000000..efe26137a --- /dev/null +++ b/java/src/in3/zksync/API.java @@ -0,0 +1,149 @@ +package in3.zksync; + +import in3.IN3; +import java.math.BigInteger; + +/** + * API for handling ZKSYNC transactions. + */ +public class API { + private IN3 in3; + + /** + * creates a zksync.API using the given incubed instance. + */ + public API(IN3 in3) { + this.in3 = in3; + } + + /** + * the address of the zksync contract. + */ + public String getContractAddress() { + return (String) in3.sendRPCasObject("zk_contract_address", new Object[] {}); + } + + /** + * the available tokens. + */ + public Token[] getTokens() { + return Token.asTokens(in3.sendRPCasObject("zk_token", new Object[] {})); + } + + /** + * returns the current balance, nonce and key for the given account. if address is null, the current configured Account will be used. + */ + public Account getAccountInfo(String address) { + return Account.asAccount(in3.sendRPCasObject("zk_account_info", address == null ? new Object[] {} : new Object[] {address})); + } + + /** + * the Transaction State. + */ + public Tx getTransactionInfo(String txid) { + return Tx.asTx(in3.sendRPCasObject("zk_tx_info", new Object[] {txid})); + } + + /** + * the EthOp State. (State of a deposit or emergencyWithdraw - Transaction ) + */ + public EthOp getEthOpInfo(String txid) { + return EthOp.asEthOp(in3.sendRPCasObject("zk_ethop_info", new Object[] {txid})); + } + + /** + * sets the sync keys and returns the confirmed pubkeyhash + */ + public String setKey(String token) { + return (String) in3.sendRPCasObject("zk_set_key", new Object[] {token}); + } + + /** + * returns the pubkeyhash based on the current config. + */ + public String getPubKeyHash() { + return (String) in3.sendRPCasObject("zk_pubkeyhash", new Object[] {}); + } + + /** + * returns the public key based on the current config. + */ + public String getPubKey() { + return (String) in3.sendRPCasObject("zk_pubkey", new Object[] {}); + } + /** + * returns the private key based on the current config. + */ + public String getSyncKey() { + return (String) in3.sendRPCasObject("zk_sync_key", new Object[] {}); + } + + /** + * returns the address of the account based on the current config. + */ + public String getAccountAddress() { + return (String) in3.sendRPCasObject("zk_account_address", new Object[] {}); + } + + /** + * signs the data and returns a musig schnorr signature. + */ + public String sign(byte[] message) { + return (String) in3.sendRPCasObject("zk_sign", new Object[] {message}); + } + + /** + * signs the data and returns a musig schnorr signature. + */ + public boolean verify(byte[] message, String signature) { + return (Boolean) in3.sendRPCasObject("zk_verify", new Object[] {message, signature}); + } + + /** + * calculates the current tx fees for the specified + */ + public TxFee getTxFee(String txType, String toAddress, String token) { + return TxFee.asTxFee(in3.sendRPCasObject("zk_get_tx_fee", new Object[] {txType, toAddress, token})); + } + + /** + * sends the specified amount of tokens to the zksync contract as deposit for the specified amount (or null if this the same as send) + * returns the ethopId + */ + public String deposit(BigInteger amount, String token, boolean approveDepositAmountForERC20, String account) { + return (String) in3.sendRPCasObject("zk_deposit", new Object[] {amount, token, approveDepositAmountForERC20, account}); + } + + /** + * transfers the specified amount of tokens in L2 + * returns the txid + */ + public String transfer(String toAddress, BigInteger amount, String token, String fromAccount) { + return (String) in3.sendRPCasObject("zk_transfer", new Object[] {toAddress, amount, token, fromAccount}); + } + + /** + * withdraw the specified amount of tokens to L1 + * returns the txid + */ + public String withdraw(String toAddress, BigInteger amount, String token, String fromAccount) { + return (String) in3.sendRPCasObject("zk_withdraw", new Object[] {toAddress, amount, token, fromAccount}); + } + + /** + * withdraw all tokens from L2 to L1. + * returns the txId + */ + public String emergencyWithdraw(String token) { + return (String) in3.sendRPCasObject("zk_emergency_withdraw", new Object[] {token}); + } + + /** + * aggregate the pubKey to one pubKeys for signing together as musig Schnorr signatures. + */ + public String aggregatePubkey(String[] pubKeys) { + StringBuilder s = new StringBuilder(pubKeys[0]); + for (int i = 1; i < pubKeys.length; i++) s.append(pubKeys[i].substring(2)); + return (String) in3.sendRPCasObject("zk_aggregate_pubkey", new Object[] {s.toString()}); + } +} diff --git a/java/src/in3/zksync/Account.java b/java/src/in3/zksync/Account.java new file mode 100644 index 000000000..a15e42646 --- /dev/null +++ b/java/src/in3/zksync/Account.java @@ -0,0 +1,66 @@ +package in3.zksync; + +import in3.utils.JSON; + +/** + * A ZKSync Account. + */ +public class Account { + + private JSON data; + + private Account(JSON data) { + this.data = data; + } + + public static Account asAccount(Object o) { + if (o == null) + return null; + return new Account((JSON) o); + } + + public static Account[] asAccounts(Object o) { + if (o == null) + return null; + Object[] a = (Object[]) o; + Account[] b = new Account[a.length]; + for (int i = 0; i < a.length; i++) + b[i] = Account.asAccount(a[i]); + return b; + } + + /** + * The address of the Account. + */ + public String getAddress() { + return data.getString("address"); + } + + /** + * id or null if it is not assigned yet. + */ + public Integer getId() { + return data.getInteger("id"); + } + + /** + * the commited state + */ + public AccountState getCommited() { + return AccountState.asAccountState(data.getObject("commited")); + } + + /** + * the pending depositing state + */ + public AccountState getDepositing() { + return AccountState.asAccountState(data.getObject("depositing")); + } + + /** + * the verified state + */ + public AccountState getVerified() { + return AccountState.asAccountState(data.getObject("verified")); + } +} diff --git a/java/src/in3/zksync/AccountState.java b/java/src/in3/zksync/AccountState.java new file mode 100644 index 000000000..96f5ae3d4 --- /dev/null +++ b/java/src/in3/zksync/AccountState.java @@ -0,0 +1,41 @@ +package in3.zksync; + +import in3.utils.JSON; +import java.math.BigInteger; + +/** + * A ZKSync AccountState. + */ +public class AccountState { + + private JSON data; + + private AccountState(JSON data) { + this.data = data; + } + + public static AccountState asAccountState(Object o) { + if (o == null) + return null; + return new AccountState((JSON) o); + } + + /** + * The nonce or TransactionCount. + */ + public Integer getNonce() { + return data.getInteger("nonce"); + } + + /** + * the assigned pubkeyhash. + */ + public String getPubKeyHash() { + return data.getString("pubKeyHash"); + } + + /** the balance of the specified token (or null) */ + public BigInteger getBalance(String token) { + return data.getBigInteger(token); + } +} diff --git a/java/src/in3/zksync/EthOp.java b/java/src/in3/zksync/EthOp.java new file mode 100644 index 000000000..5f5da806c --- /dev/null +++ b/java/src/in3/zksync/EthOp.java @@ -0,0 +1,52 @@ +package in3.zksync; + +import in3.utils.JSON; + +/** + * A ZKSync EthOperation. + */ +public class EthOp { + + private JSON data; + + private EthOp(JSON data) { + this.data = data; + } + + public static EthOp asEthOp(Object o) { + if (o == null) + return null; + return new EthOp((JSON) o); + } + + /** + * returns true, if the operation was executed + */ + public boolean isExecuted() { + return data.getBoolean("executed"); + } + + /** + * returns the BlockNumber or null if it was not executed. + */ + public Long getBlockNumber() { + JSON block = (JSON) data.getObject("block"); + return block == null ? null : data.getLong("blockNumber"); + } + + /** + * returns true if the operation is commited in L2 + */ + public boolean isCommitted() { + JSON block = (JSON) data.getObject("block"); + return block == null ? false : data.getBoolean("commited"); + } + + /** + * returns true if the operation is verified in L1 + */ + public boolean isVerified() { + JSON block = (JSON) data.getObject("block"); + return block == null ? false : data.getBoolean("verified"); + } +} diff --git a/java/src/in3/zksync/Token.java b/java/src/in3/zksync/Token.java new file mode 100644 index 000000000..94aec48b1 --- /dev/null +++ b/java/src/in3/zksync/Token.java @@ -0,0 +1,59 @@ +package in3.zksync; + +import in3.utils.JSON; + +/** + * A ZKSync Token. + */ +public class Token { + + private JSON data; + + private Token(JSON data) { + this.data = data; + } + + public static Token asToken(Object o) { + if (o == null) + return null; + return new Token((JSON) o); + } + + public static Token[] asTokens(Object o) { + if (o == null) + return null; + Object[] a = (Object[]) o; + Token[] b = new Token[a.length]; + for (int i = 0; i < a.length; i++) + b[i] = Token.asToken(a[i]); + return b; + } + + /** + * The token-address if the String. + */ + public String getAddress() { + return data.getString("address"); + } + + /** + * The decimals or number of digits after the comma. + */ + public int getDecimals() { + return data.getInteger("decimals"); + } + + /** + * id + */ + public int getId() { + return data.getInteger("id"); + } + + /** + * The Symbol. + */ + public String getSize() { + return data.getString("symbol"); + } +} diff --git a/java/src/in3/zksync/Tx.java b/java/src/in3/zksync/Tx.java new file mode 100644 index 000000000..894b76757 --- /dev/null +++ b/java/src/in3/zksync/Tx.java @@ -0,0 +1,49 @@ +package in3.zksync; + +import in3.utils.JSON; + +/** + * A ZKSync Tx. + */ +public class Tx { + + private JSON data; + + private Tx(JSON data) { + this.data = data; + } + + public static Tx asTx(Object o) { + if (o == null) + return null; + return new Tx((JSON) o); + } + + /** + * The Block-number or null. + */ + public Long getBlock() { + return data.getLong("block"); + } + + /** + * true if the tx was executed. + */ + public boolean isExecuted() { + return data.getBoolean("executed"); + } + + /** + * the reason in case the tx failed. + */ + public String getId() { + return data.getString("failReason"); + } + + /** + * if the transaction was executed, this will indicate the success. (or null) + */ + public Boolean isSuccess() { + return data.getBoolean("success"); + } +} diff --git a/java/src/in3/zksync/TxFee.java b/java/src/in3/zksync/TxFee.java new file mode 100644 index 000000000..a6c0434df --- /dev/null +++ b/java/src/in3/zksync/TxFee.java @@ -0,0 +1,61 @@ +package in3.zksync; + +import in3.utils.JSON; + +/** + * A ZKSync TxFee. + */ +public class TxFee { + + private JSON data; + + private TxFee(JSON data) { + this.data = data; + } + + public static TxFee asTxFee(Object o) { + if (o == null) + return null; + return new TxFee((JSON) o); + } + + /** + * the type of fee. + */ + public String getFeeType() { + return data.getString("feeType"); + } + + /** + * The fee paid for gas costs. + */ + public long getGasFee() { + return data.getLong("gasFee"); + } + + /** + * The gas Price in Wei + */ + public long getGasPriceWei() { + return data.getLong("gasPriceWei"); + } + + /** + * The fee for the amount. + */ + public long getGasTxAmount() { + return data.getLong("gasTxAmount"); + } + /** + * The total amoiunt of fee to be paid for the tx. + */ + public long getTotalFee() { + return data.getLong("totalFee"); + } + /** + * The zkp fee. + */ + public long getZkpFee() { + return data.getLong("zkpFee"); + } +} diff --git a/java/src/in3_jni.c b/java/src/in3_jni.c index 096c856d4..e91614415 100644 --- a/java/src/in3_jni.c +++ b/java/src/in3_jni.c @@ -42,13 +42,14 @@ #include "../../c/src/core/util/bitset.h" #include "../../c/src/core/util/log.h" #include "../../c/src/core/util/mem.h" -#include "../../c/src/nodeselect/cache.h" -#include "../../c/src/nodeselect/nodeselect_def.h" +#include "../../c/src/init/in3_init.h" +#include "../../c/src/nodeselect/full/cache.h" +#include "../../c/src/nodeselect/full/nodeselect_def.h" #include "../../c/src/signer/pk-signer/signer.h" #include "../../c/src/third-party/crypto/ecdsa.h" #include "../../c/src/third-party/crypto/secp256k1.h" #include "../../c/src/verifier/eth1/basic/eth_basic.h" -#include "../../c/src/verifier/in3_init.h" + #ifdef IPFS #include "../../c/src/third-party/libb64/cdecode.h" #include "../../c/src/third-party/libb64/cencode.h" @@ -174,10 +175,10 @@ JNIEXPORT jstring JNICALL Java_in3_IN3_sendinternal(JNIEnv* env, jobject ob, jst int res; jstring js = NULL; - in3_ctx_t* ctx = ctx_new(get_in3(env, ob), (char*) str); + in3_req_t* ctx = req_new(get_in3(env, ob), (char*) str); if (!ctx->error) { - res = in3_send_ctx(ctx); + res = in3_send_req(ctx); if (res >= 0) { d_token_t* r = d_get(ctx->responses[0], K_RESULT); if (r) @@ -209,7 +210,7 @@ JNIEXPORT jstring JNICALL Java_in3_IN3_sendinternal(JNIEnv* env, jobject ob, jst //need to release this string when done with it in order to //avoid memory leak (*env)->ReleaseStringUTFChars(env, jreq, str); - ctx_free(ctx); + req_free(ctx); if (result) { js = (*env)->NewStringUTF(env, result); @@ -282,10 +283,10 @@ JNIEXPORT jobject JNICALL Java_in3_IN3_sendobjectinternal(JNIEnv* env, jobject o int res; jobject js = NULL; - in3_ctx_t* ctx = ctx_new(get_in3(env, ob), (char*) str); + in3_req_t* ctx = req_new(get_in3(env, ob), (char*) str); if (!ctx->error) { - res = in3_send_ctx(ctx); + res = in3_send_req(ctx); if (res >= 0) { d_token_t* r = d_get(ctx->responses[0], K_RESULT); if (r) @@ -318,7 +319,7 @@ JNIEXPORT jobject JNICALL Java_in3_IN3_sendobjectinternal(JNIEnv* env, jobject o //avoid memory leak (*env)->ReleaseStringUTFChars(env, jreq, str); - ctx_free(ctx); + req_free(ctx); if (result) return js; @@ -348,42 +349,66 @@ in3_ret_t Java_in3_IN3_transport(void* plugin_data, in3_plugin_act_t action, voi UNUSED_VAR(plugin_data); UNUSED_VAR(action); - in3_request_t* req = plugin_ctx; - uint64_t start = current_ms(); + in3_http_request_t* req = plugin_ctx; + uint64_t start = current_ms(); //char** urls, int urls_len, char* payload, in3_response_t* res in3_ret_t success = IN3_OK; //payload - size_t payload_len = strlen(req->payload); - jbyteArray jpayload = (*jni)->NewByteArray(jni, payload_len); - (*jni)->SetByteArrayRegion(jni, jpayload, 0, payload_len, (jbyte*) req->payload); + jbyteArray jpayload = (*jni)->NewByteArray(jni, req->payload_len); + (*jni)->SetByteArrayRegion(jni, jpayload, 0, req->payload_len, (jbyte*) req->payload); // url-array jobject jurls = (*jni)->NewObjectArray(jni, req->urls_len, (*jni)->FindClass(jni, "java/lang/String"), NULL); for (unsigned int i = 0; i < req->urls_len; i++) (*jni)->SetObjectArrayElement(jni, jurls, i, (*jni)->NewStringUTF(jni, req->urls[i])); + // headers + int header_len = 0, hi = 0; + for (in3_req_header_t* h = req->headers; h; h = h->next) header_len++; + jstring jmethod = (*jni)->NewStringUTF(jni, req->method); + jobject jheaders = (*jni)->NewObjectArray(jni, header_len, (*jni)->FindClass(jni, "java/lang/String"), NULL); + for (in3_req_header_t* h = req->headers; h; h = h->next, hi++) (*jni)->SetObjectArrayElement(jni, jheaders, hi, (*jni)->NewStringUTF(jni, h->value)); + + (*jni)->ExceptionClear(jni); jclass cls = (*jni)->FindClass(jni, "in3/IN3"); - jmethodID mid = (*jni)->GetStaticMethodID(jni, cls, "sendRequest", "([Ljava/lang/String;[B)[[B"); - jobjectArray result = (*jni)->CallStaticObjectMethod(jni, cls, mid, jurls, jpayload); - - for (unsigned int i = 0; i < req->urls_len; i++) { - jbyteArray content = result ? (*jni)->GetObjectArrayElement(jni, result, i) : NULL; - if (content) { - const size_t l = (*jni)->GetArrayLength(jni, content); - uint8_t* bytes = _malloc(l); - (*jni)->GetByteArrayRegion(jni, content, 0, l, (jbyte*) bytes); - sb_add_range(&req->ctx->raw_response[i].data, (char*) bytes, 0, l); - req->ctx->raw_response[i].state = IN3_OK; - _free(bytes); - } - else { - sb_add_chars(&req->ctx->raw_response[i].data, "Could not fetch the data!"); - req->ctx->raw_response[i].state = IN3_ERPC; + jmethodID mid = (*jni)->GetStaticMethodID(jni, cls, "sendRequest", "(Ljava/lang/String;[Ljava/lang/String;[B[Ljava/lang/String;)[[B"); + jobjectArray result = (*jni)->CallStaticObjectMethod(jni, cls, mid, jmethod, jurls, jpayload, jheaders); + uint64_t end = current_ms(); + + // handle exception + jthrowable transport_exception = (*jni)->ExceptionOccurred(jni); + if (transport_exception) { + jclass cls = (*jni)->GetObjectClass(jni, transport_exception); + jmethodID mid = (*jni)->GetMethodID(jni, cls, "getStatus", "()I"); + int status = (*jni)->CallIntMethod(jni, transport_exception, mid); + mid = (*jni)->GetMethodID(jni, cls, "getIndex", "()I"); + int index = (*jni)->CallIntMethod(jni, transport_exception, mid); + mid = (*jni)->GetMethodID(jni, cls, "getMessage", "()Ljava/lang/String;"); + jstring jmsg = (*jni)->CallObjectMethod(jni, transport_exception, mid); + const char* msg = (*jni)->GetStringUTFChars(jni, jmsg, 0); + in3_req_add_response(req, index, 0 - status, msg, -1, (uint32_t)(end - start)); + (*jni)->ReleaseStringUTFChars(jni, jmsg, msg); + (*jni)->ExceptionClear(jni); + } + else { + for (unsigned int i = 0; i < req->urls_len; i++) { + jbyteArray content = result ? (*jni)->GetObjectArrayElement(jni, result, i) : NULL; + if (content) { + const size_t l = (*jni)->GetArrayLength(jni, content); + uint8_t* bytes = _malloc(l); + (*jni)->GetByteArrayRegion(jni, content, 0, l, (jbyte*) bytes); + sb_add_range(&req->req->raw_response[i].data, (char*) bytes, 0, l); + req->req->raw_response[i].state = IN3_OK; + _free(bytes); + } + else { + sb_add_chars(&req->req->raw_response[i].data, "Could not fetch the data!"); + req->req->raw_response[i].state = IN3_ERPC; + } + if (req->req->raw_response[i].state) success = IN3_ERPC; } - if (req->ctx->raw_response[i].state) success = IN3_ERPC; } - uint64_t end = current_ms(); - for (unsigned int i = 0; i < req->urls_len; i++) req->ctx->raw_response[i].time = (uint32_t)(end - start); + for (unsigned int i = 0; i < req->urls_len; i++) req->req->raw_response[i].time = (uint32_t)(end - start); return success; } @@ -523,7 +548,7 @@ JNIEXPORT jstring JNICALL Java_in3_eth1_SimpleWallet_decodeKeystore(JNIEnv* env, //in3_ret_t jsign(void* pk, d_signature_type_t type, bytes_t message, bytes_t account, uint8_t* dst) { in3_ret_t jsign(in3_sign_ctx_t* sc) { - in3_ctx_t* ctx = (in3_ctx_t*) sc->ctx; + in3_req_t* ctx = (in3_req_t*) sc->req; void* jp = get_java_obj_ptr(ctx->client); jclass cls = (*jni)->GetObjectClass(jni, jp); jmethodID mid = (*jni)->GetMethodID(jni, cls, "getSigner", "()Lin3/utils/Signer;"); @@ -618,6 +643,9 @@ JNIEXPORT jlong JNICALL Java_in3_IN3_init(JNIEnv* env, jobject ob, jlong jchain) in3_plugin_register(in3, PLGN_ACT_TRANSPORT, Java_in3_IN3_transport, NULL, true); in3_plugin_register(in3, PLGN_ACT_SIGN, jsign_fn, p, false); jni = env; + // turn to debug + // in3_log_set_level(LOG_TRACE); + // in3_log_set_quiet(false); return (jlong)(size_t) in3; } diff --git a/java/test/in3/IN3Mocktransport.java b/java/test/in3/IN3Mocktransport.java index bd7baeaea..abb5e0ebf 100644 --- a/java/test/in3/IN3Mocktransport.java +++ b/java/test/in3/IN3Mocktransport.java @@ -1,5 +1,6 @@ package in3; +import in3.utils.TransportException; import java.io.*; import java.net.URI; import java.net.URISyntaxException; @@ -22,7 +23,7 @@ public IN3MockTransport() { } @Override - public byte[][] handle(String[] urls, byte[] payload) { + public byte[][] handle(String method, String[] urls, byte[] payload, String[] headers) throws TransportException { byte[][] result = new byte[urls.length][]; String methodName = this.getPayloadMethod(new String(payload)); diff --git a/python/ci.yml b/python/ci.yml index 90650937d..05bdacbc2 100644 --- a/python/ci.yml +++ b/python/ci.yml @@ -82,6 +82,8 @@ python_arm: junit: python_multilib/report.xml tags: - arm + variables: + CRYPTOGRAPHY_DONT_BUILD_RUST : 1 python_win: extends: .only_python @@ -114,7 +116,7 @@ python_macos: - cd python_multilib - pip3 install --upgrade pip - pip3 install -r requirements.txt - - coverage run -m pytest --pylama --junitxml=report.xml + - coverage run -m pytest --pylama --junitxml=report.xml || echo "Failed See Test-Report!" - coverage report - coverage-badge -fo docs/coverage.svg artifacts: diff --git a/python/docs/compiled_examples.md b/python/docs/compiled_examples.md new file mode 100644 index 000000000..7c869dccc --- /dev/null +++ b/python/docs/compiled_examples.md @@ -0,0 +1,362 @@ +## Examples + +### connect_to_ethereum + +source : [in3-c/python/examples/connect_to_ethereum.py](https://github.com/blockchainsllc/in3/blob/master/python/examples/connect_to_ethereum.py) + + + +```python +""" +Connects to Ethereum and fetches attested information from each chain. +""" +import in3 + +if __name__ == '__main__': + + client = in3.Client() + try: + print('\nEthereum Main Network') + latest_block = client.eth.block_number() + gas_price = client.eth.gas_price() + print('Latest BN: {}\nGas Price: {} Wei'.format(latest_block, gas_price)) + except in3.ClientException as e: + print('Network might be unstable, try again later.\n Reason: ', str(e)) + + goerli_client = in3.Client('goerli') + try: + print('\nEthereum Goerli Test Network') + latest_block = goerli_client.eth.block_number() + gas_price = goerli_client.eth.gas_price() + print('Latest BN: {}\nGas Price: {} Wei'.format(latest_block, gas_price)) + except in3.ClientException as e: + print('Network might be unstable, try again later.\n Reason: ', str(e)) + +# Produces +""" +Ethereum Main Network +Latest BN: 9801135 +Gas Price: 2000000000 Wei + +Ethereum Goerli Test Network +Latest BN: 2460853 +Gas Price: 4610612736 Wei +""" + +``` + +### incubed_network + +source : [in3-c/python/examples/incubed_network.py](https://github.com/blockchainsllc/in3/blob/master/python/examples/incubed_network.py) + + + +```python +""" +Shows Incubed Network Nodes Stats +""" +import in3 + +if __name__ == '__main__': + + print('\nEthereum Goerli Test Network') + client = in3.Client('goerli') + try: + node_list = client.refresh_node_list() + print('\nIncubed Registry:') + print('\ttotal servers:', node_list.totalServers) + print('\tlast updated in block:', node_list.lastBlockNumber) + print('\tregistry ID:', node_list.registryId) + print('\tcontract address:', node_list.contract) + print('\nNodes Registered:\n') + for node in node_list.nodes: + print('\turl:', node.url) + print('\tdeposit:', node.deposit) + print('\tweight:', node.weight) + print('\tregistered in block:', node.registerTime) + print('\n') + except in3.ClientException as e: + print('Network might be unstable, try again later.\n Reason: ', str(e)) + +# Produces +""" +Ethereum Goerli Test Network + +Incubed Registry: + total servers: 7 + last updated in block: 2320627 + registry ID: 0x67c02e5e272f9d6b4a33716614061dd298283f86351079ef903bf0d4410a44ea + contract address: 0x5f51e413581dd76759e9eed51e63d14c8d1379c8 + +Nodes Registered: + + url: https://in3-v2.slock.it/goerli/nd-1 + deposit: 10000000000000000 + weight: 2000 + registered in block: 1576227711 + + + url: https://in3-v2.slock.it/goerli/nd-2 + deposit: 10000000000000000 + weight: 2000 + registered in block: 1576227741 + + + url: https://in3-v2.slock.it/goerli/nd-3 + deposit: 10000000000000000 + weight: 2000 + registered in block: 1576227801 + + + url: https://in3-v2.slock.it/goerli/nd-4 + deposit: 10000000000000000 + weight: 2000 + registered in block: 1576227831 + + + url: https://in3-v2.slock.it/goerli/nd-5 + deposit: 10000000000000000 + weight: 2000 + registered in block: 1576227876 + + + url: https://tincubeth.komputing.org/ + deposit: 10000000000000000 + weight: 1 + registered in block: 1578947320 + + + url: https://h5l45fkzz7oc3gmb.onion/ + deposit: 10000000000000000 + weight: 1 + registered in block: 1578954071 +""" + +``` + +### resolve_eth_names + +source : [in3-c/python/examples/resolve_eth_names.py](https://github.com/blockchainsllc/in3/blob/master/python/examples/resolve_eth_names.py) + + + +```python +""" +Resolves ENS domains to Ethereum addresses +ENS is a smart-contract system that registers and resolves `.eth` domains. +""" +import in3 + + +# Find ENS for the desired chain or the address of your own ENS resolver. https://docs.ens.domains/ens-deployments +# Instantiate In3 Client for the Ethereum main net disabling cache to get the freshest address. +client = in3.Client(cache_enabled=False) +domain = 'depraz.eth' + +if __name__ == '__main__': + + try: + print('\nEthereum Name Service') + address = client.ens_address(domain) + owner = client.ens_owner(domain) + print('\nAddress for {} @ {}: {}'.format(domain, 'mainnet', address)) + print('Owner for {} @ {}: {}'.format(domain, 'mainnet', owner)) + except in3.ClientException as e: + print('Network might be unstable, try again later.\n Reason: ', str(e)) + + +# Produces +""" +Ethereum Name Service + +Address for depraz.eth @ mainnet: 0x0b56ae81586d2728ceaf7c00a6020c5d63f02308 +Owner for depraz.eth @ mainnet: 0x6fa33809667a99a805b610c49ee2042863b1bb83 +""" + +``` + +### send_transaction + +source : [in3-c/python/examples/send_transaction.py](https://github.com/blockchainsllc/in3/blob/master/python/examples/send_transaction.py) + + + +```python +""" +Sends Ethereum transactions using Incubed. +Incubed send Transaction does all necessary automation to make sending a transaction a breeze. +Works with included `data` field for smart-contract calls. +""" +import json +import in3 +import time + + +# On Metamask, be sure to be connected to the correct chain, click on the `...` icon on the right corner of +# your Account name, select `Account Details`. There, click `Export Private Key`, copy the value to use as secret. +# By reading the terminal input, this value will stay in memory only. Don't forget to cls or clear terminal after ;) +sender_secret = input("Sender secret: ") +receiver = input("Receiver address: ") +# 1000000000000000000 == 1 ETH +# 1000000000 == 1 Gwei Check https://etherscan.io/gasTracker. +value_in_wei = 1463926659 +# None for Eth mainnet +chain = 'goerli' +client = in3.Client(chain if chain else 'mainnet') +# A transaction is only final if a certain number of blocks are mined on top of it. +# This number varies with the chain's consensus algorithm. Time can be calculated over using: +# wait_time = blocks_for_consensus * avg_block_time_in_secs +# For mainnet and paying low gas, it might take 10 minutes. +confirmation_wait_time_in_seconds = 30 +etherscan_link_mask = 'https://{}{}etherscan.io/tx/{}' + +if __name__ == '__main__': + + try: + print('-= Ethereum Transaction using Incubed =- \n') + sender = client.eth.account.recover(sender_secret) + tx = in3.eth.NewTransaction(to=receiver, value=value_in_wei) + print('[.] Sending {} Wei from {} to {}. Please wait.\n'.format(tx.value, sender.address, tx.to)) + tx_hash = client.eth.account.send_transaction(sender, tx) + print('[.] Transaction accepted with hash {}.'.format(tx_hash)) + add_dot_if_chain = '.' if chain else '' + print(etherscan_link_mask.format(chain, add_dot_if_chain, tx_hash)) + while True: + try: + print('\n[.] Waiting {} seconds for confirmation.\n'.format(confirmation_wait_time_in_seconds)) + time.sleep(confirmation_wait_time_in_seconds) + receipt: in3.eth.TransactionReceipt = client.eth.transaction_receipt(tx_hash) + print('[.] Transaction was sent successfully!\n') + print(json.dumps(receipt.to_dict(), indent=4, sort_keys=True)) + print('[.] Mined on block {} used {} GWei.'.format(receipt.blockNumber, receipt.gasUsed)) + break + except Exception: + print('[!] Transaction not mined yet, check https://etherscan.io/gasTracker.') + print('[!] Just wait some minutes longer than the average for the price paid!') + except in3.PrivateKeyNotFoundException as e: + print(str(e)) + except in3.ClientException as e: + print('Client returned error: ', str(e)) + print('Please try again.') + +# Response +""" +Ethereum Transaction using Incubed + +Sending 1463926659 Wei from 0x0b56Ae81586D2728Ceaf7C00A6020C5D63f02308 to 0x6fa33809667a99a805b610c49ee2042863b1bb83. + +Transaction accepted with hash 0xbeebda39e31e42d2a26476830fdcdc2d21e9df090af203e7601d76a43074d8d3. +https://goerli.etherscan.io/tx/0xbeebda39e31e42d2a26476830fdcdc2d21e9df090af203e7601d76a43074d8d3 + +Waiting 25 seconds for confirmation. + +Transaction was sent successfully! +{ + "From": "0x0b56Ae81586D2728Ceaf7C00A6020C5D63f02308", + "blockHash": "0x9693714c9d7dbd31f36c04fbd262532e68301701b1da1a4ee8fc04e0386d868b", + "blockNumber": 2615346, + "cumulativeGasUsed": 21000, + "gasUsed": 21000, + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "status": 1, + "to": "0x6FA33809667A99A805b610C49EE2042863b1bb83", + "transactionHash": "0xbeebda39e31e42d2a26476830fdcdc2d21e9df090af203e7601d76a43074d8d3", + "transactionIndex": 0 +} + +Mined on block 2615346 used 21000 GWei. +""" + +``` + +### smart_contract + +source : [in3-c/python/examples/smart_contract.py](https://github.com/blockchainsllc/in3/blob/master/python/examples/smart_contract.py) + + + +```python +""" +Manually calling the ENS smart-contract +![UML Sequence Diagram of how Ethereum Name Service ENS resolves a name.](https://lh5.googleusercontent.com/_OPPzaxTxKggx9HuxloeWtK8ggEfIIBKRCEA6BKMwZdzAfUpIY6cz7NK5CFmiuw7TwknbhFNVRCJsswHLqkxUEJ5KdRzpeNbyg8_H9d2RZdG28kgipT64JyPZUP--bAizozaDcxCq34) +""" +import in3 + + +client = in3.Client('goerli') + +if __name__ == '__main__': + + try: + print('-= Smart-Contract Call on Ethereum using Incubed =- \n') + domain_name = client.ens_namehash('depraz.eth') + ens_registry_addr = '0x00000000000c2e074ec69a0dfb2997ba6c7d2e1e' + ens_resolver_abi = 'resolver(bytes32):address' + + # Find resolver contract for ens name + resolver_tx = { + "to": ens_registry_addr, + "data": client.eth.contract.encode(ens_resolver_abi, domain_name) + } + tx = in3.eth.NewTransaction(**resolver_tx) + except in3.ClientException as e: + print('Something went wrong converting data.\n Reason: ', str(e)) + try: + # Make the smart contract call + print('Calling the ENS registry contract.') + encoded_resolver_addr = client.eth.contract.call(tx) + resolver_address = client.eth.contract.decode(ens_resolver_abi, encoded_resolver_addr) + except in3.ClientException as e: + print('Network might be unstable, try again later.\n Reason: ', str(e)) + try: + # Resolve name + ens_addr_abi = 'addr(bytes32):address' + name_tx = { + "to": resolver_address, + "data": client.eth.contract.encode(ens_addr_abi, domain_name) + } + except in3.ClientException as e: + print('Something went wrong converting data.\n Reason: ', str(e)) + try: + print('Calling the ENS resolver contract.') + encoded_domain_address = client.eth.contract.call(in3.eth.NewTransaction(**name_tx)) + domain_address = client.eth.contract.decode(ens_addr_abi, encoded_domain_address) + + print('\nENS domain:\n{}\nResolved by:\n{}\nTo address:\n{}'.format(domain_name, resolver_address, + domain_address)) + except in3.ClientException as e: + print('Network might be unstable, try again later.\n Reason: ', str(e)) + + +# Produces +""" +END domain: +0x4a17491df266270a8801cee362535e520a5d95896a719e4a7d869fb22a93162e +Resolved by: +0x4b1488b7a6b320d2d721406204abc3eeaa9ad329 +To address: +0x0b56ae81586d2728ceaf7c00a6020c5d63f02308 +""" + +``` + + +### Running the examples + +To run an example, you need to install in3 first: +```sh +pip install in3 +``` +This will install the library system-wide. Please consider using `virtualenv` or `pipenv` for a project-wide install. + +Then copy one of the examples and paste into a file, i.e. `example.py`: + +`MacOS` +```sh +pbpaste > example.py +``` + +Execute the example with python: +``` +python example.py +``` diff --git a/python/docs/documentation.md b/python/docs/documentation.md index af7c13a3d..bad7c656c 100644 --- a/python/docs/documentation.md +++ b/python/docs/documentation.md @@ -2,6 +2,7 @@ ## Python Incubed client + This library is based on the [C version of Incubed](http://github.com/blockchainsllc/in3), which limits the compatibility for Cython, so please contribute by compiling it to your own platform and sending us a pull-request! Go to our [readthedocs](https://in3.readthedocs.io/) page for more. @@ -27,8 +28,8 @@ print(block_number) # Mainnet's block number in3_client # incubed network api in3_client.eth # ethereum api -in3_client.account # ethereum account api -in3_client.contract # ethereum smart-contract api +in3_client.eth.account # ethereum account api +in3_client.eth.contract # ethereum smart-contract api ``` #### Developing & Tests @@ -68,13 +69,14 @@ Explanation of this source code architecture and how it is organized. For more o - **in3.libin3.enum**: Enumerations mapping C definitions to python. - **in3.libin3.lib_loader**: Bindings using Ctypes. - **in3.libin3.runtime**: Runtime object, bridging the remote procedure calls to the libin3 instances. - ## Examples ### connect_to_ethereum source : [in3-c/python/examples/connect_to_ethereum.py](https://github.com/blockchainsllc/in3/blob/master/python/examples/connect_to_ethereum.py) + + ```python """ Connects to Ethereum and fetches attested information from each chain. @@ -118,6 +120,8 @@ Gas Price: 4610612736 Wei source : [in3-c/python/examples/incubed_network.py](https://github.com/blockchainsllc/in3/blob/master/python/examples/incubed_network.py) + + ```python """ Shows Incubed Network Nodes Stats @@ -205,6 +209,8 @@ Nodes Registered: source : [in3-c/python/examples/resolve_eth_names.py](https://github.com/blockchainsllc/in3/blob/master/python/examples/resolve_eth_names.py) + + ```python """ Resolves ENS domains to Ethereum addresses @@ -244,6 +250,8 @@ Owner for depraz.eth @ mainnet: 0x6fa33809667a99a805b610c49ee2042863b1bb83 source : [in3-c/python/examples/send_transaction.py](https://github.com/blockchainsllc/in3/blob/master/python/examples/send_transaction.py) + + ```python """ Sends Ethereum transactions using Incubed. @@ -336,6 +344,8 @@ Mined on block 2615346 used 21000 GWei. source : [in3-c/python/examples/smart_contract.py](https://github.com/blockchainsllc/in3/blob/master/python/examples/smart_contract.py) + + ```python """ Manually calling the ENS smart-contract @@ -401,101 +411,36 @@ To address: ``` -### smart_meter_write - -source : [in3-c/python/examples/smart_meter_write.py](https://github.com/blockchainsllc/in3/blob/master/python/examples/smart_meter_write.py) - -```python -""" -[{"type":"event","name":"NewReadStored","inputs":[{"type":"address","name":"meter","internalType":"address","indexed":true},{"type":"uint256","name":"bucket","internalType":"uint256","indexed":true},{"type":"address","name":"operator","internalType":"address","indexed":false},{"type":"uint256","name":"timestamp","internalType":"uint256","indexed":false},{"type":"bytes","name":"data","internalType":"bytes","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"DAILY_BUCKET","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"store","inputs":[{"type":"address","name":"meter","internalType":"address"},{"type":"bytes","name":"data","internalType":"bytes"},{"type":"uint256","name":"timestamp","internalType":"uint256"},{"type":"uint256","name":"bucket","internalType":"uint256"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"storeWithDailyBucket","inputs":[{"type":"address","name":"meter","internalType":"address"},{"type":"bytes","name":"data","internalType":"bytes"},{"type":"uint256","name":"timestamp","internalType":"uint256"}],"constant":false}] -""" -import base64 -import json - -import in3 -import hashlib -import random -import time - -if __name__ == '__main__': - - c = in3.Client(chain='ewc', in3_config=in3.ClientConfig(transport_binary_format=False)) - - smart_meter_registry_addr = '0xf23FF7472FC62C6bEe2F960f5b4170Ab3C1C26d2' - # meter, bucket, operator, timestamp, data - NewReadStoredEvent = 'NewReadStored(address,uint,address,uint,bytes))' - try: - # meter, data, timestamp - storeWithDailyBucket = 'storeWithDailyBucket(address,bytes,uint256)' - meter_addr = '0x42f195EB903A350029866cf0f1D95bc2F6e1B8ea' - salt = hex(random.getrandbits(64)) - secret_read = hashlib.sha512(b'1101101') - secret_read.update(salt.encode('utf8')) - secret_read = secret_read.hexdigest() - # secret_read = base64.b64encode(secret_read.digest()) - timestamp = int(time.time()) - sender_secret = input("Sender secret: ") - sender = c.eth.account.recover(sender_secret) - encoded_contract_call = c.eth.contract.encode(storeWithDailyBucket, meter_addr, secret_read, timestamp) - tx = in3.eth.NewTransaction(to=smart_meter_registry_addr, - data=encoded_contract_call) - tx.gasLimit = c.eth.account.estimate_gas(tx) - tx_hash = c.eth.account.send_transaction(sender=sender, transaction=tx) - print('https://explorer.energyweb.org/tx/{}'.format(tx_hash)) - confirmation_wait_time_in_seconds = 60 - while True: - try: - print('\n[.] Waiting {} seconds for confirmation.\n'.format(confirmation_wait_time_in_seconds)) - time.sleep(confirmation_wait_time_in_seconds) - receipt: in3.eth.TransactionReceipt = c.eth.transaction_receipt(tx_hash) - print('[.] Transaction was sent successfully!\n') - print(json.dumps(receipt.to_dict(), indent=4, sort_keys=True)) - print('[.] Mined on block {} used {} GWei.'.format(receipt.blockNumber, receipt.gasUsed)) - break - except Exception as e: - print('[!] Transaction not mined yet, check https://etherscan.io/gasTracker.') - print('[!] Just wait some minutes longer than the average for the price paid!') - except in3.PrivateKeyNotFoundException as e: - print(str(e)) - except in3.ClientException as e: - print('Client returned error: ', str(e)) - print('Please try again.') - -``` ### Running the examples To run an example, you need to install in3 first: - ```sh pip install in3 ``` - This will install the library system-wide. Please consider using `virtualenv` or `pipenv` for a project-wide install. Then copy one of the examples and paste into a file, i.e. `example.py`: `MacOS` - ```sh pbpaste > example.py ``` Execute the example with python: - ``` python example.py ``` ## Incubed Modules -### Client +### Client ```python Client(self, chain: str = 'mainnet', in3_config: ClientConfig = None, -transport=, +transport=, cache_enabled: bool = True, test_instance: bool = False) ``` @@ -511,9 +456,9 @@ Once with the latest list at hand, the client can request any other on-chain inf - `transport` _function_ - Transport function for custom request routing. Defaults to https. - `cache_enabled` _bool_ - False will disable local storage caching. - `test_instance` _bool_ - True will create a test instance of IN3. HIGH SECURITY RISK - USE FOR TESTS ONLY. + #### refresh_node_list - ```python Client.refresh_node_list() ``` @@ -523,9 +468,9 @@ Gets the list of Incubed nodes registered in the selected chain registry contrac **Returns**: - `node_list` _NodeList_ - List of registered in3 nodes and metadata. + #### config - ```python Client.config() ``` @@ -535,9 +480,9 @@ Client configuration dictionary. **Returns**: - `config` _dict_ - Client configuration keys and values. + #### ens_namehash - ```python Client.ens_namehash(domain_name: str) ``` @@ -551,9 +496,9 @@ Name format based on [EIP-137](https://github.com/ethereum/EIPs/blob/master/EIPS **Returns**: - `node` _str_ - Formatted string referred as `node` in ENS documentation + #### ens_address - ```python Client.ens_address(domain_name: str, registry: str = None) ``` @@ -568,9 +513,9 @@ Resolves ENS domain name to what account that domain points to. **Returns**: - `address` _str_ - Ethereum address corresponding to what account that domain points to. + #### ens_owner - ```python Client.ens_owner(domain_name: str, registry: str = None) ``` @@ -585,9 +530,9 @@ Resolves ENS domain name to Ethereum address of domain owner. **Returns**: - `owner_address` _str_ - Ethereum address corresponding to domain owner. + #### ens_resolver - ```python Client.ens_resolver(domain_name: str, registry: str = None) ``` @@ -602,9 +547,9 @@ Resolves ENS domain name to Smart-contract address of the resolver registered fo **Returns**: - `resolver_contract_address` _str_ - Smart-contract address of the resolver registered for that domain. + ### ClientConfig - ```python ClientConfig(self, chain_finality_threshold: int = None, @@ -623,6 +568,7 @@ response_keep_proof: bool = None, transport_binary_format: bool = None, transport_ignore_tls: bool = None, boot_weights: bool = None, +experimental: bool = None, in3_registry: dict = None) ``` @@ -656,10 +602,11 @@ The verification policy enforces an extra step of security, adding a financial s - `transport_binary_format` - If true, the client will communicate with the server using a binary payload instead of json. - `transport_ignore_tls` - The client usually verify https tls certificates. To communicate over insecure http, turn this on. - `boot_weights` _bool_ - if true, the first request (updating the nodelist) will also fetch the current health status and use it for blacklisting unhealthy nodes. This is used only if no nodelist is availabkle from cache. +- `experimental` _bool_ - if true the client allows features marked as experimental to be used. - `in3_registry` _dict_ - In3 Registry Smart Contract configuration data + ### In3Node - ```python In3Node(self, url: str, address: Account, index: int, deposit: int, props: int, timeout: int, registerTime: int, weight: int) @@ -678,9 +625,9 @@ indeed mined are in the correct chain fork. - `timeout` _int_ - Time (in seconds) until an owner is able to receive his deposit back after he unregisters himself example: 3600 - `registerTime` _int_ - When the node was registered in (unixtime?) - `weight` _int_ - Score based on qualitative metadata to base which nodes to ask signatures from. + ### NodeList - ```python NodeList(self, nodes: [], contract: Account, registryId: str, lastBlockNumber: int, totalServers: int) @@ -696,17 +643,20 @@ network/registry id, and last block number in the selected chain. - `registryId` _str_ - uuid of this incubed network. one chain could contain more than one incubed networks. - `lastBlockNumber` _int_ - last block signed by the network - `totalServers` _int_ - Total servers number (for integrity?) + + -### EthAccountApi + +### EthAccountApi ```python EthAccountApi(self, runtime: In3Runtime, factory: EthObjectFactory) ``` Manages accounts and smart-contracts -#### create +#### create ```python EthAccountApi.create(qrng=False) ``` @@ -720,9 +670,9 @@ Creates a new Ethereum account and saves it in the wallet. **Returns**: - `account` _Account_ - Newly created Ethereum account. + #### recover - ```python EthAccountApi.recover(secret: str) ``` @@ -736,9 +686,9 @@ Recovers an account from a secret. **Returns**: - `account` _Account_ - Recovered Ethereum account. + #### parse_mnemonics - ```python EthAccountApi.parse_mnemonics(mnemonics: str) ``` @@ -752,9 +702,9 @@ Recovers an account secret from mnemonics phrase **Returns**: - `secret` _str_ - Account secret. Use `recover_account` to create a new account with this secret. + #### sign - ```python EthAccountApi.sign(private_key: str, message: str) ``` @@ -769,9 +719,9 @@ Use ECDSA to sign a message. **Returns**: - `signed_message` _str_ - ECDSA calculated r, s, and parity v, concatenated. v = 27 + (r % 2) + #### balance - ```python EthAccountApi.balance(address: str, at_block: int = 'latest') ``` @@ -781,14 +731,14 @@ Returns the balance of the account of given address. **Arguments**: - `address` _str_ - address to check for balance -- `at_block` _int or str_ - block number IN3BlockNumber or EnumBlockStatus +- `at_block` _int or str_ - block number IN3BlockNumber or EnumBlockStatus **Returns**: - `balance` _int_ - integer of the current balance in wei. + #### send_transaction - ```python EthAccountApi.send_transaction(sender: Account, transaction: NewTransaction) @@ -808,9 +758,9 @@ latest block. **Returns**: - `tx_hash` _hex_ - Transaction hash, used to get the receipt and check if the transaction was mined. + #### send_raw_transaction - ```python EthAccountApi.send_raw_transaction(signed_transaction: str) ``` @@ -825,9 +775,9 @@ Sends a signed and encoded transaction. **Returns**: - `tx_hash` _hex_ - Transaction hash, used to get the receipt and check if the transaction was mined. + #### estimate_gas - ```python EthAccountApi.estimate_gas(transaction: NewTransaction) ``` @@ -841,9 +791,9 @@ Gas estimation for transaction. Used to fill transaction.gas field. Check RawTra **Returns**: - `gas` _int_ - Calculated gas in Wei. + #### transaction_count - ```python EthAccountApi.transaction_count(address: str, at_block: int = 'latest') ``` @@ -860,9 +810,9 @@ It exists to mitigate replay attacks. **Returns**: - `tx_count` _int_ - Number of transactions mined from this address. + #### checksum_address - ```python EthAccountApi.checksum_address(address: str, add_chain_id: bool = True) ``` @@ -878,17 +828,20 @@ See [EIP55](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-55.md). **Returns**: - `checksum_address` - EIP-55 compliant, mixed-case address object. + -### EthContractApi + + +### EthContractApi ```python EthContractApi(self, runtime: In3Runtime, factory: EthObjectFactory) ``` Manages smart-contract data and transactions -#### call +#### call ```python EthContractApi.call(transaction: NewTransaction, block_number: int = 'latest') @@ -899,16 +852,15 @@ Check https://ethereum.stackexchange.com/questions/3514/how-to-call-a-contract-m **Arguments**: -transaction (NewTransaction): - + transaction (NewTransaction): - `block_number` _int or str_ - Desired block number integer or 'latest', 'earliest', 'pending'. **Returns**: - `method_returned_value` - A hexadecimal. For decoding use in3.abi_decode. + #### storage_at - ```python EthContractApi.storage_at(address: str, position: int = 0, @@ -928,9 +880,9 @@ The storage is essentially a key/value store. Use get_code to get the smart-cont **Returns**: - `storage_at` _str_ - Stored value in designed position. Use decode('hex') to see ascii format of the hex data. + #### code - ```python EthContractApi.code(address: str, at_block: int = 'latest') ``` @@ -945,9 +897,9 @@ Smart-Contract bytecode in hexadecimal. If the account is a simple wallet the fu **Returns**: - `bytecode` _str_ - Smart-Contract bytecode in hexadecimal. + #### encode - ```python EthContractApi.encode(fn_signature: str, *fn_args) ``` @@ -966,9 +918,9 @@ When you invoke a method, the arguments used must match the declaration's parame **Returns**: - `encoded_fn_call` _str_ - i.e. "0xf8b2cb4f0000000000000000000000001234567890123456789012345678901234567890" + #### decode - ```python EthContractApi.decode(fn_signature: str, encoded_value: str) ``` @@ -985,17 +937,20 @@ Based on the [Solidity specification.](https://solidity.readthedocs.io/en/v0.5.3 **Returns**: - `decoded_return_values` _tuple_ - "0x1234567890123456789012345678901234567890", "0x05" + + + -### EthereumApi +### EthereumApi ```python EthereumApi(self, runtime: In3Runtime) ``` Module based on Ethereum's api and web3.js -#### keccak256 +#### keccak256 ```python EthereumApi.keccak256(message: str) ``` @@ -1009,9 +964,9 @@ Keccak-256 digest of the given data. Compatible with Ethereum but not with SHA3- **Returns**: - `digest` _str_ - The message digest. + #### gas_price - ```python EthereumApi.gas_price() ``` @@ -1021,9 +976,9 @@ The current gas price in Wei (1 ETH equals 1000000000000000000 Wei ). **Returns**: - `price` _int_ - minimum gas value for the transaction to be mined + #### block_number - ```python EthereumApi.block_number() ``` @@ -1034,10 +989,10 @@ If you need the very latest block, change Client.Config.signatureCount to zero. **Returns**: -block_number (int) : Number of the most recent block + block_number (int) : Number of the most recent block + #### block_by_hash - ```python EthereumApi.block_by_hash(block_hash: str, get_full_block: bool = False) ``` @@ -1052,9 +1007,9 @@ Blocks can be identified by root hash of the block merkle tree (this), or sequen **Returns**: - `block` _Block_ - Desired block, if exists. + #### block_by_number - ```python EthereumApi.block_by_number(block_number: [], get_full_block: bool = False) @@ -1070,9 +1025,9 @@ Blocks can be identified by sequential number in which it was mined, or root has **Returns**: - `block` _Block_ - Desired block, if exists. + #### transaction_by_hash - ```python EthereumApi.transaction_by_hash(tx_hash: str) ``` @@ -1087,9 +1042,9 @@ Every transaction hash is unique for the whole chain. Collision could in theory **Returns**: - `transaction` - Desired transaction, if exists. + #### transaction_receipt - ```python EthereumApi.transaction_receipt(tx_hash: str) ``` @@ -1108,11 +1063,12 @@ likely that the transaction will stay in the chain. **Returns**: - `tx_receipt` - The mined Transaction data including event logs. + ### Ethereum Objects -#### DataTransferObject +#### DataTransferObject ```python DataTransferObject() ``` @@ -1120,8 +1076,8 @@ DataTransferObject() Maps marshalling objects transferred to, and from a remote facade, in this case, libin3 rpc api. For more on design-patterns see [Martin Fowler's](https://martinfowler.com/eaaCatalog/) Catalog of Patterns of Enterprise Application Architecture. -#### Transaction +#### Transaction ```python Transaction(self, From: str, to: str, gas: int, gasPrice: int, hash: str, nonce: int, transactionIndex: int, blockHash: str, @@ -1145,9 +1101,9 @@ v: int) - `blockHash` _int_ - Block number that this transaction was mined in. null when its pending. - `transactionIndex` _int_ - Integer of the transactions index position in the block. null when its pending. - `signature` _hex str_ - ECDSA of transaction.data, calculated r, s and v concatenated. V is parity set by v = 27 + (r % 2). + #### NewTransaction - ```python NewTransaction(self, From: str = None, @@ -1174,9 +1130,9 @@ Unsent transaction. Use to send a new transaction. - `nonce` _int_ - (optional) Number of transactions mined from this address. Nonce is a value that will make a transaction fail in case it is different from (transaction count + 1). It exists to mitigate replay attacks. This allows to overwrite your own pending transactions by sending a new one with the same nonce. Use in3.eth.account.get_transaction_count to get the latest value. - `hash` _hex str_ - (optional) Keccak of the transaction bytes, not part of the transaction. Also known as receipt, because this field is filled after the transaction is sent. - `signature` _hex str_ - (optional) ECDSA of transaction, r, s and v concatenated. V is parity set by v = 27 + (r % 2). + #### Filter - ```python Filter(self, fromBlock: int, toBlock: int, address: str, topics: list, blockhash: str) @@ -1186,8 +1142,8 @@ Filters are event catchers running on the Ethereum Client. Incubed has a client- An event will be stored in case it is within to and from blocks, or in the block of blockhash, contains a transaction to the designed address, and has a word listed on topics. -#### Log +#### Log ```python Log(self, address: , blockHash: , blockNumber: int, @@ -1199,8 +1155,8 @@ transactionLogIndex: int, Type: str) Transaction Log for events and data returned from smart-contract method calls. -#### TransactionReceipt +#### TransactionReceipt ```python TransactionReceipt(self, blockHash: , @@ -1221,9 +1177,8 @@ Receipt from a mined transaction. **Arguments**: -blockHash: -blockNumber: - + blockHash: + blockNumber: - `cumulativeGasUsed` - total amount of gas used by block From: - `gasUsed` - amount of gas used by this specific transaction @@ -1234,9 +1189,9 @@ blockNumber: transactionIndex: - `to` - Account to which this transaction was sent. If the transaction was a contract creation this value is set to None. - `contractAddress` - Contract Account address created, f the transaction was a contract creation, or None otherwise. + #### Account - ```python Account(self, address: str, @@ -1253,6 +1208,7 @@ An Ethereum account. - `chain_id` - ID of the chain the account is used in. - `secret` - Account private key. A 256 bit number. - `domain` - ENS Domain name. ie. niceguy.eth + ## Library Runtime @@ -1262,8 +1218,8 @@ Loads `libin3` according to host hardware architecture and OS. Maps symbols, methods and types from the library. Encapsulates low-level rpc calls into a comprehensive runtime. -### In3Runtime +### In3Runtime ```python In3Runtime(self, chain_id: int, @@ -1278,19 +1234,16 @@ Instantiate libin3 and frees it when garbage collected. - `chain_id` _int_ - Chain-id based on EIP-155. Default is 0x1 for Ethereum mainNet. - `transport_fn` - Transport function to handle the HTTP Incubed Network requests. -<<<<<<< python/docs/documentation.md -======= - `cache_enabled` _bool_ - False will disable local storage cache. - `deterministic_node_sel` _bool_ - True will make node selection deterministic. ->>>>>>> python/docs/documentation.md ### in3.libin3.rpc_api Load libin3 shared library for the current system, map function ABI, sets in3 network transport functions. -#### libin3_new +#### libin3_new ```python libin3_new(chain_id: int, transport_fn, @@ -1310,9 +1263,9 @@ Instantiate new In3 Client instance. **Returns**: - `instance` _int_ - Memory address of the client instance, return value from libin3_new + #### libin3_free - ```python libin3_free(instance: int) ``` @@ -1322,9 +1275,9 @@ Free In3 Client objects from memory. **Arguments**: - `instance` _int_ - Memory address of the client instance, return value from libin3_new + #### libin3_call - ```python libin3_call(instance: int, fn_name: bytes, fn_args: bytes) ``` @@ -1340,9 +1293,9 @@ Make Remote Procedure Call to an arbitrary method of a libin3 instance **Returns**: - `result` _int_ - Function execution status. + #### libin3_set_pk - ```python libin3_set_pk(instance: int, private_key: bytes) ``` @@ -1353,9 +1306,9 @@ Register the signer module in the In3 Client instance, with selected private key - `instance` _int_ - Memory address of the client instance, return value from libin3_new - `private_key` - 256 bit number. + #### libin3_in3_req_add_response - ```python libin3_in3_req_add_response(*args) ``` @@ -1364,10 +1317,10 @@ Transport function that registers a response to a request. **Arguments**: -\*args: + *args: + #### libin3_new_bytes_t - ```python libin3_new_bytes_t(value: bytes, length: int) ``` @@ -1382,15 +1335,13 @@ C Bytes struct **Returns**: - `ptr_addr` - address of the instance of this struct -<<<<<<< python/docs/documentation.md -======= #### libin3_register_plugin ```python libin3_register_plugin(instance: int, actions: PluginAction, -action_fn: , +action_fn: , data=None, replace_old=True) ``` @@ -1410,4 +1361,3 @@ transport it, select nodes from the in3 network, and more. - `in3_rpc_error_code` - OK will return 0. ->>>>>>> python/docs/documentation.md diff --git a/python/examples/README.md b/python/examples/README.md index 6dcb7d55e..609fb74cb 100644 --- a/python/examples/README.md +++ b/python/examples/README.md @@ -11,8 +11,6 @@ - [smart_contract](./smart_contract.py) -- [smart_meter_write](./smart_meter_write.py) - ### Running the examples To run an example, you need to install in3 first: diff --git a/python/in3/libin3/enum.py b/python/in3/libin3/enum.py index 1ec51af00..8cc2a4e27 100644 --- a/python/in3/libin3/enum.py +++ b/python/in3/libin3/enum.py @@ -88,7 +88,7 @@ class RPCCode(enum.Enum): IN3_EVERS = -8 # Version mismatch IN3_EINVALDT = -9 # Data invalid, eg. invalid/incomplete JSON IN3_EPASS = -10 # Wrong password - IN3_ERPC = -11 # RPC error (i.e. in3_ctx_t::error set) + IN3_ERPC = -11 # RPC error (i.e. in3_req_t::error set) IN3_ERPCNRES = -12 # RPC no response IN3_EUSNURL = -13 # USN URL parse error IN3_ETRANS = -14 # Transport error @@ -141,10 +141,10 @@ class PluginAction(enum.Enum): PLGN_ACT_PAY_HANDLE = 0x20000 # handles the payment PLGN_ACT_PAY_SIGN_REQ = 0x40000 # signs a request PLGN_ACT_LOG_ERROR = 0x80000 # report an error - PLGN_ACT_NL_PICK = 0x100000 # picks the data nodes, plgn_ctx will be a pointer to in3_ctx_t - PLGN_ACT_NL_PICK_FOLLOWUP = 0x200000 # called after receiving a response in order to decide whether a update is needed, plgn_ctx will be a pointer to in3_ctx_t + PLGN_ACT_NL_PICK = 0x100000 # picks the data nodes, plgn_ctx will be a pointer to in3_req_t + PLGN_ACT_NL_PICK_FOLLOWUP = 0x200000 # called after receiving a response in order to decide whether a update is needed, plgn_ctx will be a pointer to in3_req_t PLGN_ACT_NL_BLACKLIST = 0x400000 # blacklist a particular node in the nodelist, plgn_ctx will be a pointer to the node's address. - PLGN_ACT_NL_FAILABLE = 0x800000 # handle fail-able request, plgn_ctx will be a pointer to in3_ctx_t + PLGN_ACT_NL_FAILABLE = 0x800000 # handle fail-able request, plgn_ctx will be a pointer to in3_req_t PLGN_ACT_NL_OFFLINE = 0x1000000 # mark a particular node in the nodelist as offline, plgn_ctx will be a pointer to in3_nl_offline_ctx_t.* / PLGN_ACT_CHAIN_CHANGE = 0x2000000 # chain id change event, called after setting new chain id PLGN_ACT_GET_DATA = 0x4000000 # get access to plugin data as a void ptr diff --git a/python/in3/libin3/transport.py b/python/in3/libin3/transport.py index 78d8ad512..f5f9d9b8d 100644 --- a/python/in3/libin3/transport.py +++ b/python/in3/libin3/transport.py @@ -6,27 +6,31 @@ class NativeRequest(c.Structure): """ - Based on in3/client/.h in3_request_t struct + Based on in3/client/.h in3_http_request_t struct """ - _fields_ = [("payload", c.POINTER(c.c_char)), + _fields_ = [("method", c.POINTER(c.c_char)), + ("payload", c.POINTER(c.c_char)), ("urls", c.POINTER(c.POINTER(c.c_char))), ("urls_len", c.c_int), - ("results", c.c_void_p), - ("timeout", c.c_uint32), - ("times", c.c_uint32)] + ("payload_len", c.c_uint32), + ("req", c.c_void_p), + ("cptr", c.c_void_p), + ("wait", c.c_uint32), + ("headers", c.c_void_p)] """ /** request-object. * * represents a RPC-request */ - typedef struct in3_request { + typedef struct in3_http_request { + char* method /**< http-method */ char* payload; /**< the payload to send */ char** urls; /**< array of urls */ uint_fast16_t urls_len; /**< number of urls */ - struct in3_ctx* ctx; /**< the current context */ + struct in3_req* ctx; /**< the current context */ void* cptr; /**< a custom ptr to hold information during */ uint32_t wait; /**< time in ms to wait before sending out the request */ - } in3_request_t; + } in3_http_request_t; """ @@ -45,7 +49,7 @@ class NativeResponse(c.Structure): * This function should be used in the transport-function to set the response. */ NONULL void in3_req_add_response( - in3_request_t* req, /**< [in]the the request */ + in3_http_request_t* req, /**< [in]the the request */ int index, /**< [in] the index of the url, since this request could go out to many urls */ bool is_error, /**< [in] if true this will be reported as error. the message should then be the error-message */ const char* data, /**< the data or the the string*/ @@ -85,11 +89,17 @@ def payload(self): """ return c.string_at(self.in3_request.contents.payload) - def timeout(self): + def payload_len(self): """ - Get timeout of the request, `0` being no set timeout + Gets the length of the payload to be sent """ - return self.in3_request.contents.timeout + return self.in3_request.contents.payload_len + + def method(self): + """ + Gets the http-method to be used + """ + return c.string_at(self.in3_request.contents.method) class In3Response: diff --git a/python/in3/model.py b/python/in3/model.py index 6c076a32f..769f14bdc 100644 --- a/python/in3/model.py +++ b/python/in3/model.py @@ -84,6 +84,7 @@ class ClientConfig(DataTransferObject): transport_binary_format: If true, the client will communicate with the server using a binary payload instead of json. transport_ignore_tls: The client usually verify https tls certificates. To communicate over insecure http, turn this on. boot_weights (bool): if true, the first request (updating the nodelist) will also fetch the current health status and use it for blacklisting unhealthy nodes. This is used only if no nodelist is availabkle from cache. + experimental (bool): if true the client allows features marked as experimental to be used. in3_registry (dict): In3 Registry Smart Contract configuration data """ @@ -104,6 +105,7 @@ def __init__(self, transport_binary_format: bool = None, transport_ignore_tls: bool = None, boot_weights: bool = None, + experimental: bool = None, in3_registry: dict = None): self.finality: int = chain_finality_threshold self.key: str = account_secret @@ -121,6 +123,7 @@ def __init__(self, self.keepIn3: bool = response_keep_proof self.useBinary: bool = transport_binary_format self.useHttp: bool = transport_ignore_tls + self.experimental: bool = experimental self.nodeRegistry: dict = in3_registry if self.key: warnings.warn( diff --git a/python/in3/transport.py b/python/in3/transport.py index 88adbc67d..03348a831 100644 --- a/python/in3/transport.py +++ b/python/in3/transport.py @@ -20,14 +20,18 @@ def https_transport(in3_request: In3Request, in3_response: In3Response): for i in range(0, in3_request.urls_len()): try: + # TODO + # currently the payload is passed as string, but this should be changed sind the request has a payload pointing to the bytes and payload_len, + # which also could be image as raw bytes being send + # also the in3_request contains the http-header, which need to get added request_params = { 'url': str(in3_request.url_at(i), 'utf8'), - 'method': 'POST', + 'method': in3_request.method(), 'data': in3_request.payload(), 'headers': {'Content-type': 'application/json', 'Accept': 'application/json'}, } request = urllib.request.Request(**request_params) - timeout = in3_request.timeout() if in3_request.timeout() > 0 else 180000 + timeout = 180000 with urllib.request.urlopen(request, timeout=timeout) as response: if not response.status == 200: raise TransportException('Request failed with status: {}'.format(str(response.status))) diff --git a/python/tests/integrated/mock/transport.py b/python/tests/integrated/mock/transport.py index 6702e0cd9..6342f9091 100644 --- a/python/tests/integrated/mock/transport.py +++ b/python/tests/integrated/mock/transport.py @@ -25,7 +25,7 @@ def mock_transport(in3_request: In3Request, in3_response: In3Response): 'url': in3_request.url_at(i), 'data': in3_request.payload(), 'headers': {'Content-type': 'application/json'}, - 'timeout': in3_request.timeout() + 'timeout': 10000 } request_data = json.loads(http_request['data'])[0] request_method = request_data['method'] diff --git a/rust/in3-rs/Cargo.toml b/rust/in3-rs/Cargo.toml index 340511808..71fdc75dc 100644 --- a/rust/in3-rs/Cargo.toml +++ b/rust/in3-rs/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "in3" -version = "0.1.7" +version = "0.1.8" authors = ["slock.it "] description = "High-level bindings to IN3 library" license-file = "LICENSE" diff --git a/rust/in3-rs/src/btc/api.rs b/rust/in3-rs/src/btc/api.rs index 6b93b4607..0f9258daf 100644 --- a/rust/in3-rs/src/btc/api.rs +++ b/rust/in3-rs/src/btc/api.rs @@ -224,7 +224,7 @@ mod tests { fn test_btc_get_blockheader_bytes() -> In3Result<()> { let mut api = Api::new(Client::new(chain::BTC)); api.client - .configure(r#"{"autoUpdateList":false,"nodeRegistry":{"needsUpdate":false}}}"#)?; + .configure(r#"{"autoUpdateList":false,"experimental":true,"nodeRegistry":{"needsUpdate":false}}}"#)?; api.client.set_transport(Box::new(MockTransport { responses: vec![( "getblockheader", @@ -260,7 +260,7 @@ mod tests { fn test_btc_get_blockheader() -> In3Result<()> { let mut api = Api::new(Client::new(chain::BTC)); api.client - .configure(r#"{"autoUpdateList":false,"nodeRegistry":{"needsUpdate":false}}}"#)?; + .configure(r#"{"autoUpdateList":false,"experimental":true,"nodeRegistry":{"needsUpdate":false}}}"#)?; api.client.set_transport(Box::new(MockTransport { responses: vec![( "getblockheader", @@ -327,7 +327,7 @@ mod tests { fn test_btc_get_transaction_bytes() -> In3Result<()> { let mut api = Api::new(Client::new(chain::BTC)); api.client - .configure(r#"{"autoUpdateList":false,"nodeRegistry":{"needsUpdate":false}}}"#)?; + .configure(r#"{"autoUpdateList":false,"experimental":true,"nodeRegistry":{"needsUpdate":false}}}"#)?; api.client.set_transport(Box::new(MockTransport { responses: vec![( "getrawtransaction", @@ -364,7 +364,7 @@ mod tests { fn test_btc_get_transaction() -> In3Result<()> { let mut api = Api::new(Client::new(chain::BTC)); api.client - .configure(r#"{"autoUpdateList":false,"nodeRegistry":{"needsUpdate":false}}}"#)?; + .configure(r#"{"autoUpdateList":false,"experimental":true,"nodeRegistry":{"needsUpdate":false}}}"#)?; api.client.set_transport(Box::new(MockTransport { responses: vec![( "getrawtransaction", diff --git a/rust/in3-rs/src/in3.rs b/rust/in3-rs/src/in3.rs index 11f134279..8f030256e 100644 --- a/rust/in3-rs/src/in3.rs +++ b/rust/in3-rs/src/in3.rs @@ -34,7 +34,7 @@ pub mod chain { } struct Ctx { - ptr: *mut in3_sys::in3_ctx_t, + ptr: *mut in3_sys::in3_req_t, #[allow(dead_code)] config: CString, } @@ -42,9 +42,9 @@ struct Ctx { impl Ctx { fn new(in3: &mut Client, config_str: &str) -> Ctx { let config = CString::new(config_str).expect("CString::new failed"); - let ptr: *mut in3_sys::in3_ctx_t; + let ptr: *mut in3_sys::in3_req_t; unsafe { - ptr = in3_sys::ctx_new(in3.ptr, config.as_ptr()); + ptr = in3_sys::req_new(in3.ptr, config.as_ptr()); } Ctx { ptr, config } } @@ -58,8 +58,8 @@ impl Ctx { } async unsafe fn execute(&mut self) -> Result { - match in3_sys::in3_ctx_exec_state(self.ptr) { - in3_sys::state::CTX_ERROR => { + match in3_sys::in3_req_exec_state(self.ptr) { + in3_sys::state::REQ_ERROR => { while (*self.ptr).required != std::ptr::null_mut() && (*self.ptr).error == std::ptr::null_mut() { @@ -74,17 +74,17 @@ impl Ctx { Err(SysError::UnknownIn3Error) } } - in3_sys::state::CTX_SUCCESS => { + in3_sys::state::REQ_SUCCESS => { let response = CStr::from_ptr((*(*self.ptr).response_context).c) .to_str() .expect("err is not valid UTF-8"); Ok(response.to_owned()) } - in3_sys::state::CTX_WAITING_FOR_RESPONSE => Err(SysError::NotSupported), - in3_sys::state::CTX_WAITING_TO_SEND => { + in3_sys::state::REQ_WAITING_FOR_RESPONSE => Err(SysError::NotSupported), + in3_sys::state::REQ_WAITING_TO_SEND => { let request = in3_sys::in3_create_request(self.ptr); - match (*(*request).ctx).type_ { - in3_sys::ctx_type::CT_SIGN => { + match (*(*request).req).type_ { + in3_sys::ctx_type::RT_SIGN => { let slice = CStr::from_ptr((*request).payload) .to_str() .expect("result is not valid UTF-8"); @@ -104,7 +104,7 @@ impl Ctx { in3_sys::in3_req_add_response( request, 0.try_into().unwrap(), - false, + 0, res_str.0.as_mut_ptr() as *const c_char, 65, 0, @@ -112,7 +112,10 @@ impl Ctx { in3_sys::request_free(request); Err(SysError::TryAgain) } - in3_sys::ctx_type::CT_RPC => { + in3_sys::ctx_type::RT_RPC => { + let method = CStr::from_ptr((*request).method) + .to_str() + .expect("method is not valid UTF-8"); let payload = CStr::from_ptr((*request).payload) .to_str() .expect("payload is not valid UTF-8"); @@ -124,13 +127,21 @@ impl Ctx { .expect("URL is not valid UTF-8"); urls.push(url); } + let mut headers = Vec::new(); + let header_len = in3_sys::in3_get_request_headers_len(request); + for i in 0..header_len as usize { + let header = CStr::from_ptr(in3_sys::in3_get_request_headers_at(request,i as i32)) + .to_str() + .expect("header is not valid UTF-8"); + headers.push(header); + } let responses: Vec> = { let transport = { let c: &mut Client = (*self.ptr).client.into(); &mut c.transport }; - transport.fetch(payload, &urls).await + transport.fetch(method, payload, &urls, &headers).await }; // println!("{:?}", responses); for (i, resp) in responses.iter().enumerate() { @@ -140,7 +151,7 @@ impl Ctx { in3_sys::in3_req_add_response( request, i.try_into().unwrap(), // cannot fail - true, + -11, // TODO: here we need the status-code of the failed http-request as negative-value err_str.as_ptr(), -1i32, 0, @@ -151,7 +162,7 @@ impl Ctx { in3_sys::in3_req_add_response( request, i.try_into().unwrap(), // cannot fail - false, + 0, res_str.as_ptr(), -1i32, 0, @@ -159,9 +170,9 @@ impl Ctx { } } } - let res = *(*(*request).ctx).raw_response.offset(0); + let res = *(*(*request).req).raw_response.offset(0); let err = if res.state != in3_sys::in3_ret_t::IN3_OK { - let error = (*(*(*request).ctx).raw_response.offset(0)).data; + let error = (*(*(*request).req).raw_response.offset(0)).data; let error = CStr::from_ptr(error.data) .to_str() .expect("err is not valid UTF-8"); @@ -180,7 +191,7 @@ impl Ctx { #[cfg(feature = "blocking")] fn send(&mut self) -> In3Result<()> { unsafe { - let ret = in3_sys::in3_send_ctx(self.ptr); + let ret = in3_sys::in3_send_req(self.ptr); match ret { in3_sys::in3_ret_t::IN3_OK => Ok(()), _ => Err(ret.into()), @@ -192,7 +203,7 @@ impl Ctx { impl Drop for Ctx { fn drop(&mut self) { unsafe { - in3_sys::ctx_free(self.ptr); + in3_sys::req_free(self.ptr); } } } @@ -452,12 +463,15 @@ impl Client { #[cfg(feature = "blocking")] extern "C" fn in3_rust_transport( - request: *mut in3_sys::in3_request_t, + request: *mut in3_sys::in3_http_request_t, ) -> in3_sys::in3_ret_t::Type { // internally calls the rust transport impl, i.e. Client.transport let mut urls = Vec::new(); unsafe { + let method = CStr::from_ptr((*request).method) + .to_str() + .expect("method is not valid UTF-8"); let payload = CStr::from_ptr((*request).payload) .to_str() .expect("URL is not valid UTF-8"); @@ -468,9 +482,11 @@ impl Client { .expect("URL is not valid UTF-8"); urls.push(url); } + let mut headers = Vec::new(); + // TODO fill headers let c: &mut Client = (*request).in3.into(); - let responses: Vec> = c.transport.fetch_blocking(payload, &urls); + let responses: Vec> = c.transport.fetch_blocking(method, payload, &urls, &headers); let mut any_err = false; for (i, resp) in responses.iter().enumerate() { diff --git a/rust/in3-rs/src/traits.rs b/rust/in3-rs/src/traits.rs index a908f8e09..ebd32ba19 100644 --- a/rust/in3-rs/src/traits.rs +++ b/rust/in3-rs/src/traits.rs @@ -15,11 +15,11 @@ type ClientTypeId = u32; pub trait Transport { /// Sends the request to all of the uris (endpoints) and delivers the response as Strings /// in an async fashion. - async fn fetch(&mut self, request: &str, uris: &[&str]) -> Vec>; + async fn fetch(&mut self, method: &str, request: &str, uris: &[&str],headers: &[&str]) -> Vec>; /// Same as fetch() but may block. #[cfg(feature = "blocking")] - fn fetch_blocking(&mut self, request: &str, uris: &[&str]) -> Vec>; + fn fetch_blocking(&mut self, method: &str, request: &str, uris: &[&str],headers: &[&str]) -> Vec>; } /// Signer trait methods. diff --git a/rust/in3-rs/src/transport.rs b/rust/in3-rs/src/transport.rs index 89d2c5499..2ec9f9452 100644 --- a/rust/in3-rs/src/transport.rs +++ b/rust/in3-rs/src/transport.rs @@ -13,8 +13,10 @@ use crate::logging::LOGGER; use crate::traits::Transport; async fn http_async( + _method : &str, url: &str, payload: &str, + _headers: &[&str], ) -> Result> { let res = surf::post(url) .body_string(payload.to_string()) @@ -102,7 +104,7 @@ impl Transport for MockJsonTransport { /// Async fetch implementation /// /// Read responses from json - async fn fetch(&mut self, request_: &str, _uris: &[&str]) -> Vec> { + async fn fetch(&mut self, _method: &str,request_: &str, _uris: &[&str],_headers: &[&str]) -> Vec> { let request: Value = from_str(request_).unwrap(); let method_ = request[0]["method"].as_str(); let response = self.read_json(String::from(method_.unwrap())); @@ -110,7 +112,7 @@ impl Transport for MockJsonTransport { } #[cfg(feature = "blocking")] - fn fetch_blocking(&mut self, _request: &str, _uris: &[&str]) -> Vec> { + fn fetch_blocking(&mut self,_method: &str, _request: &str, _uris: &[&str],_headers: &[&str]) -> Vec> { unimplemented!() } } @@ -135,7 +137,7 @@ impl Transport for MockTransport<'_> { /// /// Pops the responses vector and returns it if it's associated request matches the i/p. /// Otherwise, returns an error string. - async fn fetch(&mut self, request: &str, _uris: &[&str]) -> Vec> { + async fn fetch(&mut self, _method: &str, request: &str, _uris: &[&str],_headers: &[&str]) -> Vec> { let response = self.responses.pop(); let request: Value = from_str(request).unwrap(); unsafe { @@ -153,7 +155,7 @@ impl Transport for MockTransport<'_> { } #[cfg(feature = "blocking")] - fn fetch_blocking(&mut self, _request: &str, _uris: &[&str]) -> Vec> { + fn fetch_blocking(&mut self, _method: &str, _request: &str, _uris: &[&str],_headers: &[&str]) -> Vec> { unimplemented!() } } @@ -168,13 +170,13 @@ pub struct HttpTransport; impl Transport for HttpTransport { /// Fetches the responses from specified URLs over HTTP. /// Errors are reported as strings. - async fn fetch(&mut self, request: &str, uris: &[&str]) -> Vec> { + async fn fetch(&mut self, method: &str, request: &str, uris: &[&str],headers: &[&str]) -> Vec> { let mut responses = vec![]; for url in uris { unsafe { LOGGER.trace(&format!("request to node '{}' ->\n {:?}\n", url, request)); } - let res = http_async(url, request).await; + let res = http_async(method, url, request, headers).await; unsafe { LOGGER.trace(&format!("response -> {:?}\n", res)); } @@ -187,11 +189,11 @@ impl Transport for HttpTransport { } #[cfg(feature = "blocking")] - fn fetch_blocking(&mut self, request: &str, uris: &[&str]) -> Vec> { + fn fetch_blocking(&mut self, method: &str, request: &str, uris: &[&str],headers: &[&str]) -> Vec> { let mut responses = vec![]; for url in uris { // println!("{:?} {:?}", url, request); - let res = async_std::task::block_on(http_async(url, request)); + let res = async_std::task::block_on(http_async(method, url, request, headers)); // println!("{:?}", res); match res { Err(_) => responses.push(Err("Transport error".to_string())), diff --git a/scripts/_in3.sh b/scripts/_in3.sh index 294e22c07..6b4cd6f65 100755 --- a/scripts/_in3.sh +++ b/scripts/_in3.sh @@ -41,6 +41,32 @@ subcmds=( 'ecrecover: extracts the address and public key from a signature ' 'key: reads the private key from JSON-Keystore file and returns the private key. ' 'createkey: generates a random key' + 'in3_checksumAddress: display the address as checksumAddress' + 'keccak: calculate the keccak hash of the ' + 'in3_toWei: returns the amount of wei of the value passed as float of eth.' + 'in3_signData: signs the as passed as argument with the configured signer. optional ' + 'in3_cacheClear: clears the local filecache' + 'in3_signTx: signs a raw transaction ' + 'zk_deposit: sends a L1-Transaction to add to the deposit ' + 'zk_transfer: transfers the given amount from the configured account to another account in L2 ' + 'zk_withdraw: transfers the given amount from the configured account in L2 to another account in L1 ' + 'zk_set_key: sets the configured key as signer for the account args: ' + 'zk_emergency_withdraw: sends a L1 Tx to withdraw all tokens from L2 ' + 'zk_sync_key: calculates and returns the pk used to sign zksync-tx (using babyjupjup curve)' + 'zk_aggregate_pubkey: calculates the combined musig public key for the concatinated public keys (each with 32 bytes)' + 'zk_pubkeyhash: returns the pubkeyhash of the signer based on the config' + 'zk_pubkey: returns the compact pubkey(32 bytes) of the signer based on the config or from the , if given' + 'zk_account_address: returns address of the zksync-account based on the config' + 'zk_account_info: returns the current balance and state of the account' + 'zk_tokens: returns a list of all available tokens' + 'zk_sign: sign the given with the syncKey. If the -zms and -zmu are passed, it will use musig schnirr sigs to create MPC-Signature' + 'zk_verify: verifies the signature of the ' + 'iamo_add_user: adds a new user to the vault-api' + 'iamo_zk_add_wallet: add a json-definition of a mutisig.' + 'iamo_zk_create_wallet: creates a multisig-definition based on the Approver-API (-zmu) ....' + 'iamo_zk_get_config: returns the configured master copy, codehash and creator for creating create2-accounts' + 'iamo_zk_create_signatures: creates a array of signatures to reach the threshold of a multisig based on and ' + 'iamo_zk_verify_signatures: verfies signatures to reach the threshold of a multisig based on and ' ) args=( @@ -54,12 +80,18 @@ args=( '-l[replaces "latest" with latest BlockNumber - the number of blocks given]:latest:(1 2 3 4 5 6 7 8 9 10)' '-s[number of signatures to use when verifying]:sigs:(1 2 3 4 5 6 7 8 9 10)' '-port[if specified it will run as http-server listening to the given port]:port:(8545)' + '-am[Allowed Methods when used with -port as comma seperated list of methods]:allowed_methods:()' '-b[the blocknumber to use when making calls]:b:(latest earliest 0x)' '-to[the target address of the call or send]:to:(0x)' - '-d[the data for a transaction. This can be a filepath, a 0x-hexvalue or - for stdin]:date:_file' + '-d[the data for a transaction. This can be a filepath, a 0x-hexvalue or - for stdin]:date:()' '-gas[the gas limit to use when sending transactions]:gas:(21000 100000 250000 500000 1000000 2000000)' - '-pk[the private key as raw or path to the keystorefile]:pk:_file' + '-gas_price[the gas price to use within a tx]:gas_price:()' + '-pk[the private key as raw or path to the keystorefile]:pk:()' + '-k[the private key to sign request for incetives payments]:k:()' '-help[displays this help message]' + '-tr[runs test request when showing in3_weights]' + '-thr[runs test request including health-check when showing in3_weights]' + '-ms[address of a imao multisig to redirect all tx through]:ms:()' '-version[displays the version]' '-debug[if given incubed will output debug information when executing]' '-value[the value to send when sending a transaction. (hexvalue or float/integer with the suffix eth]:value:(1.0eth)' @@ -69,10 +101,28 @@ args=( '-hex[the result will be returned as hex]' '-kin3[the response including in3-section is returned]' '-q[quiet no debug output]' + '-os[only sign, do not send the raw Transaction]' '-ri[read response from stdin]' '-ro[write raw response to stdout]' '-a[max number of attempts before giving up (default 5)]:attempts:(1 2 3 4 5 6 7 8 9)' '-rc[number of request per try (default 1)]:requestCount:(1 2 3 4 5 6 7 8 9)' + '-fi[read recorded request from file]:fi:()' + '-fo[recorded request and write to file]:fo:()' + '-nl[a comma seperated list of urls as address:url to be used as fixed nodelist]:nl:()' + '-bn[a comma seperated list of urls as address:url to be used as boot nodes]:bn:()' + '-zks[URL of the zksync-server]:zks:(https\://api.zksync.io/jsrpc http\://localhost\:3030)' + '-zkss[zksync signatures to pass along when signing]:zkss:()' + '-zka[zksync account to use]:zka:()' + '-zkat[zksync account type]:zkat:(pk contract create2)' + '-zsk[zksync signer seed - if not set this key will be derrived from account unless create2]:zsk:()' + '-zc2[zksync create2 arguments in the form ::. if set the account type is also changed to create2]:zc2:()' + '-zms[public keys of a musig schnorr signatures to sign with]:zms:()' + '-zmu[url for signing service matching the first remote public key]:zmu:(http\://localhost\:8080)' + '-zvpm[method for calling to verify the proof in server mode]:zvpm:(iamo_zk_verify_signatures)' + '-zcpm[method for calling to create the proof]:zcpm:(iamo_zk_create_signatures)' + '-idk[iamo device key]:idk:()' + '-imc[the master copy address to be used]:imc:()' + '-if[iamo factory address]:if:()' ':method:{_describe command subcmds}' ':arg1:{_describe command sig_in3 -- sig_erc20 -- sig_ms}' diff --git a/scripts/build.sh b/scripts/build.sh index fa6d7dd8a..527309661 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -30,7 +30,7 @@ if [ "$CONTAINER" = "bindings-debug" ]; then OPTS="-DUSE_CURL=false" fi if [ -z "$BUILDTYPE" ]; then - BUILDTYPE=DEBUG + BUILDTYPE=DEBUGG #TEST=true fi if [ "$BUILDTYPE" = "release" ]; then @@ -40,13 +40,20 @@ if [ "$BUILDTYPE" = "debug" ]; then BUILDTYPE=DEBUG TEST=true fi -OPTS="-DCMAKE_EXPORT_COMPILE_COMMANDS=true -DTEST=$TEST -DBUILD_DOC=$TEST -DJAVA=$TEST -DZKSYNC=true -DCMAKE_BUILD_TYPE=$BUILDTYPE $OPTS " +[ -z "$VERSION" ] && VERSION=$CI_COMMIT_TAG +[ -z "$VERSION" ] && VERSION=3.1.0-debug + +MIN_OPTS="-DUSE_SCRYPT=false -DETH_BASIC=true -DETH_FULL=false -DTHREADSAFE=false -DMULTISIG=false -DLOGGING=false -DCMAKE_EXPORT_COMPILE_COMMANDS=true -DTAG_VERSION=$VERSION -DZKCRYPTO_LIB=true -DTEST=$TEST -DBUILD_DOC=$TEST -DJAVA=$TEST -DZKSYNC=false -DIN3_SERVER=false -DBTC=false -DIPFS=false -DCMAKE_BUILD_TYPE=$BUILDTYPE $OPTS " +FULL_OPTS="-DUSE_SCRYPT=true -DETH_BASIC=true -DETH_FULL=true -DTHREADSAFE=true -DMULTISIG=true -DLOGGING=true -DCMAKE_EXPORT_COMPILE_COMMANDS=true -DTAG_VERSION=$VERSION -DZKCRYPTO_LIB=true -DTEST=$TEST -DBUILD_DOC=$TEST -DJAVA=$TEST -DZKSYNC=true -DIN3_SERVER=true -DBTC=true -DIPFS=true -DCMAKE_BUILD_TYPE=$BUILDTYPE $OPTS " + +OPTS=$FULL_OPTS if [ "$CONTAINER" = "--help" ]; then echo "usage $0 " echo " could be one of the following:" echo " - android-clang8-armv8" echo " - centos" + echo " - android" echo " - clang11" echo " - clang10" echo " - clang9" @@ -79,7 +86,7 @@ if [ -z "$CONTAINER" ]; then echo "local_build" touch build/container.txt cd build - cmake $OPTS .. && make -j8 + cmake $OPTS .. && make -j 8 elif [ "$CONTAINER" = "win" ]; then CONTAINER=docker.slock.it/build-images/cmake:gcc7-mingw echo $CONTAINER > build/container.txt @@ -95,6 +102,16 @@ elif [ "$CONTAINER" = "esp" ]; then echo $CONTAINER > build/container.txt docker run --rm -v $RD:$RD $CONTAINER \ /bin/bash -c "cd $RD;cp -avi scripts/qemu_xtensa.sh /opt/qemu;cd c/test/qemu/esp32;idf.py build;./make-flash-img.sh in3-espidf flash_image.bin" +elif [ "$CONTAINER" = "android" ]; then + CONTAINER=cangol/android-gradle + echo $CONTAINER > build/container.txt + CMD="cd $RD;export GRADLE_USER_HOME=$RD/.gradle" + CMD="$CMD;wget https://services.gradle.org/distributions/gradle-6.8.1-bin.zip && unzip gradle-6.8.1-bin.zip && export PATH=$RD/gradle-6.8.1/bin:/usr/local/bin:/android-sdk-linux/tools:/android-sdk-linux/platform-tools:/usr/local/gradle-5.4.1/bin:/usr/local/openjdk-8/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" + CMD="$CMD;git clone https://github.com/slockit/in3-example-android.git;cd in3-example-android" + CMD="$CMD;ln -s ../ in3" + CMD="$CMD;gradle --stacktrace build" + echo $CMD + docker run --rm -v $RD:$RD $CONTAINER /bin/bash -c "$CMD" elif [ "$CONTAINER" = "wasm_local" ]; then cd build source ~/ws/tools/emsdk/emsdk_env.sh > /dev/null @@ -103,11 +120,11 @@ elif [ "$CONTAINER" = "wasm_local" ]; then elif [ "$CONTAINER" = "wasm" ]; then CONTAINER=docker.slock.it/build-images/cmake:clang11 echo $CONTAINER > build/container.txt - docker run --rm -v $RD:$RD $CONTAINER /bin/bash -c "cd $RD/build; emcmake cmake -DWASM=true -DASMJS=false -DWASM_EMMALLOC=true -DZKSYNC=true -DWASM_EMBED=false -DCMAKE_BUILD_TYPE=$BUILDTYPE .. && make -j8" + docker run --rm -v $RD:$RD $CONTAINER /bin/bash -c "cd $RD/build; emcmake cmake -DWASM=true -DASMJS=false -DBTC_PRE_BPI34=false -DWASM_EMMALLOC=true -DZKSYNC=true -DWASM_EMBED=false -DCMAKE_BUILD_TYPE=$BUILDTYPE .. && make -j8" elif [ "$CONTAINER" = "asmjs_local" ]; then cd build source ~/ws/tools/emsdk/emsdk_env.sh > /dev/null - emcmake cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=true -DWASM=true -DASMJS=true -DWASM_EMMALLOC=true -DCMAKE_BUILD_TYPE=$BUILDTYPE .. + emcmake cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=true -DWASM=true -DASMJS=true -DZKSYNC=false -DBTC=true -DBTC_PRE_BPI34=false -DIPFS=true -DWASM_EMMALLOC=true -DCMAKE_BUILD_TYPE=$BUILDTYPE .. make -j8 in3_wasm elif [ "$CONTAINER" = "asmjs" ]; then CONTAINER=docker.slock.it/build-images/cmake:clang11 diff --git a/scripts/build_includeh.sh b/scripts/build_includeh.sh index d3260bc34..d4b296480 100755 --- a/scripts/build_includeh.sh +++ b/scripts/build_includeh.sh @@ -34,13 +34,13 @@ rm include/in3/.dirs cat <../c/include/in3.rs.h // AUTO-GENERATED FILE // See scripts/build_includeh.sh -#include "../src/core/client/context_internal.h" +#include "../src/core/client/request_internal.h" #include "../src/signer/pk-signer/signer.h" #include "../src/tools/clientdata/client_data.h" #include "../src/api/btc/btc_api.h" #include "in3/bytes.h" #include "in3/client.h" -#include "in3/context.h" +#include "in3/request.h" #include "in3/plugin.h" #include "in3/error.h" #include "in3/eth_api.h" diff --git a/scripts/macro2bin.sh b/scripts/macro2bin.sh index 02f9ed4fa..211ef09d5 100755 --- a/scripts/macro2bin.sh +++ b/scripts/macro2bin.sh @@ -67,14 +67,14 @@ while IFS="" read -r p || [ -n "$p" ]; do echo -n "${NEWDEF} " DEF=$(echo -n "$DEF" | sed 's/\\//g' | json) printf "0x${DEF}" | xxd -r -p >"${NEWDEF}"".bin" - xxd -i -a -C "${NEWDEF}"".bin" + xxd -i -a -C "${NEWDEF}"".bin" | sed -e 's/unsigned/const unsigned/' DEF="" NEWDEF="" continue fi # use old-style comments for multi-liners - printf '/*\n' +# printf '/*\n' MACRO=1 fi @@ -98,7 +98,7 @@ while IFS="" read -r p || [ -n "$p" ]; do DEF="$DEF$temp" DEF=$(echo -n "$DEF" | sed 's/\\//g' | json) printf "0x${DEF}" | xxd -r -p >"${NEWDEF}"".bin" - xxd -i -a -C "${NEWDEF}"".bin" + xxd -i -a -C "${NEWDEF}"".bin" | sed -e 's/unsigned/const unsigned/' DEF="" NEWDEF="" else diff --git a/scripts/test_python.sh b/scripts/test_python.sh new file mode 100755 index 000000000..49113b978 --- /dev/null +++ b/scripts/test_python.sh @@ -0,0 +1,10 @@ +#!/bin/sh +CWD=$PWD +cd $(dirname $0)/../build +make +cd ../python +mkdir -p in3/libin3/shared +cp ../build/lib/libin3.dylib in3/libin3/shared/libin3.x64.dylib +pip3 install -r requirements.txt +coverage run -m pytest --pylama --junitxml=report.xml +cd $CWD diff --git a/scripts/update_boot_nodes.sh b/scripts/update_boot_nodes.sh new file mode 100755 index 000000000..d90e98490 --- /dev/null +++ b/scripts/update_boot_nodes.sh @@ -0,0 +1,2 @@ +#!/bin/sh +./macro2bin.sh ../c/src/nodeselect/full/nodeselect_def_cfg_template.h > ../c/src/nodeselect/full/nodeselect_def_cfg.h diff --git a/scripts/update_keys.sh b/scripts/update_keys.sh index 932811bdc..c55c90596 100755 --- a/scripts/update_keys.sh +++ b/scripts/update_keys.sh @@ -2,7 +2,7 @@ DST=../c/src/core/util/used_keys.h echo "// this is a autogenerated file (scripts/updqate_keys.sh)! Do not edit manually!\nstatic char* USED_KEYS[] = {" > $DST echo "">tmp -for f in `ls ../c/src/*/*/*.{c,h}` +for f in `find ../c/src -name "*.c" -o -name "*.h"` do echo "check $f" cat $f | grep "key(\"" | sed 's/.*key("\([^"]*\)").*/ "\1\",/' >> tmp diff --git a/wasm/ci.yml b/wasm/ci.yml index ce0007f74..74cd5f941 100644 --- a/wasm/ci.yml +++ b/wasm/ci.yml @@ -23,7 +23,7 @@ test_asmjs: script: - mv in3_wasm wasm/test/in3 - cd wasm/test - - sh /prepare.sh +# - sh /prepare.sh - npm install - npm run test_report artifacts: @@ -58,7 +58,7 @@ test_wasm: - mv in3_wasm wasm/test/in3 - cd wasm/test - mv in3/wasm.js in3/index.js - - sh /prepare.sh +# - sh /prepare.sh - npm install - npm run test_report artifacts: @@ -79,7 +79,7 @@ test_zksync_wasm: - mv in3_wasm wasm/test/in3 - cd wasm/test - mv in3/zksync-wasm.js in3/index.js - - sh /prepare.sh +# - sh /prepare.sh - npm install - npm run test_report artifacts: @@ -99,7 +99,7 @@ test_zksync_asmjs: - mv in3_wasm wasm/test/in3 - cd wasm/test - mv in3/zksync.js in3/index.js - - sh /prepare.sh +# - sh /prepare.sh - npm install - npm run test_report artifacts: diff --git a/wasm/docs/2_examples.md b/wasm/docs/2_examples.md index cda279fdd..d5c062d03 100644 --- a/wasm/docs/2_examples.md +++ b/wasm/docs/2_examples.md @@ -2,7 +2,7 @@ ### get_block_api -source : [in3-c/wasm/examples/get_block_api.ts](https://github.com/slockit/in3-c/blob/master/wasm/examples/get_block_api.ts) +source : [in3-c/wasm/examples/get_block_api.ts](https://github.com/blockchainsllc/in3/blob/master/wasm/examples/get_block_api.ts) Reads the latest block by calling IN3's web3.js-compatible eth API. Read the eth api from web3.js docs: https://web3js.readthedocs.io/en/v1.3.0/web3-eth.html @@ -34,7 +34,7 @@ showLatestBlock().catch(console.error) ### get_block_rpc -source : [in3-c/wasm/examples/get_block_rpc.ts](https://github.com/slockit/in3-c/blob/master/wasm/examples/get_block_rpc.ts) +source : [in3-c/wasm/examples/get_block_rpc.ts](https://github.com/blockchainsllc/in3/blob/master/wasm/examples/get_block_rpc.ts) Reads the latest block by calling IN3's internal RPC to the WASM core. Learn other exclusive IN3 RPC calls here: https://in3.readthedocs.io/en/develop/rpc.html @@ -65,7 +65,7 @@ showLatestBlock().catch(console.error) ### register_pugin -source : [in3-c/wasm/examples/register_pugin.ts](https://github.com/slockit/in3-c/blob/master/wasm/examples/register_pugin.ts) +source : [in3-c/wasm/examples/register_pugin.ts](https://github.com/blockchainsllc/in3/blob/master/wasm/examples/register_pugin.ts) @@ -118,7 +118,7 @@ registerPlugin().catch(console.error) ### use_web3 -source : [in3-c/wasm/examples/use_web3.ts](https://github.com/slockit/in3-c/blob/master/wasm/examples/use_web3.ts) +source : [in3-c/wasm/examples/use_web3.ts](https://github.com/blockchainsllc/in3/blob/master/wasm/examples/use_web3.ts) use IN3 as Web3Provider in web3.js @@ -149,7 +149,7 @@ const web3 = new Web3(in3.createWeb3Provider()); ### in3_in_browser -source : [in3-c/wasm/examples/in3_in_browser.html](https://github.com/slockit/in3-c/blob/master/wasm/examples/in3_in_browser.html) +source : [in3-c/wasm/examples/in3_in_browser.html](https://github.com/blockchainsllc/in3/blob/master/wasm/examples/in3_in_browser.html) use IN3 in html diff --git a/wasm/src/in3.js b/wasm/src/in3.js index 697196736..e43bd4785 100644 --- a/wasm/src/in3.js +++ b/wasm/src/in3.js @@ -35,7 +35,12 @@ const isBrowserEnvironment = (function () { return (typeof window !== "undefined") && (this === window); }).call(); - +class HttpError extends Error { + constructor(msg, status) { + super(msg) + this.status = status + } +} // implement the transport and storage handlers /* istanbul ignore next */ if (isBrowserEnvironment) { @@ -44,16 +49,16 @@ if (isBrowserEnvironment) { get: key => window.localStorage.getItem('in3.' + key), set: (key, value) => window.localStorage.setItem('in3.' + key, value) } - in3w.transport = (url, payload, timeout) => Promise.race([ + in3w.transport = (url, payload, timeout, method, headers) => Promise.race([ fetch(url, { - method: 'POST', + method: method || 'POST', mode: 'cors', // makes it possible to access them even from the filesystem. - headers: { 'Content-Type': 'application/json', 'User-Agent': 'in3 wasm ' + getVersion() }, + headers: { 'Content-Type': 'application/json', 'User-Agent': 'in3 wasm ' + getVersion(), ...headers }, body: payload }), new Promise((_, reject) => setTimeout(() => reject(new Error('timeout')), timeout || 30000))] ).then(res => { - if (res.status < 200 || res.status >= 400) throw new Error("Error fetching" + url + ":" + res.statusText) + if (res.status < 200 || res.status >= 400) throw new HttpError("Error fetching" + url + ":" + res.statusText, res.status) return res.text() }) } @@ -76,29 +81,30 @@ else { try { // if axios is available, we use it const axios = require('' + 'axios') - in3w.transport = (url, payload, timeout = 30000) => axios.post(url, JSON.parse(payload), { timeout, headers: { 'Content-Type': 'application/json', 'User-Agent': 'in3 wasm ' + getVersion(), in3: 'wasm ' + getVersion() } }) + in3w.transport = (url, payload, timeout = 30000, method = "POST", headers = {}) => axios({ method: method || 'POST', url, data: JSON.parse(payload), timeout, headers: { 'Content-Type': 'application/json', 'User-Agent': 'in3 wasm ' + getVersion(), in3: 'wasm ' + getVersion(), ...headers } }) .then(res => { - if (res.status != 200) throw new Error("Invalid satus") + if (res.status != 200) throw new HttpError("Invalid satus", res.status) return JSON.stringify(res.data) }) } catch (xx) { // if not we use the raw http-implementation of nodejs - in3w.transport = (url, payload, timeout = 30000) => new Promise((resolve, reject) => { + in3w.transport = (url, payload, timeout = 30000, method = 'POST', headers = {}) => new Promise((resolve, reject) => { try { const postData = payload;//JSON.stringify(payload); const m = require(url.startsWith('https') ? 'https' : 'http') const req = m.request(url, { - method: 'POST', + method: method || 'POST', headers: { 'User-Agent': 'in3 wasm ' + getVersion(), in3: 'wasm ' + getVersion(), 'Content-Type': 'application/json', - 'Content-Length': Buffer.byteLength(postData) + 'Content-Length': Buffer.byteLength(postData), + ...headers }, body: payload // body data type must match "Content-Type" header }, (res) => { if (res.statusCode < 200 || res.statusCode >= 400) - reject(new Error("Invalid Status (" + res.statusCode + ') from server')) + reject(new HttpError("Invalid Status (" + res.statusCode + ') from server', res.statusCode)) else { res.setEncoding('utf8'); let result = '' @@ -181,7 +187,7 @@ class IN3 { // here we are creating the instance lazy, when the first function is called. constructor(config) { - const def = { requestCount: 2 } + const def = { requestCount: 2, chainId: 'mainnet' } this.ptr = 0; this.setConfig(config ? { ...def, ...config } : def) in3w.extensions.forEach(_ => _(this)) @@ -310,7 +316,7 @@ class IN3 { if (!(await this.signer.canSign(account))) throw new Error('unknown account ' + account) setResponse(req.ctx, toHex(await this.signer.sign(message, account, true, false)), 0, false) } catch (ex) { - setResponse(req.ctx, ex.message || ex, 0, true) + setResponse(req.ctx, ex.message || ex, 0, ex.status || true) } break; @@ -399,12 +405,18 @@ function getNextResponse(map, req) { return res.getNext() } +function map_header(headers, entry) { + let p = entry.indexOf(':') + if (p > 0) headers[entry.substr(0, p).trim()] = entry.substr(p + 1).trim() + return headers +} + function url_queue(req) { let counter = 0 const promises = [], responses = [] if (req.in3.config.debug) console.log("send req (" + req.ctx + ") to " + req.urls.join() + ' : ', JSON.stringify(req.payload, null, 2)) const transport = req.in3.transport || in3w.transport - req.urls.forEach((url, i) => transport(url, JSON.stringify(req.payload), req.timeout || 30000).then( + req.urls.forEach((url, i) => transport(url, JSON.stringify(req.payload), req.timeout || 30000, req.method, req.headers.reduce(map_header, {})).then( response => { responses.push({ i, url, response }); trigger() }, error => { responses.push({ i, url, error }); trigger() } )) @@ -414,14 +426,14 @@ function url_queue(req) { if (!req.cleanUp && req.in3.ptr && in3w.ccall('in3_is_alive', 'number', ['number', 'number'], [req.root, req.ctx])) { if (r.error) { if (req.in3.config.debug) console.error("res err (" + req.ctx + "," + r.url + ") : " + r.error) - setResponse(req.ctx, r.error.message || r.error, r.i, true) + setResponse(req.ctx, r.error.message || r.error, r.i, r.error.status || true) } else { try { if (req.in3.config.debug) console.log("res (" + req.ctx + "," + r.url + ") : " + JSON.stringify(JSON.parse(r.response), null, 2)) setResponse(req.ctx, r.response, r.i, false) } catch (x) { - setResponse(req.ctx, r.error.message || r.error, r.i, true) + setResponse(req.ctx, r.error.message || r.error, r.i, r.error.status || true) } } } @@ -519,6 +531,8 @@ if (typeof module !== "undefined") // helper functions function setResponse(ctx, msg, i, isError) { + if (isError === true) isError = -11 + else if (isError > 0) isError = 0 - isError if (msg.length > 5000) { // here we pass the string as pointer using malloc before const len = (msg.length << 2) + 1; diff --git a/wasm/src/index.d.ts b/wasm/src/index.d.ts index 6a3171fff..2fb960da1 100644 --- a/wasm/src/index.d.ts +++ b/wasm/src/index.d.ts @@ -90,6 +90,14 @@ export declare interface IN3Config { */ includeCode?: boolean + /** + * if true, features marked as experimental are allowed. + * Otherwise an exception would be thrown if those features would be used. + * + * default: false + */ + experimental?: boolean + /** * if true, the first request (updating the nodelist) will also fetch the current health status * and use it for blacklisting unhealthy nodes. This is used only if no nodelist is availabkle from cache. diff --git a/wasm/src/wasm.c b/wasm/src/wasm.c index 6c8b82c2c..ce679ce17 100644 --- a/wasm/src/wasm.c +++ b/wasm/src/wasm.c @@ -32,15 +32,15 @@ * with this program. If not, see . *******************************************************************************/ #include "../../c/src/core/client/client.h" -#include "../../c/src/core/client/context_internal.h" #include "../../c/src/core/client/keys.h" +#include "../../c/src/core/client/request_internal.h" #include "../../c/src/core/client/version.h" #include "../../c/src/core/util/mem.h" -#include "../../c/src/nodeselect/cache.h" -#include "../../c/src/nodeselect/nodelist.h" +#include "../../c/src/init/in3_init.h" +#include "../../c/src/nodeselect/full/cache.h" +#include "../../c/src/nodeselect/full/nodelist.h" #include "../../c/src/third-party/crypto/ecdsa.h" #include "../../c/src/third-party/crypto/secp256k1.h" -#include "../../c/src/verifier/in3_init.h" #ifdef ETH_FULL #include "../../c/src/third-party/tommath/tommath.h" #endif @@ -130,7 +130,7 @@ EM_JS(int, plgn_exec_term, (in3_t * c, int index), { return plgn.term(client) || 0; }) -EM_JS(int, plgn_exec_rpc_handle, (in3_t * c, in3_ctx_t* ctx, char* req, int index), { +EM_JS(int, plgn_exec_rpc_handle, (in3_t * c, in3_req_t* ctx, char* req, int index), { var client = Module.clients[c]; var plgn = client && client.plugins[index]; if (!plgn) return -4; @@ -176,7 +176,7 @@ in3_ret_t wasm_plgn(void* data, in3_plugin_act_t action, void* ctx) { case PLGN_ACT_TERM: return plgn_exec_term(ctx, index); case PLGN_ACT_SIGN_ACCOUNT: { in3_sign_account_ctx_t* sctx = ctx; - return plgn_exec_sign_accounts(sctx->ctx->client, sctx, index); + return plgn_exec_sign_accounts(sctx->req->client, sctx, index); } case PLGN_ACT_RPC_HANDLE: { // extract the request as string, so we can pass it to js @@ -185,7 +185,7 @@ in3_ret_t wasm_plgn(void* data, in3_plugin_act_t action, void* ctx) { char* req = alloca(sr.len + 1); memcpy(req, sr.data, sr.len); req[sr.len] = 0; - return plgn_exec_rpc_handle(rc->ctx->client, rc->ctx, req, index); + return plgn_exec_rpc_handle(rc->req->client, rc->req, req, index); } default: break; } @@ -202,7 +202,7 @@ void EMSCRIPTEN_KEEPALIVE wasm_register_plugin(in3_t* c, in3_plugin_act_t action /** * repareses the request for the context with a new input. */ -void EMSCRIPTEN_KEEPALIVE wasm_set_request_ctx(in3_ctx_t* ctx, char* req) { +void EMSCRIPTEN_KEEPALIVE wasm_set_request_ctx(in3_req_t* ctx, char* req) { if (!ctx->request_context) return; char* src = ctx->request_context->c; // we keep the old pointer since this may be an internal request where this needs to be freed. json_free(ctx->request_context); // throw away the old pares context @@ -226,31 +226,31 @@ void EMSCRIPTEN_KEEPALIVE wasm_set_sign_account(in3_sign_account_ctx_t* ctx, int * main execute function which generates a json representing the status and all required data to be handled in js. * The resulting string needs to be freed by the caller! */ -char* EMSCRIPTEN_KEEPALIVE ctx_execute(in3_ctx_t* ctx) { - in3_ctx_t* p = ctx; - in3_request_t* req = NULL; - sb_t* sb = sb_new("{\"status\":"); +char* EMSCRIPTEN_KEEPALIVE ctx_execute(in3_req_t* ctx) { + in3_req_t* p = ctx; + in3_http_request_t* req = NULL; + sb_t* sb = sb_new("{\"status\":"); - switch (in3_ctx_exec_state(ctx)) { - case CTX_SUCCESS: + switch (in3_req_exec_state(ctx)) { + case REQ_SUCCESS: sb_add_chars(sb, "\"ok\", \"result\":"); sb_add_chars(sb, ctx->response_context->c); break; - case CTX_ERROR: + case REQ_ERROR: sb_add_chars(sb, "\"error\",\"error\":\""); sb_add_escaped_chars(sb, ctx->error ? ctx->error : "Unknown error"); sb_add_chars(sb, "\""); break; - case CTX_WAITING_FOR_RESPONSE: + case REQ_WAITING_FOR_RESPONSE: sb_add_chars(sb, "\"waiting\",\"request\":{ \"type\": "); - sb_add_chars(sb, ctx->type == CT_SIGN ? "\"sign\"" : "\"rpc\""); + sb_add_chars(sb, ctx->type == RT_SIGN ? "\"sign\"" : "\"rpc\""); sb_add_chars(sb, ",\"ctx\":"); - sb_add_int(sb, (unsigned int) in3_ctx_last_waiting(ctx)); + sb_add_int(sb, (unsigned int) in3_req_last_waiting(ctx)); sb_add_char(sb, '}'); break; - case CTX_WAITING_TO_SEND: + case REQ_WAITING_TO_SEND: sb_add_chars(sb, "\"request\""); - in3_request_t* request = in3_create_request(ctx); + in3_http_request_t* request = in3_create_request(ctx); if (request == NULL) { sb_add_chars(sb, ",\"error\",\""); sb_add_escaped_chars(sb, ctx->error ? ctx->error : "could not create request"); @@ -259,23 +259,32 @@ char* EMSCRIPTEN_KEEPALIVE ctx_execute(in3_ctx_t* ctx) { else { uint32_t start = now(); sb_add_chars(sb, ",\"request\":{ \"type\": "); - sb_add_chars(sb, request->ctx->type == CT_SIGN ? "\"sign\"" : "\"rpc\""); + sb_add_chars(sb, request->req->type == RT_SIGN ? "\"sign\"" : "\"rpc\""); sb_add_chars(sb, ",\"timeout\":"); - sb_add_int(sb, (uint64_t) request->ctx->client->timeout); + sb_add_int(sb, (uint64_t) request->req->client->timeout); sb_add_chars(sb, ",\"wait\":"); sb_add_int(sb, (uint64_t) request->wait); sb_add_chars(sb, ",\"payload\":"); sb_add_chars(sb, request->payload); - sb_add_chars(sb, ",\"urls\":["); + sb_add_chars(sb, ",\"method\":\""); + sb_add_chars(sb, request->method); + sb_add_chars(sb, "\",\"urls\":["); for (int i = 0; i < request->urls_len; i++) { - request->ctx->raw_response[i].time = start; + request->req->raw_response[i].time = start; if (i) sb_add_char(sb, ','); sb_add_char(sb, '"'); sb_add_escaped_chars(sb, request->urls[i]); sb_add_char(sb, '"'); } + sb_add_chars(sb, "],\"headers\":["); + for (in3_req_header_t* h = request->headers; h; h = h->next) { + if (h != request->headers) sb_add_char(sb, ','); + sb_add_char(sb, '"'); + sb_add_escaped_chars(sb, h->value); + sb_add_char(sb, '"'); + } sb_add_chars(sb, "],\"ctx\":"); - sb_add_int(sb, (uint64_t) request->ctx); + sb_add_int(sb, (uint64_t) request->req); sb_add_char(sb, '}'); request_free(request); } @@ -302,11 +311,11 @@ void EMSCRIPTEN_KEEPALIVE in3_blacklist(in3_t* in3, char* url) { in3_plugin_execute_all(in3, PLGN_ACT_NL_BLACKLIST, &bctx); } -void EMSCRIPTEN_KEEPALIVE ctx_set_response(in3_ctx_t* ctx, int i, int is_error, char* msg) { +void EMSCRIPTEN_KEEPALIVE ctx_set_response(in3_req_t* ctx, int i, int is_error, char* msg) { if (!ctx->raw_response) ctx->raw_response = _calloc(sizeof(in3_response_t), i + 1); ctx->raw_response[i].time = now() - ctx->raw_response[i].time; - ctx->raw_response[i].state = is_error ? IN3_ERPC : IN3_OK; - if (ctx->type == CT_SIGN && !is_error) { + ctx->raw_response[i].state = is_error; + if (ctx->type == RT_SIGN && !is_error) { int l = (strlen(msg) + 1) / 2; if (l && msg[0] == '0' && msg[1] == 'x') l--; uint8_t* sig = alloca(l); @@ -341,7 +350,7 @@ void EMSCRIPTEN_KEEPALIVE in3_dispose(in3_t* a) { in3_set_error(NULL); } /* frees the references of the client */ -bool EMSCRIPTEN_KEEPALIVE in3_is_alive(in3_ctx_t* root, in3_ctx_t* ctx) { +bool EMSCRIPTEN_KEEPALIVE in3_is_alive(in3_req_t* root, in3_req_t* ctx) { while (root) { if (ctx == root) return true; root = root->required; @@ -357,12 +366,12 @@ char* EMSCRIPTEN_KEEPALIVE in3_last_error() { return last_error; } -in3_ctx_t* EMSCRIPTEN_KEEPALIVE in3_create_request_ctx(in3_t* c, char* payload) { +in3_req_t* EMSCRIPTEN_KEEPALIVE in3_create_request_ctx(in3_t* c, char* payload) { char* src_data = _strdupn(payload, -1); - in3_ctx_t* ctx = ctx_new(c, src_data); + in3_req_t* ctx = req_new(c, src_data); if (ctx->error) { in3_set_error(ctx->error); - ctx_free(ctx); + req_free(ctx); return NULL; } // add the src-string as cache-entry so it will be freed when finalizing. @@ -371,8 +380,8 @@ in3_ctx_t* EMSCRIPTEN_KEEPALIVE in3_create_request_ctx(in3_t* c, char* payload) return ctx; } -void EMSCRIPTEN_KEEPALIVE in3_request_free(in3_ctx_t* ctx) { - ctx_free(ctx); +void EMSCRIPTEN_KEEPALIVE in3_request_free(in3_req_t* ctx) { + req_free(ctx); } uint8_t* EMSCRIPTEN_KEEPALIVE hash_keccak(uint8_t* data, int len) { diff --git a/wasm/test/testRunner.js b/wasm/test/testRunner.js index e03952500..fb73ab6b9 100644 --- a/wasm/test/testRunner.js +++ b/wasm/test/testRunner.js @@ -180,6 +180,7 @@ async function runSingleTest(test, c) { autoUpdateList: false, includeCode: true, bootWeights: false, + experimental: true, proof: test.proof || 'standard', maxAttempts: 1, finality: test.finality || 0, diff --git a/wasm/test/util/mocker.js b/wasm/test/util/mocker.js index 05ad2dc90..fd805062a 100644 --- a/wasm/test/util/mocker.js +++ b/wasm/test/util/mocker.js @@ -84,6 +84,7 @@ function createClient(config = {}, recordName) { autoUpdateList: false, proof: 'standard', maxAttempts: 1, + experimental: true, signatureCount: 0, nodeRegistry: { needsUpdate: false