diff --git a/nimbus_verified_proxy/libverifproxy/example.c b/nimbus_verified_proxy/libverifproxy/example.c index f8cb239f01..6ef074d872 100644 --- a/nimbus_verified_proxy/libverifproxy/example.c +++ b/nimbus_verified_proxy/libverifproxy/example.c @@ -1,6 +1,6 @@ /** * nimbus_verified_proxy - * Copyright (c) 2025 Status Research & Development GmbH + * Copyright (c) 2025-2026 Status Research & Development GmbH * Licensed and distributed under either of * * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT). * * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0). @@ -18,71 +18,71 @@ char filterId[67]; bool filterCreated = false; -void onBlockNumber(Context *ctx, int status, char *res) { +void onBlockNumber(Context *ctx, int status, char *res, void *userData) { printf("Blocknumber: %s\n", res); - freeResponse(res); + freeNimAllocatedString(res); } -void onStart(Context *ctx, int status, char *res) { +void onStart(Context *ctx, int status, char *res, void *userData) { if (status < 0){ // callback onStart is called only for errors - printf("Problem while starting verified proxy\n"); + printf("Problem while starting verified proxy: %s\n", res); stopVerifProxy(ctx); freeContext(ctx); exit(EXIT_FAILURE); } } -void onStorage(Context *ctx, int status, char *res) { +void onStorage(Context *ctx, int status, char *res, void *userData) { printf("Storage: %s\n", res); - freeResponse(res); + freeNimAllocatedString(res); } -void onBalance(Context *ctx, int status, char *res) { +void onBalance(Context *ctx, int status, char *res, void *userData) { printf("Balance: %s\n", res); - freeResponse(res); + freeNimAllocatedString(res); } -void onNonce(Context *ctx, int status, char *res) { +void onNonce(Context *ctx, int status, char *res, void *userData) { printf("Nonce: %s\n", res); - freeResponse(res); + freeNimAllocatedString(res); } -void onCode(Context *ctx, int status, char *res) { +void onCode(Context *ctx, int status, char *res, void *userData) { printf("Code: %s\n", res); - freeResponse(res); + freeNimAllocatedString(res); } -void genericCallback(Context *ctx, int status, char *res) { - printf("Status: %d\n", status); +void genericCallback(Context *ctx, int status, char *res, void *userData) { + printf("ReqID: %s, Status: %d\n", (char *)userData, status); if (status < 0) printf("Error: %s\n", res); - freeResponse(res); + freeNimAllocatedString(res); } -void onFilterCreate(Context *ctx, int status, char *res) { +void onFilterCreate(Context *ctx, int status, char *res, void *userData) { if (status == RET_SUCCESS) { strncpy(filterId, &res[1], strlen(res) - 2); // remove quotes filterId[strlen(res) - 2] = '\0'; filterCreated = true; } - freeResponse(res); + freeNimAllocatedString(res); } -void onCallComplete(Context *ctx, int status, char *res) { +void onCallComplete(Context *ctx, int status, char *res, void *userData) { if (status == RET_SUCCESS) { printf("Call Complete: %s\n", res); } else { printf("Call Error: %s\n", res); } - freeResponse(res); + freeNimAllocatedString(res); } -void onLogs(Context *ctx, int status, char *res) { +void onLogs(Context *ctx, int status, char *res, void *userData) { if (status == RET_SUCCESS) { printf("Logs fetch successful\n"); } else { printf("Logs Fetch Error: %s\n", res); } - freeResponse(res); + freeNimAllocatedString(res); } void makeCalls(Context *ctx) { @@ -91,43 +91,99 @@ void makeCalls(Context *ctx) { char *CALL_ARGS = "{\"to\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\"data\": \"0x70a08231000000000000000000000000De5ae63A348C4d63343C8E20Fb6286909418c8A4\"}"; char *FILTER_OPTIONS = "{\"fromBlock\": \"latest\", \"toBlock\": \"latest\", \"topics\":[\"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef\"]}"; - eth_blockNumber(ctx, onBlockNumber); - eth_getBalance(ctx, "0x954a86C613fd1fBaC9C7A43a071A68254C75E4AC", "latest", onBalance); - eth_getStorageAt(ctx, "0x954a86C613fd1fBaC9C7A43a071A68254C75E4AC", "0x0", "latest", onStorage); - eth_getTransactionCount(ctx, "0x954a86C613fd1fBaC9C7A43a071A68254C75E4AC", "latest", onNonce); - eth_getCode(ctx, "0x954a86C613fd1fBaC9C7A43a071A68254C75E4AC", "latest", onCode); + eth_blockNumber(ctx, onBlockNumber, 0); + nvp_call(ctx, "eth_blockNumber", "[]", onBlockNumber, 0); + + eth_getBalance(ctx, "0x954a86C613fd1fBaC9C7A43a071A68254C75E4AC", "latest", onBalance, 0); + nvp_call(ctx, "eth_getBalance", "[\"0x954a86C613fd1fBaC9C7A43a071A68254C75E4AC\", \"latest\"]", onBalance, 0); + + eth_getStorageAt(ctx, "0x954a86C613fd1fBaC9C7A43a071A68254C75E4AC", "0x0", "latest", onStorage, 0); + nvp_call(ctx, "eth_getStorageAt", "[\"0x954a86C613fd1fBaC9C7A43a071A68254C75E4AC\", \"0x0\", \"latest\"]", onStorage, 0); + + eth_getTransactionCount(ctx, "0x954a86C613fd1fBaC9C7A43a071A68254C75E4AC", "latest", onNonce, 0); + nvp_call(ctx, "eth_getTransactionCount", "[\"0x954a86C613fd1fBaC9C7A43a071A68254C75E4AC\", \"latest\"]", onNonce, 0); + + eth_getCode(ctx, "0x954a86C613fd1fBaC9C7A43a071A68254C75E4AC", "latest", onCode, 0); + nvp_call(ctx, "eth_getCode", "[\"0x954a86C613fd1fBaC9C7A43a071A68254C75E4AC\", \"latest\"]", onCode, 0); /* -------- Blocks & Uncles -------- */ + char *data = "this is an rpc request context, it could also be a pointer to a structure or primary data type"; + + eth_getBlockByHash(ctx, BLOCK_HASH, false, genericCallback, data); + nvp_call(ctx, "eth_getBlockByHash", "[\"0xc62fa4cbdd48175b1171d8b7cede250ac1bea47ace4d19db344b922cd1e63111\", \"false\"]", genericCallback, data); + + eth_getBlockByNumber(ctx, "latest", false, genericCallback, data); + nvp_call(ctx, "eth_getBlockByNumber", "[\"latest\", \"false\"]", genericCallback, data); - eth_getBlockByHash(ctx, BLOCK_HASH, false, genericCallback); - eth_getBlockByNumber(ctx, "latest", false, genericCallback); - eth_getUncleCountByBlockNumber(ctx, "latest", genericCallback); - eth_getUncleCountByBlockHash(ctx, BLOCK_HASH, genericCallback); + eth_getUncleCountByBlockNumber(ctx, "latest", genericCallback, data); + nvp_call(ctx, "eth_getUncleCountByBlockNumber", "[\"latest\"]", genericCallback, data); - eth_getBlockTransactionCountByNumber(ctx, "latest", genericCallback); - eth_getBlockTransactionCountByHash(ctx, BLOCK_HASH, genericCallback); + eth_getUncleCountByBlockHash(ctx, BLOCK_HASH, genericCallback, data); + nvp_call(ctx, "eth_getUncleCountByBlockHash", "[\"0xc62fa4cbdd48175b1171d8b7cede250ac1bea47ace4d19db344b922cd1e63111\"]", genericCallback, data); + + eth_getBlockTransactionCountByNumber(ctx, "latest", genericCallback, data); + nvp_call(ctx, "eth_getBlockTransactionCountByNumber", "[\"latest\"]", genericCallback, data); + + eth_getBlockTransactionCountByHash(ctx, BLOCK_HASH, genericCallback, data); + nvp_call(ctx, "eth_getBlockTransactionCountByHash", "[\"0xc62fa4cbdd48175b1171d8b7cede250ac1bea47ace4d19db344b922cd1e63111\"]", genericCallback, data); /* -------- Transactions -------- */ - eth_getTransactionByBlockNumberAndIndex(ctx, "latest", 0ULL, genericCallback); - eth_getTransactionByBlockHashAndIndex(ctx, BLOCK_HASH, 0ULL, genericCallback); + eth_getTransactionByBlockNumberAndIndex(ctx, "latest", 0ULL, genericCallback, data); + nvp_call(ctx, "eth_getTransactionByBlockNumberAndIndex", "[\"latest\", \"0x0\"]", genericCallback, data); + + eth_getTransactionByBlockHashAndIndex(ctx, BLOCK_HASH, 0ULL, genericCallback, data); + nvp_call(ctx, "eth_getTransactionByBlockHashAndIndex", "[\"0xc62fa4cbdd48175b1171d8b7cede250ac1bea47ace4d19db344b922cd1e63111\", \"0x0\"]", genericCallback, data); - eth_getTransactionByHash(ctx, TX_HASH, genericCallback); - eth_getTransactionReceipt(ctx, TX_HASH, genericCallback); + eth_getTransactionByHash(ctx, TX_HASH, genericCallback, data); + nvp_call(ctx, "eth_getTransactionByHash", "[\"0xbbcd3d9bc70874c03453caa19fd91239abb0eef84dc61ca33e2110df81df330c\"]", genericCallback, data); - eth_getBlockReceipts(ctx, "latest", genericCallback); + eth_getTransactionReceipt(ctx, TX_HASH, genericCallback, data); + nvp_call(ctx, "eth_getTransactionReceipt", "[\"0xbbcd3d9bc70874c03453caa19fd91239abb0eef84dc61ca33e2110df81df330c\"]", genericCallback, data); + + eth_getBlockReceipts(ctx, "latest", genericCallback, data); + nvp_call(ctx, "eth_getBlockReceipts", "[\"latest\"]", genericCallback, data); /* -------- Calls, Access Lists, Gas Estimation -------- */ - eth_call(ctx, CALL_ARGS, "latest", true, onCallComplete); - eth_createAccessList(ctx, CALL_ARGS, "latest", false, onCallComplete); - eth_estimateGas(ctx, CALL_ARGS, "latest", false, onCallComplete); + eth_call(ctx, CALL_ARGS, "latest", true, onCallComplete, 0); + nvp_call(ctx, "eth_call", "[{\"to\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\"data\": \"0x70a08231000000000000000000000000De5ae63A348C4d63343C8E20Fb6286909418c8A4\"}, \"latest\", \"true\"]", onCallComplete, 0); + + eth_createAccessList(ctx, CALL_ARGS, "latest", false, onCallComplete, 0); + nvp_call(ctx, "eth_createAccessList", "[{\"to\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\"data\": \"0x70a08231000000000000000000000000De5ae63A348C4d63343C8E20Fb6286909418c8A4\"}, \"latest\", \"false\"]", onCallComplete, 0); + + eth_estimateGas(ctx, CALL_ARGS, "latest", false, onCallComplete, 0); + nvp_call(ctx, "eth_estimateGas", "[{\"to\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\"data\": \"0x70a08231000000000000000000000000De5ae63A348C4d63343C8E20Fb6286909418c8A4\"}, \"latest\", \"false\"]", onCallComplete, 0); /* -------- Logs & Filters -------- */ - eth_getLogs(ctx, FILTER_OPTIONS, onLogs); + eth_getLogs(ctx, FILTER_OPTIONS, onLogs, 0); + nvp_call(ctx, "eth_getLogs", "[{\"fromBlock\": \"latest\", \"toBlock\": \"latest\", \"topics\":[\"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef\"]}]", onLogs, 0); + if (filterCreated) { - eth_getFilterLogs(ctx, filterId, onLogs); - eth_getFilterChanges(ctx, filterId, onLogs); + eth_getFilterLogs(ctx, filterId, onLogs, 0); + eth_getFilterChanges(ctx, filterId, onLogs, 0); + } else { + nvp_call(ctx, "eth_newFilter", "[{\"fromBlock\": \"latest\", \"toBlock\": \"latest\", \"topics\":[\"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef\"]}]", onFilterCreate, 0); + eth_newFilter(ctx, FILTER_OPTIONS, onFilterCreate, 0); + } +} + +const char *BLOCK = "{\"jsonrpc\":\"2.0\",\"id\":1,\"result\":{\"baseFeePerGas\":\"0xb5d68e0a3\",\"difficulty\":\"0x0\",\"extraData\":\"0x\",\"gasLimit\":\"0x1c9c380\",\"gasUsed\":\"0x1c9811e\",\"hash\":\"0x56a9bb0302da44b8c0b3df540781424684c3af04d0b7a38d72842b762076a664\",\"logsBloom\":\"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\",\"miner\":\"0xeee27662c2b8eba3cd936a23f039f3189633e4c8\",\"mixHash\":\"0xa86c2e601b6c44eb4848f7d23d9df3113fbcac42041c49cbed5000cb4f118777\",\"nonce\":\"0x0000000000000000\",\"number\":\"0xed14f2\",\"parentHash\":\"0x55b11b918355b1ef9c5db810302ebad0bf2544255b530cdce90674d5887bb286\",\"receiptsRoot\":\"0x928073fb98ce316265ea35d95ab7e2e1206cecd85242eb841dbbcc4f568fca4b\",\"sha3Uncles\":\"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347\",\"size\":\"0x487f\",\"stateRoot\":\"0x40c07091e16263270f3579385090fea02dd5f061ba6750228fcc082ff762fda7\",\"timestamp\":\"0x6322c973\",\"transactions\":[\"0x5ad934ee3bf2f8938d8518a3b978e81f178eaa21824ee52fef83338f786e7b59\",\"0xcf92f67b37495b4149a522da5dce665cddd1c183c79ba1e870564f77ffaabbca\",\"0x714b934c3dad0f28fbc9d0438312a3801ab863480b98be4548f36a436cf270b5\",\"0x1b86278143e06a8dcd0944d336100c8187ff1e4277ef5fd39360dd7bfcdc355b\",\"0xee199f9280622e1990c649c23907d819ab6d5a27a41dc50b625812d02af8ff0f\",\"0x810681d62880142079ffd8df6bee87cebb8fa6f8c66a836f1e4c33678cb0837d\",\"0x0235355b47d026438f0c66f09db5ed2b4462044aa632164b394cd2553fb2693e\",\"0x72c32e24f7438f3f94c9dd8c2b5a3a3121ae415a011ea26a64b8745b92b44fed\",\"0xe77cbd77faeadef0c709fc23992a37510ed06c0e9f989dc4b51400015ee434ed\",\"0xc18d08faee7bbb924b77ea5d09cac3ff3bf008f51fffd30d14e54feeb3ea61e4\",\"0xc1ef8077e3df62f078182a48b18fdb82d9aa69b523d9b6f300c2b8e1dac5ebd6\",\"0x339832e1a0bbb712f1fa25cb7fb90c7c9faca2d9520c35620bd2f1106b66efc7\",\"0x553a3a38ebf871c3ab98edacd50fa9e76a8c6c39ccd352ee4e2d1b2e3a0b969f\",\"0xc158ea664d7cfbcaf9af680b3ad7712da42ca4dc2fc3fd8d2adaf65d45c2ef6c\",\"0xa950cb26eec201768a73546683f8a9d0886ab670ef5fa7e9b81d50373b799235\",\"0x22d749c5302aae6698c54867c08399f838784522fadd53ffd024fe2f16f1052e\",\"0x7036e375dbd2c2a54e9a4041e8d8ca0623fffa7adf489d79a08914b49b3c6f1f\",\"0xf037c976a34578f42c88025cd51fcc358c510b4cec459af5462200305808a6d0\",\"0xeef5e4a5a8a557f927120bddbb55cb4ad87a082c63c3cf8581ad8a4990614c65\",\"0xd6fa4d5e7042c09e6e4fb503fbd69945a71195318bc6c8116d790eea862bdd71\",\"0x732fd0215b35bc6ba2ba370fa67133c3020c46de78c8a7b7981946cea069d874\",\"0xfc5e7ea32890c90f9f884772e7cbbbaa4976688c80133835dde5b158dae6f4a8\",\"0x5fde395a33a15f2e0b012988d047af21d8d434c3f74ccca69c3579a26cc62462\",\"0x409f265e490b0b962332b08a9bea522cbbaf3f84c812b22e5e851a330cc7d3b0\",\"0x1eef2fed2a234716f9e7546049c08f136904ad2622ae3b69ab98fcfaa52018cd\",\"0x216b67f3ad43ca4a2e64fc7a7d29643a19a4c460ad771f21a1483a23205ec45d\",\"0x61fa6bfa7d2b7d522aba1b2d9899f21f05dfca3e0498b09ff8262c921262450e\",\"0x9faff8b4d5334090550fb879260d353d81c1178c6531e8ca225a9e0a032da24a\",\"0xf0e4e1f83a2a14f076e31caf5cfa9ac26254d8cfb4fe4a5dc5bcd25ee9d428a1\",\"0xe66b3c6d173fa768ed64fa5e87b5374ff3fcf0205e5bae65ee958160c2da9fa7\",\"0x05d528b4a8a659ccea73c3946b6c049b09cbc714aefd0d26bf17739157f2fcd5\",\"0xccd037ccb864784af8932e68b1335d03ad108acac16591fe2118b3056b03b942\",\"0x1f3647004a42dca3eef8801ee35705c8f63abfec50fb2144984bcdf0e3b1741a\",\"0x8889b2ddfedc4da7b03a155ac4141978503ce7963e2f26bfc8ee94b596f43d30\",\"0x511248feb7d0e1b585b413a2adc17fa3b291ced1449031fe45ac41f602bb9b30\",\"0xa28db5a9e809a14486e747d017def59c4ef458c7b28c30e64826ec429da0d358\",\"0xe8153d04b57a972ede68a6bacbf2b5d7300764008748ba6fcee5a948da7a2c61\",\"0xf16d6eb80ec921c5ef06e1acd5a0a0f005eff6b980dd150ea079e47a61af371d\",\"0xff22311453c633e90a34514dd8c623d8fad5a8424438b86007c7db8665b4f644\",\"0x8116c74edd4607b4229babd542b13cdb99e9f7ac31d19e1be40ff43b8d740770\",\"0x44503d86e543e5574afd67df4e2ee11033a1e26573bf1abf3477a954e27e0bf6\",\"0x119c2cdcfa03938e6cd7ce3f8d99dde5062d96ec9cc25c891291784bd6d34bd1\",\"0x69a19ec0f276e8e022d6bdaebd3db544a8329a686110cea653e5590add13e34e\",\"0xb6fa2bdc210a93a55d70a68fb35fae461533262f23f70d044f21df0cb9e5c488\",\"0xadfb7d1527cc88307ef4d42d1b9728f220e746aae0db16d51b056563bb8d8e20\",\"0x35d8d742844b967047de36dbd3af43144e395be9c5afc396a281070e3de4abaa\",\"0xea1435bcea16eadc48fc64fc28a90b36e054e9a2e79109651e72ef140706bbf2\",\"0xff527682816e12a83d188b61a2e4bc5b110100c59d14560495b67e5944aab130\",\"0xcb9f25127bd802e39d8297bfbdf4e63d66387513f88beb813069550ab7f504d9\",\"0xf043430838905980a823430e5c499bd19cea82f301f6e6b92598dfb5a5d5d919\",\"0xbdb461b75bc5dbd1da7dbe3c1d3c540e5f09ebd034de12de06a2235d046bf996\",\"0x2f6dcd0baee7e9ed29d4137f66ac997caf90117da391d4b37cc8ba04a2029bb6\",\"0x4f4bec2cf3076789402b606b644f6df0f0db8c04d3ff78320177a641d94daf88\",\"0x08c87430710930718e5cc23c16c8f6f5cc5417a17f46c17c27102b9129adc1a1\",\"0xdc57e2c6414198a302c313bb79f292ec714957182dc6e6a51c739718e3378d06\",\"0x3af096859a880d9c33718eda59cb96e1504db7390d0e086c7260d91e87139eab\",\"0xf5787c239852670e313cf5eed13cf89c2ba1f5209b37c28595123f5940996338\",\"0xbbc970691625eda88a1cc18841f1fc8907f86549c93c230353d876a9718cb483\",\"0xceae7d3ab98899982623304631355510a70a1ca73fe3cb8a88216dea99e89c1d\",\"0xdd3b620b49afa578c51266b7e38da38f466150385f54a4878f3a0b794bdb926f\",\"0x1e66b94dc423d6b95c9161b4b88d8862e1d05704379386e1b5e6b7f28d62c646\",\"0xd29b41f69babd4c5c680234579467ecb3857e39e42c5b53680bc230f6832b425\",\"0x2eee61013dfe1380c8794aa110522f112ff83be81ac34e9f7995dac81b6cfced\",\"0xfe1d19700fcd7d337e8ac2f985eef5e1ef05b4802d26a1637788a2d9d3464277\",\"0xb2c83000b69838c40fc55b81970e05099bd6bb9687ae80a66b8b86f38cfe26e7\",\"0x63c06123f3faac825ff6c61a08bc551e60628d68e1479d52620ded995d0f24bc\",\"0x1d4e4495d368f7f07f62af7ca6c22215a83d872a123dfcdbb6704d8d9f3e5a92\",\"0x181372058f61ffd1e64d8c1a3732234414fdb8443a57b488b940d4eeeafe7223\",\"0x0374cabdae148b333f73a939ce24c54a613f46db615599f3a25f850493a06384\",\"0x7e6735c14377af079e148458b4e10e8a0e061c3d0e85ed53fb51680b2e373d86\",\"0xda595d3ed8d21d0af4859d4f84e17cf6436470770d084dde94d2a7cf53406bf7\",\"0x1ed7f450ac9df7e9350567679574fda3b241f7eee1997df32aa00ef4f5f5e9f2\",\"0xf25815081739f4fff71b857c2007519e9d5b742819a0209dfcf82fed66555d50\",\"0x1d88b8e30c399767d64caebb6eb53fc8ade60a9782e36383973385257c79d8c3\",\"0x000b787fdfd48ea77db5bba828b64cf04253210841921b0f478bab4d01b35448\",\"0xaa10c416b655d7810e8aa17a232e021c9a472d41d3867ffc1c5b905a4a261a01\",\"0x96362d53e53ec15a69315edcd2477a85aefbc375262865cf3e17c683d9a3c781\",\"0x0790001ef84d89fd5bd397bbf221a97b6a4ddc744ba2c3b9d0466957857b1ac5\",\"0x09b57a092d6cf3939eb4f9f59ef4121fa438b2b1a0544fce1772f42b3944502c\",\"0xf1ea27d7b3f760a68b4d57d25bb36886dbde8d76356dcdb77cf6b5e69627844d\"],\"transactionsRoot\":\"0x1ea1746468686159ce730c1cc49a886721244e5d1fa9a06d6d4196b6f013c82c\",\"uncles\":[]}}\r\n"; + +void send_error_transport(Context *ctx, char *name, char *params, CallBackProc cb, void *userData) { + printf("Transport Request - Name: %s, params: %s\n", name, params); + if(strcmp(name, "eth_getBlockByNumber")) { + char *res = (char *)malloc(strlen(BLOCK)); + strcpy(res, BLOCK); + + // free the params string if we are done using it + freeNimAllocatedString(params); + + cb(ctx, RET_SUCCESS, res, userData); + free(res); } else { - eth_newFilter(ctx, FILTER_OPTIONS, onFilterCreate); + // free the params string if we are done using it + freeNimAllocatedString(params); + + cb(ctx, RET_ERROR, "transport not implemented yet", userData); } } @@ -138,13 +194,14 @@ int main() { "{" "\"eth2Network\": \"mainnet\"," "\"trustedBlockRoot\": \"0x2558d82e8b29c4151a0683e4f9d480d229d84b27b51a976f56722e014227e723\"," - "\"backendUrl\": \"https://eth.blockrazor.xyz\"," + "\"backendUrls\": \"https://eth.blockrazor.xyz\"," "\"beaconApiUrls\": \"http://testing.mainnet.beacon-api.nimbus.team,http://www.lightclientdata.org\"," "\"logLevel\": \"FATAL\"," "\"logStdout\": \"None\"" "}"; - Context *ctx = startVerifProxy(jsonConfig, onStart); + char *userData = "verifyproxy example implementation in C"; + Context *ctx = startVerifProxy(jsonConfig, send_error_transport, onStart, userData); time_t start = time(NULL); diff --git a/nimbus_verified_proxy/libverifproxy/setup.nim b/nimbus_verified_proxy/libverifproxy/setup.nim index 2efc31e932..3338acebfd 100644 --- a/nimbus_verified_proxy/libverifproxy/setup.nim +++ b/nimbus_verified_proxy/libverifproxy/setup.nim @@ -8,19 +8,269 @@ import chronos, std/json, + stint, beacon_chain/spec/digest, beacon_chain/nimbus_binary_common, + web3/[eth_api_types, conversions], ../engine/types, ../engine/engine, ../lc/lc, ../lc_backend, ../nimbus_verified_proxy, ../nimbus_verified_proxy_conf, - ../json_rpc_backend, ./types type ProxyError = object of CatchableError +proc transportCallback[T]( + ctx: ptr Context, status: cint, res: cstring, userData: pointer +) {.cdecl, gcsafe, raises: [].} = + let data = cast[ref CallBackData[T]](userData) + if status == RET_SUCCESS: + # using $ on C allocated strings copies the context therefore it is safe to free the + # pointer on the C side. Also allows managing the memeory on one end only. + let deserResult = unpackArg($res, T) + if deserResult.isErr(): + data.fut.complete(EngineResult[T].err((BackendDecodingError, deserResult.error))) + return + data.fut.complete(EngineResult[T].ok(deserResult.get())) + elif status == RET_ERROR: + data.fut.complete(EngineResult[T].err((BackendError, $res))) + elif status == RET_CANCELLED: + data.fut.fail((ref CancelledError)(msg: $res)) + +proc getEthApiBackend*(ctx: ptr Context, transportProc: TransportProc): EthApiBackend = + let + ethChainIdProc = proc(): Future[EngineResult[UInt256]] {. + async: (raises: [CancelledError]) + .} = + let fut = + Future[EngineResult[UInt256]].Raising([CancelledError]).init("blkByHash") + transportProc( + ctx, "eth_chainId", "[]", transportCallback[UInt256], createCbData(fut) + ) + await fut + + getBlockByHashProc = proc( + blkHash: Hash32, fullTransactions: bool + ): Future[EngineResult[BlockObject]] {.async: (raises: [CancelledError]).} = + let + fut = + Future[EngineResult[BlockObject]].Raising([CancelledError]).init("blkByHash") + fullFlagStr = if fullTransactions: "true" else: "false" + blkHashSer = packArg(blkHash).valueOr: + return err((BackendEncodingError, error)) + params = "[" & blkHashSer & ", " & fullFlagStr & "]" + + transportProc( + ctx, + "eth_getBlockByHash", + alloc(params), + transportCallback[BlockObject], + createCbData(fut), + ) + await fut + + getBlockByNumberProc = proc( + blkNum: BlockTag, fullTransactions: bool + ): Future[EngineResult[BlockObject]] {.async: (raises: [CancelledError]).} = + let + fut = Future[EngineResult[BlockObject]].Raising([CancelledError]).init( + "blkByNumber" + ) + fullFlagStr = if fullTransactions: "true" else: "false" + blkNumSer = packArg(blkNum).valueOr: + return err((BackendEncodingError, error)) + params = "[" & blkNumSer & ", " & fullFlagStr & "]" + + transportProc( + ctx, + "eth_getBlockByNumber", + alloc(params), + transportCallback[BlockObject], + createCbData(fut), + ) + await fut + + getProofProc = proc( + address: Address, slots: seq[UInt256], blockId: BlockTag + ): Future[EngineResult[ProofResponse]] {.async: (raises: [CancelledError]).} = + let + fut = + Future[EngineResult[ProofResponse]].Raising([CancelledError]).init("getProof") + addressSer = packArg(address).valueOr: + return err((BackendEncodingError, error)) + slotsSer = packArg(slots).valueOr: + return err((BackendEncodingError, error)) + blockIdSer = packArg(blockId).valueOr: + return err((BackendEncodingError, error)) + + params = "[" & addressSer & ", " & slotsSer & ", " & blockIdSer & "]" + + transportProc( + ctx, + "eth_getProof", + alloc(params), + transportCallback[ProofResponse], + createCbData(fut), + ) + await fut + + createAccessListProc = proc( + txArgs: TransactionArgs, blockId: BlockTag + ): Future[EngineResult[AccessListResult]] {.async: (raises: [CancelledError]).} = + let + fut = Future[EngineResult[AccessListResult]].Raising([CancelledError]).init( + "createAL" + ) + txArgsSer = packArg(txArgs).valueOr: + return err((BackendEncodingError, error)) + blockIdSer = packArg(blockId).valueOr: + return err((BackendEncodingError, error)) + params = "[" & txArgsSer & ", " & blockIdSer & "]" + + transportProc( + ctx, + "eth_createAccessList", + alloc(params), + transportCallback[AccessListResult], + createCbData(fut), + ) + await fut + + getCodeProc = proc( + address: Address, blockId: BlockTag + ): Future[EngineResult[seq[byte]]] {.async: (raises: [CancelledError]).} = + let + fut = Future[EngineResult[seq[byte]]].Raising([CancelledError]).init("getCode") + addressSer = packArg(address).valueOr: + return err((BackendEncodingError, error)) + blockIdSer = packArg(blockId).valueOr: + return err((BackendEncodingError, error)) + params = "[" & addressSer & ", " & blockIdSer & "]" + + transportProc( + ctx, + "eth_getCode", + alloc(params), + transportCallback[seq[byte]], + createCbData(fut), + ) + await fut + + getTransactionByHashProc = proc( + txHash: Hash32 + ): Future[EngineResult[TransactionObject]] {.async: (raises: [CancelledError]).} = + let + fut = Future[EngineResult[TransactionObject]].Raising([CancelledError]).init( + "getTxByHash" + ) + txHashSer = packArg(txHash).valueOr: + return err((BackendEncodingError, error)) + params = "[" & txHashSer & "]" + + transportProc( + ctx, + "eth_getTransactionByHash", + alloc(params), + transportCallback[TransactionObject], + createCbData(fut), + ) + await fut + + getTransactionReceiptProc = proc( + txHash: Hash32 + ): Future[EngineResult[ReceiptObject]] {.async: (raises: [CancelledError]).} = + let + fut = Future[EngineResult[ReceiptObject]].Raising([CancelledError]).init( + "getRxByHash" + ) + txHashSer = packArg(txHash).valueOr: + return err((BackendEncodingError, error)) + params = "[" & txHashSer & "]" + + transportProc( + ctx, + "eth_getTransactionReceipt", + alloc(params), + transportCallback[ReceiptObject], + createCbData(fut), + ) + await fut + + getBlockReceiptsProc = proc( + blockId: BlockTag + ): Future[EngineResult[Opt[seq[ReceiptObject]]]] {. + async: (raises: [CancelledError]) + .} = + let + fut = Future[EngineResult[Opt[seq[ReceiptObject]]]] + .Raising([CancelledError]) + .init("getBlockRxs") + blockIdSer = packArg(blockId).valueOr: + return err((BackendEncodingError, error)) + params = "[" & blockIdSer & "]" + + transportProc( + ctx, + "eth_getBlockReceipts", + alloc(params), + transportCallback[Opt[seq[ReceiptObject]]], + createCbData(fut), + ) + await fut + + getLogsProc = proc( + filterOptions: FilterOptions + ): Future[EngineResult[seq[LogObject]]] {.async: (raises: [CancelledError]).} = + let + fut = + Future[EngineResult[seq[LogObject]]].Raising([CancelledError]).init("getLogs") + filterOptionsSer = packArg(filterOptions).valueOr: + return err((BackendEncodingError, error)) + params = "[" & filterOptionsSer & "]" + + transportProc( + ctx, + "eth_getLogs", + alloc(params), + transportCallback[seq[LogObject]], + createCbData(fut), + ) + await fut + + sendRawTxProc = proc( + txBytes: seq[byte] + ): Future[EngineResult[Hash32]] {.async: (raises: [CancelledError]).} = + let + fut = Future[EngineResult[Hash32]].Raising([CancelledError]).init("sendRawTx") + txBytesSer = packArg(txBytes).valueOr: + return err((BackendEncodingError, error)) + params = "[" & txBytesSer & "]" + + transportProc( + ctx, + "eth_sendRawTransaction", + alloc(params), + transportCallback[Hash32], + createCbData(fut), + ) + await fut + + EthApiBackend( + eth_chainId: ethChainIdProc, + eth_getBlockByHash: getBlockByHashProc, + eth_getBlockByNumber: getBlockByNumberProc, + eth_getProof: getProofProc, + eth_createAccessList: createAccessListProc, + eth_getCode: getCodeProc, + eth_getBlockReceipts: getBlockReceiptsProc, + eth_getLogs: getLogsProc, + eth_getTransactionByHash: getTransactionByHashProc, + eth_getTransactionReceipt: getTransactionReceiptProc, + eth_sendRawTransaction: sendRawTxProc, + ) + proc load(T: type VerifiedProxyConf, configJson: string): T {.raises: [ProxyError].} = let jsonNode = try: @@ -81,7 +331,7 @@ proc load(T: type VerifiedProxyConf, configJson: string): T {.raises: [ProxyErro ) proc run*( - ctx: ptr Context, configJson: string + ctx: ptr Context, configJson: string, transportProc: TransportProc ) {.async: (raises: [ProxyError, CancelledError]).} = let config = VerifiedProxyConf.load(configJson) @@ -100,9 +350,6 @@ proc run*( raise newException(ProxyError, error.errMsg) lc = LightClient.new(config.eth2Network, some config.trustedBlockRoot) - # initialize backend for JSON-RPC - jsonRpcClientPool = JsonRpcClientPool.new() - # initialize backend for light client updates lcRestClientPool = LCRestClientPool.new(lc.cfg, lc.forkDigests) @@ -113,17 +360,11 @@ proc run*( # add light client backend lc.setBackend(lcRestClientPool.getEthLCBackend()) - # the backend only needs the url to connect to - engine.backend = jsonRpcClientPool.getEthApiBackend() + engine.backend = getEthApiBackend(ctx, transportProc) # inject the frontend into c context ctx.frontend = engine.frontend - # start backend - var status = await jsonRpcClientPool.addEndpoints(config.backendUrls) - if status.isErr(): - raise newException(ProxyError, status.error.errMsg) - # adding endpoints will also start the backend if lcRestClientPool.addEndpoints(config.beaconApiUrls).isErr(): raise newException(ProxyError, "Couldn't add endpoints for light client queries") diff --git a/nimbus_verified_proxy/libverifproxy/types.nim b/nimbus_verified_proxy/libverifproxy/types.nim index 8d4688cb75..9db56ce203 100644 --- a/nimbus_verified_proxy/libverifproxy/types.nim +++ b/nimbus_verified_proxy/libverifproxy/types.nim @@ -1,16 +1,23 @@ # nimbus_verified_proxy -# Copyright (c) 2025 Status Research & Development GmbH +# Copyright (c) 2025-2026 Status Research & Development GmbH # Licensed and distributed under either of # * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT). # * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0). # at your option. This file may not be copied, modified, or distributed except according to those terms. -import std/lists, ../engine/types, chronos +import + std/[strutils, lists], + stint, + stew/byteutils, + ../engine/types, + chronos, + json_rpc/[jsonmarshal], + web3/[eth_api_types, conversions] type Task* = ref object - status*: int - name*: string + status*: cint + userData*: pointer response*: string finished*: bool cb*: CallBackProc @@ -23,11 +30,85 @@ type stop*: bool frontend*: EthApiFrontend - CallBackProc* = - proc(ctx: ptr Context, status: int, res: cstring) {.cdecl, gcsafe, raises: [].} + CallBackProc* = proc(ctx: ptr Context, status: cint, res: cstring, userData: pointer) {. + cdecl, gcsafe, raises: [] + .} + + TransportProc* = proc( + ctx: ptr Context, + name: cstring, + params: cstring, + cb: CallBackProc, + userData: pointer, + ) {.cdecl, gcsafe, raises: [].} + + CallBackData*[T] = object + fut*: Future[EngineResult[T]] const RET_SUCCESS*: cint = 0 # when the call to eth api frontend is successful const RET_ERROR*: cint = -1 # when the call to eth api frontend failed with an error const RET_CANCELLED*: cint = -2 # when the call to the eth api frontend was cancelled +# when an error occured while deserializing arguments from C to Nim const RET_DESER_ERROR*: cint = -3 - # when an error occured while deserializing arguments from C to Nim + +proc createCbData*[T](fut: Future[EngineResult[T]]): pointer = + let data = CallBackData[T].new() + data.fut = fut + + cast[pointer](data) + +# taken from nim-json-rpc and adapted +func unpackArg*( + arg: string, argType: type Address +): Result[Address, string] {.raises: [].} = + try: + ok(Address.fromHex(arg)) + except ValueError as e: + err("Parameter of type " & $argType & " coudln't be decoded: " & e.msg) + +func unpackArg*( + arg: string, argType: type BlockTag +): Result[BlockTag, string] {.raises: [].} = + try: + ok(BlockTag(kind: bidNumber, number: Quantity(fromHex[uint64](arg)))) + except ValueError: + # if it is an invalid alias it verification engine will throw an error + ok(BlockTag(kind: bidAlias, alias: arg)) + +func unpackArg*( + arg: string, argType: type UInt256 +): Result[UInt256, string] {.raises: [].} = + try: + ok(UInt256.fromHex(arg)) + except ValueError as e: + err("Parameter of type " & $argType & " coudldn't be decoded: " & e.msg) + +func unpackArg*( + arg: string, argType: type Hash32 +): Result[Hash32, string] {.raises: [].} = + try: + ok(Hash32.fromHex(arg)) + except ValueError as e: + err("Parameter of type " & $argType & " coudldn't be decoded: " & e.msg) + +# generalized overloading +func unpackArg*(arg: string, argType: type): Result[argType, string] {.raises: [].} = + try: + ok(JrpcConv.decode(arg, argType)) + except CatchableError as e: + err("Parameter of type " & $argType & " coudln't be decoded: " & e.msg) + +# generalized overloading +func packArg*[T](arg: T): Result[string, string] {.raises: [].} = + try: + ok(JrpcConv.encode(arg)) + except CatchableError as e: + err("Parameter coudln't be encoded: " & e.msg) + +proc alloc*(str: string): cstring = + var ret = cast[cstring](allocShared(str.len + 1)) + let s = cast[seq[char]](str) + for i in 0 ..< str.len: + ret[i] = s[i] + ret[str.len] = '\0' + return ret diff --git a/nimbus_verified_proxy/libverifproxy/verifproxy.h b/nimbus_verified_proxy/libverifproxy/verifproxy.h index f66caf4d0a..011bd92093 100644 --- a/nimbus_verified_proxy/libverifproxy/verifproxy.h +++ b/nimbus_verified_proxy/libverifproxy/verifproxy.h @@ -1,6 +1,6 @@ /** * nimbus_verified_proxy - * Copyright (c) 2024-2025 Status Research & Development GmbH + * Copyright (c) 2024-2026 Status Research & Development GmbH * Licensed and distributed under either of * * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT). * * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0). @@ -43,12 +43,30 @@ typedef struct Context Context; /** * Callback used for all asynchronous ETH API calls. * - * @param ctx Execution context passed to the original request. - * @param status return codes as defined above - * @param result pointer of the JSON encoded result string (allocated by Nim - - * must be freed using freeResponse) + * @param ctx Execution context passed to the original request. + * @param status return codes as defined above + * @param result pointer of the JSON encoded result string (allocated by Nim - + * must be freed using freeNimAllocatedString) + * @param userData pointer to user data */ -typedef void (*CallBackProc)(Context *ctx, int status, char *result); +typedef void (*CallBackProc)(Context *ctx, int status, char *result, void *userData); + +/** + * Transport functions used to dispatch JSON RPC requests. (Must be implemented in the + * application using the verified proxy library) + * + * @param ctx Execution context passed to the original request. + * @param name name of the RPC method + * @param params JSON serialized params required for the RPC method.(allocated by Nim - + * must be freed using freeNimAllocatedString) + * heap by nim and must be freed by C using freeNimString + * @param cb Callback to be called with userData passed (see below) + * @param userData pointer to user data. Used to link multiple response callbacks + * back to their queries. Implementation of transport functions + * must appropriately relay back the userData via the transport + * callback function (see above) + */ +typedef void (*TransportProc)(Context *ctx, char *name, char *params, CallBackProc cb, void *userData); /** * Start the verification proxy with a given configuration. @@ -56,17 +74,20 @@ typedef void (*CallBackProc)(Context *ctx, int status, char *result); * @param configJson JSON string describing the configuration for the verification proxy. * @param onStart Callback invoked once the proxy has started. NOTE: The callback is invoked * only on error otherwise the proxy runs indefinitely + * @param userData pointer to user data * @return Pointer to a new Context object representing the running proxy. * Must be freed using freeContext() when no longer needed. */ -ETH_RESULT_USE_CHECK Context *startVerifProxy(char* configJson, CallBackProc onStart); +ETH_RESULT_USE_CHECK Context *startVerifProxy(char* configJson, TransportProc transport, CallBackProc onStart, void *userData); /** - * Free the JSON encoded result returned via the callback. + * Free strings allocated by Nim. This currently include the JSON encoded result + * returned via the callback for eth_* methods and the params string passed via + * the transport proc * * @param res pointer to the JSON encoded result string */ -void freeResponse(char *res); +void freeNimAllocatedString(char *res); /** * Free a Context object returned by startVerifProxy(). @@ -93,6 +114,17 @@ void stopVerifProxy(Context *ctx); */ void processVerifProxyTasks(Context *ctx); +/** + * call any RPC method + * + * @param ctx Context pointer. + * @param name Name of the RPC method + * @param params parameters required for the RPC method + * @param cb Callback invoked with a hex block number. + * @param userData pointer to user data + */ +void nvp_call(Context *ctx, char* name, char* params, CallBackProc cb, void *userData); + /* ========================================================================== */ /* BASIC CHAIN DATA */ /* ========================================================================== */ @@ -100,34 +132,38 @@ void processVerifProxyTasks(Context *ctx); /** * Retrieve the current blockchain head block number. * - * @param ctx Context pointer. - * @param cb Callback invoked with a hex block number. + * @param ctx Context pointer. + * @param cb Callback invoked with a hex block number. + * @param userData pointer to user data */ -void eth_blockNumber(Context *ctx, CallBackProc cb); +void eth_blockNumber(Context *ctx, CallBackProc cb, void *userData); /** * Retrieve the EIP-4844 blob base fee. * - * @param ctx Context pointer. - * @param cb Callback invoked with a hex blob base fee. + * @param ctx Context pointer. + * @param cb Callback invoked with a hex blob base fee. + * @param userData pointer to user data */ -void eth_blobBaseFee(Context *ctx, CallBackProc cb); +void eth_blobBaseFee(Context *ctx, CallBackProc cb, void *userData); /** * Retrieve the current gas price. * - * @param ctx Context pointer. - * @param cb Callback invoked with a hex gas price. + * @param ctx Context pointer. + * @param cb Callback invoked with a hex gas price. + * @param userData pointer to user data */ -void eth_gasPrice(Context *ctx, CallBackProc cb); +void eth_gasPrice(Context *ctx, CallBackProc cb, void *userData); /** * Retrieve the suggested priority fee per gas. * - * @param ctx Context pointer. - * @param cb Callback invoked with a hex gas tip. + * @param ctx Context pointer. + * @param cb Callback invoked with a hex gas tip. + * @param userData pointer to user data */ -void eth_maxPriorityFeePerGas(Context *ctx, CallBackProc cb); +void eth_maxPriorityFeePerGas(Context *ctx, CallBackProc cb, void *userData); /* ========================================================================== */ @@ -142,8 +178,9 @@ void eth_maxPriorityFeePerGas(Context *ctx, CallBackProc cb); * @param blockTag A block identifier: "latest", "pending", "earliest", or a hex * block number such as "0x10d4f". * @param cb Callback with the hex balance. + * @param userData pointer to user data */ -void eth_getBalance(Context *ctx, char *address, char *blockTag, CallBackProc cb); +void eth_getBalance(Context *ctx, char *address, char *blockTag, CallBackProc cb, void *userData); /** * Retrieve storage from a contract. @@ -154,8 +191,9 @@ void eth_getBalance(Context *ctx, char *address, char *blockTag, CallBackProc cb * @param blockTag A block identifier: "latest", "pending", "earliest", or a hex * block number such as "0x10d4f". * @param cb Callback with the 32-byte hex slot value. + * @param userData pointer to user data */ -void eth_getStorageAt(Context *ctx, char *address, char *slot, char *blockTag, CallBackProc cb); +void eth_getStorageAt(Context *ctx, char *address, char *slot, char *blockTag, CallBackProc cb, void *userData); /** * Retrieve an address's transaction count (nonce). @@ -165,8 +203,9 @@ void eth_getStorageAt(Context *ctx, char *address, char *slot, char *blockTag, C * @param blockTag A block identifier: "latest", "pending", "earliest", or a hex * block number such as "0x10d4f". * @param cb Callback with the hex nonce. + * @param userData pointer to user data */ -void eth_getTransactionCount(Context *ctx, char *address, char *blockTag, CallBackProc cb); +void eth_getTransactionCount(Context *ctx, char *address, char *blockTag, CallBackProc cb, void *userData); /** * Retrieve bytecode stored at an address. @@ -176,8 +215,9 @@ void eth_getTransactionCount(Context *ctx, char *address, char *blockTag, CallBa * @param blockTag A block identifier: "latest", "pending", "earliest", or a hex * block number such as "0x10d4f". * @param cb Callback with hex bytecode. + * @param userData pointer to user data */ -void eth_getCode(Context *ctx, char *address, char *blockTag, CallBackProc cb); +void eth_getCode(Context *ctx, char *address, char *blockTag, CallBackProc cb, void *userData); /* ========================================================================== */ @@ -191,8 +231,9 @@ void eth_getCode(Context *ctx, char *address, char *blockTag, CallBackProc cb); * @param blockHash 32-byte hex encode block hash. * @param fullTransactions Whether full tx objects should be included. * @param cb Callback with block data. + * @param userData pointer to user data */ -void eth_getBlockByHash(Context *ctx, char *blockHash, bool fullTransactions, CallBackProc cb); +void eth_getBlockByHash(Context *ctx, char *blockHash, bool fullTransactions, CallBackProc cb, void *userData); /** * Retrieve a block by number or tag. @@ -202,8 +243,9 @@ void eth_getBlockByHash(Context *ctx, char *blockHash, bool fullTransactions, Ca * block number such as "0x10d4f". * @param fullTransactions Whether full tx objects should be included. * @param cb Callback with block data. + * @param userData pointer to user data */ -void eth_getBlockByNumber(Context *ctx, char *blockTag, bool fullTransactions, CallBackProc cb); +void eth_getBlockByNumber(Context *ctx, char *blockTag, bool fullTransactions, CallBackProc cb, void *userData); /** * Get the number of uncles in a block. @@ -212,8 +254,9 @@ void eth_getBlockByNumber(Context *ctx, char *blockTag, bool fullTransactions, C * @param blockTag A block identifier: "latest", "pending", "earliest", or a hex * block number such as "0x10d4f". * @param cb Callback with hex uncle count. + * @param userData pointer to user data */ -void eth_getUncleCountByBlockNumber(Context *ctx, char *blockTag, CallBackProc cb); +void eth_getUncleCountByBlockNumber(Context *ctx, char *blockTag, CallBackProc cb, void *userData); /** * Get the number of uncles in a block. @@ -221,8 +264,9 @@ void eth_getUncleCountByBlockNumber(Context *ctx, char *blockTag, CallBackProc c * @param ctx Context pointer. * @param blockHash 32-byte hex encode block hash. * @param cb Callback with hex uncle count. + * @param userData pointer to user data */ -void eth_getUncleCountByBlockHash(Context *ctx, char *blockHash, CallBackProc cb); +void eth_getUncleCountByBlockHash(Context *ctx, char *blockHash, CallBackProc cb, void *userData); /** * Get the number of transactions in a block. @@ -231,8 +275,9 @@ void eth_getUncleCountByBlockHash(Context *ctx, char *blockHash, CallBackProc cb * @param blockTag A block identifier: "latest", "pending", "earliest", or a hex * block number such as "0x10d4f". * @param cb Callback with hex transaction count. + * @param userData pointer to user data */ -void eth_getBlockTransactionCountByNumber(Context *ctx, char *blockTag, CallBackProc cb); +void eth_getBlockTransactionCountByNumber(Context *ctx, char *blockTag, CallBackProc cb, void *userData); /** * Get the number of transactions in a block identified by hash. @@ -240,8 +285,9 @@ void eth_getBlockTransactionCountByNumber(Context *ctx, char *blockTag, CallBack * @param ctx Context pointer. * @param blockHash 32-byte hex encode block hash. * @param cb Callback with hex transaction count. + * @param userData pointer to user data */ -void eth_getBlockTransactionCountByHash(Context *ctx, char *blockHash, CallBackProc cb); +void eth_getBlockTransactionCountByHash(Context *ctx, char *blockHash, CallBackProc cb, void *userData); /* ========================================================================== */ @@ -256,12 +302,14 @@ void eth_getBlockTransactionCountByHash(Context *ctx, char *blockHash, CallBackP * block number such as "0x10d4f". * @param index Zero-based transaction index * @param cb Callback with transaction object. + * @param userData pointer to user data */ void eth_getTransactionByBlockNumberAndIndex( Context *ctx, char *blockTag, unsigned long long index, - CallBackProc cb + CallBackProc cb, + void *userData ); /** @@ -271,31 +319,35 @@ void eth_getTransactionByBlockNumberAndIndex( * @param blockHash 32-byte hex encode block hash. * @param index Zero-based transaction index. * @param cb Callback with transaction data. + * @param userData pointer to user data */ void eth_getTransactionByBlockHashAndIndex( Context *ctx, char *blockHash, unsigned long long index, - CallBackProc cb + CallBackProc cb, + void *userData ); /** * Retrieve a transaction by hash. * - * @param ctx Context pointer. - * @param txHash 32-byte hex encoded transaction hash. - * @param cb Callback with transaction object. + * @param ctx Context pointer. + * @param txHash 32-byte hex encoded transaction hash. + * @param cb Callback with transaction object. + * @param userData pointer to user data */ -void eth_getTransactionByHash(Context *ctx, char *txHash, CallBackProc cb); +void eth_getTransactionByHash(Context *ctx, char *txHash, CallBackProc cb, void *userData); /** * Retrieve a transaction receipt by hash. * - * @param ctx Context pointer. - * @param txHash 32-byte hex encoded transaction hash. - * @param cb Callback with receipt data. + * @param ctx Context pointer. + * @param txHash 32-byte hex encoded transaction hash. + * @param cb Callback with receipt data. + * @param userData pointer to user data */ -void eth_getTransactionReceipt(Context *ctx, char *txHash, CallBackProc cb); +void eth_getTransactionReceipt(Context *ctx, char *txHash, CallBackProc cb, void *userData); /* ========================================================================== */ @@ -311,13 +363,15 @@ void eth_getTransactionReceipt(Context *ctx, char *txHash, CallBackProc cb); * block number such as "0x10d4f". * @param optimisticStateFetch Whether optimistic state fetching is allowed. * @param cb Callback with call return data. + * @param userData pointer to user data */ void eth_call( Context *ctx, char *txArgs, char *blockTag, bool optimisticStateFetch, - CallBackProc cb + CallBackProc cb, + void *userData ); /** @@ -329,13 +383,15 @@ void eth_call( * block number such as "0x10d4f". * @param optimisticStateFetch Whether optimistic state fetching is allowed. * @param cb Callback with access list object. + * @param userData pointer to user data */ void eth_createAccessList( Context *ctx, char *txArgs, char *blockTag, bool optimisticStateFetch, - CallBackProc cb + CallBackProc cb, + void *userData ); /** @@ -347,13 +403,15 @@ void eth_createAccessList( * block number such as "0x10d4f". * @param optimisticStateFetch Whether optimistic state fetching is allowed. * @param cb Callback with hex gas estimate. + * @param userData pointer to user data */ void eth_estimateGas( Context *ctx, char *txArgs, char *blockTag, bool optimisticStateFetch, - CallBackProc cb + CallBackProc cb, + void *userData ); @@ -367,8 +425,9 @@ void eth_estimateGas( * @param ctx Context pointer. * @param filterOptions JSON encoded string specifying the log filtering rules. * @param cb Callback with array of matching logs. + * @param userData pointer to user data */ -void eth_getLogs(Context *ctx, char *filterOptions, CallBackProc cb); +void eth_getLogs(Context *ctx, char *filterOptions, CallBackProc cb, void *userData); /** * Create a new log filter. @@ -376,8 +435,9 @@ void eth_getLogs(Context *ctx, char *filterOptions, CallBackProc cb); * @param ctx Context pointer. * @param filterOptions JSON encoded string specifying the log filtering rules. * @param cb Callback with filter ID (hex string). + * @param userData pointer to user data */ -void eth_newFilter(Context *ctx, char *filterOptions, CallBackProc cb); +void eth_newFilter(Context *ctx, char *filterOptions, CallBackProc cb, void *userData); /** * Remove an installed filter. @@ -385,8 +445,9 @@ void eth_newFilter(Context *ctx, char *filterOptions, CallBackProc cb); * @param ctx Context pointer. * @param filterId filter ID as a hex encoded string (as returned by eth_newFilter) * @param cb Callback with boolean result. + * @param userData pointer to user data */ -void eth_uninstallFilter(Context *ctx, char *filterId, CallBackProc cb); +void eth_uninstallFilter(Context *ctx, char *filterId, CallBackProc cb, void *userData); /** * Retrieve all logs for an installed filter. @@ -394,8 +455,9 @@ void eth_uninstallFilter(Context *ctx, char *filterId, CallBackProc cb); * @param ctx Context pointer. * @param filterId filter ID as a hex encoded string (as returned by eth_newFilter) * @param cb Callback with log result array. + * @param userData pointer to user data */ -void eth_getFilterLogs(Context *ctx, char *filterId, CallBackProc cb); +void eth_getFilterLogs(Context *ctx, char *filterId, CallBackProc cb, void *userData); /** * Retrieve new logs since the previous poll. @@ -403,8 +465,9 @@ void eth_getFilterLogs(Context *ctx, char *filterId, CallBackProc cb); * @param ctx Context pointer. * @param filterId filter ID as a hex encoded string (as returned by eth_newFilter) * @param cb Callback with an array of new logs. + * @param userData pointer to user data */ -void eth_getFilterChanges(Context *ctx, char *filterId, CallBackProc cb); +void eth_getFilterChanges(Context *ctx, char *filterId, CallBackProc cb, void *userData); /* ========================================================================== */ @@ -418,8 +481,9 @@ void eth_getFilterChanges(Context *ctx, char *filterId, CallBackProc cb); * @param blockTag A block identifier: "latest", "pending", "earliest", or a hex * block number such as "0x10d4f". * @param cb Callback with an array of receipts. + * @param userData pointer to user data */ -void eth_getBlockReceipts(Context *ctx, char *blockTag, CallBackProc cb); +void eth_getBlockReceipts(Context *ctx, char *blockTag, CallBackProc cb, void *userData); /** * Send a signed transaction to the RPC provider to be relayed in the network. @@ -427,8 +491,9 @@ void eth_getBlockReceipts(Context *ctx, char *blockTag, CallBackProc cb); * @param ctx Context pointer. * @param blockTag Hex encoded signed transaction. * @param cb Callback with an array of receipts. + * @param userData pointer to user data */ -void eth_sendRawTransaction(Context *ctx, char *txHexBytes, CallBackProc cb); +void eth_sendRawTransaction(Context *ctx, char *txHexBytes, CallBackProc cb, void *userData); #ifdef __cplusplus } diff --git a/nimbus_verified_proxy/libverifproxy/verifproxy.nim b/nimbus_verified_proxy/libverifproxy/verifproxy.nim index bbc4698b1d..0b37c3e93f 100644 --- a/nimbus_verified_proxy/libverifproxy/verifproxy.nim +++ b/nimbus_verified_proxy/libverifproxy/verifproxy.nim @@ -8,7 +8,7 @@ import chronos, stew/byteutils, - std/[atomics, json, net, strutils, lists], + std/[atomics, json, net, lists], beacon_chain/spec/[digest, network], beacon_chain/nimbus_binary_common, json_rpc/[jsonmarshal], @@ -36,7 +36,7 @@ proc initLib() = locals = addr(locals) nimGC_setStackBottom(locals) -proc freeResponse(res: cstring) {.exported.} = +proc freeNimAllocatedString(res: cstring) {.exported.} = deallocShared(res) proc toUnmanagedPtr[T](x: ref T): ptr T = @@ -53,14 +53,6 @@ proc destroy[T](x: ptr T) = proc freeContext(ctx: ptr Context) {.exported.} = ctx.destroy() -proc alloc(str: string): cstring = - var ret = cast[cstring](allocShared(str.len + 1)) - let s = cast[seq[char]](str) - for i in 0 ..< str.len: - ret[i] = s[i] - ret[str.len] = '\0' - return ret - proc processVerifProxyTasks(ctx: ptr Context) {.exported.} = var delList: seq[int] = @[] @@ -74,33 +66,40 @@ proc processVerifProxyTasks(ctx: ptr Context) {.exported.} = for taskNode in ctx.tasks.nodes: let task = taskNode.value if task.finished: - task.cb(ctx, task.status, alloc(task.response)) + task.cb(ctx, task.status, alloc(task.response), task.userData) ctx.tasks.remove(taskNode) ctx.taskLen -= 1 if ctx.taskLen > 0: poll() -proc createTask(cb: CallBackProc): Task = +proc createTask(cb: CallBackProc, userData: pointer): Task = let task = Task() task.finished = false task.cb = cb + task.userData = userData task -proc startVerifProxy(configJson: cstring, cb: CallBackProc): ptr Context {.exported.} = +proc startVerifProxy( + configJson: cstring, + transportProc: TransportProc, + cb: CallBackProc, + userData: pointer, +): ptr Context {.exported.} = let ctx = Context.new().toUnmanagedPtr() ctx.stop = false try: initLib() except Exception as e: - cb(ctx, RET_DESER_ERROR, alloc(e.msg)) + cb(ctx, RET_DESER_ERROR, alloc(e.msg), userData) + return let - task = createTask(cb) - fut = run(ctx, $configJson) + task = createTask(cb, userData) + fut = run(ctx, $configJson, transportProc) - fut.addCallback proc(_: pointer) {.gcsafe.} = + proc processFuture[T](fut: Future[T], task: Task) {.gcsafe.} = if fut.cancelled(): task.response = Json.encode(fut.error()) task.finished = true @@ -114,6 +113,12 @@ proc startVerifProxy(configJson: cstring, cb: CallBackProc): ptr Context {.expor task.finished = true task.status = RET_SUCCESS + if not fut.finished: + fut.addCallback proc(_: pointer) {.gcsafe.} = + processFuture(fut, task) + else: + processFuture(fut, task) + task.fut = fut ctx.tasks.add(task) ctx.taskLen += 1 @@ -124,20 +129,20 @@ proc stopVerifProxy(ctx: ptr Context) {.exported.} = ctx.stop = true # NOTE: this is not the C callback. This is just a callback for the future -template callbackToC(ctx: ptr Context, cb: CallBackProc, asyncCall: untyped) = - let task = createTask(cb) - ctx.tasks.add(task) - ctx.taskLen += 1 - - let fut = asyncCall +template callbackToC( + ctx: ptr Context, cb: CallBackProc, userData: pointer, asyncCall: untyped +) = + let + task = createTask(cb, userData) + fut = asyncCall - fut.addCallback proc(_: pointer) {.gcsafe.} = + proc processFuture[T](fut: Future[T], task: Task) {.gcsafe.} = if fut.cancelled(): - task.response = Json.encode(fut.error()) + task.response = Json.encode(fut.error().msg) task.finished = true task.status = RET_CANCELLED elif fut.failed(): - task.response = Json.encode(fut.error()) + task.response = Json.encode(fut.error().msg) task.finished = true task.status = RET_ERROR else: @@ -151,66 +156,39 @@ template callbackToC(ctx: ptr Context, cb: CallBackProc, asyncCall: untyped) = task.finished = true task.status = RET_SUCCESS - task.fut = fut - -# taken from nim-json-rpc and adapted -func unpackArg( - arg: string, argType: type Address -): Result[Address, string] {.raises: [].} = - try: - ok(Address.fromHex(arg)) - except ValueError as e: - err("Parameter of type " & $argType & " coudln't be decoded: " & e.msg) - -func unpackArg( - arg: string, argType: type BlockTag -): Result[BlockTag, string] {.raises: [].} = - try: - ok(BlockTag(kind: bidNumber, number: Quantity(fromHex[uint64](arg)))) - except ValueError: - # if it is an invalid alias it verification engine will throw an error - ok(BlockTag(kind: bidAlias, alias: arg)) - -func unpackArg( - arg: string, argType: type UInt256 -): Result[UInt256, string] {.raises: [].} = - try: - ok(UInt256.fromHex(arg)) - except ValueError as e: - err("Parameter of type " & $argType & " coudldn't be decoded: " & e.msg) - -func unpackArg( - arg: string, argType: type Hash32 -): Result[Hash32, string] {.raises: [].} = - try: - ok(Hash32.fromHex(arg)) - except ValueError as e: - err("Parameter of type " & $argType & " coudldn't be decoded: " & e.msg) + if not fut.finished: + fut.addCallback proc(_: pointer) {.gcsafe.} = + processFuture(fut, task) + else: + processFuture(fut, task) -# generalized overloading -func unpackArg(arg: string, argType: type): Result[argType, string] {.raises: [].} = - try: - ok(JrpcConv.decode(arg, argType)) - except CatchableError as e: - err("Parameter of type " & $argType & " coudln't be decoded: " & e.msg) + task.fut = fut + ctx.tasks.add(task) + ctx.taskLen += 1 -proc eth_blockNumber(ctx: ptr Context, cb: CallBackProc) {.exported.} = - callbackToC(ctx, cb): +proc eth_blockNumber( + ctx: ptr Context, cb: CallBackProc, userData: pointer +) {.exported.} = + callbackToC(ctx, cb, userData): ctx.frontend.eth_blockNumber() proc eth_getBalance( - ctx: ptr Context, address: cstring, blockTag: cstring, cb: CallBackProc + ctx: ptr Context, + address: cstring, + blockTag: cstring, + cb: CallBackProc, + userData: pointer, ) {.exported.} = let addressTyped = unpackArg($address, Address).valueOr: - cb(ctx, RET_DESER_ERROR, alloc(error)) + cb(ctx, RET_DESER_ERROR, alloc(error), userData) return blockTagTyped = unpackArg($blockTag, BlockTag).valueOr: - cb(ctx, RET_DESER_ERROR, alloc(error)) + cb(ctx, RET_DESER_ERROR, alloc(error), userData) return - callbackToC(ctx, cb): + callbackToC(ctx, cb, userData): ctx.frontend.eth_getBalance(addressTyped, blockTagTyped) proc eth_getStorageAt( @@ -219,137 +197,162 @@ proc eth_getStorageAt( slot: cstring, blockTag: cstring, cb: CallBackProc, + userData: pointer, ) {.exported.} = let addressTyped = unpackArg($address, Address).valueOr: - cb(ctx, RET_DESER_ERROR, alloc(error)) + cb(ctx, RET_DESER_ERROR, alloc(error), userData) return slotTyped = unpackArg($slot, UInt256).valueOr: - cb(ctx, RET_DESER_ERROR, alloc(error)) + cb(ctx, RET_DESER_ERROR, alloc(error), userData) return blockTagTyped = unpackArg($blockTag, BlockTag).valueOr: - cb(ctx, RET_DESER_ERROR, alloc(error)) + cb(ctx, RET_DESER_ERROR, alloc(error), userData) return - callbackToC(ctx, cb): + callbackToC(ctx, cb, userData): ctx.frontend.eth_getStorageAt(addressTyped, slotTyped, blockTagTyped) proc eth_getTransactionCount( - ctx: ptr Context, address: cstring, blockTag: cstring, cb: CallBackProc + ctx: ptr Context, + address: cstring, + blockTag: cstring, + cb: CallBackProc, + userData: pointer, ) {.exported.} = let addressTyped = unpackArg($address, Address).valueOr: - cb(ctx, RET_DESER_ERROR, alloc(error)) + cb(ctx, RET_DESER_ERROR, alloc(error), userData) return blockTagTyped = unpackArg($blockTag, BlockTag).valueOr: - cb(ctx, RET_DESER_ERROR, alloc(error)) + cb(ctx, RET_DESER_ERROR, alloc(error), userData) return - callbackToC(ctx, cb): + callbackToC(ctx, cb, userData): ctx.frontend.eth_getTransactionCount(addressTyped, blockTagTyped) proc eth_getCode( - ctx: ptr Context, address: cstring, blockTag: cstring, cb: CallBackProc + ctx: ptr Context, + address: cstring, + blockTag: cstring, + cb: CallBackProc, + userData: pointer, ) {.exported.} = let addressTyped = unpackArg($address, Address).valueOr: - cb(ctx, RET_DESER_ERROR, alloc(error)) + cb(ctx, RET_DESER_ERROR, alloc(error), userData) return blockTagTyped = unpackArg($blockTag, BlockTag).valueOr: - cb(ctx, RET_DESER_ERROR, alloc(error)) + cb(ctx, RET_DESER_ERROR, alloc(error), userData) return - callbackToC(ctx, cb): + callbackToC(ctx, cb, userData): ctx.frontend.eth_getCode(addressTyped, blockTagTyped) proc eth_getBlockByHash( - ctx: ptr Context, blockHash: cstring, fullTransactions: bool, cb: CallBackProc + ctx: ptr Context, + blockHash: cstring, + fullTransactions: bool, + cb: CallBackProc, + userData: pointer, ) {.exported.} = let blockHashTyped = unpackArg($blockHash, Hash32).valueOr: - cb(ctx, RET_DESER_ERROR, alloc(error)) + cb(ctx, RET_DESER_ERROR, alloc(error), userData) return - callbackToC(ctx, cb): + callbackToC(ctx, cb, userData): ctx.frontend.eth_getBlockByHash(blockHashTyped, fullTransactions) proc eth_getBlockByNumber( - ctx: ptr Context, blockTag: cstring, fullTransactions: bool, cb: CallBackProc + ctx: ptr Context, + blockTag: cstring, + fullTransactions: bool, + cb: CallBackProc, + userData: pointer, ) {.exported.} = let blockTagTyped = unpackArg($blockTag, BlockTag).valueOr: - cb(ctx, RET_DESER_ERROR, alloc(error)) + cb(ctx, RET_DESER_ERROR, alloc(error), userData) return - callbackToC(ctx, cb): + callbackToC(ctx, cb, userData): ctx.frontend.eth_getBlockByNumber(blockTagTyped, fullTransactions) proc eth_getUncleCountByBlockNumber( - ctx: ptr Context, blockTag: cstring, cb: CallBackProc + ctx: ptr Context, blockTag: cstring, cb: CallBackProc, userData: pointer ) {.exported.} = let blockTagTyped = unpackArg($blockTag, BlockTag).valueOr: - cb(ctx, RET_DESER_ERROR, alloc(error)) + cb(ctx, RET_DESER_ERROR, alloc(error), userData) return - callbackToC(ctx, cb): + callbackToC(ctx, cb, userData): ctx.frontend.eth_getUncleCountByBlockNumber(blockTagTyped) proc eth_getUncleCountByBlockHash( - ctx: ptr Context, blockHash: cstring, cb: CallBackProc + ctx: ptr Context, blockHash: cstring, cb: CallBackProc, userData: pointer ) {.exported.} = let blockHashTyped = unpackArg($blockHash, Hash32).valueOr: - cb(ctx, RET_DESER_ERROR, alloc(error)) + cb(ctx, RET_DESER_ERROR, alloc(error), userData) return - callbackToC(ctx, cb): + callbackToC(ctx, cb, userData): ctx.frontend.eth_getUncleCountByBlockHash(blockHashTyped) proc eth_getBlockTransactionCountByNumber( - ctx: ptr Context, blockTag: cstring, cb: CallBackProc + ctx: ptr Context, blockTag: cstring, cb: CallBackProc, userData: pointer ) {.exported.} = let blockTagTyped = unpackArg($blockTag, BlockTag).valueOr: - cb(ctx, RET_DESER_ERROR, alloc(error)) + cb(ctx, RET_DESER_ERROR, alloc(error), userData) return - callbackToC(ctx, cb): + callbackToC(ctx, cb, userData): ctx.frontend.eth_getBlockTransactionCountByNumber(blockTagTyped) proc eth_getBlockTransactionCountByHash( - ctx: ptr Context, blockHash: cstring, cb: CallBackProc + ctx: ptr Context, blockHash: cstring, cb: CallBackProc, userData: pointer ) {.exported.} = let blockHashTyped = unpackArg($blockHash, Hash32).valueOr: - cb(ctx, RET_DESER_ERROR, alloc(error)) + cb(ctx, RET_DESER_ERROR, alloc(error), userData) return - callbackToC(ctx, cb): + callbackToC(ctx, cb, userData): ctx.frontend.eth_getBlockTransactionCountByHash(blockHashTyped) proc eth_getTransactionByBlockNumberAndIndex( - ctx: ptr Context, blockTag: cstring, index: culonglong, cb: CallBackProc + ctx: ptr Context, + blockTag: cstring, + index: culonglong, + cb: CallBackProc, + userData: pointer, ) {.exported.} = let blockTagTyped = unpackArg($blockTag, BlockTag).valueOr: - cb(ctx, RET_DESER_ERROR, alloc(error)) + cb(ctx, RET_DESER_ERROR, alloc(error), userData) return indexTyped = Quantity(uint64(index)) - callbackToC(ctx, cb): + callbackToC(ctx, cb, userData): ctx.frontend.eth_getTransactionByBlockNumberAndIndex(blockTagTyped, indexTyped) proc eth_getTransactionByBlockHashAndIndex( - ctx: ptr Context, blockHash: cstring, index: culonglong, cb: CallBackProc + ctx: ptr Context, + blockHash: cstring, + index: culonglong, + cb: CallBackProc, + userData: pointer, ) {.exported.} = let blockHashTyped = unpackArg($blockHash, Hash32).valueOr: - cb(ctx, RET_DESER_ERROR, alloc(error)) + cb(ctx, RET_DESER_ERROR, alloc(error), userData) return indexTyped = Quantity(uint64(index)) - callbackToC(ctx, cb): + callbackToC(ctx, cb, userData): ctx.frontend.eth_getTransactionByBlockHashAndIndex(blockHashTyped, indexTyped) proc eth_call( @@ -358,17 +361,18 @@ proc eth_call( blockTag: cstring, optimisticStateFetch: bool, cb: CallBackProc, + userData: pointer, ) {.exported.} = let txArgsTyped = unpackArg($txArgs, TransactionArgs).valueOr: - cb(ctx, RET_DESER_ERROR, alloc(error)) + cb(ctx, RET_DESER_ERROR, alloc(error), userData) return blockTagTyped = unpackArg($blockTag, BlockTag).valueOr: - cb(ctx, RET_DESER_ERROR, alloc(error)) + cb(ctx, RET_DESER_ERROR, alloc(error), userData) return - callbackToC(ctx, cb): + callbackToC(ctx, cb, userData): ctx.frontend.eth_call(txArgsTyped, blockTagTyped, optimisticStateFetch) proc eth_createAccessList( @@ -377,17 +381,18 @@ proc eth_createAccessList( blockTag: cstring, optimisticStateFetch: bool, cb: CallBackProc, + userData: pointer, ) {.exported.} = let txArgsTyped = unpackArg($txArgs, TransactionArgs).valueOr: - cb(ctx, RET_DESER_ERROR, alloc(error)) + cb(ctx, RET_DESER_ERROR, alloc(error), userData) return blockTagTyped = unpackArg($blockTag, BlockTag).valueOr: - cb(ctx, RET_DESER_ERROR, alloc(error)) + cb(ctx, RET_DESER_ERROR, alloc(error), userData) return - callbackToC(ctx, cb): + callbackToC(ctx, cb, userData): ctx.frontend.eth_createAccessList(txArgsTyped, blockTagTyped, optimisticStateFetch) proc eth_estimateGas( @@ -396,109 +401,290 @@ proc eth_estimateGas( blockTag: cstring, optimisticStateFetch: bool, cb: CallBackProc, + userData: pointer, ) {.exported.} = let txArgsTyped = unpackArg($txArgs, TransactionArgs).valueOr: - cb(ctx, RET_DESER_ERROR, alloc(error)) + cb(ctx, RET_DESER_ERROR, alloc(error), userData) return blockTagTyped = unpackArg($blockTag, BlockTag).valueOr: - cb(ctx, RET_DESER_ERROR, alloc(error)) + cb(ctx, RET_DESER_ERROR, alloc(error), userData) return - callbackToC(ctx, cb): + callbackToC(ctx, cb, userData): ctx.frontend.eth_estimateGas(txArgsTyped, blockTagTyped, optimisticStateFetch) proc eth_getTransactionByHash( - ctx: ptr Context, txHash: cstring, cb: CallBackProc + ctx: ptr Context, txHash: cstring, cb: CallBackProc, userData: pointer ) {.exported.} = let txHashTyped = unpackArg($txHash, Hash32).valueOr: - cb(ctx, RET_DESER_ERROR, alloc(error)) + cb(ctx, RET_DESER_ERROR, alloc(error), userData) return - callbackToC(ctx, cb): + callbackToC(ctx, cb, userData): ctx.frontend.eth_getTransactionByHash(txHashTyped) proc eth_getBlockReceipts( - ctx: ptr Context, blockTag: cstring, cb: CallBackProc + ctx: ptr Context, blockTag: cstring, cb: CallBackProc, userData: pointer ) {.exported.} = let blockTagTyped = unpackArg($blockTag, BlockTag).valueOr: - cb(ctx, RET_DESER_ERROR, alloc(error)) + cb(ctx, RET_DESER_ERROR, alloc(error), userData) return - callbackToC(ctx, cb): + callbackToC(ctx, cb, userData): ctx.frontend.eth_getBlockReceipts(blockTagTyped) proc eth_getTransactionReceipt( - ctx: ptr Context, txHash: cstring, cb: CallBackProc + ctx: ptr Context, txHash: cstring, cb: CallBackProc, userData: pointer ) {.exported.} = let txHashTyped = unpackArg($txHash, Hash32).valueOr: - cb(ctx, RET_DESER_ERROR, alloc(error)) + cb(ctx, RET_DESER_ERROR, alloc(error), userData) return - callbackToC(ctx, cb): + callbackToC(ctx, cb, userData): ctx.frontend.eth_getTransactionReceipt(txHashTyped) proc eth_getLogs( - ctx: ptr Context, filterOptions: cstring, cb: CallBackProc + ctx: ptr Context, filterOptions: cstring, cb: CallBackProc, userData: pointer ) {.exported.} = let filterOptionsTyped = unpackArg($filterOptions, FilterOptions).valueOr: - cb(ctx, RET_DESER_ERROR, alloc(error)) + cb(ctx, RET_DESER_ERROR, alloc(error), userData) return - callbackToC(ctx, cb): + callbackToC(ctx, cb, userData): ctx.frontend.eth_getLogs(filterOptionsTyped) proc eth_newFilter( - ctx: ptr Context, filterOptions: cstring, cb: CallBackProc + ctx: ptr Context, filterOptions: cstring, cb: CallBackProc, userData: pointer ) {.exported.} = let filterOptionsTyped = unpackArg($filterOptions, FilterOptions).valueOr: - cb(ctx, RET_DESER_ERROR, alloc(error)) + cb(ctx, RET_DESER_ERROR, alloc(error), userData) return - callbackToC(ctx, cb): + callbackToC(ctx, cb, userData): ctx.frontend.eth_newFilter(filterOptionsTyped) proc eth_uninstallFilter( - ctx: ptr Context, filterId: cstring, cb: CallBackProc + ctx: ptr Context, filterId: cstring, cb: CallBackProc, userData: pointer ) {.exported.} = - callbackToC(ctx, cb): + callbackToC(ctx, cb, userData): ctx.frontend.eth_uninstallFilter($filterId) proc eth_getFilterLogs( - ctx: ptr Context, filterId: cstring, cb: CallBackProc + ctx: ptr Context, filterId: cstring, cb: CallBackProc, userData: pointer ) {.exported.} = - callbackToC(ctx, cb): + callbackToC(ctx, cb, userData): ctx.frontend.eth_getFilterLogs($filterId) proc eth_getFilterChanges( - ctx: ptr Context, filterId: cstring, cb: CallBackProc + ctx: ptr Context, filterId: cstring, cb: CallBackProc, userData: pointer ) {.exported.} = - callbackToC(ctx, cb): + callbackToC(ctx, cb, userData): ctx.frontend.eth_getFilterChanges($filterId) -proc eth_blobBaseFee(ctx: ptr Context, cb: CallBackProc) {.exported.} = - callbackToC(ctx, cb): +proc eth_blobBaseFee( + ctx: ptr Context, cb: CallBackProc, userData: pointer +) {.exported.} = + callbackToC(ctx, cb, userData): ctx.frontend.eth_blobBaseFee() -proc eth_gasPrice(ctx: ptr Context, cb: CallBackProc) {.exported.} = - callbackToC(ctx, cb): +proc eth_gasPrice(ctx: ptr Context, cb: CallBackProc, userData: pointer) {.exported.} = + callbackToC(ctx, cb, userData): ctx.frontend.eth_gasPrice() -proc eth_maxPriorityFeePerGas(ctx: ptr Context, cb: CallBackProc) {.exported.} = - callbackToC(ctx, cb): +proc eth_maxPriorityFeePerGas( + ctx: ptr Context, cb: CallBackProc, userData: pointer +) {.exported.} = + callbackToC(ctx, cb, userData): ctx.frontend.eth_maxPriorityFeePerGas() proc eth_sendRawTransaction( - ctx: ptr Context, txHexBytes: cstring, cb: CallBackProc + ctx: ptr Context, txHexBytes: cstring, cb: CallBackProc, userData: pointer ) {.exported.} = let txBytes = try: let temp = hexToSeqByte($txHexBytes) temp except ValueError as e: - cb(ctx, RET_DESER_ERROR, alloc(e.msg)) + cb(ctx, RET_DESER_ERROR, alloc(e.msg), userData) return - callbackToC(ctx, cb): + callbackToC(ctx, cb, userData): ctx.frontend.eth_sendRawTransaction(txBytes) + +proc nvp_call( + ctx: ptr Context, + name: cstring, + params: cstring, + cb: CallBackProc, + userData: pointer, +) {.exported.} = + let parsedParams = + try: + let jsonNode = parseJson($params) + jsonNode.getElems(@[]) + except CatchableError as e: + cb(ctx, RET_DESER_ERROR, alloc(e.msg), userData) + return + + template requireParams(n: int) = + if parsedParams.len < n: + # we use alloc for static strings because the C will try to free the string + cb(ctx, RET_DESER_ERROR, alloc("parameters missing"), userData) + return + + case $name + of "eth_blockNumber": + requireParams(0) + eth_blockNumber(ctx, cb, userData) + of "eth_getBalance": + requireParams(2) + eth_getBalance( + ctx, + parsedParams[0].getStr().cstring, + parsedParams[1].getStr().cstring, + cb, + userData, + ) + of "eth_getStorageAt": + requireParams(3) + eth_getStorageAt( + ctx, + parsedParams[0].getStr().cstring, + parsedParams[1].getStr().cstring, + parsedParams[2].getStr().cstring, + cb, + userData, + ) + of "eth_getTransactionCount": + requireParams(2) + eth_getTransactionCount( + ctx, + parsedParams[0].getStr().cstring, + parsedParams[1].getStr().cstring, + cb, + userData, + ) + of "eth_getCode": + requireParams(2) + eth_getCode( + ctx, + parsedParams[0].getStr().cstring, + parsedParams[1].getStr().cstring, + cb, + userData, + ) + of "eth_getBlockByHash": + requireParams(2) + eth_getBlockByHash( + ctx, parsedParams[0].getStr().cstring, parsedParams[1].getBool(), cb, userData + ) + of "eth_getBlockByNumber": + requireParams(2) + eth_getBlockByNumber( + ctx, parsedParams[0].getStr().cstring, parsedParams[1].getBool(), cb, userData + ) + of "eth_getUncleCountByBlockNumber": + requireParams(1) + eth_getUncleCountByBlockNumber(ctx, parsedParams[0].getStr().cstring, cb, userData) + of "eth_getUncleCountByBlockHash": + requireParams(1) + eth_getUncleCountByBlockHash(ctx, parsedParams[0].getStr().cstring, cb, userData) + of "eth_getBlockTransactionCountByNumber": + requireParams(1) + eth_getBlockTransactionCountByNumber( + ctx, parsedParams[0].getStr().cstring, cb, userData + ) + of "eth_getBlockTransactionCountByHash": + requireParams(1) + eth_getBlockTransactionCountByHash( + ctx, parsedParams[0].getStr().cstring, cb, userData + ) + of "eth_getTransactionByBlockNumberAndIndex": + requireParams(2) + eth_getTransactionByBlockNumberAndIndex( + ctx, + parsedParams[0].getStr().cstring, + parsedParams[1].getBiggestInt().culonglong, + cb, + userData, + ) + of "eth_getTransactionByBlockHashAndIndex": + requireParams(2) + eth_getTransactionByBlockHashAndIndex( + ctx, + parsedParams[0].getStr().cstring, + parsedParams[1].getBiggestInt().culonglong, + cb, + userData, + ) + of "eth_call": + requireParams(3) + eth_call( + ctx, + ($parsedParams[0]).cstring, + parsedParams[1].getStr().cstring, + parsedParams[2].getBool(), + cb, + userData, + ) + of "eth_createAccessList": + requireParams(3) + eth_createAccessList( + ctx, + ($parsedParams[0]).cstring, + parsedParams[1].getStr().cstring, + parsedParams[2].getBool(), + cb, + userData, + ) + of "eth_estimateGas": + requireParams(3) + eth_estimateGas( + ctx, + ($parsedParams[0]).cstring, + parsedParams[1].getStr().cstring, + parsedParams[2].getBool(), + cb, + userData, + ) + of "eth_getTransactionByHash": + requireParams(1) + eth_getTransactionByHash(ctx, parsedParams[0].getStr().cstring, cb, userData) + of "eth_getBlockReceipts": + requireParams(1) + eth_getBlockReceipts(ctx, parsedParams[0].getStr().cstring, cb, userData) + of "eth_getTransactionReceipt": + requireParams(1) + eth_getTransactionReceipt(ctx, parsedParams[0].getStr().cstring, cb, userData) + of "eth_getLogs": + requireParams(1) + eth_getLogs(ctx, ($parsedParams[0]).cstring, cb, userData) + of "eth_newFilter": + requireParams(1) + eth_newFilter(ctx, ($parsedParams[0]).cstring, cb, userData) + of "eth_uninstallFilter": + requireParams(1) + eth_uninstallFilter(ctx, parsedParams[0].getStr().cstring, cb, userData) + of "eth_getFilterLogs": + requireParams(1) + eth_getFilterLogs(ctx, parsedParams[0].getStr().cstring, cb, userData) + of "eth_getFilterChanges": + requireParams(1) + eth_getFilterChanges(ctx, parsedParams[0].getStr().cstring, cb, userData) + of "eth_blobBaseFee": + requireParams(0) + eth_blobBaseFee(ctx, cb, userData) + of "eth_gasPrice": + requireParams(0) + eth_gasPrice(ctx, cb, userData) + of "eth_maxPriorityFeePerGas": + requireParams(0) + eth_maxPriorityFeePerGas(ctx, cb, userData) + of "eth_sendRawTransaction": + requireParams(1) + eth_sendRawTransaction(ctx, parsedParams[0].getStr().cstring, cb, userData) + else: + # we use alloc for static strings because the C will try to free the string + cb(ctx, RET_DESER_ERROR, alloc("unknown method"), userData)