From 65670727931407d78a8472d3807a27297a8e302e Mon Sep 17 00:00:00 2001 From: a Date: Mon, 24 Oct 2022 20:58:24 -0500 Subject: [PATCH] ok i guess --- cmd/rpcdaemon/README.md | 527 ++ cmd/rpcdaemon/cli/config.go | 678 ++ cmd/rpcdaemon/cli/httpcfg/http_cfg.go | 52 + cmd/rpcdaemon/cli/rpc_allow_list.go | 43 + cmd/rpcdaemon/commands/daemon.go | 156 + cmd/rpcdaemon/commands/error_messages.go | 10 + .../commands/get_chain_config_test.go | 39 + cmd/rpcdaemon/commands/otterscan_api.go | 526 ++ .../commands/otterscan_block_details.go | 97 + .../commands/otterscan_contract_creator.go | 245 + .../commands/otterscan_default_tracer.go | 38 + .../commands/otterscan_generic_tracer.go | 78 + cmd/rpcdaemon/commands/otterscan_has_code.go | 31 + .../commands/otterscan_search_backward.go | 128 + .../otterscan_search_backward_multi_test.go | 109 + .../otterscan_search_backward_test.go | 143 + .../commands/otterscan_search_forward.go | 107 + .../otterscan_search_forward_multi_test.go | 108 + .../commands/otterscan_search_forward_test.go | 143 + .../commands/otterscan_search_multi.go | 63 + .../commands/otterscan_search_test.go | 31 + .../commands/otterscan_search_trace.go | 103 + .../otterscan_trace_contract_creator.go | 50 + .../commands/otterscan_trace_operations.go | 60 + .../commands/otterscan_trace_touch.go | 27 + .../commands/otterscan_trace_transaction.go | 87 + ...terscan_transaction_by_sender_and_nonce.go | 163 + .../commands/otterscan_transaction_error.go | 23 + cmd/rpcdaemon/commands/otterscan_types.go | 94 + cmd/rpcdaemon/commands/utils_eth_api.go | 295 + cmd/rpcdaemon/commands/utils_eth_call.go | 66 + cmd/rpcdaemon/commands/utils_eth_receipts.go | 112 + cmd/rpcdaemon/commands/utils_storage_range.go | 42 + cmd/rpcdaemon/health/check_block.go | 23 + cmd/rpcdaemon/health/check_peers.go | 28 + cmd/rpcdaemon/health/check_synced.go | 25 + cmd/rpcdaemon/health/check_time.go | 35 + cmd/rpcdaemon/health/health.go | 227 + cmd/rpcdaemon/health/health_test.go | 562 ++ cmd/rpcdaemon/health/interfaces.go | 17 + cmd/rpcdaemon/health/parse_api.go | 22 + cmd/rpcdaemon/main.go | 43 + cmd/rpcdaemon/postman/README.md | 18 + cmd/rpcdaemon/postman/RPC_Testing.json | 4235 ++++++++++ cmd/rpcdaemon/postman/Trace_Testing.json | 7474 +++++++++++++++++ cmd/rpcdaemon/rpcdaemontest/test_util.go | 321 + cmd/rpcdaemon/rpcservices/eth_backend.go | 310 + cmd/rpcdaemon/rpcservices/eth_mining.go | 43 + cmd/rpcdaemon/rpcservices/eth_txpool.go | 50 + cmd/rpcdaemon/test.http | 222 + cmd/rpcdaemon/testdata/.gitignore | 5 + cmd/rpcdaemon/testdata/sed_file | 22 + cmd/rpcdaemon/testdata/trace_tests | 76 + cmd/server/main.go | 69 + erigon_internal/debug/api.go | 239 + erigon_internal/debug/flags.go | 217 + erigon_internal/debug/loudpanic.go | 27 + erigon_internal/debug/loudpanic_fallback.go | 24 + erigon_internal/debug/signal.go | 43 + erigon_internal/debug/signal_windows.go | 33 + erigon_internal/debug/trace.go | 63 + erigon_internal/debug/trace_fallback.go | 31 + erigon_internal/ethapi/api.go | 1039 +++ erigon_internal/ethapi/backend.go | 56 + erigon_internal/ethapi/get_proof.go | 234 + erigon_internal/ethapi/state_overrides.go | 50 + erigon_internal/logging/flags.go | 56 + erigon_internal/logging/logging.go | 162 + go.mod | 149 + go.sum | 889 ++ package.json | 3 + src/App.tsx | 2 +- 72 files changed, 21617 insertions(+), 1 deletion(-) create mode 100644 cmd/rpcdaemon/README.md create mode 100644 cmd/rpcdaemon/cli/config.go create mode 100644 cmd/rpcdaemon/cli/httpcfg/http_cfg.go create mode 100644 cmd/rpcdaemon/cli/rpc_allow_list.go create mode 100644 cmd/rpcdaemon/commands/daemon.go create mode 100644 cmd/rpcdaemon/commands/error_messages.go create mode 100644 cmd/rpcdaemon/commands/get_chain_config_test.go create mode 100644 cmd/rpcdaemon/commands/otterscan_api.go create mode 100644 cmd/rpcdaemon/commands/otterscan_block_details.go create mode 100644 cmd/rpcdaemon/commands/otterscan_contract_creator.go create mode 100644 cmd/rpcdaemon/commands/otterscan_default_tracer.go create mode 100644 cmd/rpcdaemon/commands/otterscan_generic_tracer.go create mode 100644 cmd/rpcdaemon/commands/otterscan_has_code.go create mode 100644 cmd/rpcdaemon/commands/otterscan_search_backward.go create mode 100644 cmd/rpcdaemon/commands/otterscan_search_backward_multi_test.go create mode 100644 cmd/rpcdaemon/commands/otterscan_search_backward_test.go create mode 100644 cmd/rpcdaemon/commands/otterscan_search_forward.go create mode 100644 cmd/rpcdaemon/commands/otterscan_search_forward_multi_test.go create mode 100644 cmd/rpcdaemon/commands/otterscan_search_forward_test.go create mode 100644 cmd/rpcdaemon/commands/otterscan_search_multi.go create mode 100644 cmd/rpcdaemon/commands/otterscan_search_test.go create mode 100644 cmd/rpcdaemon/commands/otterscan_search_trace.go create mode 100644 cmd/rpcdaemon/commands/otterscan_trace_contract_creator.go create mode 100644 cmd/rpcdaemon/commands/otterscan_trace_operations.go create mode 100644 cmd/rpcdaemon/commands/otterscan_trace_touch.go create mode 100644 cmd/rpcdaemon/commands/otterscan_trace_transaction.go create mode 100644 cmd/rpcdaemon/commands/otterscan_transaction_by_sender_and_nonce.go create mode 100644 cmd/rpcdaemon/commands/otterscan_transaction_error.go create mode 100644 cmd/rpcdaemon/commands/otterscan_types.go create mode 100644 cmd/rpcdaemon/commands/utils_eth_api.go create mode 100644 cmd/rpcdaemon/commands/utils_eth_call.go create mode 100644 cmd/rpcdaemon/commands/utils_eth_receipts.go create mode 100644 cmd/rpcdaemon/commands/utils_storage_range.go create mode 100644 cmd/rpcdaemon/health/check_block.go create mode 100644 cmd/rpcdaemon/health/check_peers.go create mode 100644 cmd/rpcdaemon/health/check_synced.go create mode 100644 cmd/rpcdaemon/health/check_time.go create mode 100644 cmd/rpcdaemon/health/health.go create mode 100644 cmd/rpcdaemon/health/health_test.go create mode 100644 cmd/rpcdaemon/health/interfaces.go create mode 100644 cmd/rpcdaemon/health/parse_api.go create mode 100644 cmd/rpcdaemon/main.go create mode 100644 cmd/rpcdaemon/postman/README.md create mode 100644 cmd/rpcdaemon/postman/RPC_Testing.json create mode 100644 cmd/rpcdaemon/postman/Trace_Testing.json create mode 100644 cmd/rpcdaemon/rpcdaemontest/test_util.go create mode 100644 cmd/rpcdaemon/rpcservices/eth_backend.go create mode 100644 cmd/rpcdaemon/rpcservices/eth_mining.go create mode 100644 cmd/rpcdaemon/rpcservices/eth_txpool.go create mode 100644 cmd/rpcdaemon/test.http create mode 100644 cmd/rpcdaemon/testdata/.gitignore create mode 100644 cmd/rpcdaemon/testdata/sed_file create mode 100644 cmd/rpcdaemon/testdata/trace_tests create mode 100644 cmd/server/main.go create mode 100644 erigon_internal/debug/api.go create mode 100644 erigon_internal/debug/flags.go create mode 100644 erigon_internal/debug/loudpanic.go create mode 100644 erigon_internal/debug/loudpanic_fallback.go create mode 100644 erigon_internal/debug/signal.go create mode 100644 erigon_internal/debug/signal_windows.go create mode 100644 erigon_internal/debug/trace.go create mode 100644 erigon_internal/debug/trace_fallback.go create mode 100644 erigon_internal/ethapi/api.go create mode 100644 erigon_internal/ethapi/backend.go create mode 100644 erigon_internal/ethapi/get_proof.go create mode 100644 erigon_internal/ethapi/state_overrides.go create mode 100644 erigon_internal/logging/flags.go create mode 100644 erigon_internal/logging/logging.go create mode 100644 go.mod create mode 100644 go.sum diff --git a/cmd/rpcdaemon/README.md b/cmd/rpcdaemon/README.md new file mode 100644 index 0000000..e313313 --- /dev/null +++ b/cmd/rpcdaemon/README.md @@ -0,0 +1,527 @@ +- [Introduction](#introduction) +- [Getting Started](#getting-started) + * [Running locally](#running-locally) + * [Running remotely](#running-remotely) + * [Healthcheck](#healthcheck) + * [Testing](#testing) +- [FAQ](#faq) + * [Relations between prune options and rpc methods](#relations-between-prune-options-and-rpc-method) + * [RPC Implementation Status](#rpc-implementation-status) + * [Securing the communication between RPC daemon and Erigon instance via TLS and authentication](#securing-the-communication-between-rpc-daemon-and-erigon-instance-via-tls-and-authentication) + * [Ethstats](#ethstats) + * [Allowing only specific methods (Allowlist)](#allowing-only-specific-methods--allowlist-) + * [Trace transactions progress](#trace-transactions-progress) + * [Clients getting timeout, but server load is low](#clients-getting-timeout--but-server-load-is-low) + * [Server load too high](#server-load-too-high) + * [Faster Batch requests](#faster-batch-requests) +- [For Developers](#for-developers) + * [Code generation](#code-generation) + +## Introduction + +Erigon's `rpcdaemon` runs in its own seperate process. + +This brings many benefits including easier development, the ability to run multiple daemons at once, and the ability to +run the daemon remotely. It is possible to run the daemon locally as well (read-only) if both processes have access to +the data folder. + +## Getting Started + +The `rpcdaemon` gets built as part of the main `erigon` build process, but you can build it directly with this command: + +```[bash] +make rpcdaemon +``` + +### Running locally + +Run `rpcdaemon` on same computer with Erigon. It's default option because it using Shared Memory access to Erigon's db - +it's much faster than TCP access. Provide both `--datadir` and `--private.api.addr` flags: + +```[bash] +make erigon +./build/bin/erigon --datadir= --private.api.addr=localhost:9090 +make rpcdaemon +./build/bin/rpcdaemon --datadir= --txpool.api.addr=localhost:9090 --private.api.addr=localhost:9090 --http.api=eth,erigon,web3,net,debug,trace,txpool +``` + +Note that we've also specified which RPC namespaces to enable in the above command by `--http.api` flag. + +### Running remotely + +To start the daemon remotely - just don't set `--datadir` flag: + +```[bash] +make erigon +./build/bin/erigon --datadir= --private.api.addr=0.0.0.0:9090 +make rpcdaemon +./build/bin/rpcdaemon --private.api.addr=:9090 --txpool.api.addr=localhost:9090 --http.api=eth,erigon,web3,net,debug,trace,txpool +``` + +The daemon should respond with something like: + +```[bash] +INFO [date-time] HTTP endpoint opened url=localhost:8545... +``` + +When RPC daemon runs remotely, by default it maintains a state cache, which is updated every time when Erigon imports a +new block. When state cache is reasonably warm, it allows such remote RPC daemon to execute queries related to `latest` +block (i.e. to current state) with comparable performance to a local RPC daemon +(around 2x slower vs 10x slower without state cache). Since there can be multiple such RPC daemons per one Erigon node, +it may scale well for some workloads that are heavy on the current state queries. + +### Healthcheck + +There are 2 options for running healtchecks, POST request, or GET request with custom headers. Both options are available +at the `/health` endpoint. + +#### POST request + +If the health check is successful it returns 200 OK. + +If the health check fails it returns 500 Internal Server Error. + +Configuration of the health check is sent as POST body of the method. + +``` +{ + "min_peer_count": , + "known_block": +} +``` + +Not adding a check disables that. + +**`min_peer_count`** -- checks for mimimum of healthy node peers. Requires +`net` namespace to be listed in `http.api`. + +**`known_block`** -- sets up the block that node has to know about. Requires +`eth` namespace to be listed in `http.api`. + +Example request +```http POST http://localhost:8545/health --raw '{"min_peer_count": 3, "known_block": "0x1F"}'``` +Example response + +``` +{ + "check_block": "HEALTHY", + "healthcheck_query": "HEALTHY", + "min_peer_count": "HEALTHY" +} +``` + +#### GET with headers + +If the healthcheck is successful it will return a 200 status code. + +If the healthcheck fails for any reason a status 500 will be returned. This is true if one of the criteria requested +fails its check. + +You can set any number of values on the `X-ERIGON-HEALTHCHECK` header. Ones that are not included are skipped in the +checks. + +Available Options: +- `synced` - will check if the node has completed syncing +- `min_peer_count` - will check that the node has at least `` many peers +- `check_block` - will check that the node is at least ahead of the `` specified +- `max_seconds_behind` - will check that the node is no more than `` behind from its latest block + +Example Request +``` +curl --location --request GET 'http://localhost:8545/health' \ +--header 'X-ERIGON-HEALTHCHECK: min_peer_count1' \ +--header 'X-ERIGON-HEALTHCHECK: synced' \ +--header 'X-ERIGON-HEALTHCHECK: max_seconds_behind600' +``` + +Example Response +``` +{ + "check_block":"DISABLED", + "max_seconds_behind":"HEALTHY", + "min_peer_count":"HEALTHY", + "synced":"HEALTHY" +} +``` + +### Testing + +By default, the `rpcdaemon` serves data from `localhost:8545`. You may send `curl` commands to see if things are +working. + +Try `eth_blockNumber` for example. In a third terminal window enter this command: + +```[bash] +curl -X POST -H "Content-Type: application/json" --data '{"jsonrpc": "2.0", "method": "eth_blockNumber", "params": [], "id":1}' localhost:8545 +``` + +This should return something along the lines of this (depending on how far your Erigon node has synced): + +```[bash] +{ + "jsonrpc": "2.0", + "id": 1, + "result":" 0xa5b9ba" +} +``` + +Also, there +are [extensive instructions for using Postman](https://github.com/ledgerwatch/erigon/wiki/Using-Postman-to-Test-TurboGeth-RPC) +to test the RPC. + +## FAQ + +### Relations between prune options and RPC methods + +Next options available (by `--prune` flag): + +``` +* h - prune history (ChangeSets, HistoryIndices - used to access historical state, like eth_getStorageAt, eth_getBalanceAt, debug_traceTransaction, trace_block, trace_transaction, etc.) +* r - prune receipts (Receipts, Logs, LogTopicIndex, LogAddressIndex - used by eth_getLogs and similar RPC methods) +* t - prune tx lookup (used to get transaction by hash) +* c - prune call traces (used by trace_filter method) +``` + +By default data pruned after 90K blocks, can change it by flags like `--prune.history.after=100_000` + +Some methods, if not found historical data in DB, can fallback to old blocks re-execution - but it require `h`. + +### RPC Implementation Status + +Label "remote" means: `--private.api.addr` flag is required. + +The following table shows the current implementation status of Erigon's RPC daemon. + +| Command | Avail | Notes | +| ------------------------------------------ |---------|--------------------------------------| +| admin_nodeInfo | Yes | | +| admin_peers | Yes | | +| | | | +| web3_clientVersion | Yes | | +| web3_sha3 | Yes | | +| | | | +| net_listening | HC | (`remote` hard coded returns true) | +| net_peerCount | Limited | internal sentries only | +| net_version | Yes | `remote`. | +| | | | +| eth_blockNumber | Yes | | +| eth_chainID/eth_chainId | Yes | | +| eth_protocolVersion | Yes | | +| eth_syncing | Yes | | +| eth_gasPrice | Yes | | +| eth_maxPriorityFeePerGas | Yes | | +| eth_feeHistory | Yes | | +| | | | +| eth_getBlockByHash | Yes | | +| eth_getBlockByNumber | Yes | | +| eth_getBlockTransactionCountByHash | Yes | | +| eth_getBlockTransactionCountByNumber | Yes | | +| eth_getUncleByBlockHashAndIndex | Yes | | +| eth_getUncleByBlockNumberAndIndex | Yes | | +| eth_getUncleCountByBlockHash | Yes | | +| eth_getUncleCountByBlockNumber | Yes | | +| | | | +| eth_getTransactionByHash | Yes | | +| eth_getRawTransactionByHash | Yes | | +| eth_getTransactionByBlockHashAndIndex | Yes | | +| eth_retRawTransactionByBlockHashAndIndex | Yes | | +| eth_getTransactionByBlockNumberAndIndex | Yes | | +| eth_retRawTransactionByBlockNumberAndIndex | Yes | | +| eth_getTransactionReceipt | Yes | | +| eth_getBlockReceipts | Yes | | +| | | | +| eth_estimateGas | Yes | | +| eth_getBalance | Yes | | +| eth_getCode | Yes | | +| eth_getTransactionCount | Yes | | +| eth_getStorageAt | Yes | | +| eth_call | Yes | | +| eth_callMany | Yes | Erigon Method PR#4567 | +| eth_callBundle | Yes | | +| eth_createAccessList | Yes | | +| | | | +| eth_newFilter | Yes | Added by PR#4253 | +| eth_newBlockFilter | Yes | | +| eth_newPendingTransactionFilter | Yes | | +| eth_getFilterChanges | Yes | | +| eth_uninstallFilter | Yes | | +| eth_getLogs | Yes | | +| | | | +| eth_accounts | No | deprecated | +| eth_sendRawTransaction | Yes | `remote`. | +| eth_sendTransaction | - | not yet implemented | +| eth_sign | No | deprecated | +| eth_signTransaction | - | not yet implemented | +| eth_signTypedData | - | ???? | +| | | | +| eth_getProof | - | not yet implemented | +| | | | +| eth_mining | Yes | returns true if --mine flag provided | +| eth_coinbase | Yes | | +| eth_hashrate | Yes | | +| eth_submitHashrate | Yes | | +| eth_getWork | Yes | | +| eth_submitWork | Yes | | +| | | | +| eth_subscribe | Limited | Websock Only - newHeads, | +| | | newPendingTransactions, | +| | | newPendingBlock | +| eth_unsubscribe | Yes | Websock Only | +| | | | +| engine_newPayloadV1 | Yes | | +| engine_forkchoiceUpdatedV1 | Yes | | +| engine_getPayloadV1 | Yes | | +| engine_exchangeTransitionConfigurationV1 | Yes | | +| | | | +| debug_accountRange | Yes | Private Erigon debug module | +| debug_accountAt | Yes | Private Erigon debug module | +| debug_getModifiedAccountsByNumber | Yes | | +| debug_getModifiedAccountsByHash | Yes | | +| debug_storageRangeAt | Yes | | +| debug_traceBlockByHash | Yes | Streaming (can handle huge results) | +| debug_traceBlockByNumber | Yes | Streaming (can handle huge results) | +| debug_traceTransaction | Yes | Streaming (can handle huge results) | +| debug_traceCall | Yes | Streaming (can handle huge results) | +| debug_traceCallMany | Yes | Erigon Method PR#4567. | +| | | | +| trace_call | Yes | | +| trace_callMany | Yes | | +| trace_rawTransaction | - | not yet implemented (come help!) | +| trace_replayBlockTransactions | yes | stateDiff only (come help!) | +| trace_replayTransaction | yes | stateDiff only (come help!) | +| trace_block | Yes | | +| trace_filter | Yes | no pagination, but streaming | +| trace_get | Yes | | +| trace_transaction | Yes | | +| | | | +| txpool_content | Yes | `remote` | +| txpool_status | Yes | `remote` | +| | | | +| eth_getCompilers | No | deprecated | +| eth_compileLLL | No | deprecated | +| eth_compileSolidity | No | deprecated | +| eth_compileSerpent | No | deprecated | +| | | | +| db_putString | No | deprecated | +| db_getString | No | deprecated | +| db_putHex | No | deprecated | +| db_getHex | No | deprecated | +| | | | +| erigon_getHeaderByHash | Yes | Erigon only | +| erigon_getHeaderByNumber | Yes | Erigon only | +| erigon_getLogsByHash | Yes | Erigon only | +| erigon_forks | Yes | Erigon only | +| erigon_issuance | Yes | Erigon only | +| erigon_GetBlockByTimestamp | Yes | Erigon only | +| erigon_BlockNumber | Yes | Erigon only | +| | | | +| bor_getSnapshot | Yes | Bor only | +| bor_getAuthor | Yes | Bor only | +| bor_getSnapshotAtHash | Yes | Bor only | +| bor_getSigners | Yes | Bor only | +| bor_getSignersAtHash | Yes | Bor only | +| bor_getCurrentProposer | Yes | Bor only | +| bor_getCurrentValidators | Yes | Bor only | +| bor_getRootHash | Yes | Bor only | + +This table is constantly updated. Please visit again. + +### Securing the communication between RPC daemon and Erigon instance via TLS and authentication + +In some cases, it is useful to run Erigon nodes in a different network (for example, in a Public cloud), but RPC daemon +locally. To ensure the integrity of communication and access control to the Erigon node, TLS authentication can be +enabled. On the high level, the process consists of these steps (this process needs to be done for any "cluster" of +Erigon and RPC daemon nodes that are supposed to work together): + +1. Generate key pair for the Certificate Authority (CA). The private key of CA will be used to authorise new Erigon + instances as well as new RPC daemon instances, so that they can mutually authenticate. +2. Create CA certificate file that needs to be deployed on any Erigon instance and any RPC daemon. This CA cerf file is + used as a "root of trust", whatever is in it, will be trusted by the participants when they authenticate their + counterparts. +3. For each Erigon instance and each RPC daemon instance, generate a key pair. If you are lazy, you can generate one + pair for all Erigon nodes, and one pair for all RPC daemons, and copy these keys around. +4. Using the CA private key, create cerificate file for each public key generated on the previous step. This + effectively "inducts" these keys into the "cluster of trust". +5. On each instance, deploy 3 files - CA certificate, instance key, and certificate signed by CA for this instance key. + +Following is the detailed description of how it can be done using `openssl` suite of tools. + +Generate CA key pair using Elliptic Curve (as opposed to RSA). The generated CA key will be in the file `CA-key.pem`. +Access to this file will allow anyone to later include any new instance key pair into the "cluster of trust", so keep it +secure. + +``` +openssl ecparam -name prime256v1 -genkey -noout -out CA-key.pem +``` + +Create CA self-signed certificate (this command will ask questions, answers aren't important for now). The file created +by this command is `CA-cert.pem` + +``` +openssl req -x509 -new -nodes -key CA-key.pem -sha256 -days 3650 -out CA-cert.pem +``` + +For Erigon node, generate a key pair: + +``` +openssl ecparam -name prime256v1 -genkey -noout -out erigon-key.pem +``` + +Also, generate one for the RPC daemon: + +``` +openssl ecparam -name prime256v1 -genkey -noout -out RPC-key.pem +``` + +Now create certificate signing request for Erigon key pair: + +``` +openssl req -new -key erigon-key.pem -out erigon.csr +``` + +And from this request, produce the certificate (signed by CA), proving that this key is now part of the "cluster of +trust" + +``` +openssl x509 -req -in erigon.csr -CA CA-cert.pem -CAkey CA-key.pem -CAcreateserial -out erigon.crt -days 3650 -sha256 +``` + +Then, produce the certificate signing request for RPC daemon key pair: + +``` +openssl req -new -key RPC-key.pem -out RPC.csr +``` + +And from this request, produce the certificate (signed by CA), proving that this key is now part of the "cluster of +trust" + +``` +openssl x509 -req -in RPC.csr -CA CA-cert.pem -CAkey CA-key.pem -CAcreateserial -out RPC.crt -days 3650 -sha256 +``` + +When this is all done, these three files need to be placed on the machine where Erigon is running: `CA-cert.pem` +, `erigon-key.pem`, `erigon.crt`. And Erigon needs to be run with these extra options: + +``` +--tls --tls.cacert CA-cert.pem --tls.key erigon-key.pem --tls.cert erigon.crt +``` + +On the RPC daemon machine, these three files need to be placed: `CA-cert.pem`, `RPC-key.pem`, and `RPC.crt`. And RPC +daemon needs to be started with these extra options: + +``` +--tls.key RPC-key.pem --tls.cacert CA-cert.pem --tls.cert RPC.crt +``` + +**WARNING** Normally, the "client side" (which in our case is RPC daemon), verifies that the host name of the server +matches the "Common Name" attribute of the "server" cerificate. At this stage, this verification is turned off, and it +will be turned on again once we have updated the instruction above on how to properly generate cerificates with "Common +Name". + +When running Erigon instance in the Google Cloud, for example, you need to specify the **Internal IP** in +the `--private.api.addr` option. And, you will need to open the firewall on the port you are using, to that connection +to the Erigon instances can be made. + +### Ethstats + +This version of the RPC daemon is compatible with [ethstats-client](https://github.com/goerli/ethstats-client). + +To run ethstats, run the RPC daemon remotely and open some of the APIs. + +`./build/bin/rpcdaemon --private.api.addr=localhost:9090 --http.api=net,eth,web3` + +Then update your `app.json` for ethstats-client like that: + +```json +[ + { + "name": "ethstats", + "script": "app.js", + "log_date_format": "YYYY-MM-DD HH:mm Z", + "merge_logs": false, + "watch": false, + "max_restarts": 10, + "exec_interpreter": "node", + "exec_mode": "fork_mode", + "env": { + "NODE_ENV": "production", + "RPC_HOST": "localhost", + "RPC_PORT": "8545", + "LISTENING_PORT": "30303", + "INSTANCE_NAME": "Erigon node", + "CONTACT_DETAILS": , + "WS_SERVER": "wss://ethstats.net/api", + "WS_SECRET": , + "VERBOSITY": 2 + } + } +] +``` + +Run ethstats-client through pm2 as usual. + +You will see these warnings in the RPC daemon output, but they are expected + +``` +WARN [11-05|09:03:47.911] Served conn=127.0.0.1:59753 method=eth_newBlockFilter reqid=5 t="21.194µs" err="the method eth_newBlockFilter does not exist/is not available" +WARN [11-05|09:03:47.911] Served conn=127.0.0.1:59754 method=eth_newPendingTransactionFilter reqid=6 t="9.053µs" err="the method eth_newPendingTransactionFilter does not exist/is not available" +``` + +### Allowing only specific methods (Allowlist) + +In some cases you might want to only allow certain methods in the namespaces and hide others. That is possible +with `rpc.accessList` flag. + +1. Create a file, say, `rules.json` + +2. Add the following content + +```json +{ + "allow": [ + "net_version", + "web3_eth_getBlockByHash" + ] +} +``` + +3. Provide this file to the rpcdaemon using `--rpc.accessList` flag + +``` +> rpcdaemon --private.api.addr=localhost:9090 --http.api=eth,debug,net,web3 --rpc.accessList=rules.json +``` + +Now only these two methods are available. + +### Clients getting timeout, but server load is low + +In this case: increase default rate-limit - amount of requests server handle simultaneously - requests over this limit +will wait. Increase it - if your 'hot data' is small or have much RAM or see "request timeout" while server load is low. + +``` +./build/bin/erigon --private.api.addr=localhost:9090 --private.api.ratelimit=1024 +``` + +### Server load too high + +Reduce `--private.api.ratelimit` + +### Read DB directly without Json-RPC/Graphql + +[./../../docs/programmers_guide/db_faq.md](./../../docs/programmers_guide/db_faq.md) + +### Faster Batch requests + +Currently batch requests are spawn multiple goroutines and process all sub-requests in parallel. To limit impact of 1 +huge batch to other users - added flag `--rpc.batch.concurrency` (default: 2). Increase it to process large batches +faster. + +Known Issue: if at least 1 request is "streamable" (has parameter of type *jsoniter.Stream) - then whole batch will +processed sequentially (on 1 goroutine). + +## For Developers + +### Code generation + +`go.mod` stores right version of generators, use `make grpc` to install it and generate code (it also installs protoc +into ./build/bin folder). diff --git a/cmd/rpcdaemon/cli/config.go b/cmd/rpcdaemon/cli/config.go new file mode 100644 index 0000000..dd8394b --- /dev/null +++ b/cmd/rpcdaemon/cli/config.go @@ -0,0 +1,678 @@ +package cli + +import ( + "context" + "crypto/rand" + "encoding/binary" + "errors" + "fmt" + "net" + "net/http" + "os" + "path/filepath" + "strings" + "time" + + "github.com/ledgerwatch/erigon-lib/common/dir" + libstate "github.com/ledgerwatch/erigon-lib/state" + "github.com/ledgerwatch/erigon/eth/ethconfig" + "github.com/ledgerwatch/erigon/rpc/rpccfg" + + "github.com/wmitsuda/otterscan/cmd/rpcdaemon/cli/httpcfg" + "github.com/wmitsuda/otterscan/cmd/rpcdaemon/health" + "github.com/wmitsuda/otterscan/cmd/rpcdaemon/rpcservices" + "github.com/wmitsuda/otterscan/erigon_internal/debug" + "github.com/wmitsuda/otterscan/erigon_internal/logging" + + "github.com/ledgerwatch/erigon-lib/direct" + "github.com/ledgerwatch/erigon-lib/gointerfaces" + "github.com/ledgerwatch/erigon-lib/gointerfaces/grpcutil" + "github.com/ledgerwatch/erigon-lib/gointerfaces/remote" + "github.com/ledgerwatch/erigon-lib/gointerfaces/txpool" + "github.com/ledgerwatch/erigon-lib/kv" + "github.com/ledgerwatch/erigon-lib/kv/kvcache" + kv2 "github.com/ledgerwatch/erigon-lib/kv/mdbx" + "github.com/ledgerwatch/erigon-lib/kv/remotedb" + "github.com/ledgerwatch/erigon-lib/kv/remotedbserver" + "github.com/ledgerwatch/erigon/cmd/utils" + "github.com/ledgerwatch/erigon/common" + "github.com/ledgerwatch/erigon/common/hexutil" + "github.com/ledgerwatch/erigon/common/paths" + "github.com/ledgerwatch/erigon/core/rawdb" + "github.com/ledgerwatch/erigon/node" + "github.com/ledgerwatch/erigon/node/nodecfg" + "github.com/ledgerwatch/erigon/node/nodecfg/datadir" + "github.com/ledgerwatch/erigon/params" + "github.com/ledgerwatch/erigon/rpc" + "github.com/ledgerwatch/erigon/turbo/rpchelper" + "github.com/ledgerwatch/erigon/turbo/services" + "github.com/ledgerwatch/erigon/turbo/snapshotsync" + "github.com/ledgerwatch/erigon/turbo/snapshotsync/snap" + "github.com/ledgerwatch/log/v3" + "github.com/spf13/cobra" + "golang.org/x/sync/semaphore" + "google.golang.org/grpc" + grpcHealth "google.golang.org/grpc/health" + "google.golang.org/grpc/health/grpc_health_v1" +) + +var rootCmd = &cobra.Command{ + Use: "rpcdaemon", + Short: "rpcdaemon is JSON RPC server that connects to Erigon node for remote DB access", +} + +func RootCommand() (*cobra.Command, *httpcfg.HttpCfg) { + utils.CobraFlags(rootCmd, debug.Flags, utils.MetricFlags, logging.Flags) + + cfg := &httpcfg.HttpCfg{Enabled: true, StateCache: kvcache.DefaultCoherentConfig} + rootCmd.PersistentFlags().StringVar(&cfg.PrivateApiAddr, "private.api.addr", "127.0.0.1:9090", "private api network address, for example: 127.0.0.1:9090") + rootCmd.PersistentFlags().StringVar(&cfg.DataDir, "datadir", "", "path to Erigon working directory") + rootCmd.PersistentFlags().StringVar(&cfg.HttpListenAddress, "http.addr", nodecfg.DefaultHTTPHost, "HTTP-RPC server listening interface") + rootCmd.PersistentFlags().StringVar(&cfg.TLSCertfile, "tls.cert", "", "certificate for client side TLS handshake") + rootCmd.PersistentFlags().StringVar(&cfg.TLSKeyFile, "tls.key", "", "key file for client side TLS handshake") + rootCmd.PersistentFlags().StringVar(&cfg.TLSCACert, "tls.cacert", "", "CA certificate for client side TLS handshake") + rootCmd.PersistentFlags().IntVar(&cfg.HttpPort, "http.port", nodecfg.DefaultHTTPPort, "HTTP-RPC server listening port") + rootCmd.PersistentFlags().StringSliceVar(&cfg.HttpCORSDomain, "http.corsdomain", []string{}, "Comma separated list of domains from which to accept cross origin requests (browser enforced)") + rootCmd.PersistentFlags().StringSliceVar(&cfg.HttpVirtualHost, "http.vhosts", nodecfg.DefaultConfig.HTTPVirtualHosts, "Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard.") + rootCmd.PersistentFlags().BoolVar(&cfg.HttpCompression, "http.compression", true, "Disable http compression") + rootCmd.PersistentFlags().StringSliceVar(&cfg.API, "http.api", []string{"eth", "erigon"}, "API's offered over the HTTP-RPC interface: eth,erigon,web3,net,debug,trace,txpool,db. Supported methods: https://github.com/ledgerwatch/erigon/tree/devel/cmd/rpcdaemon") + rootCmd.PersistentFlags().Uint64Var(&cfg.Gascap, "rpc.gascap", 50000000, "Sets a cap on gas that can be used in eth_call/estimateGas") + rootCmd.PersistentFlags().Uint64Var(&cfg.MaxTraces, "trace.maxtraces", 200, "Sets a limit on traces that can be returned in trace_filter") + rootCmd.PersistentFlags().BoolVar(&cfg.WebsocketEnabled, "ws", false, "Enable Websockets") + rootCmd.PersistentFlags().BoolVar(&cfg.WebsocketCompression, "ws.compression", false, "Enable Websocket compression (RFC 7692)") + rootCmd.PersistentFlags().StringVar(&cfg.RpcAllowListFilePath, "rpc.accessList", "", "Specify granular (method-by-method) API allowlist") + rootCmd.PersistentFlags().UintVar(&cfg.RpcBatchConcurrency, utils.RpcBatchConcurrencyFlag.Name, 2, utils.RpcBatchConcurrencyFlag.Usage) + rootCmd.PersistentFlags().BoolVar(&cfg.RpcStreamingDisable, utils.RpcStreamingDisableFlag.Name, false, utils.RpcStreamingDisableFlag.Usage) + rootCmd.PersistentFlags().IntVar(&cfg.DBReadConcurrency, utils.DBReadConcurrencyFlag.Name, utils.DBReadConcurrencyFlag.Value, utils.DBReadConcurrencyFlag.Usage) + rootCmd.PersistentFlags().BoolVar(&cfg.TraceCompatibility, "trace.compat", false, "Bug for bug compatibility with OE for trace_ routines") + rootCmd.PersistentFlags().StringVar(&cfg.TxPoolApiAddr, "txpool.api.addr", "", "txpool api network address, for example: 127.0.0.1:9090 (default: use value of --private.api.addr)") + rootCmd.PersistentFlags().BoolVar(&cfg.Sync.UseSnapshots, "snapshot", true, utils.SnapshotFlag.Usage) + rootCmd.PersistentFlags().IntVar(&cfg.StateCache.KeysLimit, "state.cache", kvcache.DefaultCoherentConfig.KeysLimit, "Amount of keys to store in StateCache (enabled if no --datadir set). Set 0 to disable StateCache. 1_000_000 keys ~ equal to 2Gb RAM (maybe we will add RAM accounting in future versions).") + rootCmd.PersistentFlags().BoolVar(&cfg.GRPCServerEnabled, "grpc", false, "Enable GRPC server") + rootCmd.PersistentFlags().StringVar(&cfg.GRPCListenAddress, "grpc.addr", nodecfg.DefaultGRPCHost, "GRPC server listening interface") + rootCmd.PersistentFlags().IntVar(&cfg.GRPCPort, "grpc.port", nodecfg.DefaultGRPCPort, "GRPC server listening port") + rootCmd.PersistentFlags().BoolVar(&cfg.GRPCHealthCheckEnabled, "grpc.healthcheck", false, "Enable GRPC health check") + rootCmd.PersistentFlags().BoolVar(&cfg.TraceRequests, utils.HTTPTraceFlag.Name, false, "Trace HTTP requests with INFO level") + rootCmd.PersistentFlags().DurationVar(&cfg.HTTPTimeouts.ReadTimeout, "http.timeouts.read", rpccfg.DefaultHTTPTimeouts.ReadTimeout, "Maximum duration for reading the entire request, including the body.") + rootCmd.PersistentFlags().DurationVar(&cfg.HTTPTimeouts.WriteTimeout, "http.timeouts.write", rpccfg.DefaultHTTPTimeouts.WriteTimeout, "Maximum duration before timing out writes of the response. It is reset whenever a new request's header is read") + rootCmd.PersistentFlags().DurationVar(&cfg.HTTPTimeouts.IdleTimeout, "http.timeouts.idle", rpccfg.DefaultHTTPTimeouts.IdleTimeout, "Maximum amount of time to wait for the next request when keep-alives are enabled. If http.timeouts.idle is zero, the value of http.timeouts.read is used") + rootCmd.PersistentFlags().DurationVar(&cfg.EvmCallTimeout, "rpc.evmtimeout", rpccfg.DefaultEvmCallTimeout, "Maximum amount of time to wait for the answer from EVM call.") + + if err := rootCmd.MarkPersistentFlagFilename("rpc.accessList", "json"); err != nil { + panic(err) + } + if err := rootCmd.MarkPersistentFlagDirname("datadir"); err != nil { + panic(err) + } + + rootCmd.PersistentPreRunE = func(cmd *cobra.Command, args []string) error { + if err := debug.SetupCobra(cmd); err != nil { + return err + } + cfg.WithDatadir = cfg.DataDir != "" + if cfg.WithDatadir { + if cfg.DataDir == "" { + cfg.DataDir = paths.DefaultDataDir() + } + cfg.Dirs = datadir.New(cfg.DataDir) + } + if cfg.TxPoolApiAddr == "" { + cfg.TxPoolApiAddr = cfg.PrivateApiAddr + } + return nil + } + rootCmd.PersistentPostRunE = func(cmd *cobra.Command, args []string) error { + debug.Exit() + return nil + } + + cfg.StateCache.MetricsLabel = "rpc" + + return rootCmd, cfg +} + +type StateChangesClient interface { + StateChanges(ctx context.Context, in *remote.StateChangeRequest, opts ...grpc.CallOption) (remote.KV_StateChangesClient, error) +} + +func subscribeToStateChangesLoop(ctx context.Context, client StateChangesClient, cache kvcache.Cache) { + go func() { + for { + select { + case <-ctx.Done(): + return + default: + } + if err := subscribeToStateChanges(ctx, client, cache); err != nil { + if grpcutil.IsRetryLater(err) || grpcutil.IsEndOfStream(err) { + time.Sleep(3 * time.Second) + continue + } + log.Warn("[txpool.handleStateChanges]", "err", err) + } + } + }() +} + +func subscribeToStateChanges(ctx context.Context, client StateChangesClient, cache kvcache.Cache) error { + streamCtx, cancel := context.WithCancel(ctx) + defer cancel() + stream, err := client.StateChanges(streamCtx, &remote.StateChangeRequest{WithStorage: true, WithTransactions: false}, grpc.WaitForReady(true)) + if err != nil { + return err + } + for req, err := stream.Recv(); ; req, err = stream.Recv() { + if err != nil { + return err + } + if req == nil { + return nil + } + + cache.OnNewBlock(req) + } +} + +func checkDbCompatibility(ctx context.Context, db kv.RoDB) error { + // DB schema version compatibility check + var version []byte + var compatErr error + var compatTx kv.Tx + if compatTx, compatErr = db.BeginRo(ctx); compatErr != nil { + return fmt.Errorf("open Ro Tx for DB schema compability check: %w", compatErr) + } + defer compatTx.Rollback() + if version, compatErr = compatTx.GetOne(kv.DatabaseInfo, kv.DBSchemaVersionKey); compatErr != nil { + return fmt.Errorf("read version for DB schema compability check: %w", compatErr) + } + if len(version) != 12 { + return fmt.Errorf("database does not have major schema version. upgrade and restart Erigon core") + } + major := binary.BigEndian.Uint32(version) + minor := binary.BigEndian.Uint32(version[4:]) + patch := binary.BigEndian.Uint32(version[8:]) + var compatible bool + dbSchemaVersion := &kv.DBSchemaVersion + if major != dbSchemaVersion.Major { + compatible = false + } else if minor != dbSchemaVersion.Minor { + compatible = false + } else { + compatible = true + } + if !compatible { + return fmt.Errorf("incompatible DB Schema versions: reader %d.%d.%d, database %d.%d.%d", + dbSchemaVersion.Major, dbSchemaVersion.Minor, dbSchemaVersion.Patch, + major, minor, patch) + } + log.Info("DB schemas compatible", "reader", fmt.Sprintf("%d.%d.%d", dbSchemaVersion.Major, dbSchemaVersion.Minor, dbSchemaVersion.Patch), + "database", fmt.Sprintf("%d.%d.%d", major, minor, patch)) + return nil +} + +func EmbeddedServices(ctx context.Context, + erigonDB kv.RoDB, stateCacheCfg kvcache.CoherentConfig, + blockReader services.FullBlockReader, snapshots *snapshotsync.RoSnapshots, agg *libstate.Aggregator22, + ethBackendServer remote.ETHBACKENDServer, txPoolServer txpool.TxpoolServer, miningServer txpool.MiningServer, +) (eth rpchelper.ApiBackend, txPool txpool.TxpoolClient, mining txpool.MiningClient, stateCache kvcache.Cache, ff *rpchelper.Filters, err error) { + if stateCacheCfg.KeysLimit > 0 { + stateCache = kvcache.NewDummy() + // notification about new blocks (state stream) doesn't work now inside erigon - because + // erigon does send this stream to privateAPI (erigon with enabled rpc, still have enabled privateAPI). + // without this state stream kvcache can't work and only slow-down things + // + //stateCache = kvcache.New(stateCacheCfg) + } else { + stateCache = kvcache.NewDummy() + } + kvRPC := remotedbserver.NewKvServer(ctx, erigonDB, snapshots, agg) + stateDiffClient := direct.NewStateDiffClientDirect(kvRPC) + subscribeToStateChangesLoop(ctx, stateDiffClient, stateCache) + + directClient := direct.NewEthBackendClientDirect(ethBackendServer) + + eth = rpcservices.NewRemoteBackend(directClient, erigonDB, blockReader) + txPool = direct.NewTxPoolClient(txPoolServer) + mining = direct.NewMiningClient(miningServer) + ff = rpchelper.New(ctx, eth, txPool, mining, func() {}) + + return +} + +// RemoteServices - use when RPCDaemon run as independent process. Still it can use --datadir flag to enable +// `cfg.WithDatadir` (mode when it on 1 machine with Erigon) +func RemoteServices(ctx context.Context, cfg httpcfg.HttpCfg, logger log.Logger, rootCancel context.CancelFunc) ( + db kv.RoDB, borDb kv.RoDB, + eth rpchelper.ApiBackend, txPool txpool.TxpoolClient, mining txpool.MiningClient, + stateCache kvcache.Cache, blockReader services.FullBlockReader, + ff *rpchelper.Filters, agg *libstate.Aggregator22, err error) { + if !cfg.WithDatadir && cfg.PrivateApiAddr == "" { + return nil, nil, nil, nil, nil, nil, nil, ff, nil, fmt.Errorf("either remote db or local db must be specified") + } + + // Do not change the order of these checks. Chaindata needs to be checked first, because PrivateApiAddr has default value which is not "" + // If PrivateApiAddr is checked first, the Chaindata option will never work + if cfg.WithDatadir { + dir.MustExist(cfg.Dirs.SnapHistory) + var rwKv kv.RwDB + log.Trace("Creating chain db", "path", cfg.Dirs.Chaindata) + limiter := semaphore.NewWeighted(int64(cfg.DBReadConcurrency)) + rwKv, err = kv2.NewMDBX(logger).RoTxsLimiter(limiter).Path(cfg.Dirs.Chaindata).Readonly().Open() + if err != nil { + return nil, nil, nil, nil, nil, nil, nil, ff, nil, err + } + if compatErr := checkDbCompatibility(ctx, rwKv); compatErr != nil { + return nil, nil, nil, nil, nil, nil, nil, ff, nil, compatErr + } + db = rwKv + stateCache = kvcache.NewDummy() + blockReader = snapshotsync.NewBlockReader() + + // bor (consensus) specific db + var borKv kv.RoDB + borDbPath := filepath.Join(cfg.DataDir, "bor") + { + // ensure db exist + tmpDb, err := kv2.NewMDBX(logger).Path(borDbPath).Label(kv.ConsensusDB).Open() + if err != nil { + return nil, nil, nil, nil, nil, nil, nil, ff, nil, err + } + tmpDb.Close() + } + log.Trace("Creating consensus db", "path", borDbPath) + borKv, err = kv2.NewMDBX(logger).Path(borDbPath).Label(kv.ConsensusDB).Readonly().Open() + if err != nil { + return nil, nil, nil, nil, nil, nil, nil, ff, nil, err + } + // Skip the compatibility check, until we have a schema in erigon-lib + borDb = borKv + } else { + if cfg.StateCache.KeysLimit > 0 { + stateCache = kvcache.NewDummy() + //stateCache = kvcache.New(cfg.StateCache) + } else { + stateCache = kvcache.NewDummy() + } + log.Info("if you run RPCDaemon on same machine with Erigon add --datadir option") + } + + if db != nil { + var cc *params.ChainConfig + if err := db.View(context.Background(), func(tx kv.Tx) error { + genesisBlock, err := rawdb.ReadBlockByNumber(tx, 0) + if err != nil { + return err + } + if genesisBlock == nil { + return fmt.Errorf("genesis not found in DB. Likely Erigon was never started on this datadir") + } + cc, err = rawdb.ReadChainConfig(tx, genesisBlock.Hash()) + if err != nil { + return err + } + cfg.Snap.Enabled, err = snap.Enabled(tx) + if err != nil { + return err + } + return nil + }); err != nil { + return nil, nil, nil, nil, nil, nil, nil, ff, nil, err + } + if cc == nil { + return nil, nil, nil, nil, nil, nil, nil, ff, nil, fmt.Errorf("chain config not found in db. Need start erigon at least once on this db") + } + cfg.Snap.Enabled = cfg.Snap.Enabled || cfg.Sync.UseSnapshots + } + + creds, err := grpcutil.TLS(cfg.TLSCACert, cfg.TLSCertfile, cfg.TLSKeyFile) + if err != nil { + return nil, nil, nil, nil, nil, nil, nil, ff, nil, fmt.Errorf("open tls cert: %w", err) + } + conn, err := grpcutil.Connect(creds, cfg.PrivateApiAddr) + if err != nil { + return nil, nil, nil, nil, nil, nil, nil, ff, nil, fmt.Errorf("could not connect to execution service privateApi: %w", err) + } + + kvClient := remote.NewKVClient(conn) + remoteKv, err := remotedb.NewRemote(gointerfaces.VersionFromProto(remotedbserver.KvServiceAPIVersion), logger, kvClient).Open() + if err != nil { + return nil, nil, nil, nil, nil, nil, nil, ff, nil, fmt.Errorf("could not connect to remoteKv: %w", err) + } + + subscribeToStateChangesLoop(ctx, kvClient, stateCache) + + onNewSnapshot := func() {} + if cfg.WithDatadir { + if cfg.Snap.Enabled { + + allSnapshots := snapshotsync.NewRoSnapshots(cfg.Snap, cfg.Dirs.Snap) + // To povide good UX - immediatly can read snapshots after RPCDaemon start, even if Erigon is down + // Erigon does store list of snapshots in db: means RPCDaemon can read this list now, but read by `kvClient.Snapshots` after establish grpc connection + allSnapshots.OptimisticReopenWithDB(db) + allSnapshots.LogStat() + + if agg, err = libstate.NewAggregator22(cfg.Dirs.SnapHistory, cfg.Dirs.Tmp, ethconfig.HistoryV3AggregationStep, db); err != nil { + return nil, nil, nil, nil, nil, nil, nil, ff, nil, fmt.Errorf("create aggregator: %w", err) + } + if err = agg.ReopenFiles(); err != nil { + return nil, nil, nil, nil, nil, nil, nil, ff, nil, fmt.Errorf("create aggregator: %w", err) + } + + db.View(context.Background(), func(tx kv.Tx) error { + agg.LogStats(tx, func(endTxNumMinimax uint64) uint64 { + _, histBlockNumProgress, _ := rawdb.TxNums.FindBlockNum(tx, endTxNumMinimax) + return histBlockNumProgress + }) + return nil + }) + + onNewSnapshot = func() { + go func() { // don't block events processing by network communication + reply, err := kvClient.Snapshots(ctx, &remote.SnapshotsRequest{}, grpc.WaitForReady(true)) + if err != nil { + log.Warn("[Snapshots] reopen", "err", err) + return + } + if err := allSnapshots.ReopenList(reply.BlockFiles, true); err != nil { + log.Error("[Snapshots] reopen", "err", err) + } else { + allSnapshots.LogStat() + } + + if err = agg.ReopenFiles(); err != nil { + log.Error("[Snapshots] reopen", "err", err) + } else { + db.View(context.Background(), func(tx kv.Tx) error { + agg.LogStats(tx, func(endTxNumMinimax uint64) uint64 { + _, histBlockNumProgress, _ := rawdb.TxNums.FindBlockNum(tx, endTxNumMinimax) + return histBlockNumProgress + }) + return nil + }) + } + }() + } + onNewSnapshot() + // TODO: how to don't block startup on remote RPCDaemon? + // txNums = exec22.TxNumsFromDB(allSnapshots, db) + blockReader = snapshotsync.NewBlockReaderWithSnapshots(allSnapshots) + } else { + log.Info("Use --snapshots=false") + } + } + + if !cfg.WithDatadir { + blockReader = snapshotsync.NewRemoteBlockReader(remote.NewETHBACKENDClient(conn)) + } + remoteEth := rpcservices.NewRemoteBackend(remote.NewETHBACKENDClient(conn), db, blockReader) + blockReader = remoteEth + + txpoolConn := conn + if cfg.TxPoolApiAddr != cfg.PrivateApiAddr { + txpoolConn, err = grpcutil.Connect(creds, cfg.TxPoolApiAddr) + if err != nil { + return nil, nil, nil, nil, nil, nil, nil, ff, nil, fmt.Errorf("could not connect to txpool api: %w", err) + } + } + + mining = txpool.NewMiningClient(txpoolConn) + miningService := rpcservices.NewMiningService(mining) + txPool = txpool.NewTxpoolClient(txpoolConn) + txPoolService := rpcservices.NewTxPoolService(txPool) + if db == nil { + db = remoteKv + } + eth = remoteEth + go func() { + if !remoteKv.EnsureVersionCompatibility() { + rootCancel() + } + if !remoteEth.EnsureVersionCompatibility() { + rootCancel() + } + if mining != nil && !miningService.EnsureVersionCompatibility() { + rootCancel() + } + if !txPoolService.EnsureVersionCompatibility() { + rootCancel() + } + }() + + ff = rpchelper.New(ctx, eth, txPool, mining, onNewSnapshot) + return db, borDb, eth, txPool, mining, stateCache, blockReader, ff, agg, err +} + +func StartRpcServer(ctx context.Context, cfg httpcfg.HttpCfg, rpcAPI []rpc.API, authAPI []rpc.API) error { + if len(authAPI) > 0 { + engineInfo, err := startAuthenticatedRpcServer(cfg, authAPI) + if err != nil { + return err + } + go stopAuthenticatedRpcServer(ctx, engineInfo) + } + + if cfg.Enabled { + return startRegularRpcServer(ctx, cfg, rpcAPI) + } + + return nil +} + +func startRegularRpcServer(ctx context.Context, cfg httpcfg.HttpCfg, rpcAPI []rpc.API) error { + // register apis and create handler stack + httpEndpoint := fmt.Sprintf("%s:%d", cfg.HttpListenAddress, cfg.HttpPort) + + log.Trace("TraceRequests = %t\n", cfg.TraceRequests) + srv := rpc.NewServer(cfg.RpcBatchConcurrency, cfg.TraceRequests, cfg.RpcStreamingDisable) + + allowListForRPC, err := parseAllowListForRPC(cfg.RpcAllowListFilePath) + if err != nil { + return err + } + srv.SetAllowList(allowListForRPC) + + var defaultAPIList []rpc.API + + for _, api := range rpcAPI { + if api.Namespace != "engine" { + defaultAPIList = append(defaultAPIList, api) + } + } + + var apiFlags []string + for _, flag := range cfg.API { + if flag != "engine" { + apiFlags = append(apiFlags, flag) + } + } + + if err := node.RegisterApisFromWhitelist(defaultAPIList, apiFlags, srv, false); err != nil { + return fmt.Errorf("could not start register RPC apis: %w", err) + } + + httpHandler := node.NewHTTPHandlerStack(srv, cfg.HttpCORSDomain, cfg.HttpVirtualHost, cfg.HttpCompression) + var wsHandler http.Handler + if cfg.WebsocketEnabled { + wsHandler = srv.WebsocketHandler([]string{"*"}, nil, cfg.WebsocketCompression) + } + + apiHandler, err := createHandler(cfg, defaultAPIList, httpHandler, wsHandler, nil) + if err != nil { + return err + } + + listener, _, err := node.StartHTTPEndpoint(httpEndpoint, cfg.HTTPTimeouts, apiHandler) + if err != nil { + return fmt.Errorf("could not start RPC api: %w", err) + } + info := []interface{}{"url", httpEndpoint, "ws", cfg.WebsocketEnabled, + "ws.compression", cfg.WebsocketCompression, "grpc", cfg.GRPCServerEnabled} + + var ( + healthServer *grpcHealth.Server + grpcServer *grpc.Server + grpcListener net.Listener + grpcEndpoint string + ) + if cfg.GRPCServerEnabled { + grpcEndpoint = fmt.Sprintf("%s:%d", cfg.GRPCListenAddress, cfg.GRPCPort) + if grpcListener, err = net.Listen("tcp", grpcEndpoint); err != nil { + return fmt.Errorf("could not start GRPC listener: %w", err) + } + grpcServer = grpc.NewServer() + if cfg.GRPCHealthCheckEnabled { + healthServer = grpcHealth.NewServer() + grpc_health_v1.RegisterHealthServer(grpcServer, healthServer) + } + go grpcServer.Serve(grpcListener) + info = append(info, "grpc.port", cfg.GRPCPort) + } + + log.Info("HTTP endpoint opened", info...) + + defer func() { + srv.Stop() + shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + _ = listener.Shutdown(shutdownCtx) + log.Info("HTTP endpoint closed", "url", httpEndpoint) + + if cfg.GRPCServerEnabled { + if cfg.GRPCHealthCheckEnabled { + healthServer.Shutdown() + } + grpcServer.GracefulStop() + _ = grpcListener.Close() + log.Info("GRPC endpoint closed", "url", grpcEndpoint) + } + }() + <-ctx.Done() + log.Info("Exiting...") + return nil +} + +type engineInfo struct { + Srv *rpc.Server + EngineSrv *rpc.Server + EngineListener *http.Server + EngineHttpEndpoint string +} + +func startAuthenticatedRpcServer(cfg httpcfg.HttpCfg, rpcAPI []rpc.API) (*engineInfo, error) { + log.Trace("TraceRequests = %t\n", cfg.TraceRequests) + srv := rpc.NewServer(cfg.RpcBatchConcurrency, cfg.TraceRequests, cfg.RpcStreamingDisable) + + engineListener, engineSrv, engineHttpEndpoint, err := createEngineListener(cfg, rpcAPI) + if err != nil { + return nil, fmt.Errorf("could not start RPC api for engine: %w", err) + } + return &engineInfo{Srv: srv, EngineSrv: engineSrv, EngineListener: engineListener, EngineHttpEndpoint: engineHttpEndpoint}, nil +} + +func stopAuthenticatedRpcServer(ctx context.Context, engineInfo *engineInfo) { + defer func() { + engineInfo.Srv.Stop() + if engineInfo.EngineSrv != nil { + engineInfo.EngineSrv.Stop() + } + shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + if engineInfo.EngineListener != nil { + _ = engineInfo.EngineListener.Shutdown(shutdownCtx) + log.Info("Engine HTTP endpoint close", "url", engineInfo.EngineHttpEndpoint) + } + }() + <-ctx.Done() + log.Info("Exiting Engine...") +} + +// isWebsocket checks the header of a http request for a websocket upgrade request. +func isWebsocket(r *http.Request) bool { + return strings.EqualFold(r.Header.Get("Upgrade"), "websocket") && + strings.Contains(strings.ToLower(r.Header.Get("Connection")), "upgrade") +} + +// obtainJWTSecret loads the jwt-secret, either from the provided config, +// or from the default location. If neither of those are present, it generates +// a new secret and stores to the default location. +func obtainJWTSecret(cfg httpcfg.HttpCfg) ([]byte, error) { + // try reading from file + log.Info("Reading JWT secret", "path", cfg.JWTSecretPath) + // If we run the rpcdaemon and datadir is not specified we just use jwt.hex in current directory. + if len(cfg.JWTSecretPath) == 0 { + cfg.JWTSecretPath = "jwt.hex" + } + if data, err := os.ReadFile(cfg.JWTSecretPath); err == nil { + jwtSecret := common.FromHex(strings.TrimSpace(string(data))) + if len(jwtSecret) == 32 { + return jwtSecret, nil + } + log.Error("Invalid JWT secret", "path", cfg.JWTSecretPath, "length", len(jwtSecret)) + return nil, errors.New("invalid JWT secret") + } + // Need to generate one + jwtSecret := make([]byte, 32) + rand.Read(jwtSecret) + + if err := os.WriteFile(cfg.JWTSecretPath, []byte(hexutil.Encode(jwtSecret)), 0600); err != nil { + return nil, err + } + log.Info("Generated JWT secret", "path", cfg.JWTSecretPath) + return jwtSecret, nil +} + +func createHandler(cfg httpcfg.HttpCfg, apiList []rpc.API, httpHandler http.Handler, wsHandler http.Handler, jwtSecret []byte) (http.Handler, error) { + var handler http.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // adding a healthcheck here + if health.ProcessHealthcheckIfNeeded(w, r, apiList) { + return + } + if cfg.WebsocketEnabled && wsHandler != nil && isWebsocket(r) { + wsHandler.ServeHTTP(w, r) + return + } + + if jwtSecret != nil && !rpc.CheckJwtSecret(w, r, jwtSecret) { + return + } + + httpHandler.ServeHTTP(w, r) + }) + + return handler, nil +} + +func createEngineListener(cfg httpcfg.HttpCfg, engineApi []rpc.API) (*http.Server, *rpc.Server, string, error) { + engineHttpEndpoint := fmt.Sprintf("%s:%d", cfg.AuthRpcHTTPListenAddress, cfg.AuthRpcPort) + + engineSrv := rpc.NewServer(cfg.RpcBatchConcurrency, cfg.TraceRequests, true) + + if err := node.RegisterApisFromWhitelist(engineApi, nil, engineSrv, true); err != nil { + return nil, nil, "", fmt.Errorf("could not start register RPC engine api: %w", err) + } + + jwtSecret, err := obtainJWTSecret(cfg) + if err != nil { + return nil, nil, "", err + } + + wsHandler := engineSrv.WebsocketHandler([]string{"*"}, jwtSecret, cfg.WebsocketCompression) + + engineHttpHandler := node.NewHTTPHandlerStack(engineSrv, nil /* authCors */, cfg.AuthRpcVirtualHost, cfg.HttpCompression) + + engineApiHandler, err := createHandler(cfg, engineApi, engineHttpHandler, wsHandler, jwtSecret) + if err != nil { + return nil, nil, "", err + } + + engineListener, _, err := node.StartHTTPEndpoint(engineHttpEndpoint, cfg.AuthRpcTimeouts, engineApiHandler) + if err != nil { + return nil, nil, "", fmt.Errorf("could not start RPC api: %w", err) + } + + engineInfo := []interface{}{"url", engineHttpEndpoint, "ws", true, "ws.compression", cfg.WebsocketCompression} + log.Info("HTTP endpoint opened for Engine API", engineInfo...) + + return engineListener, engineSrv, engineHttpEndpoint, nil +} diff --git a/cmd/rpcdaemon/cli/httpcfg/http_cfg.go b/cmd/rpcdaemon/cli/httpcfg/http_cfg.go new file mode 100644 index 0000000..6d490d8 --- /dev/null +++ b/cmd/rpcdaemon/cli/httpcfg/http_cfg.go @@ -0,0 +1,52 @@ +package httpcfg + +import ( + "github.com/ledgerwatch/erigon-lib/kv/kvcache" + "github.com/ledgerwatch/erigon/eth/ethconfig" + "github.com/ledgerwatch/erigon/node/nodecfg/datadir" + "github.com/ledgerwatch/erigon/rpc/rpccfg" + "time" +) + +type HttpCfg struct { + Enabled bool + PrivateApiAddr string + WithDatadir bool // Erigon's database can be read by separated processes on same machine - in read-only mode - with full support of transactions. It will share same "OS PageCache" with Erigon process. + DataDir string + Dirs datadir.Dirs + HttpListenAddress string + AuthRpcHTTPListenAddress string + TLSCertfile string + TLSCACert string + TLSKeyFile string + HttpPort int + AuthRpcPort int + HttpCORSDomain []string + HttpVirtualHost []string + AuthRpcVirtualHost []string + HttpCompression bool + API []string + Gascap uint64 + MaxTraces uint64 + WebsocketEnabled bool + WebsocketCompression bool + RpcAllowListFilePath string + RpcBatchConcurrency uint + RpcStreamingDisable bool + DBReadConcurrency int + TraceCompatibility bool // Bug for bug compatibility for trace_ routines with OpenEthereum + TxPoolApiAddr string + StateCache kvcache.CoherentConfig + Snap ethconfig.Snapshot + Sync ethconfig.Sync + GRPCServerEnabled bool + GRPCListenAddress string + GRPCPort int + GRPCHealthCheckEnabled bool + StarknetGRPCAddress string + JWTSecretPath string // Engine API Authentication + TraceRequests bool // Always trace requests in INFO level + HTTPTimeouts rpccfg.HTTPTimeouts + AuthRpcTimeouts rpccfg.HTTPTimeouts + EvmCallTimeout time.Duration +} diff --git a/cmd/rpcdaemon/cli/rpc_allow_list.go b/cmd/rpcdaemon/cli/rpc_allow_list.go new file mode 100644 index 0000000..dbf6fbf --- /dev/null +++ b/cmd/rpcdaemon/cli/rpc_allow_list.go @@ -0,0 +1,43 @@ +package cli + +import ( + "encoding/json" + "io" + "os" + "strings" + + "github.com/ledgerwatch/erigon/rpc" +) + +type allowListFile struct { + Allow rpc.AllowList `json:"allow"` +} + +func parseAllowListForRPC(path string) (rpc.AllowList, error) { + path = strings.TrimSpace(path) + if path == "" { // no file is provided + return nil, nil + } + + file, err := os.Open(path) + if err != nil { + return nil, err + } + defer func() { + file.Close() //nolint: errcheck + }() + + fileContents, err := io.ReadAll(file) + if err != nil { + return nil, err + } + + var allowListFileObj allowListFile + + err = json.Unmarshal(fileContents, &allowListFileObj) + if err != nil { + return nil, err + } + + return allowListFileObj.Allow, nil +} diff --git a/cmd/rpcdaemon/commands/daemon.go b/cmd/rpcdaemon/commands/daemon.go new file mode 100644 index 0000000..090b420 --- /dev/null +++ b/cmd/rpcdaemon/commands/daemon.go @@ -0,0 +1,156 @@ +package commands + +import ( + "github.com/ledgerwatch/erigon-lib/gointerfaces/txpool" + "github.com/ledgerwatch/erigon-lib/kv" + "github.com/ledgerwatch/erigon-lib/kv/kvcache" + libstate "github.com/ledgerwatch/erigon-lib/state" + "github.com/ledgerwatch/erigon/cmd/rpcdaemon/commands" + "github.com/ledgerwatch/erigon/rpc" + "github.com/ledgerwatch/erigon/turbo/rpchelper" + "github.com/ledgerwatch/erigon/turbo/services" + + "github.com/wmitsuda/otterscan/cmd/rpcdaemon/cli/httpcfg" + + erigonHttpcfg "github.com/ledgerwatch/erigon/cmd/rpcdaemon/cli/httpcfg" +) + +// APIList describes the list of available RPC apis +func APIList(db kv.RoDB, borDb kv.RoDB, eth rpchelper.ApiBackend, txPool txpool.TxpoolClient, mining txpool.MiningClient, + filters *rpchelper.Filters, stateCache kvcache.Cache, + blockReader services.FullBlockReader, agg *libstate.Aggregator22, cfg httpcfg.HttpCfg) (list []rpc.API) { + tcfg := erigonHttpcfg.HttpCfg{ + MaxTraces: cfg.MaxTraces, + Gascap: cfg.Gascap, + TraceCompatibility: cfg.TraceCompatibility, + } + baseUtils := NewBaseUtilsApi(filters, stateCache, blockReader, agg, cfg.WithDatadir, cfg.EvmCallTimeout) + base := commands.NewBaseApi(filters, stateCache, blockReader, agg, cfg.WithDatadir, cfg.EvmCallTimeout) + ethImpl := commands.NewEthAPI(base, db, eth, txPool, mining, cfg.Gascap) + erigonImpl := commands.NewErigonAPI(base, db, eth) + txpoolImpl := commands.NewTxPoolAPI(base, db, txPool) + netImpl := commands.NewNetAPIImpl(eth) + debugImpl := commands.NewPrivateDebugAPI(base, db, cfg.Gascap) + traceImpl := commands.NewTraceAPI(base, db, &tcfg) + web3Impl := commands.NewWeb3APIImpl(eth) + dbImpl := commands.NewDBAPIImpl() /* deprecated */ + adminImpl := commands.NewAdminAPI(eth) + parityImpl := commands.NewParityAPIImpl(db) + borImpl := commands.NewBorAPI(base, db, borDb) // bor (consensus) specific + otsImpl := NewOtterscanAPI(baseUtils, db) + + for _, enabledAPI := range cfg.API { + switch enabledAPI { + case "eth": + list = append(list, rpc.API{ + Namespace: "eth", + Public: true, + Service: commands.EthAPI(ethImpl), + Version: "1.0", + }) + case "debug": + list = append(list, rpc.API{ + Namespace: "debug", + Public: true, + Service: commands.PrivateDebugAPI(debugImpl), + Version: "1.0", + }) + case "net": + list = append(list, rpc.API{ + Namespace: "net", + Public: true, + Service: commands.NetAPI(netImpl), + Version: "1.0", + }) + case "txpool": + list = append(list, rpc.API{ + Namespace: "txpool", + Public: true, + Service: commands.TxPoolAPI(txpoolImpl), + Version: "1.0", + }) + case "web3": + list = append(list, rpc.API{ + Namespace: "web3", + Public: true, + Service: commands.Web3API(web3Impl), + Version: "1.0", + }) + case "trace": + list = append(list, rpc.API{ + Namespace: "trace", + Public: true, + Service: commands.TraceAPI(traceImpl), + Version: "1.0", + }) + case "db": /* Deprecated */ + list = append(list, rpc.API{ + Namespace: "db", + Public: true, + Service: commands.DBAPI(dbImpl), + Version: "1.0", + }) + case "erigon": + list = append(list, rpc.API{ + Namespace: "erigon", + Public: true, + Service: commands.ErigonAPI(erigonImpl), + Version: "1.0", + }) + case "bor": + list = append(list, rpc.API{ + Namespace: "bor", + Public: true, + Service: commands.BorAPI(borImpl), + Version: "1.0", + }) + case "admin": + list = append(list, rpc.API{ + Namespace: "admin", + Public: false, + Service: commands.AdminAPI(adminImpl), + Version: "1.0", + }) + case "parity": + list = append(list, rpc.API{ + Namespace: "parity", + Public: false, + Service: commands.ParityAPI(parityImpl), + Version: "1.0", + }) + case "ots": + list = append(list, rpc.API{ + Namespace: "ots", + Public: true, + Service: OtterscanAPI(otsImpl), + Version: "1.0", + }) + } + } + + return list +} + +func AuthAPIList(db kv.RoDB, eth rpchelper.ApiBackend, txPool txpool.TxpoolClient, mining txpool.MiningClient, + filters *rpchelper.Filters, stateCache kvcache.Cache, blockReader services.FullBlockReader, + agg *libstate.Aggregator22, + cfg httpcfg.HttpCfg) (list []rpc.API) { + base := commands.NewBaseApi(filters, stateCache, blockReader, agg, cfg.WithDatadir, cfg.EvmCallTimeout) + + ethImpl := commands.NewEthAPI(base, db, eth, txPool, mining, cfg.Gascap) + engineImpl := commands.NewEngineAPI(base, db, eth) + + list = append(list, rpc.API{ + Namespace: "eth", + Public: true, + Service: commands.EthAPI(ethImpl), + Version: "1.0", + }, rpc.API{ + Namespace: "engine", + Public: true, + Service: commands.EngineAPI(engineImpl), + Version: "1.0", + }) + + return list +} diff --git a/cmd/rpcdaemon/commands/error_messages.go b/cmd/rpcdaemon/commands/error_messages.go new file mode 100644 index 0000000..b593ea5 --- /dev/null +++ b/cmd/rpcdaemon/commands/error_messages.go @@ -0,0 +1,10 @@ +package commands + +// NotImplemented is the URI prefix for smartcard wallets. +const NotImplemented = "the method is currently not implemented: %s" + +// NotAvailableChainData x +const NotAvailableChainData = "the function %s is not available, please use --private.api.addr option instead of --datadir option" + +// NotAvailableDeprecated x +const NotAvailableDeprecated = "the method has been deprecated: %s" diff --git a/cmd/rpcdaemon/commands/get_chain_config_test.go b/cmd/rpcdaemon/commands/get_chain_config_test.go new file mode 100644 index 0000000..a4ed4fd --- /dev/null +++ b/cmd/rpcdaemon/commands/get_chain_config_test.go @@ -0,0 +1,39 @@ +package commands + +import ( + "context" + "testing" + + "github.com/ledgerwatch/erigon-lib/kv/memdb" + "github.com/ledgerwatch/erigon/core" +) + +func TestGetChainConfig(t *testing.T) { + db := memdb.NewTestDB(t) + config, _, err := core.CommitGenesisBlock(db, core.DefaultGenesisBlock()) + if err != nil { + t.Fatalf("setting up genensis block: %v", err) + } + + tx, txErr := db.BeginRo(context.Background()) + if txErr != nil { + t.Fatalf("error starting tx: %v", txErr) + } + defer tx.Rollback() + + api := &BaseAPI{} + config1, err1 := api.chainConfig(tx) + if err1 != nil { + t.Fatalf("reading chain config: %v", err1) + } + if config.String() != config1.String() { + t.Fatalf("read different config: %s, expected %s", config1.String(), config.String()) + } + config2, err2 := api.chainConfig(tx) + if err2 != nil { + t.Fatalf("reading chain config: %v", err2) + } + if config.String() != config2.String() { + t.Fatalf("read different config: %s, expected %s", config2.String(), config.String()) + } +} diff --git a/cmd/rpcdaemon/commands/otterscan_api.go b/cmd/rpcdaemon/commands/otterscan_api.go new file mode 100644 index 0000000..9fe130f --- /dev/null +++ b/cmd/rpcdaemon/commands/otterscan_api.go @@ -0,0 +1,526 @@ +package commands + +import ( + "context" + "errors" + "fmt" + "math/big" + "sync" + + "github.com/holiman/uint256" + "github.com/ledgerwatch/erigon-lib/kv" + "github.com/ledgerwatch/erigon/cmd/rpcdaemon/commands" + "github.com/ledgerwatch/erigon/common" + "github.com/ledgerwatch/erigon/common/hexutil" + "github.com/ledgerwatch/erigon/consensus/ethash" + "github.com/ledgerwatch/erigon/core" + "github.com/ledgerwatch/erigon/core/rawdb" + "github.com/ledgerwatch/erigon/core/types" + "github.com/ledgerwatch/erigon/core/vm" + "github.com/ledgerwatch/erigon/params" + "github.com/ledgerwatch/erigon/rpc" + "github.com/ledgerwatch/erigon/turbo/rpchelper" + "github.com/ledgerwatch/erigon/turbo/transactions" + "github.com/ledgerwatch/log/v3" + + "github.com/wmitsuda/otterscan/erigon_internal/ethapi" +) + +// API_LEVEL Must be incremented every time new additions are made +const API_LEVEL = 8 + +type TransactionsWithReceipts struct { + Txs []*commands.RPCTransaction `json:"txs"` + Receipts []map[string]interface{} `json:"receipts"` + FirstPage bool `json:"firstPage"` + LastPage bool `json:"lastPage"` +} + +type OtterscanAPI interface { + GetApiLevel() uint8 + GetInternalOperations(ctx context.Context, hash common.Hash) ([]*InternalOperation, error) + SearchTransactionsBefore(ctx context.Context, addr common.Address, blockNum uint64, pageSize uint16) (*TransactionsWithReceipts, error) + SearchTransactionsAfter(ctx context.Context, addr common.Address, blockNum uint64, pageSize uint16) (*TransactionsWithReceipts, error) + GetBlockDetails(ctx context.Context, number rpc.BlockNumber) (map[string]interface{}, error) + GetBlockDetailsByHash(ctx context.Context, hash common.Hash) (map[string]interface{}, error) + GetBlockTransactions(ctx context.Context, number rpc.BlockNumber, pageNumber uint8, pageSize uint8) (map[string]interface{}, error) + HasCode(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (bool, error) + TraceTransaction(ctx context.Context, hash common.Hash) ([]*TraceEntry, error) + GetTransactionError(ctx context.Context, hash common.Hash) (hexutil.Bytes, error) + GetTransactionBySenderAndNonce(ctx context.Context, addr common.Address, nonce uint64) (*common.Hash, error) + GetContractCreator(ctx context.Context, addr common.Address) (*ContractCreatorData, error) +} + +type OtterscanAPIImpl struct { + *BaseAPIUtils + + db kv.RoDB +} + +func NewOtterscanAPI(base *BaseAPIUtils, db kv.RoDB) *OtterscanAPIImpl { + return &OtterscanAPIImpl{ + BaseAPIUtils: base, + db: db, + } +} + +func (api *OtterscanAPIImpl) GetApiLevel() uint8 { + return API_LEVEL +} + +// TODO: dedup from eth_txs.go#GetTransactionByHash +func (api *OtterscanAPIImpl) getTransactionByHash(ctx context.Context, tx kv.Tx, hash common.Hash) (types.Transaction, *types.Block, common.Hash, uint64, uint64, error) { + // https://infura.io/docs/ethereum/json-rpc/eth-getTransactionByHash + blockNum, ok, err := api.txnLookup(ctx, tx, hash) + if err != nil { + return nil, nil, common.Hash{}, 0, 0, err + } + if !ok { + return nil, nil, common.Hash{}, 0, 0, nil + } + + block, err := api.blockByNumberWithSenders(tx, blockNum) + if err != nil { + return nil, nil, common.Hash{}, 0, 0, err + } + if block == nil { + return nil, nil, common.Hash{}, 0, 0, nil + } + blockHash := block.Hash() + var txnIndex uint64 + var txn types.Transaction + for i, transaction := range block.Transactions() { + if transaction.Hash() == hash { + txn = transaction + txnIndex = uint64(i) + break + } + } + + // Add GasPrice for the DynamicFeeTransaction + // var baseFee *big.Int + // if chainConfig.IsLondon(blockNum) && blockHash != (common.Hash{}) { + // baseFee = block.BaseFee() + // } + + // if no transaction was found then we return nil + if txn == nil { + return nil, nil, common.Hash{}, 0, 0, nil + } + return txn, block, blockHash, blockNum, txnIndex, nil +} + +func (api *OtterscanAPIImpl) runTracer(ctx context.Context, tx kv.Tx, hash common.Hash, tracer vm.Tracer) (*core.ExecutionResult, error) { + txn, block, blockHash, _, txIndex, err := api.getTransactionByHash(ctx, tx, hash) + if err != nil { + return nil, err + } + if txn == nil { + return nil, fmt.Errorf("transaction %#x not found", hash) + } + + chainConfig, err := api.chainConfig(tx) + if err != nil { + return nil, err + } + + getHeader := func(hash common.Hash, number uint64) *types.Header { + return rawdb.ReadHeader(tx, hash, number) + } + msg, blockCtx, txCtx, ibs, _, err := transactions.ComputeTxEnv(ctx, block, chainConfig, getHeader, ethash.NewFaker(), tx, blockHash, txIndex) + if err != nil { + return nil, err + } + + var vmConfig vm.Config + if tracer == nil { + vmConfig = vm.Config{} + } else { + vmConfig = vm.Config{Debug: true, Tracer: tracer} + } + vmenv := vm.NewEVM(blockCtx, txCtx, ibs, chainConfig, vmConfig) + + result, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas()), true, false /* gasBailout */) + if err != nil { + return nil, fmt.Errorf("tracing failed: %v", err) + } + + return result, nil +} + +func (api *OtterscanAPIImpl) GetInternalOperations(ctx context.Context, hash common.Hash) ([]*InternalOperation, error) { + tx, err := api.db.BeginRo(ctx) + if err != nil { + return nil, err + } + defer tx.Rollback() + + tracer := NewOperationsTracer(ctx) + if _, err := api.runTracer(ctx, tx, hash, tracer); err != nil { + return nil, err + } + + return tracer.Results, nil +} + +// Search transactions that touch a certain address. +// +// It searches back a certain block (excluding); the results are sorted descending. +// +// The pageSize indicates how many txs may be returned. If there are less txs than pageSize, +// they are just returned. But it may return a little more than pageSize if there are more txs +// than the necessary to fill pageSize in the last found block, i.e., let's say you want pageSize == 25, +// you already found 24 txs, the next block contains 4 matches, then this function will return 28 txs. +func (api *OtterscanAPIImpl) SearchTransactionsBefore(ctx context.Context, addr common.Address, blockNum uint64, pageSize uint16) (*TransactionsWithReceipts, error) { + dbtx, err := api.db.BeginRo(ctx) + if err != nil { + return nil, err + } + defer dbtx.Rollback() + + log.Info("got cursor") + + callFromCursor, err := dbtx.Cursor(kv.CallFromIndex) + if err != nil { + return nil, err + } + defer callFromCursor.Close() + log.Info("call from cur") + + callToCursor, err := dbtx.Cursor(kv.CallToIndex) + if err != nil { + return nil, err + } + defer callToCursor.Close() + log.Info("cur to call") + + chainConfig, err := api.chainConfig(dbtx) + if err != nil { + return nil, err + } + + isFirstPage := false + if blockNum == 0 { + isFirstPage = true + } else { + // Internal search code considers blockNum [including], so adjust the value + blockNum-- + } + + // Initialize search cursors at the first shard >= desired block number + callFromProvider := NewCallCursorBackwardBlockProvider(callFromCursor, addr, blockNum) + callToProvider := NewCallCursorBackwardBlockProvider(callToCursor, addr, blockNum) + callFromToProvider := newCallFromToBlockProvider(false, callFromProvider, callToProvider) + + txs := make([]*commands.RPCTransaction, 0, pageSize) + receipts := make([]map[string]interface{}, 0, pageSize) + + resultCount := uint16(0) + hasMore := true + for { + if resultCount >= pageSize || !hasMore { + break + } + var results []*TransactionsWithReceipts + results, hasMore, err = api.traceBlocks(ctx, addr, chainConfig, pageSize, resultCount, callFromToProvider) + if err != nil { + return nil, err + } + for _, r := range results { + if r == nil { + return nil, errors.New("internal error during search tracing") + } + + for i := len(r.Txs) - 1; i >= 0; i-- { + txs = append(txs, r.Txs[i]) + } + for i := len(r.Receipts) - 1; i >= 0; i-- { + receipts = append(receipts, r.Receipts[i]) + } + + resultCount += uint16(len(r.Txs)) + if resultCount >= pageSize { + break + } + } + } + + return &TransactionsWithReceipts{txs, receipts, isFirstPage, !hasMore}, nil +} + +// Search transactions that touch a certain address. +// +// It searches forward a certain block (excluding); the results are sorted descending. +// +// The pageSize indicates how many txs may be returned. If there are less txs than pageSize, +// they are just returned. But it may return a little more than pageSize if there are more txs +// than the necessary to fill pageSize in the last found block, i.e., let's say you want pageSize == 25, +// you already found 24 txs, the next block contains 4 matches, then this function will return 28 txs. +func (api *OtterscanAPIImpl) SearchTransactionsAfter(ctx context.Context, addr common.Address, blockNum uint64, pageSize uint16) (*TransactionsWithReceipts, error) { + dbtx, err := api.db.BeginRo(ctx) + if err != nil { + return nil, err + } + defer dbtx.Rollback() + + callFromCursor, err := dbtx.Cursor(kv.CallFromIndex) + if err != nil { + return nil, err + } + defer callFromCursor.Close() + + callToCursor, err := dbtx.Cursor(kv.CallToIndex) + if err != nil { + return nil, err + } + defer callToCursor.Close() + + chainConfig, err := api.chainConfig(dbtx) + if err != nil { + return nil, err + } + + isLastPage := false + if blockNum == 0 { + isLastPage = true + } else { + // Internal search code considers blockNum [including], so adjust the value + blockNum++ + } + + // Initialize search cursors at the first shard >= desired block number + callFromProvider := NewCallCursorForwardBlockProvider(callFromCursor, addr, blockNum) + callToProvider := NewCallCursorForwardBlockProvider(callToCursor, addr, blockNum) + callFromToProvider := newCallFromToBlockProvider(true, callFromProvider, callToProvider) + + txs := make([]*commands.RPCTransaction, 0, pageSize) + receipts := make([]map[string]interface{}, 0, pageSize) + + resultCount := uint16(0) + hasMore := true + for { + if resultCount >= pageSize || !hasMore { + break + } + + var results []*TransactionsWithReceipts + results, hasMore, err = api.traceBlocks(ctx, addr, chainConfig, pageSize, resultCount, callFromToProvider) + if err != nil { + return nil, err + } + + for _, r := range results { + if r == nil { + return nil, errors.New("internal error during search tracing") + } + + txs = append(txs, r.Txs...) + receipts = append(receipts, r.Receipts...) + + resultCount += uint16(len(r.Txs)) + if resultCount >= pageSize { + break + } + } + } + + // Reverse results + lentxs := len(txs) + for i := 0; i < lentxs/2; i++ { + txs[i], txs[lentxs-1-i] = txs[lentxs-1-i], txs[i] + receipts[i], receipts[lentxs-1-i] = receipts[lentxs-1-i], receipts[i] + } + return &TransactionsWithReceipts{txs, receipts, !hasMore, isLastPage}, nil +} + +func (api *OtterscanAPIImpl) traceBlocks(ctx context.Context, addr common.Address, chainConfig *params.ChainConfig, pageSize, resultCount uint16, callFromToProvider BlockProvider) ([]*TransactionsWithReceipts, bool, error) { + var wg sync.WaitGroup + + // Estimate the common case of user address having at most 1 interaction/block and + // trace N := remaining page matches as number of blocks to trace concurrently. + // TODO: this is not optimimal for big contract addresses; implement some better heuristics. + estBlocksToTrace := pageSize - resultCount + results := make([]*TransactionsWithReceipts, estBlocksToTrace) + totalBlocksTraced := 0 + hasMore := true + + for i := 0; i < int(estBlocksToTrace); i++ { + var nextBlock uint64 + var err error + nextBlock, hasMore, err = callFromToProvider() + if err != nil { + return nil, false, err + } + // TODO: nextBlock == 0 seems redundant with hasMore == false + if !hasMore && nextBlock == 0 { + break + } + + wg.Add(1) + totalBlocksTraced++ + go api.searchTraceBlock(ctx, &wg, addr, chainConfig, i, nextBlock, results) + } + wg.Wait() + + return results[:totalBlocksTraced], hasMore, nil +} + +func (api *OtterscanAPIImpl) delegateGetBlockByNumber(tx kv.Tx, b *types.Block, number rpc.BlockNumber, inclTx bool) (map[string]interface{}, error) { + td, err := rawdb.ReadTd(tx, b.Hash(), b.NumberU64()) + if err != nil { + return nil, err + } + response, err := ethapi.RPCMarshalBlock(b, inclTx, inclTx) + if !inclTx { + delete(response, "transactions") // workaround for https://github.com/ledgerwatch/erigon/issues/4989#issuecomment-1218415666 + } + response["totalDifficulty"] = (*hexutil.Big)(td) + response["transactionCount"] = b.Transactions().Len() + + if err == nil && number == rpc.PendingBlockNumber { + // Pending blocks need to nil out a few fields + for _, field := range []string{"hash", "nonce", "miner"} { + response[field] = nil + } + } + + // Explicitly drop unwanted fields + response["logsBloom"] = nil + return response, err +} + +// TODO: temporary workaround due to API breakage from watch_the_burn +type internalIssuance struct { + BlockReward string `json:"blockReward,omitempty"` + UncleReward string `json:"uncleReward,omitempty"` + Issuance string `json:"issuance,omitempty"` +} + +func (api *OtterscanAPIImpl) delegateIssuance(tx kv.Tx, block *types.Block, chainConfig *params.ChainConfig) (internalIssuance, error) { + if chainConfig.Ethash == nil { + // Clique for example has no issuance + return internalIssuance{}, nil + } + + minerReward, uncleRewards := ethash.AccumulateRewards(chainConfig, block.Header(), block.Uncles()) + issuance := minerReward + for _, r := range uncleRewards { + p := r // avoids warning? + issuance.Add(&issuance, &p) + } + + var ret internalIssuance + ret.BlockReward = hexutil.EncodeBig(minerReward.ToBig()) + ret.Issuance = hexutil.EncodeBig(issuance.ToBig()) + issuance.Sub(&issuance, &minerReward) + ret.UncleReward = hexutil.EncodeBig(issuance.ToBig()) + return ret, nil +} + +func (api *OtterscanAPIImpl) delegateBlockFees(ctx context.Context, tx kv.Tx, block *types.Block, senders []common.Address, chainConfig *params.ChainConfig) (uint64, error) { + receipts, err := api.getReceipts(ctx, tx, chainConfig, block, senders) + if err != nil { + return 0, fmt.Errorf("getReceipts error: %v", err) + } + + fees := uint64(0) + for _, receipt := range receipts { + txn := block.Transactions()[receipt.TransactionIndex] + effectiveGasPrice := uint64(0) + if !chainConfig.IsLondon(block.NumberU64()) { + effectiveGasPrice = txn.GetPrice().Uint64() + } else { + baseFee, _ := uint256.FromBig(block.BaseFee()) + gasPrice := new(big.Int).Add(block.BaseFee(), txn.GetEffectiveGasTip(baseFee).ToBig()) + effectiveGasPrice = gasPrice.Uint64() + } + fees += effectiveGasPrice * receipt.GasUsed + } + + return fees, nil +} + +func (api *OtterscanAPIImpl) getBlockWithSenders(ctx context.Context, number rpc.BlockNumber, tx kv.Tx) (*types.Block, []common.Address, error) { + if number == rpc.PendingBlockNumber { + return api.pendingBlock(), nil, nil + } + + n, hash, _, err := rpchelper.GetBlockNumber(rpc.BlockNumberOrHashWithNumber(number), tx, api.filters) + if err != nil { + return nil, nil, err + } + + block, senders, err := api._blockReader.BlockWithSenders(ctx, tx, hash, n) + return block, senders, err +} + +func (api *OtterscanAPIImpl) GetBlockTransactions(ctx context.Context, number rpc.BlockNumber, pageNumber uint8, pageSize uint8) (map[string]interface{}, error) { + tx, err := api.db.BeginRo(ctx) + if err != nil { + return nil, err + } + defer tx.Rollback() + + b, senders, err := api.getBlockWithSenders(ctx, number, tx) + if err != nil { + return nil, err + } + if b == nil { + return nil, nil + } + + chainConfig, err := api.chainConfig(tx) + if err != nil { + return nil, err + } + + getBlockRes, err := api.delegateGetBlockByNumber(tx, b, number, true) + if err != nil { + return nil, err + } + + // Receipts + receipts, err := api.getReceipts(ctx, tx, chainConfig, b, senders) + if err != nil { + return nil, fmt.Errorf("getReceipts error: %v", err) + } + result := make([]map[string]interface{}, 0, len(receipts)) + for _, receipt := range receipts { + txn := b.Transactions()[receipt.TransactionIndex] + marshalledRcpt := marshalReceipt(receipt, txn, chainConfig, b, txn.Hash(), true) + marshalledRcpt["logs"] = nil + marshalledRcpt["logsBloom"] = nil + result = append(result, marshalledRcpt) + } + + // Pruned block attrs + prunedBlock := map[string]interface{}{} + for _, k := range []string{"timestamp", "miner", "baseFeePerGas"} { + prunedBlock[k] = getBlockRes[k] + } + + // Crop tx input to 4bytes + var txs = getBlockRes["transactions"].([]interface{}) + for _, rawTx := range txs { + rpcTx := rawTx.(*ethapi.RPCTransaction) + if len(rpcTx.Input) >= 4 { + rpcTx.Input = rpcTx.Input[:4] + } + } + + // Crop page + pageEnd := b.Transactions().Len() - int(pageNumber)*int(pageSize) + pageStart := pageEnd - int(pageSize) + if pageEnd < 0 { + pageEnd = 0 + } + if pageStart < 0 { + pageStart = 0 + } + + response := map[string]interface{}{} + getBlockRes["transactions"] = getBlockRes["transactions"].([]interface{})[pageStart:pageEnd] + response["fullblock"] = getBlockRes + response["receipts"] = result[pageStart:pageEnd] + return response, nil +} diff --git a/cmd/rpcdaemon/commands/otterscan_block_details.go b/cmd/rpcdaemon/commands/otterscan_block_details.go new file mode 100644 index 0000000..5775081 --- /dev/null +++ b/cmd/rpcdaemon/commands/otterscan_block_details.go @@ -0,0 +1,97 @@ +package commands + +import ( + "context" + "fmt" + + "github.com/ledgerwatch/erigon/common" + "github.com/ledgerwatch/erigon/common/hexutil" + "github.com/ledgerwatch/erigon/core/rawdb" + "github.com/ledgerwatch/erigon/rpc" +) + +func (api *OtterscanAPIImpl) GetBlockDetails(ctx context.Context, number rpc.BlockNumber) (map[string]interface{}, error) { + tx, err := api.db.BeginRo(ctx) + if err != nil { + return nil, err + } + defer tx.Rollback() + + b, senders, err := api.getBlockWithSenders(ctx, number, tx) + if err != nil { + return nil, err + } + if b == nil { + return nil, nil + } + + chainConfig, err := api.chainConfig(tx) + if err != nil { + return nil, err + } + + getBlockRes, err := api.delegateGetBlockByNumber(tx, b, number, false) + if err != nil { + return nil, err + } + getIssuanceRes, err := api.delegateIssuance(tx, b, chainConfig) + if err != nil { + return nil, err + } + feesRes, err := api.delegateBlockFees(ctx, tx, b, senders, chainConfig) + if err != nil { + return nil, err + } + + response := map[string]interface{}{} + response["block"] = getBlockRes + response["issuance"] = getIssuanceRes + response["totalFees"] = hexutil.Uint64(feesRes) + return response, nil +} + +// TODO: remove duplication with GetBlockDetails +func (api *OtterscanAPIImpl) GetBlockDetailsByHash(ctx context.Context, hash common.Hash) (map[string]interface{}, error) { + tx, err := api.db.BeginRo(ctx) + if err != nil { + return nil, err + } + defer tx.Rollback() + + // b, senders, err := rawdb.ReadBlockByHashWithSenders(tx, hash) + blockNumber := rawdb.ReadHeaderNumber(tx, hash) + if blockNumber == nil { + return nil, fmt.Errorf("couldn't find block number for hash %v", hash.Bytes()) + } + b, senders, err := api._blockReader.BlockWithSenders(ctx, tx, hash, *blockNumber) + if err != nil { + return nil, err + } + if b == nil { + return nil, nil + } + + chainConfig, err := api.chainConfig(tx) + if err != nil { + return nil, err + } + + getBlockRes, err := api.delegateGetBlockByNumber(tx, b, rpc.BlockNumber(b.Number().Int64()), false) + if err != nil { + return nil, err + } + getIssuanceRes, err := api.delegateIssuance(tx, b, chainConfig) + if err != nil { + return nil, err + } + feesRes, err := api.delegateBlockFees(ctx, tx, b, senders, chainConfig) + if err != nil { + return nil, err + } + + response := map[string]interface{}{} + response["block"] = getBlockRes + response["issuance"] = getIssuanceRes + response["totalFees"] = hexutil.Uint64(feesRes) + return response, nil +} diff --git a/cmd/rpcdaemon/commands/otterscan_contract_creator.go b/cmd/rpcdaemon/commands/otterscan_contract_creator.go new file mode 100644 index 0000000..b3e8630 --- /dev/null +++ b/cmd/rpcdaemon/commands/otterscan_contract_creator.go @@ -0,0 +1,245 @@ +package commands + +import ( + "bytes" + "context" + "fmt" + "sort" + + "github.com/RoaringBitmap/roaring/roaring64" + "github.com/ledgerwatch/erigon-lib/kv" + "github.com/ledgerwatch/erigon/common" + "github.com/ledgerwatch/erigon/common/changeset" + "github.com/ledgerwatch/erigon/consensus/ethash" + "github.com/ledgerwatch/erigon/core" + "github.com/ledgerwatch/erigon/core/state" + "github.com/ledgerwatch/erigon/core/types" + "github.com/ledgerwatch/erigon/core/types/accounts" + "github.com/ledgerwatch/erigon/core/vm" + "github.com/ledgerwatch/erigon/params" + "github.com/ledgerwatch/erigon/turbo/shards" + "github.com/ledgerwatch/log/v3" +) + +type ContractCreatorData struct { + Tx common.Hash `json:"hash"` + Creator common.Address `json:"creator"` +} + +func (api *OtterscanAPIImpl) GetContractCreator(ctx context.Context, addr common.Address) (*ContractCreatorData, error) { + tx, err := api.db.BeginRo(ctx) + if err != nil { + return nil, err + } + defer tx.Rollback() + + reader := state.NewPlainStateReader(tx) + plainStateAcc, err := reader.ReadAccountData(addr) + if err != nil { + return nil, err + } + + // No state == non existent + if plainStateAcc == nil { + return nil, nil + } + + // EOA? + if plainStateAcc.IsEmptyCodeHash() { + return nil, nil + } + + // Contract; search for creation tx; navigate forward on AccountsHistory/ChangeSets + // + // We search shards in forward order on purpose because popular contracts may have + // dozens of states changes due to ETH deposits/withdraw after contract creation, + // so it is optimal to search from the beginning even if the contract has multiple + // incarnations. + accHistory, err := tx.Cursor(kv.AccountsHistory) + if err != nil { + return nil, err + } + defer accHistory.Close() + + accCS, err := tx.CursorDupSort(kv.AccountChangeSet) + if err != nil { + return nil, err + } + defer accCS.Close() + + // Locate shard that contains the block where incarnation changed + acs := changeset.Mapper[kv.AccountChangeSet] + k, v, err := accHistory.Seek(acs.IndexChunkKey(addr.Bytes(), 0)) + if err != nil { + return nil, err + } + if !bytes.HasPrefix(k, addr.Bytes()) { + log.Error("Couldn't find any shard for account history", "addr", addr) + return nil, fmt.Errorf("could't find any shard for account history addr=%v", addr) + } + + var acc accounts.Account + bm := roaring64.NewBitmap() + prevShardMaxBl := uint64(0) + for { + _, err := bm.ReadFrom(bytes.NewReader(v)) + if err != nil { + return nil, err + } + + // Shortcut precheck + st, err := acs.Find(accCS, bm.Maximum(), addr.Bytes()) + if err != nil { + return nil, err + } + if st == nil { + log.Error("Unexpected error, couldn't find changeset", "block", bm.Maximum(), "addr", addr) + return nil, fmt.Errorf("unexpected error, couldn't find changeset block=%v addr=%v", bm.Maximum(), addr) + } + + // Found the shard where the incarnation change happens; ignore all + // next shards + if err := acc.DecodeForStorage(st); err != nil { + return nil, err + } + if acc.Incarnation >= plainStateAcc.Incarnation { + break + } + prevShardMaxBl = bm.Maximum() + + k, v, err = accHistory.Next() + if err != nil { + return nil, err + } + + // No more shards; it means the max bl from previous shard + // contains the incarnation change + if !bytes.HasPrefix(k, addr.Bytes()) { + break + } + } + + // Binary search block number inside shard; get first block where desired + // incarnation appears + blocks := bm.ToArray() + var searchErr error + r := sort.Search(len(blocks), func(i int) bool { + bl := blocks[i] + st, err := acs.Find(accCS, bl, addr.Bytes()) + if err != nil { + searchErr = err + return false + } + if st == nil { + log.Error("Unexpected error, couldn't find changeset", "block", bl, "addr", addr) + return false + } + + if err := acc.DecodeForStorage(st); err != nil { + searchErr = err + return false + } + if acc.Incarnation < plainStateAcc.Incarnation { + return false + } + return true + }) + + if searchErr != nil { + return nil, searchErr + } + + // The sort.Search function finds the first block where the incarnation has + // changed to the desired one, so we get the previous block from the bitmap; + // however if the found block is already the first one from the bitmap, it means + // the block we want is the max block from the previous shard. + blockFound := prevShardMaxBl + if r > 0 { + blockFound = blocks[r-1] + } + + // Trace block, find tx and contract creator + chainConfig, err := api.chainConfig(tx) + if err != nil { + return nil, err + } + tracer := NewCreateTracer(ctx, addr) + if err := api.deployerFinder(tx, ctx, blockFound, chainConfig, tracer); err != nil { + return nil, err + } + + return &ContractCreatorData{ + Tx: tracer.Tx.Hash(), + Creator: tracer.Creator, + }, nil +} + +func (api *OtterscanAPIImpl) deployerFinder(dbtx kv.Tx, ctx context.Context, blockNum uint64, chainConfig *params.ChainConfig, tracer GenericTracer) error { + block, err := api.blockByNumberWithSenders(dbtx, blockNum) + if err != nil { + return err + } + if block == nil { + return nil + } + + reader := state.NewPlainState(dbtx, blockNum) + stateCache := shards.NewStateCache(32, 0 /* no limit */) + cachedReader := state.NewCachedReader(reader, stateCache) + noop := state.NewNoopWriter() + cachedWriter := state.NewCachedWriter(noop, stateCache) + + ibs := state.New(cachedReader) + signer := types.MakeSigner(chainConfig, blockNum) + + getHeader := func(hash common.Hash, number uint64) *types.Header { + h, e := api._blockReader.Header(ctx, dbtx, hash, number) + if e != nil { + log.Error("getHeader error", "number", number, "hash", hash, "err", e) + } + return h + } + engine := ethash.NewFaker() + + header := block.Header() + rules := chainConfig.Rules(block.NumberU64()) + // we can filter away anything that does not include 0xf0, 0xf5, or 0x38, aka create, create2 or codesize opcodes + // while this will result in false positives, it should reduce the time a lot. + // it can be improved in the future with smarter algorithms (ala, looking for + deployers := map[common.Address]struct{}{} + for _, tx := range block.Transactions() { + dat := tx.GetData() + for _, v := range dat { + if sender, ok := tx.GetSender(); ok { + if v == 0xf0 || v == 0xf5 { + deployers[sender] = struct{}{} + } + } + } + } + for idx, tx := range block.Transactions() { + if sender, ok := tx.GetSender(); ok { + if _, ok := deployers[sender]; !ok { + continue + } + } + ibs.Prepare(tx.Hash(), block.Hash(), idx) + + msg, _ := tx.AsMessage(*signer, header.BaseFee, rules) + + BlockContext := core.NewEVMBlockContext(header, core.GetHashFn(header, getHeader), engine, nil) + TxContext := core.NewEVMTxContext(msg) + + vmenv := vm.NewEVM(BlockContext, TxContext, ibs, chainConfig, vm.Config{Debug: true, Tracer: tracer}) + if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.GetGas()), true /* refunds */, false /* gasBailout */); err != nil { + return err + } + _ = ibs.FinalizeTx(vmenv.ChainConfig().Rules(block.NumberU64()), cachedWriter) + + if tracer.Found() { + tracer.SetTransaction(tx) + return nil + } + } + return nil +} diff --git a/cmd/rpcdaemon/commands/otterscan_default_tracer.go b/cmd/rpcdaemon/commands/otterscan_default_tracer.go new file mode 100644 index 0000000..fa02318 --- /dev/null +++ b/cmd/rpcdaemon/commands/otterscan_default_tracer.go @@ -0,0 +1,38 @@ +package commands + +import ( + "math/big" + "time" + + "github.com/ledgerwatch/erigon/common" + "github.com/ledgerwatch/erigon/core/vm" +) + +// Helper implementation of vm.Tracer; since the interface is big and most +// custom tracers implement just a few of the methods, this is a base struct +// to avoid lots of empty boilerplate code +type DefaultTracer struct { +} + +func (t *DefaultTracer) CaptureStart(env *vm.EVM, depth int, from common.Address, to common.Address, precompile bool, create bool, calltype vm.CallType, input []byte, gas uint64, value *big.Int, code []byte) { +} + +func (t *DefaultTracer) CaptureState(env *vm.EVM, pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) { +} + +func (t *DefaultTracer) CaptureFault(env *vm.EVM, pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) { +} + +func (t *DefaultTracer) CaptureEnd(depth int, output []byte, startGas, endGas uint64, d time.Duration, err error) { +} + +func (t *DefaultTracer) CaptureSelfDestruct(from common.Address, to common.Address, value *big.Int) { +} + +func (t *DefaultTracer) CaptureAccountRead(account common.Address) error { + return nil +} + +func (t *DefaultTracer) CaptureAccountWrite(account common.Address) error { + return nil +} diff --git a/cmd/rpcdaemon/commands/otterscan_generic_tracer.go b/cmd/rpcdaemon/commands/otterscan_generic_tracer.go new file mode 100644 index 0000000..fcff9a9 --- /dev/null +++ b/cmd/rpcdaemon/commands/otterscan_generic_tracer.go @@ -0,0 +1,78 @@ +package commands + +import ( + "context" + + "github.com/ledgerwatch/erigon-lib/kv" + "github.com/ledgerwatch/erigon/common" + "github.com/ledgerwatch/erigon/consensus/ethash" + "github.com/ledgerwatch/erigon/core" + "github.com/ledgerwatch/erigon/core/state" + "github.com/ledgerwatch/erigon/core/types" + "github.com/ledgerwatch/erigon/core/vm" + "github.com/ledgerwatch/erigon/params" + "github.com/ledgerwatch/erigon/turbo/shards" + "github.com/ledgerwatch/log/v3" +) + +type GenericTracer interface { + vm.Tracer + SetTransaction(tx types.Transaction) + Found() bool +} + +func (api *OtterscanAPIImpl) genericTracer(dbtx kv.Tx, ctx context.Context, blockNum uint64, chainConfig *params.ChainConfig, tracer GenericTracer) error { + block, err := api.blockByNumberWithSenders(dbtx, blockNum) + if err != nil { + return err + } + log.Info("got block with senders") + if block == nil { + return nil + } + + reader := state.NewPlainState(dbtx, blockNum) + stateCache := shards.NewStateCache(32, 0 /* no limit */) + cachedReader := state.NewCachedReader(reader, stateCache) + noop := state.NewNoopWriter() + cachedWriter := state.NewCachedWriter(noop, stateCache) + + ibs := state.New(cachedReader) + signer := types.MakeSigner(chainConfig, blockNum) + log.Info("created states") + + getHeader := func(hash common.Hash, number uint64) *types.Header { + h, e := api._blockReader.Header(ctx, dbtx, hash, number) + if e != nil { + log.Error("getHeader error", "number", number, "hash", hash, "err", e) + } + return h + } + engine := ethash.NewFaker() + + header := block.Header() + rules := chainConfig.Rules(block.NumberU64()) + log.Info("got transactions", "amt", len(block.Transactions())) + for idx, tx := range block.Transactions() { + log.Info("processing txn", "idx", idx) + ibs.Prepare(tx.Hash(), block.Hash(), idx) + + msg, _ := tx.AsMessage(*signer, header.BaseFee, rules) + + BlockContext := core.NewEVMBlockContext(header, core.GetHashFn(header, getHeader), engine, nil) + TxContext := core.NewEVMTxContext(msg) + + vmenv := vm.NewEVM(BlockContext, TxContext, ibs, chainConfig, vm.Config{Debug: true, Tracer: tracer}) + if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.GetGas()), true /* refunds */, false /* gasBailout */); err != nil { + return err + } + _ = ibs.FinalizeTx(vmenv.ChainConfig().Rules(block.NumberU64()), cachedWriter) + + if tracer.Found() { + tracer.SetTransaction(tx) + return nil + } + } + + return nil +} diff --git a/cmd/rpcdaemon/commands/otterscan_has_code.go b/cmd/rpcdaemon/commands/otterscan_has_code.go new file mode 100644 index 0000000..d5b267c --- /dev/null +++ b/cmd/rpcdaemon/commands/otterscan_has_code.go @@ -0,0 +1,31 @@ +package commands + +import ( + "context" + "fmt" + + "github.com/ledgerwatch/erigon/common" + "github.com/ledgerwatch/erigon/rpc" + "github.com/ledgerwatch/erigon/turbo/adapter" + "github.com/ledgerwatch/erigon/turbo/rpchelper" +) + +func (api *OtterscanAPIImpl) HasCode(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (bool, error) { + tx, err := api.db.BeginRo(ctx) + if err != nil { + return false, fmt.Errorf("hasCode cannot open tx: %w", err) + } + defer tx.Rollback() + + blockNumber, _, _, err := rpchelper.GetBlockNumber(blockNrOrHash, tx, api.filters) + if err != nil { + return false, err + } + + reader := adapter.NewStateReader(tx, blockNumber) + acc, err := reader.ReadAccountData(address) + if acc == nil || err != nil { + return false, err + } + return !acc.IsEmptyCodeHash(), nil +} diff --git a/cmd/rpcdaemon/commands/otterscan_search_backward.go b/cmd/rpcdaemon/commands/otterscan_search_backward.go new file mode 100644 index 0000000..4d8193e --- /dev/null +++ b/cmd/rpcdaemon/commands/otterscan_search_backward.go @@ -0,0 +1,128 @@ +package commands + +import ( + "bytes" + + "github.com/RoaringBitmap/roaring/roaring64" + "github.com/ledgerwatch/erigon-lib/kv" + "github.com/ledgerwatch/erigon/common" +) + +// Given a ChunkLocator, moves back over the chunks and inside each chunk, moves +// backwards over the block numbers. +func NewBackwardBlockProvider(chunkLocator ChunkLocator, maxBlock uint64) BlockProvider { + // block == 0 means no max + if maxBlock == 0 { + maxBlock = MaxBlockNum + } + var iter roaring64.IntIterable64 + var chunkProvider ChunkProvider + isFirst := true + finished := false + + return func() (uint64, bool, error) { + if finished { + return 0, false, nil + } + + if isFirst { + isFirst = false + + // Try to get first chunk + var ok bool + var err error + chunkProvider, ok, err = chunkLocator(maxBlock) + if err != nil { + finished = true + return 0, false, err + } + if !ok { + finished = true + return 0, false, nil + } + if chunkProvider == nil { + finished = true + return 0, false, nil + } + + // Has at least the first chunk; initialize the iterator + chunk, ok, err := chunkProvider() + if err != nil { + finished = true + return 0, false, err + } + if !ok { + finished = true + return 0, false, nil + } + + bm := roaring64.NewBitmap() + if _, err := bm.ReadFrom(bytes.NewReader(chunk)); err != nil { + finished = true + return 0, false, err + } + + // It can happen that on the first chunk we'll get a chunk that contains + // the last block <= maxBlock in the middle of the chunk/bitmap, so we + // remove all blocks after it (since there is no AdvanceIfNeeded() in + // IntIterable64) + if maxBlock != MaxBlockNum { + bm.RemoveRange(maxBlock+1, MaxBlockNum) + } + iter = bm.ReverseIterator() + + // This means it is the last chunk and the min block is > the last one + if !iter.HasNext() { + chunk, ok, err := chunkProvider() + if err != nil { + finished = true + return 0, false, err + } + if !ok { + finished = true + return 0, false, nil + } + + bm := roaring64.NewBitmap() + if _, err := bm.ReadFrom(bytes.NewReader(chunk)); err != nil { + finished = true + return 0, false, err + } + + iter = bm.ReverseIterator() + } + } + + nextBlock := iter.Next() + hasNext := iter.HasNext() + if !hasNext { + iter = nil + + // Check if there is another chunk to get blocks from + chunk, ok, err := chunkProvider() + if err != nil { + return 0, false, err + } + if !ok { + finished = true + return nextBlock, false, nil + } + + hasNext = true + + bm := roaring64.NewBitmap() + if _, err := bm.ReadFrom(bytes.NewReader(chunk)); err != nil { + finished = true + return 0, false, err + } + iter = bm.ReverseIterator() + } + + return nextBlock, hasNext, nil + } +} + +func NewCallCursorBackwardBlockProvider(cursor kv.Cursor, addr common.Address, maxBlock uint64) BlockProvider { + chunkLocator := newCallChunkLocator(cursor, addr, false) + return NewBackwardBlockProvider(chunkLocator, maxBlock) +} diff --git a/cmd/rpcdaemon/commands/otterscan_search_backward_multi_test.go b/cmd/rpcdaemon/commands/otterscan_search_backward_multi_test.go new file mode 100644 index 0000000..4aabcda --- /dev/null +++ b/cmd/rpcdaemon/commands/otterscan_search_backward_multi_test.go @@ -0,0 +1,109 @@ +package commands + +import ( + "testing" +) + +func TestFromToBackwardBlockProviderWith1Chunk(t *testing.T) { + // Mocks 1 chunk + chunk1 := createBitmap(t, []uint64{1000, 1005, 1010}) + + chunkLocator := newMockBackwardChunkLocator([][]byte{chunk1}) + fromBlockProvider := NewBackwardBlockProvider(chunkLocator, 0) + toBlockProvider := NewBackwardBlockProvider(newMockBackwardChunkLocator([][]byte{}), 0) + blockProvider := newCallFromToBlockProvider(true, fromBlockProvider, toBlockProvider) + + checkNext(t, blockProvider, 1010, true) + checkNext(t, blockProvider, 1005, true) + checkNext(t, blockProvider, 1000, false) +} + +func TestFromToBackwardBlockProviderWith1ChunkMiddleBlock(t *testing.T) { + // Mocks 1 chunk + chunk1 := createBitmap(t, []uint64{1000, 1005, 1010}) + + chunkLocator := newMockBackwardChunkLocator([][]byte{chunk1}) + fromBlockProvider := NewBackwardBlockProvider(chunkLocator, 1005) + toBlockProvider := NewBackwardBlockProvider(newMockBackwardChunkLocator([][]byte{}), 0) + blockProvider := newCallFromToBlockProvider(true, fromBlockProvider, toBlockProvider) + + checkNext(t, blockProvider, 1005, true) + checkNext(t, blockProvider, 1000, false) +} + +func TestFromToBackwardBlockProviderWith1ChunkNotExactBlock(t *testing.T) { + // Mocks 1 chunk + chunk1 := createBitmap(t, []uint64{1000, 1005, 1010}) + + chunkLocator := newMockBackwardChunkLocator([][]byte{chunk1}) + fromBlockProvider := NewBackwardBlockProvider(chunkLocator, 1003) + toBlockProvider := NewBackwardBlockProvider(newMockBackwardChunkLocator([][]byte{}), 0) + blockProvider := newCallFromToBlockProvider(true, fromBlockProvider, toBlockProvider) + + checkNext(t, blockProvider, 1000, false) +} + +func TestFromToBackwardBlockProviderWith1ChunkLastBlock(t *testing.T) { + // Mocks 1 chunk + chunk1 := createBitmap(t, []uint64{1000, 1005, 1010}) + + chunkLocator := newMockBackwardChunkLocator([][]byte{chunk1}) + fromBlockProvider := NewBackwardBlockProvider(chunkLocator, 1000) + toBlockProvider := NewBackwardBlockProvider(newMockBackwardChunkLocator([][]byte{}), 0) + blockProvider := newCallFromToBlockProvider(true, fromBlockProvider, toBlockProvider) + + checkNext(t, blockProvider, 1000, false) +} + +func TestFromToBackwardBlockProviderWith1ChunkBlockNotFound(t *testing.T) { + // Mocks 1 chunk + chunk1 := createBitmap(t, []uint64{1000, 1005, 1010}) + + chunkLocator := newMockBackwardChunkLocator([][]byte{chunk1}) + fromBlockProvider := NewBackwardBlockProvider(chunkLocator, 900) + toBlockProvider := NewBackwardBlockProvider(newMockBackwardChunkLocator([][]byte{}), 0) + blockProvider := newCallFromToBlockProvider(true, fromBlockProvider, toBlockProvider) + + checkNext(t, blockProvider, 0, false) +} + +func TestFromToBackwardBlockProviderWithNoChunks(t *testing.T) { + chunkLocator := newMockBackwardChunkLocator([][]byte{}) + fromBlockProvider := NewBackwardBlockProvider(chunkLocator, 0) + toBlockProvider := NewBackwardBlockProvider(newMockBackwardChunkLocator([][]byte{}), 0) + blockProvider := newCallFromToBlockProvider(true, fromBlockProvider, toBlockProvider) + + checkNext(t, blockProvider, 0, false) +} + +func TestFromToBackwardBlockProviderWithMultipleChunks(t *testing.T) { + // Mocks 2 chunks + chunk1 := createBitmap(t, []uint64{1000, 1005, 1010}) + chunk2 := createBitmap(t, []uint64{1501, 1600}) + + chunkLocator := newMockBackwardChunkLocator([][]byte{chunk1, chunk2}) + fromBlockProvider := NewBackwardBlockProvider(chunkLocator, 0) + toBlockProvider := NewBackwardBlockProvider(newMockBackwardChunkLocator([][]byte{}), 0) + blockProvider := newCallFromToBlockProvider(true, fromBlockProvider, toBlockProvider) + + checkNext(t, blockProvider, 1600, true) + checkNext(t, blockProvider, 1501, true) + checkNext(t, blockProvider, 1010, true) + checkNext(t, blockProvider, 1005, true) + checkNext(t, blockProvider, 1000, false) +} + +func TestFromToBackwardBlockProviderWithMultipleChunksBlockBetweenChunks(t *testing.T) { + // Mocks 2 chunks + chunk1 := createBitmap(t, []uint64{1000, 1005, 1010}) + chunk2 := createBitmap(t, []uint64{1501, 1600}) + + chunkLocator := newMockBackwardChunkLocator([][]byte{chunk1, chunk2}) + fromBlockProvider := NewBackwardBlockProvider(chunkLocator, 1500) + toBlockProvider := NewBackwardBlockProvider(newMockBackwardChunkLocator([][]byte{}), 0) + blockProvider := newCallFromToBlockProvider(true, fromBlockProvider, toBlockProvider) + + checkNext(t, blockProvider, 1010, true) + checkNext(t, blockProvider, 1005, true) + checkNext(t, blockProvider, 1000, false) +} diff --git a/cmd/rpcdaemon/commands/otterscan_search_backward_test.go b/cmd/rpcdaemon/commands/otterscan_search_backward_test.go new file mode 100644 index 0000000..9f85b7e --- /dev/null +++ b/cmd/rpcdaemon/commands/otterscan_search_backward_test.go @@ -0,0 +1,143 @@ +package commands + +import ( + "bytes" + "testing" + + "github.com/RoaringBitmap/roaring/roaring64" +) + +func newMockBackwardChunkLocator(chunks [][]byte) ChunkLocator { + return func(block uint64) (ChunkProvider, bool, error) { + for i, v := range chunks { + bm := roaring64.NewBitmap() + if _, err := bm.ReadFrom(bytes.NewReader(v)); err != nil { + return nil, false, err + } + if block > bm.Maximum() { + continue + } + + return newMockBackwardChunkProvider(chunks[:i+1]), true, nil + } + + // Not found; return the last to simulate the behavior of returning + // everything up to the 0xffff... chunk + if len(chunks) > 0 { + return newMockBackwardChunkProvider(chunks), true, nil + } + + return nil, true, nil + } +} + +func newMockBackwardChunkProvider(chunks [][]byte) ChunkProvider { + i := len(chunks) - 1 + return func() ([]byte, bool, error) { + if i < 0 { + return nil, false, nil + } + + chunk := chunks[i] + i-- + return chunk, true, nil + } +} +func TestBackwardBlockProviderWith1Chunk(t *testing.T) { + // Mocks 1 chunk + chunk1 := createBitmap(t, []uint64{1000, 1005, 1010}) + + chunkLocator := newMockBackwardChunkLocator([][]byte{chunk1}) + blockProvider := NewBackwardBlockProvider(chunkLocator, 0) + + checkNext(t, blockProvider, 1010, true) + checkNext(t, blockProvider, 1005, true) + checkNext(t, blockProvider, 1000, false) +} + +func TestBackwardBlockProviderWith1ChunkMiddleBlock(t *testing.T) { + // Mocks 1 chunk + chunk1 := createBitmap(t, []uint64{1000, 1005, 1010}) + + chunkLocator := newMockBackwardChunkLocator([][]byte{chunk1}) + blockProvider := NewBackwardBlockProvider(chunkLocator, 1005) + + checkNext(t, blockProvider, 1005, true) + checkNext(t, blockProvider, 1000, false) +} + +func TestBackwardBlockProviderWith1ChunkNotExactBlock(t *testing.T) { + // Mocks 1 chunk + chunk1 := createBitmap(t, []uint64{1000, 1005, 1010}) + + chunkLocator := newMockBackwardChunkLocator([][]byte{chunk1}) + blockProvider := NewBackwardBlockProvider(chunkLocator, 1003) + + checkNext(t, blockProvider, 1000, false) +} + +func TestBackwardBlockProviderWith1ChunkLastBlock(t *testing.T) { + // Mocks 1 chunk + chunk1 := createBitmap(t, []uint64{1000, 1005, 1010}) + + chunkLocator := newMockBackwardChunkLocator([][]byte{chunk1}) + blockProvider := NewBackwardBlockProvider(chunkLocator, 1000) + + checkNext(t, blockProvider, 1000, false) +} + +func TestBackwardBlockProviderWith1ChunkBlockNotFound(t *testing.T) { + // Mocks 1 chunk + chunk1 := createBitmap(t, []uint64{1000, 1005, 1010}) + + chunkLocator := newMockBackwardChunkLocator([][]byte{chunk1}) + blockProvider := NewBackwardBlockProvider(chunkLocator, 900) + + checkNext(t, blockProvider, 0, false) +} + +func TestBackwardBlockProviderWithNoChunks(t *testing.T) { + chunkLocator := newMockBackwardChunkLocator([][]byte{}) + blockProvider := NewBackwardBlockProvider(chunkLocator, 0) + + checkNext(t, blockProvider, 0, false) +} + +func TestBackwardBlockProviderWithMultipleChunks(t *testing.T) { + // Mocks 2 chunks + chunk1 := createBitmap(t, []uint64{1000, 1005, 1010}) + chunk2 := createBitmap(t, []uint64{1501, 1600}) + + chunkLocator := newMockBackwardChunkLocator([][]byte{chunk1, chunk2}) + blockProvider := NewBackwardBlockProvider(chunkLocator, 0) + + checkNext(t, blockProvider, 1600, true) + checkNext(t, blockProvider, 1501, true) + checkNext(t, blockProvider, 1010, true) + checkNext(t, blockProvider, 1005, true) + checkNext(t, blockProvider, 1000, false) +} + +func TestBackwardBlockProviderWithMultipleChunksBlockBetweenChunks(t *testing.T) { + // Mocks 2 chunks + chunk1 := createBitmap(t, []uint64{1000, 1005, 1010}) + chunk2 := createBitmap(t, []uint64{1501, 1600}) + + chunkLocator := newMockBackwardChunkLocator([][]byte{chunk1, chunk2}) + blockProvider := NewBackwardBlockProvider(chunkLocator, 1500) + + checkNext(t, blockProvider, 1010, true) + checkNext(t, blockProvider, 1005, true) + checkNext(t, blockProvider, 1000, false) +} + +func TestBackwardBlockProviderWithMultipleChunksBlockNotFound(t *testing.T) { + // Mocks 2 chunks + chunk1 := createBitmap(t, []uint64{1000, 1005, 1010}) + chunk2 := createBitmap(t, []uint64{1501, 1600}) + + chunkLocator := newMockBackwardChunkLocator([][]byte{chunk1, chunk2}) + blockProvider := NewBackwardBlockProvider(chunkLocator, 900) + + checkNext(t, blockProvider, 0, false) +} diff --git a/cmd/rpcdaemon/commands/otterscan_search_forward.go b/cmd/rpcdaemon/commands/otterscan_search_forward.go new file mode 100644 index 0000000..f9774c6 --- /dev/null +++ b/cmd/rpcdaemon/commands/otterscan_search_forward.go @@ -0,0 +1,107 @@ +package commands + +import ( + "bytes" + + "github.com/RoaringBitmap/roaring/roaring64" + "github.com/ledgerwatch/erigon-lib/kv" + "github.com/ledgerwatch/erigon/common" +) + +// Given a ChunkLocator, moves forward over the chunks and inside each chunk, moves +// forward over the block numbers. +func NewForwardBlockProvider(chunkLocator ChunkLocator, minBlock uint64) BlockProvider { + var iter roaring64.IntPeekable64 + var chunkProvider ChunkProvider + isFirst := true + finished := false + + return func() (uint64, bool, error) { + if finished { + return 0, false, nil + } + + if isFirst { + isFirst = false + + // Try to get first chunk + var ok bool + var err error + chunkProvider, ok, err = chunkLocator(minBlock) + if err != nil { + finished = true + return 0, false, err + } + if !ok { + finished = true + return 0, false, nil + } + if chunkProvider == nil { + finished = true + return 0, false, nil + } + + // Has at least the first chunk; initialize the iterator + chunk, ok, err := chunkProvider() + if err != nil { + finished = true + return 0, false, err + } + if !ok { + finished = true + return 0, false, nil + } + + bm := roaring64.NewBitmap() + if _, err := bm.ReadFrom(bytes.NewReader(chunk)); err != nil { + finished = true + return 0, false, err + } + iter = bm.Iterator() + + // It can happen that on the first chunk we'll get a chunk that contains + // the first block >= minBlock in the middle of the chunk/bitmap, so we + // skip all previous blocks before it. + iter.AdvanceIfNeeded(minBlock) + + // This means it is the last chunk and the min block is > the last one + if !iter.HasNext() { + finished = true + return 0, false, nil + } + } + + nextBlock := iter.Next() + hasNext := iter.HasNext() + if !hasNext { + iter = nil + + // Check if there is another chunk to get blocks from + chunk, ok, err := chunkProvider() + if err != nil { + finished = true + return 0, false, err + } + if !ok { + finished = true + return nextBlock, false, nil + } + + hasNext = true + + bm := roaring64.NewBitmap() + if _, err := bm.ReadFrom(bytes.NewReader(chunk)); err != nil { + finished = true + return 0, false, err + } + iter = bm.Iterator() + } + + return nextBlock, hasNext, nil + } +} + +func NewCallCursorForwardBlockProvider(cursor kv.Cursor, addr common.Address, minBlock uint64) BlockProvider { + chunkLocator := newCallChunkLocator(cursor, addr, true) + return NewForwardBlockProvider(chunkLocator, minBlock) +} diff --git a/cmd/rpcdaemon/commands/otterscan_search_forward_multi_test.go b/cmd/rpcdaemon/commands/otterscan_search_forward_multi_test.go new file mode 100644 index 0000000..cc1112e --- /dev/null +++ b/cmd/rpcdaemon/commands/otterscan_search_forward_multi_test.go @@ -0,0 +1,108 @@ +package commands + +import ( + "testing" +) + +func TestFromToForwardBlockProviderWith1Chunk(t *testing.T) { + // Mocks 1 chunk + chunk1 := createBitmap(t, []uint64{1000, 1005, 1010}) + + chunkLocator := newMockForwardChunkLocator([][]byte{chunk1}) + fromBlockProvider := NewForwardBlockProvider(chunkLocator, 0) + toBlockProvider := NewForwardBlockProvider(newMockForwardChunkLocator([][]byte{}), 0) + blockProvider := newCallFromToBlockProvider(false, fromBlockProvider, toBlockProvider) + + checkNext(t, blockProvider, 1000, true) + checkNext(t, blockProvider, 1005, true) + checkNext(t, blockProvider, 1010, false) +} + +func TestFromToForwardBlockProviderWith1ChunkMiddleBlock(t *testing.T) { + // Mocks 1 chunk + chunk1 := createBitmap(t, []uint64{1000, 1005, 1010}) + + chunkLocator := newMockForwardChunkLocator([][]byte{chunk1}) + fromBlockProvider := NewForwardBlockProvider(chunkLocator, 1005) + toBlockProvider := NewForwardBlockProvider(newMockForwardChunkLocator([][]byte{}), 0) + blockProvider := newCallFromToBlockProvider(false, fromBlockProvider, toBlockProvider) + + checkNext(t, blockProvider, 1005, true) + checkNext(t, blockProvider, 1010, false) +} + +func TestFromToForwardBlockProviderWith1ChunkNotExactBlock(t *testing.T) { + // Mocks 1 chunk + chunk1 := createBitmap(t, []uint64{1000, 1005, 1010}) + + chunkLocator := newMockForwardChunkLocator([][]byte{chunk1}) + fromBlockProvider := NewForwardBlockProvider(chunkLocator, 1007) + toBlockProvider := NewForwardBlockProvider(newMockForwardChunkLocator([][]byte{}), 0) + blockProvider := newCallFromToBlockProvider(false, fromBlockProvider, toBlockProvider) + + checkNext(t, blockProvider, 1010, false) +} + +func TestFromToForwardBlockProviderWith1ChunkLastBlock(t *testing.T) { + // Mocks 1 chunk + chunk1 := createBitmap(t, []uint64{1000, 1005, 1010}) + + chunkLocator := newMockForwardChunkLocator([][]byte{chunk1}) + fromBlockProvider := NewForwardBlockProvider(chunkLocator, 1010) + toBlockProvider := NewForwardBlockProvider(newMockForwardChunkLocator([][]byte{}), 0) + blockProvider := newCallFromToBlockProvider(false, fromBlockProvider, toBlockProvider) + + checkNext(t, blockProvider, 1010, false) +} + +func TestFromToForwardBlockProviderWith1ChunkBlockNotFound(t *testing.T) { + // Mocks 1 chunk + chunk1 := createBitmap(t, []uint64{1000, 1005, 1010}) + + chunkLocator := newMockForwardChunkLocator([][]byte{chunk1}) + fromBlockProvider := NewForwardBlockProvider(chunkLocator, 1100) + toBlockProvider := NewForwardBlockProvider(newMockForwardChunkLocator([][]byte{}), 0) + blockProvider := newCallFromToBlockProvider(false, fromBlockProvider, toBlockProvider) + + checkNext(t, blockProvider, 0, false) +} + +func TestFromToForwardBlockProviderWithNoChunks(t *testing.T) { + chunkLocator := newMockForwardChunkLocator([][]byte{}) + fromBlockProvider := NewForwardBlockProvider(chunkLocator, 0) + toBlockProvider := NewForwardBlockProvider(newMockForwardChunkLocator([][]byte{}), 0) + blockProvider := newCallFromToBlockProvider(false, fromBlockProvider, toBlockProvider) + + checkNext(t, blockProvider, 0, false) +} + +func TestFromToForwardBlockProviderWithMultipleChunks(t *testing.T) { + // Mocks 2 chunks + chunk1 := createBitmap(t, []uint64{1000, 1005, 1010}) + chunk2 := createBitmap(t, []uint64{1501, 1600}) + + chunkLocator := newMockForwardChunkLocator([][]byte{chunk1, chunk2}) + fromBlockProvider := NewForwardBlockProvider(chunkLocator, 0) + toBlockProvider := NewForwardBlockProvider(newMockForwardChunkLocator([][]byte{}), 0) + blockProvider := newCallFromToBlockProvider(false, fromBlockProvider, toBlockProvider) + + checkNext(t, blockProvider, 1000, true) + checkNext(t, blockProvider, 1005, true) + checkNext(t, blockProvider, 1010, true) + checkNext(t, blockProvider, 1501, true) + checkNext(t, blockProvider, 1600, false) +} + +func TestFromToForwardBlockProviderWithMultipleChunksBlockBetweenChunks(t *testing.T) { + // Mocks 2 chunks + chunk1 := createBitmap(t, []uint64{1000, 1005, 1010}) + chunk2 := createBitmap(t, []uint64{1501, 1600}) + + chunkLocator := newMockForwardChunkLocator([][]byte{chunk1, chunk2}) + fromBlockProvider := NewForwardBlockProvider(chunkLocator, 1300) + toBlockProvider := NewForwardBlockProvider(newMockForwardChunkLocator([][]byte{}), 0) + blockProvider := newCallFromToBlockProvider(false, fromBlockProvider, toBlockProvider) + + checkNext(t, blockProvider, 1501, true) + checkNext(t, blockProvider, 1600, false) +} diff --git a/cmd/rpcdaemon/commands/otterscan_search_forward_test.go b/cmd/rpcdaemon/commands/otterscan_search_forward_test.go new file mode 100644 index 0000000..8be2709 --- /dev/null +++ b/cmd/rpcdaemon/commands/otterscan_search_forward_test.go @@ -0,0 +1,143 @@ +package commands + +import ( + "bytes" + "testing" + + "github.com/RoaringBitmap/roaring/roaring64" +) + +func newMockForwardChunkLocator(chunks [][]byte) ChunkLocator { + return func(block uint64) (ChunkProvider, bool, error) { + for i, v := range chunks { + bm := roaring64.NewBitmap() + if _, err := bm.ReadFrom(bytes.NewReader(v)); err != nil { + return nil, false, err + } + if block > bm.Maximum() { + continue + } + + return newMockForwardChunkProvider(chunks[i:]), true, nil + } + + // Not found; return the last to simulate the behavior of returning + // the 0xffff... chunk + if len(chunks) > 0 { + return newMockForwardChunkProvider(chunks[len(chunks)-1:]), true, nil + } + + return nil, true, nil + } +} + +func newMockForwardChunkProvider(chunks [][]byte) ChunkProvider { + i := 0 + return func() ([]byte, bool, error) { + if i >= len(chunks) { + return nil, false, nil + } + + chunk := chunks[i] + i++ + return chunk, true, nil + } +} + +func TestForwardBlockProviderWith1Chunk(t *testing.T) { + // Mocks 1 chunk + chunk1 := createBitmap(t, []uint64{1000, 1005, 1010}) + + chunkLocator := newMockForwardChunkLocator([][]byte{chunk1}) + blockProvider := NewForwardBlockProvider(chunkLocator, 0) + + checkNext(t, blockProvider, 1000, true) + checkNext(t, blockProvider, 1005, true) + checkNext(t, blockProvider, 1010, false) +} + +func TestForwardBlockProviderWith1ChunkMiddleBlock(t *testing.T) { + // Mocks 1 chunk + chunk1 := createBitmap(t, []uint64{1000, 1005, 1010}) + + chunkLocator := newMockForwardChunkLocator([][]byte{chunk1}) + blockProvider := NewForwardBlockProvider(chunkLocator, 1005) + + checkNext(t, blockProvider, 1005, true) + checkNext(t, blockProvider, 1010, false) +} + +func TestForwardBlockProviderWith1ChunkNotExactBlock(t *testing.T) { + // Mocks 1 chunk + chunk1 := createBitmap(t, []uint64{1000, 1005, 1010}) + + chunkLocator := newMockForwardChunkLocator([][]byte{chunk1}) + blockProvider := NewForwardBlockProvider(chunkLocator, 1007) + + checkNext(t, blockProvider, 1010, false) +} + +func TestForwardBlockProviderWith1ChunkLastBlock(t *testing.T) { + // Mocks 1 chunk + chunk1 := createBitmap(t, []uint64{1000, 1005, 1010}) + + chunkLocator := newMockForwardChunkLocator([][]byte{chunk1}) + blockProvider := NewForwardBlockProvider(chunkLocator, 1010) + + checkNext(t, blockProvider, 1010, false) +} + +func TestForwardBlockProviderWith1ChunkBlockNotFound(t *testing.T) { + // Mocks 1 chunk + chunk1 := createBitmap(t, []uint64{1000, 1005, 1010}) + + chunkLocator := newMockForwardChunkLocator([][]byte{chunk1}) + blockProvider := NewForwardBlockProvider(chunkLocator, 1100) + + checkNext(t, blockProvider, 0, false) +} + +func TestForwardBlockProviderWithNoChunks(t *testing.T) { + chunkLocator := newMockForwardChunkLocator([][]byte{}) + blockProvider := NewForwardBlockProvider(chunkLocator, 0) + + checkNext(t, blockProvider, 0, false) +} + +func TestForwardBlockProviderWithMultipleChunks(t *testing.T) { + // Mocks 2 chunks + chunk1 := createBitmap(t, []uint64{1000, 1005, 1010}) + chunk2 := createBitmap(t, []uint64{1501, 1600}) + + chunkLocator := newMockForwardChunkLocator([][]byte{chunk1, chunk2}) + blockProvider := NewForwardBlockProvider(chunkLocator, 0) + + checkNext(t, blockProvider, 1000, true) + checkNext(t, blockProvider, 1005, true) + checkNext(t, blockProvider, 1010, true) + checkNext(t, blockProvider, 1501, true) + checkNext(t, blockProvider, 1600, false) +} + +func TestForwardBlockProviderWithMultipleChunksBlockBetweenChunks(t *testing.T) { + // Mocks 2 chunks + chunk1 := createBitmap(t, []uint64{1000, 1005, 1010}) + chunk2 := createBitmap(t, []uint64{1501, 1600}) + + chunkLocator := newMockForwardChunkLocator([][]byte{chunk1, chunk2}) + blockProvider := NewForwardBlockProvider(chunkLocator, 1300) + + checkNext(t, blockProvider, 1501, true) + checkNext(t, blockProvider, 1600, false) +} + +func TestForwardBlockProviderWithMultipleChunksBlockNotFound(t *testing.T) { + // Mocks 2 chunks + chunk1 := createBitmap(t, []uint64{1000, 1005, 1010}) + chunk2 := createBitmap(t, []uint64{1501, 1600}) + + chunkLocator := newMockForwardChunkLocator([][]byte{chunk1, chunk2}) + blockProvider := NewForwardBlockProvider(chunkLocator, 1700) + + checkNext(t, blockProvider, 0, false) +} diff --git a/cmd/rpcdaemon/commands/otterscan_search_multi.go b/cmd/rpcdaemon/commands/otterscan_search_multi.go new file mode 100644 index 0000000..c5bdba0 --- /dev/null +++ b/cmd/rpcdaemon/commands/otterscan_search_multi.go @@ -0,0 +1,63 @@ +package commands + +func newCallFromToBlockProvider(isBackwards bool, callFromProvider, callToProvider BlockProvider) BlockProvider { + var nextFrom, nextTo uint64 + var hasMoreFrom, hasMoreTo bool + initialized := false + + return func() (uint64, bool, error) { + if !initialized { + initialized = true + + var err error + if nextFrom, hasMoreFrom, err = callFromProvider(); err != nil { + return 0, false, err + } + hasMoreFrom = hasMoreFrom || nextFrom != 0 + + if nextTo, hasMoreTo, err = callToProvider(); err != nil { + return 0, false, err + } + hasMoreTo = hasMoreTo || nextTo != 0 + } + + if !hasMoreFrom && !hasMoreTo { + return 0, false, nil + } + + var blockNum uint64 + if !hasMoreFrom { + blockNum = nextTo + } else if !hasMoreTo { + blockNum = nextFrom + } else { + blockNum = nextFrom + if isBackwards { + if nextTo < nextFrom { + blockNum = nextTo + } + } else { + if nextTo > nextFrom { + blockNum = nextTo + } + } + } + + // Pull next; it may be that from AND to contains the same blockNum + if hasMoreFrom && blockNum == nextFrom { + var err error + if nextFrom, hasMoreFrom, err = callFromProvider(); err != nil { + return 0, false, err + } + hasMoreFrom = hasMoreFrom || nextFrom != 0 + } + if hasMoreTo && blockNum == nextTo { + var err error + if nextTo, hasMoreTo, err = callToProvider(); err != nil { + return 0, false, err + } + hasMoreTo = hasMoreTo || nextTo != 0 + } + return blockNum, hasMoreFrom || hasMoreTo, nil + } +} diff --git a/cmd/rpcdaemon/commands/otterscan_search_test.go b/cmd/rpcdaemon/commands/otterscan_search_test.go new file mode 100644 index 0000000..e4a7c3b --- /dev/null +++ b/cmd/rpcdaemon/commands/otterscan_search_test.go @@ -0,0 +1,31 @@ +package commands + +import ( + "testing" + + "github.com/RoaringBitmap/roaring/roaring64" +) + +func createBitmap(t *testing.T, blocks []uint64) []byte { + bm := roaring64.NewBitmap() + bm.AddMany(blocks) + + chunk, err := bm.ToBytes() + if err != nil { + t.Fatal(err) + } + return chunk +} + +func checkNext(t *testing.T, blockProvider BlockProvider, expectedBlock uint64, expectedHasNext bool) { + bl, hasNext, err := blockProvider() + if err != nil { + t.Fatal(err) + } + if bl != expectedBlock { + t.Fatalf("Expected block %d, received %d", expectedBlock, bl) + } + if expectedHasNext != hasNext { + t.Fatalf("Expected hasNext=%t, received=%t; at block=%d", expectedHasNext, hasNext, expectedBlock) + } +} diff --git a/cmd/rpcdaemon/commands/otterscan_search_trace.go b/cmd/rpcdaemon/commands/otterscan_search_trace.go new file mode 100644 index 0000000..6087115 --- /dev/null +++ b/cmd/rpcdaemon/commands/otterscan_search_trace.go @@ -0,0 +1,103 @@ +package commands + +import ( + "context" + "sync" + + "github.com/ledgerwatch/erigon-lib/kv" + "github.com/ledgerwatch/erigon/cmd/rpcdaemon/commands" + "github.com/ledgerwatch/erigon/common" + "github.com/ledgerwatch/erigon/consensus/ethash" + "github.com/ledgerwatch/erigon/core" + "github.com/ledgerwatch/erigon/core/rawdb" + "github.com/ledgerwatch/erigon/core/state" + "github.com/ledgerwatch/erigon/core/types" + "github.com/ledgerwatch/erigon/core/vm" + "github.com/ledgerwatch/erigon/params" + "github.com/ledgerwatch/erigon/turbo/shards" + "github.com/ledgerwatch/log/v3" +) + +func (api *OtterscanAPIImpl) searchTraceBlock(ctx context.Context, wg *sync.WaitGroup, addr common.Address, chainConfig *params.ChainConfig, idx int, bNum uint64, results []*TransactionsWithReceipts) { + wg.Done() + // Trace block for Txs + newdbtx, err := api.db.BeginRo(ctx) + if err != nil { + log.Error("Search trace error", "err", err) + results[idx] = nil + return + } + defer newdbtx.Rollback() + _, result, err := api.traceBlock(newdbtx, ctx, bNum, addr, chainConfig) + if err != nil { + log.Error("Search trace error", "err", err) + results[idx] = nil + return + } + results[idx] = result +} + +func (api *OtterscanAPIImpl) traceBlock(dbtx kv.Tx, ctx context.Context, blockNum uint64, searchAddr common.Address, chainConfig *params.ChainConfig) (bool, *TransactionsWithReceipts, error) { + rpcTxs := make([]*commands.RPCTransaction, 0) + receipts := make([]map[string]interface{}, 0) + + // Retrieve the transaction and assemble its EVM context + blockHash, err := rawdb.ReadCanonicalHash(dbtx, blockNum) + if err != nil { + return false, nil, err + } + + block, senders, err := api._blockReader.BlockWithSenders(ctx, dbtx, blockHash, blockNum) + if err != nil { + return false, nil, err + } + + reader := state.NewPlainState(dbtx, blockNum) + stateCache := shards.NewStateCache(32, 0 /* no limit */) + cachedReader := state.NewCachedReader(reader, stateCache) + noop := state.NewNoopWriter() + cachedWriter := state.NewCachedWriter(noop, stateCache) + + ibs := state.New(cachedReader) + signer := types.MakeSigner(chainConfig, blockNum) + + getHeader := func(hash common.Hash, number uint64) *types.Header { + h, e := api._blockReader.Header(ctx, dbtx, hash, number) + if e != nil { + log.Error("getHeader error", "number", number, "hash", hash, "err", e) + } + return h + } + engine := ethash.NewFaker() + + blockReceipts := rawdb.ReadReceipts(dbtx, block, senders) + header := block.Header() + rules := chainConfig.Rules(block.NumberU64()) + found := false + for idx, tx := range block.Transactions() { + ibs.Prepare(tx.Hash(), block.Hash(), idx) + + msg, _ := tx.AsMessage(*signer, header.BaseFee, rules) + + tracer := NewTouchTracer(searchAddr) + BlockContext := core.NewEVMBlockContext(header, core.GetHashFn(header, getHeader), engine, nil) + TxContext := core.NewEVMTxContext(msg) + + vmenv := vm.NewEVM(BlockContext, TxContext, ibs, chainConfig, vm.Config{Debug: true, Tracer: tracer}) + if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.GetGas()), true /* refunds */, false /* gasBailout */); err != nil { + return false, nil, err + } + _ = ibs.FinalizeTx(vmenv.ChainConfig().Rules(block.NumberU64()), cachedWriter) + + if tracer.Found { + rpcTx := newRPCTransaction(tx, block.Hash(), blockNum, uint64(idx), block.BaseFee()) + mReceipt := marshalReceipt(blockReceipts[idx], tx, chainConfig, block, tx.Hash(), true) + mReceipt["timestamp"] = block.Time() + rpcTxs = append(rpcTxs, rpcTx) + receipts = append(receipts, mReceipt) + found = true + } + } + + return found, &TransactionsWithReceipts{rpcTxs, receipts, false, false}, nil +} diff --git a/cmd/rpcdaemon/commands/otterscan_trace_contract_creator.go b/cmd/rpcdaemon/commands/otterscan_trace_contract_creator.go new file mode 100644 index 0000000..7875282 --- /dev/null +++ b/cmd/rpcdaemon/commands/otterscan_trace_contract_creator.go @@ -0,0 +1,50 @@ +package commands + +import ( + "context" + "math/big" + + "github.com/ledgerwatch/erigon/common" + "github.com/ledgerwatch/erigon/core/types" + "github.com/ledgerwatch/erigon/core/vm" +) + +type CreateTracer struct { + DefaultTracer + ctx context.Context + target common.Address + found bool + Creator common.Address + Tx types.Transaction +} + +func NewCreateTracer(ctx context.Context, target common.Address) *CreateTracer { + return &CreateTracer{ + ctx: ctx, + target: target, + found: false, + } +} + +func (t *CreateTracer) SetTransaction(tx types.Transaction) { + t.Tx = tx +} + +func (t *CreateTracer) Found() bool { + return t.found +} + +func (t *CreateTracer) CaptureStart(env *vm.EVM, depth int, from common.Address, to common.Address, precompile bool, create bool, calltype vm.CallType, input []byte, gas uint64, value *big.Int, code []byte) { + if t.found { + return + } + if !create { + return + } + if to != t.target { + return + } + + t.found = true + t.Creator = from +} diff --git a/cmd/rpcdaemon/commands/otterscan_trace_operations.go b/cmd/rpcdaemon/commands/otterscan_trace_operations.go new file mode 100644 index 0000000..59e8e05 --- /dev/null +++ b/cmd/rpcdaemon/commands/otterscan_trace_operations.go @@ -0,0 +1,60 @@ +package commands + +import ( + "context" + "math/big" + + "github.com/ledgerwatch/erigon/common" + "github.com/ledgerwatch/erigon/common/hexutil" + "github.com/ledgerwatch/erigon/core/vm" +) + +type OperationType int + +const ( + OP_TRANSFER OperationType = 0 + OP_SELF_DESTRUCT OperationType = 1 + OP_CREATE OperationType = 2 + OP_CREATE2 OperationType = 3 +) + +type InternalOperation struct { + Type OperationType `json:"type"` + From common.Address `json:"from"` + To common.Address `json:"to"` + Value *hexutil.Big `json:"value"` +} + +type OperationsTracer struct { + DefaultTracer + ctx context.Context + Results []*InternalOperation +} + +func NewOperationsTracer(ctx context.Context) *OperationsTracer { + return &OperationsTracer{ + ctx: ctx, + Results: make([]*InternalOperation, 0), + } +} + +func (t *OperationsTracer) CaptureStart(env *vm.EVM, depth int, from common.Address, to common.Address, precompile bool, create bool, calltype vm.CallType, input []byte, gas uint64, value *big.Int, code []byte) { + if depth == 0 { + return + } + + if calltype == vm.CALLT && value.Uint64() != 0 { + t.Results = append(t.Results, &InternalOperation{OP_TRANSFER, from, to, (*hexutil.Big)(value)}) + return + } + if calltype == vm.CREATET { + t.Results = append(t.Results, &InternalOperation{OP_CREATE, from, to, (*hexutil.Big)(value)}) + } + if calltype == vm.CREATE2T { + t.Results = append(t.Results, &InternalOperation{OP_CREATE2, from, to, (*hexutil.Big)(value)}) + } +} + +func (l *OperationsTracer) CaptureSelfDestruct(from common.Address, to common.Address, value *big.Int) { + l.Results = append(l.Results, &InternalOperation{OP_SELF_DESTRUCT, from, to, (*hexutil.Big)(value)}) +} diff --git a/cmd/rpcdaemon/commands/otterscan_trace_touch.go b/cmd/rpcdaemon/commands/otterscan_trace_touch.go new file mode 100644 index 0000000..98db6a9 --- /dev/null +++ b/cmd/rpcdaemon/commands/otterscan_trace_touch.go @@ -0,0 +1,27 @@ +package commands + +import ( + "bytes" + "math/big" + + "github.com/ledgerwatch/erigon/common" + "github.com/ledgerwatch/erigon/core/vm" +) + +type TouchTracer struct { + DefaultTracer + searchAddr common.Address + Found bool +} + +func NewTouchTracer(searchAddr common.Address) *TouchTracer { + return &TouchTracer{ + searchAddr: searchAddr, + } +} + +func (t *TouchTracer) CaptureStart(env *vm.EVM, depth int, from common.Address, to common.Address, precompile bool, create bool, calltype vm.CallType, input []byte, gas uint64, value *big.Int, code []byte) { + if !t.Found && (bytes.Equal(t.searchAddr.Bytes(), from.Bytes()) || bytes.Equal(t.searchAddr.Bytes(), to.Bytes())) { + t.Found = true + } +} diff --git a/cmd/rpcdaemon/commands/otterscan_trace_transaction.go b/cmd/rpcdaemon/commands/otterscan_trace_transaction.go new file mode 100644 index 0000000..3ba73df --- /dev/null +++ b/cmd/rpcdaemon/commands/otterscan_trace_transaction.go @@ -0,0 +1,87 @@ +package commands + +import ( + "context" + "math/big" + + "github.com/ledgerwatch/erigon/common" + "github.com/ledgerwatch/erigon/common/hexutil" + "github.com/ledgerwatch/erigon/core/vm" +) + +func (api *OtterscanAPIImpl) TraceTransaction(ctx context.Context, hash common.Hash) ([]*TraceEntry, error) { + tx, err := api.db.BeginRo(ctx) + if err != nil { + return nil, err + } + defer tx.Rollback() + + tracer := NewTransactionTracer(ctx) + if _, err := api.runTracer(ctx, tx, hash, tracer); err != nil { + return nil, err + } + + return tracer.Results, nil +} + +type TraceEntry struct { + Type string `json:"type"` + Depth int `json:"depth"` + From common.Address `json:"from"` + To common.Address `json:"to"` + Value *hexutil.Big `json:"value"` + Input hexutil.Bytes `json:"input"` +} + +type TransactionTracer struct { + DefaultTracer + ctx context.Context + Results []*TraceEntry +} + +func NewTransactionTracer(ctx context.Context) *TransactionTracer { + return &TransactionTracer{ + ctx: ctx, + Results: make([]*TraceEntry, 0), + } +} + +func (t *TransactionTracer) CaptureStart(env *vm.EVM, depth int, from common.Address, to common.Address, precompile bool, create bool, callType vm.CallType, input []byte, gas uint64, value *big.Int, code []byte) { + if precompile { + return + } + + inputCopy := make([]byte, len(input)) + copy(inputCopy, input) + _value := new(big.Int) + _value.Set(value) + if callType == vm.CALLT { + t.Results = append(t.Results, &TraceEntry{"CALL", depth, from, to, (*hexutil.Big)(_value), inputCopy}) + return + } + if callType == vm.STATICCALLT { + t.Results = append(t.Results, &TraceEntry{"STATICCALL", depth, from, to, nil, inputCopy}) + return + } + if callType == vm.DELEGATECALLT { + t.Results = append(t.Results, &TraceEntry{"DELEGATECALL", depth, from, to, nil, inputCopy}) + return + } + if callType == vm.CALLCODET { + t.Results = append(t.Results, &TraceEntry{"CALLCODE", depth, from, to, (*hexutil.Big)(_value), inputCopy}) + return + } + if callType == vm.CREATET { + t.Results = append(t.Results, &TraceEntry{"CREATE", depth, from, to, (*hexutil.Big)(value), inputCopy}) + return + } + if callType == vm.CREATE2T { + t.Results = append(t.Results, &TraceEntry{"CREATE2", depth, from, to, (*hexutil.Big)(value), inputCopy}) + return + } +} + +func (l *TransactionTracer) CaptureSelfDestruct(from common.Address, to common.Address, value *big.Int) { + last := l.Results[len(l.Results)-1] + l.Results = append(l.Results, &TraceEntry{"SELFDESTRUCT", last.Depth + 1, from, to, (*hexutil.Big)(value), nil}) +} diff --git a/cmd/rpcdaemon/commands/otterscan_transaction_by_sender_and_nonce.go b/cmd/rpcdaemon/commands/otterscan_transaction_by_sender_and_nonce.go new file mode 100644 index 0000000..b94ee60 --- /dev/null +++ b/cmd/rpcdaemon/commands/otterscan_transaction_by_sender_and_nonce.go @@ -0,0 +1,163 @@ +package commands + +import ( + "bytes" + "context" + "sort" + + "github.com/RoaringBitmap/roaring/roaring64" + "github.com/ledgerwatch/erigon-lib/kv" + "github.com/ledgerwatch/erigon/common" + "github.com/ledgerwatch/erigon/common/changeset" + "github.com/ledgerwatch/erigon/core/rawdb" + "github.com/ledgerwatch/erigon/core/types/accounts" +) + +func (api *OtterscanAPIImpl) GetTransactionBySenderAndNonce(ctx context.Context, addr common.Address, nonce uint64) (*common.Hash, error) { + tx, err := api.db.BeginRo(ctx) + if err != nil { + return nil, err + } + defer tx.Rollback() + + accHistoryC, err := tx.Cursor(kv.AccountsHistory) + if err != nil { + return nil, err + } + defer accHistoryC.Close() + + accChangesC, err := tx.CursorDupSort(kv.AccountChangeSet) + if err != nil { + return nil, err + } + defer accChangesC.Close() + + // Locate the chunk where the nonce happens + acs := changeset.Mapper[kv.AccountChangeSet] + k, v, err := accHistoryC.Seek(acs.IndexChunkKey(addr.Bytes(), 0)) + if err != nil { + return nil, err + } + + bitmap := roaring64.New() + maxBlPrevChunk := uint64(0) + var acc accounts.Account + + for { + if k == nil || !bytes.HasPrefix(k, addr.Bytes()) { + // Check plain state + data, err := tx.GetOne(kv.PlainState, addr.Bytes()) + if err != nil { + return nil, err + } + if err := acc.DecodeForStorage(data); err != nil { + return nil, err + } + + // Nonce changed in plain state, so it means the last block of last chunk + // contains the actual nonce change + if acc.Nonce > nonce { + break + } + + // Not found; asked for nonce still not used + return nil, nil + } + + // Inspect block changeset + if _, err := bitmap.ReadFrom(bytes.NewReader(v)); err != nil { + return nil, err + } + maxBl := bitmap.Maximum() + data, err := acs.Find(accChangesC, maxBl, addr.Bytes()) + if err != nil { + return nil, err + } + if err := acc.DecodeForStorage(data); err != nil { + return nil, err + } + + // Desired nonce was found in this chunk + if acc.Nonce > nonce { + break + } + + maxBlPrevChunk = maxBl + k, v, err = accHistoryC.Next() + if err != nil { + return nil, err + } + } + + // Locate the exact block inside chunk when the nonce changed + blocks := bitmap.ToArray() + var errSearch error = nil + idx := sort.Search(len(blocks), func(i int) bool { + if errSearch != nil { + return false + } + + // Locate the block changeset + data, err := acs.Find(accChangesC, blocks[i], addr.Bytes()) + if err != nil { + errSearch = err + return false + } + + if err := acc.DecodeForStorage(data); err != nil { + errSearch = err + return false + } + + // Since the state contains the nonce BEFORE the block changes, we look for + // the block when the nonce changed to be > the desired once, which means the + // previous history block contains the actual change; it may contain multiple + // nonce changes. + return acc.Nonce > nonce + }) + if errSearch != nil { + return nil, errSearch + } + + // Since the changeset contains the state BEFORE the change, we inspect + // the block before the one we found; if it is the first block inside the chunk, + // we use the last block from prev chunk + nonceBlock := maxBlPrevChunk + if idx > 0 { + nonceBlock = blocks[idx-1] + } + found, txHash, err := api.findNonce(ctx, tx, addr, nonce, nonceBlock) + if err != nil { + return nil, err + } + if !found { + return nil, nil + } + + return &txHash, nil +} + +func (api *OtterscanAPIImpl) findNonce(ctx context.Context, tx kv.Tx, addr common.Address, nonce uint64, blockNum uint64) (bool, common.Hash, error) { + hash, err := rawdb.ReadCanonicalHash(tx, blockNum) + if err != nil { + return false, common.Hash{}, err + } + block, senders, err := api._blockReader.BlockWithSenders(ctx, tx, hash, blockNum) + if err != nil { + return false, common.Hash{}, err + } + + txs := block.Transactions() + for i, s := range senders { + if s != addr { + continue + } + + t := txs[i] + if t.GetNonce() == nonce { + return true, t.Hash(), nil + } + } + + return false, common.Hash{}, nil +} diff --git a/cmd/rpcdaemon/commands/otterscan_transaction_error.go b/cmd/rpcdaemon/commands/otterscan_transaction_error.go new file mode 100644 index 0000000..2cccc80 --- /dev/null +++ b/cmd/rpcdaemon/commands/otterscan_transaction_error.go @@ -0,0 +1,23 @@ +package commands + +import ( + "context" + + "github.com/ledgerwatch/erigon/common" + "github.com/ledgerwatch/erigon/common/hexutil" +) + +func (api *OtterscanAPIImpl) GetTransactionError(ctx context.Context, hash common.Hash) (hexutil.Bytes, error) { + tx, err := api.db.BeginRo(ctx) + if err != nil { + return nil, err + } + defer tx.Rollback() + + result, err := api.runTracer(ctx, tx, hash, nil) + if err != nil { + return nil, err + } + + return result.Revert(), nil +} diff --git a/cmd/rpcdaemon/commands/otterscan_types.go b/cmd/rpcdaemon/commands/otterscan_types.go new file mode 100644 index 0000000..ddd57f1 --- /dev/null +++ b/cmd/rpcdaemon/commands/otterscan_types.go @@ -0,0 +1,94 @@ +package commands + +import ( + "bytes" + "encoding/binary" + + "github.com/ledgerwatch/erigon-lib/kv" + "github.com/ledgerwatch/erigon/common" +) + +// Bootstrap a function able to locate a series of byte chunks containing +// related block numbers, starting from a specific block number (greater or equal than). +type ChunkLocator func(block uint64) (chunkProvider ChunkProvider, ok bool, err error) + +// Allows to iterate over a set of byte chunks. +// +// If err is not nil, it indicates an error and the other returned values should be +// ignored. +// +// If err is nil and ok is true, the returned chunk should contain the raw chunk data. +// +// If err is nil and ok is false, it indicates that there is no more data. Subsequent calls +// to the same function should return (nil, false, nil). +type ChunkProvider func() (chunk []byte, ok bool, err error) + +type BlockProvider func() (nextBlock uint64, hasMore bool, err error) + +// Standard key format for call from/to indexes [address + block] +func callIndexKey(addr common.Address, block uint64) []byte { + key := make([]byte, common.AddressLength+8) + copy(key[:common.AddressLength], addr.Bytes()) + binary.BigEndian.PutUint64(key[common.AddressLength:], block) + return key +} + +const MaxBlockNum = ^uint64(0) + +// This ChunkLocator searches over a cursor with a key format of [common.Address, block uint64], +// where block is the first block number contained in the chunk value. +// +// It positions the cursor on the chunk that contains the first block >= minBlock. +func newCallChunkLocator(cursor kv.Cursor, addr common.Address, navigateForward bool) ChunkLocator { + return func(minBlock uint64) (ChunkProvider, bool, error) { + searchKey := callIndexKey(addr, minBlock) + k, _, err := cursor.Seek(searchKey) + if k == nil { + return nil, false, nil + } + if err != nil { + return nil, false, err + } + + return newCallChunkProvider(cursor, addr, navigateForward), true, nil + } +} + +// This ChunkProvider is built by NewForwardChunkLocator and advances the cursor forward until +// there is no more chunks for the desired addr. +func newCallChunkProvider(cursor kv.Cursor, addr common.Address, navigateForward bool) ChunkProvider { + first := true + var err error + // TODO: is this flag really used? + eof := false + return func() ([]byte, bool, error) { + if err != nil { + return nil, false, err + } + if eof { + return nil, false, nil + } + + var k, v []byte + if first { + first = false + k, v, err = cursor.Current() + } else { + if navigateForward { + k, v, err = cursor.Next() + } else { + k, v, err = cursor.Prev() + } + } + + if err != nil { + eof = true + return nil, false, err + } + if !bytes.HasPrefix(k, addr.Bytes()) { + eof = true + return nil, false, nil + } + return v, true, nil + } +} diff --git a/cmd/rpcdaemon/commands/utils_eth_api.go b/cmd/rpcdaemon/commands/utils_eth_api.go new file mode 100644 index 0000000..db20644 --- /dev/null +++ b/cmd/rpcdaemon/commands/utils_eth_api.go @@ -0,0 +1,295 @@ +package commands + +import ( + "bytes" + "context" + "math/big" + "sync" + "time" + + lru "github.com/hashicorp/golang-lru" + "github.com/holiman/uint256" + "github.com/ledgerwatch/erigon-lib/kv" + libstate "github.com/ledgerwatch/erigon-lib/state" + "github.com/ledgerwatch/log/v3" + + "github.com/ledgerwatch/erigon-lib/kv/kvcache" + "github.com/ledgerwatch/erigon/cmd/rpcdaemon/commands" + "github.com/ledgerwatch/erigon/common" + "github.com/ledgerwatch/erigon/common/hexutil" + "github.com/ledgerwatch/erigon/common/math" + "github.com/ledgerwatch/erigon/consensus/misc" + "github.com/ledgerwatch/erigon/core/rawdb" + "github.com/ledgerwatch/erigon/core/types" + "github.com/ledgerwatch/erigon/params" + "github.com/ledgerwatch/erigon/rpc" + "github.com/ledgerwatch/erigon/turbo/rpchelper" + "github.com/ledgerwatch/erigon/turbo/services" +) + +type BaseAPIUtils struct { + *commands.BaseAPI + + stateCache kvcache.Cache // thread-safe + blocksLRU *lru.Cache // thread-safe + filters *rpchelper.Filters + _chainConfig *params.ChainConfig + _genesis *types.Block + _genesisLock sync.RWMutex + + _historyV3 *bool + _historyV3Lock sync.RWMutex + + _blockReader services.FullBlockReader + _txnReader services.TxnReader + _agg *libstate.Aggregator22 + + evmCallTimeout time.Duration +} + +func NewBaseUtilsApi(f *rpchelper.Filters, stateCache kvcache.Cache, blockReader services.FullBlockReader, agg *libstate.Aggregator22, singleNodeMode bool, evmCallTimeout time.Duration) *BaseAPIUtils { + blocksLRUSize := 128 // ~32Mb + if !singleNodeMode { + blocksLRUSize = 512 + } + blocksLRU, err := lru.New(blocksLRUSize) + if err != nil { + panic(err) + } + + return &BaseAPIUtils{filters: f, stateCache: stateCache, blocksLRU: blocksLRU, _blockReader: blockReader, _txnReader: blockReader, _agg: agg, evmCallTimeout: evmCallTimeout} +} + +func (api *BaseAPIUtils) chainConfig(tx kv.Tx) (*params.ChainConfig, error) { + cfg, _, err := api.chainConfigWithGenesis(tx) + return cfg, err +} + +// nolint:unused +func (api *BaseAPIUtils) genesis(tx kv.Tx) (*types.Block, error) { + _, genesis, err := api.chainConfigWithGenesis(tx) + return genesis, err +} + +func (api *BaseAPIUtils) txnLookup(ctx context.Context, tx kv.Tx, txnHash common.Hash) (uint64, bool, error) { + return api._txnReader.TxnLookup(ctx, tx, txnHash) +} + +func (api *BaseAPIUtils) blockByNumberWithSenders(tx kv.Tx, number uint64) (*types.Block, error) { + hash, hashErr := rawdb.ReadCanonicalHash(tx, number) + if hashErr != nil { + return nil, hashErr + } + return api.blockWithSenders(tx, hash, number) +} +func (api *BaseAPIUtils) blockByHashWithSenders(tx kv.Tx, hash common.Hash) (*types.Block, error) { + if api.blocksLRU != nil { + if it, ok := api.blocksLRU.Get(hash); ok && it != nil { + return it.(*types.Block), nil + } + } + number := rawdb.ReadHeaderNumber(tx, hash) + if number == nil { + return nil, nil + } + + return api.blockWithSenders(tx, hash, *number) +} +func (api *BaseAPIUtils) blockWithSenders(tx kv.Tx, hash common.Hash, number uint64) (*types.Block, error) { + if api.blocksLRU != nil { + if it, ok := api.blocksLRU.Get(hash); ok && it != nil { + return it.(*types.Block), nil + } + } + block, _, err := api._blockReader.BlockWithSenders(context.Background(), tx, hash, number) + if err != nil { + return nil, err + } + if block == nil { // don't save nil's to cache + return nil, nil + } + // don't save empty blocks to cache, because in Erigon + // if block become non-canonical - we remove it's transactions, but block can become canonical in future + if block.Transactions().Len() == 0 { + return block, nil + } + if api.blocksLRU != nil { + // calc fields before put to cache + for _, txn := range block.Transactions() { + txn.Hash() + } + block.Hash() + api.blocksLRU.Add(hash, block) + } + return block, nil +} + +func (api *BaseAPIUtils) historyV3(tx kv.Tx) bool { + api._historyV3Lock.RLock() + historyV3 := api._historyV3 + api._historyV3Lock.RUnlock() + + if historyV3 != nil { + return *historyV3 + } + enabled, err := rawdb.HistoryV3.Enabled(tx) + if err != nil { + log.Warn("HisoryV2Enabled: read", "err", err) + return false + } + api._historyV3Lock.Lock() + api._historyV3 = &enabled + api._historyV3Lock.Unlock() + return enabled +} + +func (api *BaseAPIUtils) chainConfigWithGenesis(tx kv.Tx) (*params.ChainConfig, *types.Block, error) { + api._genesisLock.RLock() + cc, genesisBlock := api._chainConfig, api._genesis + api._genesisLock.RUnlock() + + if cc != nil { + return cc, genesisBlock, nil + } + genesisBlock, err := rawdb.ReadBlockByNumber(tx, 0) + if err != nil { + return nil, nil, err + } + cc, err = rawdb.ReadChainConfig(tx, genesisBlock.Hash()) + if err != nil { + return nil, nil, err + } + if cc != nil && genesisBlock != nil { + api._genesisLock.Lock() + api._genesis = genesisBlock + api._chainConfig = cc + api._genesisLock.Unlock() + } + return cc, genesisBlock, nil +} + +func (api *BaseAPIUtils) pendingBlock() *types.Block { + return api.filters.LastPendingBlock() +} + +func (api *BaseAPIUtils) blockByRPCNumber(number rpc.BlockNumber, tx kv.Tx) (*types.Block, error) { + n, _, _, err := rpchelper.GetBlockNumber(rpc.BlockNumberOrHashWithNumber(number), tx, api.filters) + if err != nil { + return nil, err + } + + block, err := api.blockByNumberWithSenders(tx, n) + return block, err +} + +func (api *BaseAPIUtils) headerByRPCNumber(number rpc.BlockNumber, tx kv.Tx) (*types.Header, error) { + n, h, _, err := rpchelper.GetBlockNumber(rpc.BlockNumberOrHashWithNumber(number), tx, api.filters) + if err != nil { + return nil, err + } + return api._blockReader.Header(context.Background(), tx, h, n) +} + +// newRPCTransaction returns a transaction that will serialize to the RPC +// representation, with the given location metadata set (if available). +func newRPCTransaction(tx types.Transaction, blockHash common.Hash, blockNumber uint64, index uint64, baseFee *big.Int) *commands.RPCTransaction { + // Determine the signer. For replay-protected transactions, use the most permissive + // signer, because we assume that signers are backwards-compatible with old + // transactions. For non-protected transactions, the homestead signer signer is used + // because the return value of ChainId is zero for those transactions. + var chainId *big.Int + result := &commands.RPCTransaction{ + Type: hexutil.Uint64(tx.Type()), + Gas: hexutil.Uint64(tx.GetGas()), + Hash: tx.Hash(), + Input: hexutil.Bytes(tx.GetData()), + Nonce: hexutil.Uint64(tx.GetNonce()), + To: tx.GetTo(), + Value: (*hexutil.Big)(tx.GetValue().ToBig()), + } + switch t := tx.(type) { + case *types.LegacyTx: + chainId = types.DeriveChainId(&t.V).ToBig() + result.GasPrice = (*hexutil.Big)(t.GasPrice.ToBig()) + result.V = (*hexutil.Big)(t.V.ToBig()) + result.R = (*hexutil.Big)(t.R.ToBig()) + result.S = (*hexutil.Big)(t.S.ToBig()) + case *types.AccessListTx: + chainId = t.ChainID.ToBig() + result.ChainID = (*hexutil.Big)(chainId) + result.GasPrice = (*hexutil.Big)(t.GasPrice.ToBig()) + result.V = (*hexutil.Big)(t.V.ToBig()) + result.R = (*hexutil.Big)(t.R.ToBig()) + result.S = (*hexutil.Big)(t.S.ToBig()) + result.Accesses = &t.AccessList + case *types.DynamicFeeTransaction: + chainId = t.ChainID.ToBig() + result.ChainID = (*hexutil.Big)(chainId) + result.Tip = (*hexutil.Big)(t.Tip.ToBig()) + result.FeeCap = (*hexutil.Big)(t.FeeCap.ToBig()) + result.V = (*hexutil.Big)(t.V.ToBig()) + result.R = (*hexutil.Big)(t.R.ToBig()) + result.S = (*hexutil.Big)(t.S.ToBig()) + result.Accesses = &t.AccessList + baseFee, overflow := uint256.FromBig(baseFee) + if baseFee != nil && !overflow && blockHash != (common.Hash{}) { + // price = min(tip + baseFee, gasFeeCap) + price := math.Min256(new(uint256.Int).Add(tx.GetTip(), baseFee), tx.GetFeeCap()) + result.GasPrice = (*hexutil.Big)(price.ToBig()) + } else { + result.GasPrice = nil + } + } + signer := types.LatestSignerForChainID(chainId) + result.From, _ = tx.Sender(*signer) + if blockHash != (common.Hash{}) { + result.BlockHash = &blockHash + result.BlockNumber = (*hexutil.Big)(new(big.Int).SetUint64(blockNumber)) + result.TransactionIndex = (*hexutil.Uint64)(&index) + } + return result +} + +// newRPCBorTransaction returns a Bor transaction that will serialize to the RPC +// representation, with the given location metadata set (if available). +func newRPCBorTransaction(opaqueTx types.Transaction, txHash common.Hash, blockHash common.Hash, blockNumber uint64, index uint64, baseFee *big.Int) *commands.RPCTransaction { + tx := opaqueTx.(*types.LegacyTx) + result := &commands.RPCTransaction{ + Type: hexutil.Uint64(tx.Type()), + ChainID: (*hexutil.Big)(new(big.Int)), + GasPrice: (*hexutil.Big)(tx.GasPrice.ToBig()), + Gas: hexutil.Uint64(tx.GetGas()), + Hash: txHash, + Input: hexutil.Bytes(tx.GetData()), + Nonce: hexutil.Uint64(tx.GetNonce()), + From: common.Address{}, + To: tx.GetTo(), + Value: (*hexutil.Big)(tx.GetValue().ToBig()), + } + if blockHash != (common.Hash{}) { + result.BlockHash = &blockHash + result.BlockNumber = (*hexutil.Big)(new(big.Int).SetUint64(blockNumber)) + result.TransactionIndex = (*hexutil.Uint64)(&index) + } + return result +} + +// newRPCPendingTransaction returns a pending transaction that will serialize to the RPC representation +func newRPCPendingTransaction(tx types.Transaction, current *types.Header, config *params.ChainConfig) *commands.RPCTransaction { + var baseFee *big.Int + if current != nil { + baseFee = misc.CalcBaseFee(config, current) + } + return newRPCTransaction(tx, common.Hash{}, 0, 0, baseFee) +} + +// newRPCRawTransactionFromBlockIndex returns the bytes of a transaction given a block and a transaction index. +func newRPCRawTransactionFromBlockIndex(b *types.Block, index uint64) (hexutil.Bytes, error) { + txs := b.Transactions() + if index >= uint64(len(txs)) { + return nil, nil + } + var buf bytes.Buffer + err := txs[index].MarshalBinary(&buf) + return buf.Bytes(), err +} diff --git a/cmd/rpcdaemon/commands/utils_eth_call.go b/cmd/rpcdaemon/commands/utils_eth_call.go new file mode 100644 index 0000000..f4a1b50 --- /dev/null +++ b/cmd/rpcdaemon/commands/utils_eth_call.go @@ -0,0 +1,66 @@ +package commands + +import ( + "context" + + "github.com/ledgerwatch/erigon-lib/kv" + + "github.com/ledgerwatch/erigon/common" + "github.com/ledgerwatch/erigon/common/hexutil" + "github.com/ledgerwatch/erigon/core/types" + "github.com/ledgerwatch/erigon/params" + "github.com/ledgerwatch/erigon/rpc" + "github.com/ledgerwatch/erigon/turbo/rpchelper" +) + +// headerByNumberOrHash - intent to read recent headers only +func headerByNumberOrHash(ctx context.Context, tx kv.Tx, blockNrOrHash rpc.BlockNumberOrHash, api *BaseAPIUtils) (*types.Header, error) { + blockNum, _, _, err := rpchelper.GetBlockNumber(blockNrOrHash, tx, api.filters) + if err != nil { + return nil, err + } + header, err := api._blockReader.HeaderByNumber(ctx, tx, blockNum) + if err != nil { + return nil, err + } + // header can be nil + return header, nil +} + +// accessListResult returns an optional accesslist +// Its the result of the `eth_createAccessList` RPC call. +// It contains an error if the transaction itself failed. +type accessListResult struct { + Accesslist *types.AccessList `json:"accessList"` + Error string `json:"error,omitempty"` + GasUsed hexutil.Uint64 `json:"gasUsed"` +} + +// to address is warm already, so we can save by adding it to the access list +// only if we are adding a lot of its storage slots as well +func optimizeToInAccessList(accessList *accessListResult, to common.Address) { + indexToRemove := -1 + + for i := 0; i < len(*accessList.Accesslist); i++ { + entry := (*accessList.Accesslist)[i] + if entry.Address != to { + continue + } + + // https://eips.ethereum.org/EIPS/eip-2930#charging-less-for-accesses-in-the-access-list + accessListSavingPerSlot := params.ColdSloadCostEIP2929 - params.WarmStorageReadCostEIP2929 - params.TxAccessListStorageKeyGas + + numSlots := uint64(len(entry.StorageKeys)) + if numSlots*accessListSavingPerSlot <= params.TxAccessListAddressGas { + indexToRemove = i + } + } + + if indexToRemove >= 0 { + *accessList.Accesslist = removeIndex(*accessList.Accesslist, indexToRemove) + } +} + +func removeIndex(s types.AccessList, index int) types.AccessList { + return append(s[:index], s[index+1:]...) +} diff --git a/cmd/rpcdaemon/commands/utils_eth_receipts.go b/cmd/rpcdaemon/commands/utils_eth_receipts.go new file mode 100644 index 0000000..38e2acf --- /dev/null +++ b/cmd/rpcdaemon/commands/utils_eth_receipts.go @@ -0,0 +1,112 @@ +package commands + +import ( + "context" + "math/big" + + "github.com/holiman/uint256" + "github.com/ledgerwatch/erigon-lib/kv" + "github.com/ledgerwatch/erigon/common" + "github.com/ledgerwatch/erigon/common/hexutil" + "github.com/ledgerwatch/erigon/consensus/ethash" + "github.com/ledgerwatch/erigon/core" + "github.com/ledgerwatch/erigon/core/rawdb" + "github.com/ledgerwatch/erigon/core/state" + "github.com/ledgerwatch/erigon/core/types" + "github.com/ledgerwatch/erigon/core/vm" + "github.com/ledgerwatch/erigon/params" + "github.com/ledgerwatch/erigon/turbo/transactions" + "github.com/ledgerwatch/log/v3" +) + +func (api *BaseAPIUtils) getReceipts(ctx context.Context, tx kv.Tx, chainConfig *params.ChainConfig, block *types.Block, senders []common.Address) (types.Receipts, error) { + if cached := rawdb.ReadReceipts(tx, block, senders); cached != nil { + return cached, nil + } + + getHeader := func(hash common.Hash, number uint64) *types.Header { + h, e := api._blockReader.Header(ctx, tx, hash, number) + if e != nil { + log.Error("getHeader error", "number", number, "hash", hash, "err", e) + } + return h + } + _, _, _, ibs, _, err := transactions.ComputeTxEnv(ctx, block, chainConfig, getHeader, ethash.NewFaker(), tx, block.Hash(), 0) + if err != nil { + return nil, err + } + + usedGas := new(uint64) + gp := new(core.GasPool).AddGas(block.GasLimit()) + + ethashFaker := ethash.NewFaker() + noopWriter := state.NewNoopWriter() + + receipts := make(types.Receipts, len(block.Transactions())) + + for i, txn := range block.Transactions() { + ibs.Prepare(txn.Hash(), block.Hash(), i) + header := block.Header() + receipt, _, err := core.ApplyTransaction(chainConfig, core.GetHashFn(header, getHeader), ethashFaker, nil, gp, ibs, noopWriter, header, txn, usedGas, vm.Config{}) + if err != nil { + return nil, err + } + receipt.BlockHash = block.Hash() + receipts[i] = receipt + } + + return receipts, nil +} + +func marshalReceipt(receipt *types.Receipt, txn types.Transaction, chainConfig *params.ChainConfig, block *types.Block, txnHash common.Hash, signed bool) map[string]interface{} { + var chainId *big.Int + switch t := txn.(type) { + case *types.LegacyTx: + if t.Protected() { + chainId = types.DeriveChainId(&t.V).ToBig() + } + case *types.AccessListTx: + chainId = t.ChainID.ToBig() + case *types.DynamicFeeTransaction: + chainId = t.ChainID.ToBig() + } + + var from common.Address + if signed { + signer := types.LatestSignerForChainID(chainId) + from, _ = txn.Sender(*signer) + } + + fields := map[string]interface{}{ + "blockHash": receipt.BlockHash, + "blockNumber": hexutil.Uint64(receipt.BlockNumber.Uint64()), + "transactionHash": txnHash, + "transactionIndex": hexutil.Uint64(receipt.TransactionIndex), + "from": from, + "to": txn.GetTo(), + "type": hexutil.Uint(txn.Type()), + "gasUsed": hexutil.Uint64(receipt.GasUsed), + "cumulativeGasUsed": hexutil.Uint64(receipt.CumulativeGasUsed), + "contractAddress": nil, + "logs": receipt.Logs, + "logsBloom": types.CreateBloom(types.Receipts{receipt}), + } + + if !chainConfig.IsLondon(block.NumberU64()) { + fields["effectiveGasPrice"] = hexutil.Uint64(txn.GetPrice().Uint64()) + } else { + baseFee, _ := uint256.FromBig(block.BaseFee()) + gasPrice := new(big.Int).Add(block.BaseFee(), txn.GetEffectiveGasTip(baseFee).ToBig()) + fields["effectiveGasPrice"] = hexutil.Uint64(gasPrice.Uint64()) + } + // Assign receipt status. + fields["status"] = hexutil.Uint64(receipt.Status) + if receipt.Logs == nil { + fields["logs"] = [][]*types.Log{} + } + // If the ContractAddress is 20 0x0 bytes, assume it is not a contract creation + if receipt.ContractAddress != (common.Address{}) { + fields["contractAddress"] = receipt.ContractAddress + } + return fields +} diff --git a/cmd/rpcdaemon/commands/utils_storage_range.go b/cmd/rpcdaemon/commands/utils_storage_range.go new file mode 100644 index 0000000..141be61 --- /dev/null +++ b/cmd/rpcdaemon/commands/utils_storage_range.go @@ -0,0 +1,42 @@ +package commands + +import ( + "fmt" + + "github.com/holiman/uint256" + "github.com/ledgerwatch/erigon/common" + "github.com/ledgerwatch/erigon/core/state" +) + +// StorageRangeResult is the result of a debug_storageRangeAt API call. +type StorageRangeResult struct { + Storage StorageMap `json:"storage"` + NextKey *common.Hash `json:"nextKey"` // nil if Storage includes the last key in the trie. +} + +// StorageMap a map from storage locations to StorageEntry items +type StorageMap map[common.Hash]StorageEntry + +// StorageEntry an entry in storage of the account +type StorageEntry struct { + Key *common.Hash `json:"key"` + Value common.Hash `json:"value"` +} + +func StorageRangeAt(stateReader *state.PlainState, contractAddress common.Address, start []byte, maxResult int) (StorageRangeResult, error) { + result := StorageRangeResult{Storage: StorageMap{}} + resultCount := 0 + + if err := stateReader.ForEachStorage(contractAddress, common.BytesToHash(start), func(key, seckey common.Hash, value uint256.Int) bool { + if resultCount < maxResult { + result.Storage[seckey] = StorageEntry{Key: &key, Value: value.Bytes32()} + } else { + result.NextKey = &key + } + resultCount++ + return resultCount <= maxResult + }, maxResult+1); err != nil { + return StorageRangeResult{}, fmt.Errorf("error walking over storage: %w", err) + } + return result, nil +} diff --git a/cmd/rpcdaemon/health/check_block.go b/cmd/rpcdaemon/health/check_block.go new file mode 100644 index 0000000..8978b6f --- /dev/null +++ b/cmd/rpcdaemon/health/check_block.go @@ -0,0 +1,23 @@ +package health + +import ( + "context" + "fmt" + + "github.com/ledgerwatch/erigon/rpc" +) + +func checkBlockNumber(blockNumber rpc.BlockNumber, api EthAPI) error { + if api == nil { + return fmt.Errorf("no connection to the Erigon server or `eth` namespace isn't enabled") + } + data, err := api.GetBlockByNumber(context.TODO(), blockNumber, false) + if err != nil { + return err + } + if len(data) == 0 { // block not found + return fmt.Errorf("no known block with number %v (%x hex)", blockNumber, blockNumber) + } + + return nil +} diff --git a/cmd/rpcdaemon/health/check_peers.go b/cmd/rpcdaemon/health/check_peers.go new file mode 100644 index 0000000..4e55a59 --- /dev/null +++ b/cmd/rpcdaemon/health/check_peers.go @@ -0,0 +1,28 @@ +package health + +import ( + "context" + "errors" + "fmt" +) + +var ( + errNotEnoughPeers = errors.New("not enough peers") +) + +func checkMinPeers(minPeerCount uint, api NetAPI) error { + if api == nil { + return fmt.Errorf("no connection to the Erigon server or `net` namespace isn't enabled") + } + + peerCount, err := api.PeerCount(context.TODO()) + if err != nil { + return err + } + + if uint64(peerCount) < uint64(minPeerCount) { + return fmt.Errorf("%w: %d (minimum %d)", errNotEnoughPeers, peerCount, minPeerCount) + } + + return nil +} diff --git a/cmd/rpcdaemon/health/check_synced.go b/cmd/rpcdaemon/health/check_synced.go new file mode 100644 index 0000000..af39a22 --- /dev/null +++ b/cmd/rpcdaemon/health/check_synced.go @@ -0,0 +1,25 @@ +package health + +import ( + "errors" + "net/http" + + "github.com/ledgerwatch/log/v3" +) + +var ( + errNotSynced = errors.New("not synced") +) + +func checkSynced(ethAPI EthAPI, r *http.Request) error { + i, err := ethAPI.Syncing(r.Context()) + if err != nil { + log.Root().Warn("unable to process synced request", "err", err.Error()) + return err + } + if i == nil || i == false { + return nil + } + + return errNotSynced +} diff --git a/cmd/rpcdaemon/health/check_time.go b/cmd/rpcdaemon/health/check_time.go new file mode 100644 index 0000000..d604521 --- /dev/null +++ b/cmd/rpcdaemon/health/check_time.go @@ -0,0 +1,35 @@ +package health + +import ( + "errors" + "fmt" + "net/http" + + "github.com/ledgerwatch/erigon/rpc" +) + +var ( + errTimestampTooOld = errors.New("timestamp too old") +) + +func checkTime( + r *http.Request, + seconds int, + ethAPI EthAPI, +) error { + i, err := ethAPI.GetBlockByNumber(r.Context(), rpc.LatestBlockNumber, false) + if err != nil { + return err + } + timestamp := 0 + if ts, ok := i["timestamp"]; ok { + if cs, ok := ts.(uint64); ok { + timestamp = int(cs) + } + } + if timestamp > seconds { + return fmt.Errorf("%w: got ts: %d, need: %d", errTimestampTooOld, timestamp, seconds) + } + + return nil +} diff --git a/cmd/rpcdaemon/health/health.go b/cmd/rpcdaemon/health/health.go new file mode 100644 index 0000000..f99ecac --- /dev/null +++ b/cmd/rpcdaemon/health/health.go @@ -0,0 +1,227 @@ +package health + +import ( + "encoding/json" + "errors" + "fmt" + "io" + "net/http" + "strconv" + "strings" + "time" + + "github.com/ledgerwatch/log/v3" + + "github.com/ledgerwatch/erigon/rpc" +) + +type requestBody struct { + MinPeerCount *uint `json:"min_peer_count"` + BlockNumber *rpc.BlockNumber `json:"known_block"` +} + +const ( + urlPath = "/health" + healthHeader = "X-ERIGON-HEALTHCHECK" + synced = "synced" + minPeerCount = "min_peer_count" + checkBlock = "check_block" + maxSecondsBehind = "max_seconds_behind" +) + +var ( + errCheckDisabled = errors.New("error check disabled") + errBadHeaderValue = errors.New("bad header value") +) + +func ProcessHealthcheckIfNeeded( + w http.ResponseWriter, + r *http.Request, + rpcAPI []rpc.API, +) bool { + if !strings.EqualFold(r.URL.Path, urlPath) { + return false + } + + netAPI, ethAPI := parseAPI(rpcAPI) + + headers := r.Header.Values(healthHeader) + if len(headers) != 0 { + processFromHeaders(headers, ethAPI, netAPI, w, r) + } else { + processFromBody(w, r, netAPI, ethAPI) + } + + return true +} + +func processFromHeaders(headers []string, ethAPI EthAPI, netAPI NetAPI, w http.ResponseWriter, r *http.Request) { + var ( + errCheckSynced = errCheckDisabled + errCheckPeer = errCheckDisabled + errCheckBlock = errCheckDisabled + errCheckSeconds = errCheckDisabled + ) + + for _, header := range headers { + lHeader := strings.ToLower(header) + if lHeader == synced { + errCheckSynced = checkSynced(ethAPI, r) + } + if strings.HasPrefix(lHeader, minPeerCount) { + peers, err := strconv.Atoi(strings.TrimPrefix(lHeader, minPeerCount)) + if err != nil { + errCheckPeer = err + break + } + errCheckPeer = checkMinPeers(uint(peers), netAPI) + } + if strings.HasPrefix(lHeader, checkBlock) { + block, err := strconv.Atoi(strings.TrimPrefix(lHeader, checkBlock)) + if err != nil { + errCheckBlock = err + break + } + errCheckBlock = checkBlockNumber(rpc.BlockNumber(block), ethAPI) + } + if strings.HasPrefix(lHeader, maxSecondsBehind) { + seconds, err := strconv.Atoi(strings.TrimPrefix(lHeader, maxSecondsBehind)) + if err != nil { + errCheckSeconds = err + break + } + if seconds < 0 { + errCheckSeconds = errBadHeaderValue + break + } + now := time.Now().Unix() + errCheckSeconds = checkTime(r, int(now)-seconds, ethAPI) + } + } + + reportHealthFromHeaders(errCheckSynced, errCheckPeer, errCheckBlock, errCheckSeconds, w) +} + +func processFromBody(w http.ResponseWriter, r *http.Request, netAPI NetAPI, ethAPI EthAPI) { + body, errParse := parseHealthCheckBody(r.Body) + defer r.Body.Close() + + var errMinPeerCount = errCheckDisabled + var errCheckBlock = errCheckDisabled + + if errParse != nil { + log.Root().Warn("unable to process healthcheck request", "err", errParse) + } else { + // 1. net_peerCount + if body.MinPeerCount != nil { + errMinPeerCount = checkMinPeers(*body.MinPeerCount, netAPI) + } + // 2. custom query (shouldn't fail) + if body.BlockNumber != nil { + errCheckBlock = checkBlockNumber(*body.BlockNumber, ethAPI) + } + // TODO add time from the last sync cycle + } + + err := reportHealthFromBody(errParse, errMinPeerCount, errCheckBlock, w) + if err != nil { + log.Root().Warn("unable to process healthcheck request", "err", err) + } +} + +func parseHealthCheckBody(reader io.Reader) (requestBody, error) { + var body requestBody + + bodyBytes, err := io.ReadAll(reader) + if err != nil { + return body, err + } + + err = json.Unmarshal(bodyBytes, &body) + if err != nil { + return body, err + } + + return body, nil +} + +func reportHealthFromBody(errParse, errMinPeerCount, errCheckBlock error, w http.ResponseWriter) error { + statusCode := http.StatusOK + errors := make(map[string]string) + + if shouldChangeStatusCode(errParse) { + statusCode = http.StatusInternalServerError + } + errors["healthcheck_query"] = errorStringOrOK(errParse) + + if shouldChangeStatusCode(errMinPeerCount) { + statusCode = http.StatusInternalServerError + } + errors["min_peer_count"] = errorStringOrOK(errMinPeerCount) + + if shouldChangeStatusCode(errCheckBlock) { + statusCode = http.StatusInternalServerError + } + errors["check_block"] = errorStringOrOK(errCheckBlock) + + return writeResponse(w, errors, statusCode) +} + +func reportHealthFromHeaders(errCheckSynced, errCheckPeer, errCheckBlock, errCheckSeconds error, w http.ResponseWriter) error { + statusCode := http.StatusOK + errs := make(map[string]string) + + if shouldChangeStatusCode(errCheckSynced) { + statusCode = http.StatusInternalServerError + } + errs[synced] = errorStringOrOK(errCheckSynced) + + if shouldChangeStatusCode(errCheckPeer) { + statusCode = http.StatusInternalServerError + } + errs[minPeerCount] = errorStringOrOK(errCheckPeer) + + if shouldChangeStatusCode(errCheckBlock) { + statusCode = http.StatusInternalServerError + } + errs[checkBlock] = errorStringOrOK(errCheckBlock) + + if shouldChangeStatusCode(errCheckSeconds) { + statusCode = http.StatusInternalServerError + } + errs[maxSecondsBehind] = errorStringOrOK(errCheckSeconds) + + return writeResponse(w, errs, statusCode) +} + +func writeResponse(w http.ResponseWriter, errs map[string]string, statusCode int) error { + w.WriteHeader(statusCode) + + bodyJson, err := json.Marshal(errs) + if err != nil { + return err + } + + _, err = w.Write(bodyJson) + if err != nil { + return err + } + + return nil +} + +func shouldChangeStatusCode(err error) bool { + return err != nil && !errors.Is(err, errCheckDisabled) +} + +func errorStringOrOK(err error) string { + if err == nil { + return "HEALTHY" + } + + if errors.Is(err, errCheckDisabled) { + return "DISABLED" + } + + return fmt.Sprintf("ERROR: %v", err) +} diff --git a/cmd/rpcdaemon/health/health_test.go b/cmd/rpcdaemon/health/health_test.go new file mode 100644 index 0000000..39c71c9 --- /dev/null +++ b/cmd/rpcdaemon/health/health_test.go @@ -0,0 +1,562 @@ +package health + +import ( + "context" + "encoding/json" + "errors" + "io" + "net/http" + "net/http/httptest" + "strings" + "testing" + "time" + + "github.com/ledgerwatch/erigon/common/hexutil" + "github.com/ledgerwatch/erigon/rpc" +) + +type netApiStub struct { + response hexutil.Uint + error error +} + +func (n *netApiStub) PeerCount(_ context.Context) (hexutil.Uint, error) { + return n.response, n.error +} + +type ethApiStub struct { + blockResult map[string]interface{} + blockError error + syncingResult interface{} + syncingError error +} + +func (e *ethApiStub) GetBlockByNumber(_ context.Context, _ rpc.BlockNumber, _ bool) (map[string]interface{}, error) { + return e.blockResult, e.blockError +} + +func (e *ethApiStub) Syncing(_ context.Context) (interface{}, error) { + return e.syncingResult, e.syncingError +} + +func TestProcessHealthcheckIfNeeded_HeadersTests(t *testing.T) { + cases := []struct { + headers []string + netApiResponse hexutil.Uint + netApiError error + ethApiBlockResult map[string]interface{} + ethApiBlockError error + ethApiSyncingResult interface{} + ethApiSyncingError error + expectedStatusCode int + expectedBody map[string]string + }{ + // 0 - sync check enabled - syncing + { + headers: []string{"synced"}, + netApiResponse: hexutil.Uint(1), + netApiError: nil, + ethApiBlockResult: make(map[string]interface{}), + ethApiBlockError: nil, + ethApiSyncingResult: false, + ethApiSyncingError: nil, + expectedStatusCode: http.StatusOK, + expectedBody: map[string]string{ + synced: "HEALTHY", + minPeerCount: "DISABLED", + checkBlock: "DISABLED", + maxSecondsBehind: "DISABLED", + }, + }, + // 1 - sync check enabled - not syncing + { + headers: []string{"synced"}, + netApiResponse: hexutil.Uint(1), + netApiError: nil, + ethApiBlockResult: make(map[string]interface{}), + ethApiBlockError: nil, + ethApiSyncingResult: struct{}{}, + ethApiSyncingError: nil, + expectedStatusCode: http.StatusInternalServerError, + expectedBody: map[string]string{ + synced: "ERROR: not synced", + minPeerCount: "DISABLED", + checkBlock: "DISABLED", + maxSecondsBehind: "DISABLED", + }, + }, + // 2 - sync check enabled - error checking sync + { + headers: []string{"synced"}, + netApiResponse: hexutil.Uint(1), + netApiError: nil, + ethApiBlockResult: make(map[string]interface{}), + ethApiBlockError: nil, + ethApiSyncingResult: struct{}{}, + ethApiSyncingError: errors.New("problem checking sync"), + expectedStatusCode: http.StatusInternalServerError, + expectedBody: map[string]string{ + synced: "ERROR: problem checking sync", + minPeerCount: "DISABLED", + checkBlock: "DISABLED", + maxSecondsBehind: "DISABLED", + }, + }, + // 3 - peer count enabled - good request + { + headers: []string{"min_peer_count1"}, + netApiResponse: hexutil.Uint(1), + netApiError: nil, + ethApiBlockResult: make(map[string]interface{}), + ethApiBlockError: nil, + ethApiSyncingResult: false, + ethApiSyncingError: nil, + expectedStatusCode: http.StatusOK, + expectedBody: map[string]string{ + synced: "DISABLED", + minPeerCount: "HEALTHY", + checkBlock: "DISABLED", + maxSecondsBehind: "DISABLED", + }, + }, + // 4 - peer count enabled - not enough peers + { + headers: []string{"min_peer_count10"}, + netApiResponse: hexutil.Uint(1), + netApiError: nil, + ethApiBlockResult: make(map[string]interface{}), + ethApiBlockError: nil, + ethApiSyncingResult: false, + ethApiSyncingError: nil, + expectedStatusCode: http.StatusInternalServerError, + expectedBody: map[string]string{ + synced: "DISABLED", + minPeerCount: "ERROR: not enough peers: 1 (minimum 10)", + checkBlock: "DISABLED", + maxSecondsBehind: "DISABLED", + }, + }, + // 5 - peer count enabled - error checking peers + { + headers: []string{"min_peer_count10"}, + netApiResponse: hexutil.Uint(1), + netApiError: errors.New("problem checking peers"), + ethApiBlockResult: make(map[string]interface{}), + ethApiBlockError: nil, + ethApiSyncingResult: false, + ethApiSyncingError: nil, + expectedStatusCode: http.StatusInternalServerError, + expectedBody: map[string]string{ + synced: "DISABLED", + minPeerCount: "ERROR: problem checking peers", + checkBlock: "DISABLED", + maxSecondsBehind: "DISABLED", + }, + }, + // 6 - peer count enabled - badly formed request + { + headers: []string{"min_peer_countABC"}, + netApiResponse: hexutil.Uint(1), + netApiError: nil, + ethApiBlockResult: make(map[string]interface{}), + ethApiBlockError: nil, + ethApiSyncingResult: false, + ethApiSyncingError: nil, + expectedStatusCode: http.StatusInternalServerError, + expectedBody: map[string]string{ + synced: "DISABLED", + minPeerCount: "ERROR: strconv.Atoi: parsing \"abc\": invalid syntax", + checkBlock: "DISABLED", + maxSecondsBehind: "DISABLED", + }, + }, + // 7 - block check - all ok + { + headers: []string{"check_block10"}, + netApiResponse: hexutil.Uint(1), + netApiError: nil, + ethApiBlockResult: map[string]interface{}{"test": struct{}{}}, + ethApiBlockError: nil, + ethApiSyncingResult: false, + ethApiSyncingError: nil, + expectedStatusCode: http.StatusOK, + expectedBody: map[string]string{ + synced: "DISABLED", + minPeerCount: "DISABLED", + checkBlock: "HEALTHY", + maxSecondsBehind: "DISABLED", + }, + }, + // 8 - block check - no block found + { + headers: []string{"check_block10"}, + netApiResponse: hexutil.Uint(1), + netApiError: nil, + ethApiBlockResult: map[string]interface{}{}, + ethApiBlockError: nil, + ethApiSyncingResult: false, + ethApiSyncingError: nil, + expectedStatusCode: http.StatusInternalServerError, + expectedBody: map[string]string{ + synced: "DISABLED", + minPeerCount: "DISABLED", + checkBlock: "ERROR: no known block with number 10 (a hex)", + maxSecondsBehind: "DISABLED", + }, + }, + // 9 - block check - error checking block + { + headers: []string{"check_block10"}, + netApiResponse: hexutil.Uint(1), + netApiError: nil, + ethApiBlockResult: map[string]interface{}{}, + ethApiBlockError: errors.New("problem checking block"), + ethApiSyncingResult: false, + ethApiSyncingError: nil, + expectedStatusCode: http.StatusInternalServerError, + expectedBody: map[string]string{ + synced: "DISABLED", + minPeerCount: "DISABLED", + checkBlock: "ERROR: problem checking block", + maxSecondsBehind: "DISABLED", + }, + }, + // 10 - block check - badly formed request + { + headers: []string{"check_blockABC"}, + netApiResponse: hexutil.Uint(1), + netApiError: nil, + ethApiBlockResult: map[string]interface{}{}, + ethApiBlockError: nil, + ethApiSyncingResult: false, + ethApiSyncingError: nil, + expectedStatusCode: http.StatusInternalServerError, + expectedBody: map[string]string{ + synced: "DISABLED", + minPeerCount: "DISABLED", + checkBlock: "ERROR: strconv.Atoi: parsing \"abc\": invalid syntax", + maxSecondsBehind: "DISABLED", + }, + }, + // 11 - seconds check - all ok + { + headers: []string{"max_seconds_behind60"}, + netApiResponse: hexutil.Uint(1), + netApiError: nil, + ethApiBlockResult: map[string]interface{}{ + "timestamp": time.Now().Add(1 * time.Second).Unix(), + }, + ethApiBlockError: nil, + ethApiSyncingResult: false, + ethApiSyncingError: nil, + expectedStatusCode: http.StatusOK, + expectedBody: map[string]string{ + synced: "DISABLED", + minPeerCount: "DISABLED", + checkBlock: "DISABLED", + maxSecondsBehind: "HEALTHY", + }, + }, + // 12 - seconds check - too old + { + headers: []string{"max_seconds_behind60"}, + netApiResponse: hexutil.Uint(1), + netApiError: nil, + ethApiBlockResult: map[string]interface{}{ + "timestamp": uint64(time.Now().Add(1 * time.Hour).Unix()), + }, + ethApiBlockError: nil, + ethApiSyncingResult: false, + ethApiSyncingError: nil, + expectedStatusCode: http.StatusInternalServerError, + expectedBody: map[string]string{ + synced: "DISABLED", + minPeerCount: "DISABLED", + checkBlock: "DISABLED", + maxSecondsBehind: "ERROR: timestamp too old: got ts:", + }, + }, + // 13 - seconds check - less than 0 seconds + { + headers: []string{"max_seconds_behind-1"}, + netApiResponse: hexutil.Uint(1), + netApiError: nil, + ethApiBlockResult: map[string]interface{}{ + "timestamp": uint64(time.Now().Add(1 * time.Hour).Unix()), + }, + ethApiBlockError: nil, + ethApiSyncingResult: false, + ethApiSyncingError: nil, + expectedStatusCode: http.StatusInternalServerError, + expectedBody: map[string]string{ + synced: "DISABLED", + minPeerCount: "DISABLED", + checkBlock: "DISABLED", + maxSecondsBehind: "ERROR: bad header value", + }, + }, + // 14 - seconds check - badly formed request + { + headers: []string{"max_seconds_behindABC"}, + netApiResponse: hexutil.Uint(1), + netApiError: nil, + ethApiBlockResult: map[string]interface{}{}, + ethApiBlockError: nil, + ethApiSyncingResult: false, + ethApiSyncingError: nil, + expectedStatusCode: http.StatusInternalServerError, + expectedBody: map[string]string{ + synced: "DISABLED", + minPeerCount: "DISABLED", + checkBlock: "DISABLED", + maxSecondsBehind: "ERROR: strconv.Atoi: parsing \"abc\": invalid syntax", + }, + }, + // 15 - all checks - report ok + { + headers: []string{"synced", "check_block10", "min_peer_count1", "max_seconds_behind60"}, + netApiResponse: hexutil.Uint(10), + netApiError: nil, + ethApiBlockResult: map[string]interface{}{ + "timestamp": time.Now().Add(1 * time.Second).Unix(), + }, + ethApiBlockError: nil, + ethApiSyncingResult: false, + ethApiSyncingError: nil, + expectedStatusCode: http.StatusOK, + expectedBody: map[string]string{ + synced: "HEALTHY", + minPeerCount: "HEALTHY", + checkBlock: "HEALTHY", + maxSecondsBehind: "HEALTHY", + }, + }, + } + + for idx, c := range cases { + w := httptest.NewRecorder() + r, err := http.NewRequest(http.MethodGet, "http://localhost:9090/health", nil) + if err != nil { + t.Errorf("%v: creating request: %v", idx, err) + } + + for _, header := range c.headers { + r.Header.Add("X-ERIGON-HEALTHCHECK", header) + } + + netAPI := rpc.API{ + Namespace: "", + Version: "", + Service: &netApiStub{ + response: c.netApiResponse, + error: c.netApiError, + }, + Public: false, + } + + ethAPI := rpc.API{ + Namespace: "", + Version: "", + Service: ðApiStub{ + blockResult: c.ethApiBlockResult, + blockError: c.ethApiBlockError, + syncingResult: c.ethApiSyncingResult, + syncingError: c.ethApiSyncingError, + }, + Public: false, + } + + apis := make([]rpc.API, 2) + apis[0] = netAPI + apis[1] = ethAPI + + ProcessHealthcheckIfNeeded(w, r, apis) + + result := w.Result() + if result.StatusCode != c.expectedStatusCode { + t.Errorf("%v: expected status code: %v, but got: %v", idx, c.expectedStatusCode, result.StatusCode) + } + + bodyBytes, err := io.ReadAll(result.Body) + if err != nil { + t.Errorf("%v: reading response body: %s", idx, err) + } + + var body map[string]string + err = json.Unmarshal(bodyBytes, &body) + if err != nil { + t.Errorf("%v: unmarshalling the response body: %s", idx, err) + } + result.Body.Close() + + for k, v := range c.expectedBody { + val, found := body[k] + if !found { + t.Errorf("%v: expected the key: %s to be in the response body but it wasn't there", idx, k) + } + if !strings.Contains(val, v) { + t.Errorf("%v: expected the response body key: %s to contain: %s, but it contained: %s", idx, k, v, val) + } + } + } +} + +func TestProcessHealthcheckIfNeeded_RequestBody(t *testing.T) { + cases := []struct { + body string + netApiResponse hexutil.Uint + netApiError error + ethApiBlockResult map[string]interface{} + ethApiBlockError error + expectedStatusCode int + expectedBody map[string]string + }{ + // 0 - happy path + { + body: "{\"min_peer_count\": 1, \"known_block\": 123}", + netApiResponse: hexutil.Uint(1), + netApiError: nil, + ethApiBlockResult: map[string]interface{}{"test": struct{}{}}, + ethApiBlockError: nil, + expectedStatusCode: http.StatusOK, + expectedBody: map[string]string{ + "healthcheck_query": "HEALTHY", + "min_peer_count": "HEALTHY", + "check_block": "HEALTHY", + }, + }, + // 1 - bad request body + { + body: "{\"min_peer_count\" 1, \"known_block\": 123}", + netApiResponse: hexutil.Uint(1), + netApiError: nil, + ethApiBlockResult: map[string]interface{}{"test": struct{}{}}, + ethApiBlockError: nil, + expectedStatusCode: http.StatusInternalServerError, + expectedBody: map[string]string{ + "healthcheck_query": "ERROR:", + "min_peer_count": "DISABLED", + "check_block": "DISABLED", + }, + }, + // 2 - min peers - error from api + { + body: "{\"min_peer_count\": 1, \"known_block\": 123}", + netApiResponse: hexutil.Uint(1), + netApiError: errors.New("problem getting peers"), + ethApiBlockResult: map[string]interface{}{"test": struct{}{}}, + ethApiBlockError: nil, + expectedStatusCode: http.StatusInternalServerError, + expectedBody: map[string]string{ + "healthcheck_query": "HEALTHY", + "min_peer_count": "ERROR: problem getting peers", + "check_block": "HEALTHY", + }, + }, + // 3 - min peers - not enough peers + { + body: "{\"min_peer_count\": 10, \"known_block\": 123}", + netApiResponse: hexutil.Uint(1), + netApiError: nil, + ethApiBlockResult: map[string]interface{}{"test": struct{}{}}, + ethApiBlockError: nil, + expectedStatusCode: http.StatusInternalServerError, + expectedBody: map[string]string{ + "healthcheck_query": "HEALTHY", + "min_peer_count": "ERROR: not enough peers", + "check_block": "HEALTHY", + }, + }, + // 4 - check block - no block + { + body: "{\"min_peer_count\": 1, \"known_block\": 123}", + netApiResponse: hexutil.Uint(1), + netApiError: nil, + ethApiBlockResult: map[string]interface{}{}, + ethApiBlockError: nil, + expectedStatusCode: http.StatusInternalServerError, + expectedBody: map[string]string{ + "healthcheck_query": "HEALTHY", + "min_peer_count": "HEALTHY", + "check_block": "ERROR: no known block with number ", + }, + }, + // 5 - check block - error getting block info + { + body: "{\"min_peer_count\": 1, \"known_block\": 123}", + netApiResponse: hexutil.Uint(1), + netApiError: nil, + ethApiBlockResult: map[string]interface{}{}, + ethApiBlockError: errors.New("problem getting block"), + expectedStatusCode: http.StatusInternalServerError, + expectedBody: map[string]string{ + "healthcheck_query": "HEALTHY", + "min_peer_count": "HEALTHY", + "check_block": "ERROR: problem getting block", + }, + }, + } + + for idx, c := range cases { + w := httptest.NewRecorder() + r, err := http.NewRequest(http.MethodGet, "http://localhost:9090/health", nil) + if err != nil { + t.Errorf("%v: creating request: %v", idx, err) + } + + r.Body = io.NopCloser(strings.NewReader(c.body)) + + netAPI := rpc.API{ + Namespace: "", + Version: "", + Service: &netApiStub{ + response: c.netApiResponse, + error: c.netApiError, + }, + Public: false, + } + + ethAPI := rpc.API{ + Namespace: "", + Version: "", + Service: ðApiStub{ + blockResult: c.ethApiBlockResult, + blockError: c.ethApiBlockError, + }, + Public: false, + } + + apis := make([]rpc.API, 2) + apis[0] = netAPI + apis[1] = ethAPI + + ProcessHealthcheckIfNeeded(w, r, apis) + + result := w.Result() + if result.StatusCode != c.expectedStatusCode { + t.Errorf("%v: expected status code: %v, but got: %v", idx, c.expectedStatusCode, result.StatusCode) + } + + bodyBytes, err := io.ReadAll(result.Body) + if err != nil { + t.Errorf("%v: reading response body: %s", idx, err) + } + + var body map[string]string + err = json.Unmarshal(bodyBytes, &body) + if err != nil { + t.Errorf("%v: unmarshalling the response body: %s", idx, err) + } + result.Body.Close() + + for k, v := range c.expectedBody { + val, found := body[k] + if !found { + t.Errorf("%v: expected the key: %s to be in the response body but it wasn't there", idx, k) + } + if !strings.Contains(val, v) { + t.Errorf("%v: expected the response body key: %s to contain: %s, but it contained: %s", idx, k, v, val) + } + } + } +} diff --git a/cmd/rpcdaemon/health/interfaces.go b/cmd/rpcdaemon/health/interfaces.go new file mode 100644 index 0000000..c8bdca5 --- /dev/null +++ b/cmd/rpcdaemon/health/interfaces.go @@ -0,0 +1,17 @@ +package health + +import ( + "context" + + "github.com/ledgerwatch/erigon/common/hexutil" + "github.com/ledgerwatch/erigon/rpc" +) + +type NetAPI interface { + PeerCount(_ context.Context) (hexutil.Uint, error) +} + +type EthAPI interface { + GetBlockByNumber(_ context.Context, number rpc.BlockNumber, fullTx bool) (map[string]interface{}, error) + Syncing(ctx context.Context) (interface{}, error) +} diff --git a/cmd/rpcdaemon/health/parse_api.go b/cmd/rpcdaemon/health/parse_api.go new file mode 100644 index 0000000..21e003e --- /dev/null +++ b/cmd/rpcdaemon/health/parse_api.go @@ -0,0 +1,22 @@ +package health + +import ( + "github.com/ledgerwatch/erigon/rpc" +) + +func parseAPI(api []rpc.API) (netAPI NetAPI, ethAPI EthAPI) { + for _, rpc := range api { + if rpc.Service == nil { + continue + } + + if netCandidate, ok := rpc.Service.(NetAPI); ok { + netAPI = netCandidate + } + + if ethCandidate, ok := rpc.Service.(EthAPI); ok { + ethAPI = ethCandidate + } + } + return netAPI, ethAPI +} diff --git a/cmd/rpcdaemon/main.go b/cmd/rpcdaemon/main.go new file mode 100644 index 0000000..0510168 --- /dev/null +++ b/cmd/rpcdaemon/main.go @@ -0,0 +1,43 @@ +package main + +import ( + "os" + + "github.com/ledgerwatch/erigon-lib/common" + "github.com/ledgerwatch/log/v3" + "github.com/spf13/cobra" + + "github.com/wmitsuda/otterscan/cmd/rpcdaemon/cli" + mycmds "github.com/wmitsuda/otterscan/cmd/rpcdaemon/commands" +) + +func main() { + cmd, cfg := cli.RootCommand() + rootCtx, rootCancel := common.RootContext() + cmd.RunE = func(cmd *cobra.Command, args []string) error { + ctx := cmd.Context() + logger := log.New() + db, borDb, backend, txPool, mining, stateCache, blockReader, ff, agg, err := cli.RemoteServices(ctx, *cfg, logger, rootCancel) + if err != nil { + log.Error("Could not connect to DB", "err", err) + return nil + } + defer db.Close() + if borDb != nil { + defer borDb.Close() + } + + apiList := mycmds.APIList(db, borDb, backend, txPool, mining, ff, stateCache, blockReader, agg, *cfg) + if err := cli.StartRpcServer(ctx, *cfg, apiList, nil); err != nil { + log.Error(err.Error()) + return nil + } + + return nil + } + + if err := cmd.ExecuteContext(rootCtx); err != nil { + log.Error(err.Error()) + os.Exit(1) + } +} diff --git a/cmd/rpcdaemon/postman/README.md b/cmd/rpcdaemon/postman/README.md new file mode 100644 index 0000000..0b9c232 --- /dev/null +++ b/cmd/rpcdaemon/postman/README.md @@ -0,0 +1,18 @@ +# Postman testing + +There are two files here: + +- RPC_Testing.json +- Trace_Testing.json + +You can import them into Postman using these +instructions: https://github.com/ledgerwatch/erigon/wiki/Using-Postman-to-Test-TurboGeth-RPC + +The first one is used to generate help text and other documentation as well as running a sanity check against a new +release. There is basically one test for each of the 81 RPC endpoints. + +The second file contains 31 test cases specifically for the nine trace routines (five tests for five of the routines, +three for another, one each for the other three). + +Another collection of related tests can be found +here: https://github.com/Great-Hill-Corporation/trueblocks-core/tree/develop/src/other/trace_tests diff --git a/cmd/rpcdaemon/postman/RPC_Testing.json b/cmd/rpcdaemon/postman/RPC_Testing.json new file mode 100644 index 0000000..0dce372 --- /dev/null +++ b/cmd/rpcdaemon/postman/RPC_Testing.json @@ -0,0 +1,4235 @@ +{ + "info": { + "_postman_id": "72c52f91-c09d-4af6-abb4-162b9c5532b2", + "name": "RPC_Testing", + "description": "A collection holding all the Ethereum JSON RPC API calls", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" + }, + "item": [ + { + "name": "web3", + "item": [ + { + "name": "clientVersion", + "event": [ + { + "listen": "test", + "script": { + "id": "6c4da7d1-aa83-40f8-bdad-b68cb42415a4", + "exec": [ + "pm.test('Has correct result', function() {", + " const jsonData = pm.response.json();", + " var messages = {", + " '{{NETHERMIND}}': 'Nethermind',", + " '{{ERIGON}}': 'Erigon',", + " '{{SILKRPC}}': 'Erigon',", + " '{{PARITY}}': 'Parity-Ethereum',", + " }", + " var parts = jsonData.result.split('/');", + " pm.expect(parts[0]).to.deep.equals(messages[pm.environment.get('HOST')]);", + "})", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"jsonrpc\": \"2.0\",\n \"method\": \"web3_clientVersion\",\n \"params\": [],\n \"id\": \"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Returns the current client version.\r\n\r\n**Parameters**\r\n\r\nNone\r\n\r\n**Returns**\r\n\r\nSTRING - The current client version string including node name and version" + }, + "response": [] + }, + { + "name": "sha3", + "event": [ + { + "listen": "test", + "script": { + "id": "d8ebbf3d-8ae7-460a-9808-4b4b8a08d289", + "exec": [ + "var expected = {", + " \"jsonrpc\": \"2.0\",", + " \"id\": \"1\",", + " \"result\": \"0x47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad\"", + "}", + "", + "pm.test('Has correct result', function() {", + " pm.expect(pm.response.json()).to.be.deep.equal(expected);", + "})", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "id": "78f0ca53-f4fe-4396-a87a-e1c81899822a", + "exec": [""], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"web3_sha3\",\n\t\"params\":[\"0x68656c6c6f20776f726c64\"],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Returns Keccak-256 (not the standardized SHA3-256) of the given data.\r\n\r\n**Parameters**\r\n\r\nDATA - The data to convert into a SHA3 hash\r\n\r\n**Returns**\r\n\r\nDATA - The SHA3 result of the given input string" + }, + "response": [] + } + ], + "protocolProfileBehavior": {} + }, + { + "name": "net", + "item": [ + { + "name": "listening", + "event": [ + { + "listen": "test", + "script": { + "id": "322f2289-938f-4cfb-adde-3d4f0c54455e", + "exec": [ + "expected = {", + " \"jsonrpc\": \"2.0\",", + " \"id\": \"1\",", + " \"result\": true", + "}", + "", + "pm.test('Returns true (hardcoded)', function() {", + " pm.expect(pm.response.json()).to.be.deep.equal(expected)", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"net_listening\",\n\t\"params\":[],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Returns true if client is actively listening for network connections.\r\n\r\n**TODO**\r\n\r\nThe code currently returns a hard coded true value. Remove hard coded value.\r\n\r\n**Parameters**\r\n\r\nNone\r\n\r\n**Returns**\r\n\r\nBoolean - true when listening, false otherwise" + }, + "response": [] + }, + { + "name": "version", + "event": [ + { + "listen": "test", + "script": { + "id": "a7d33b17-7d1d-49db-b30a-82d8c695c1d4", + "exec": [ + "expected = {", + " \"jsonrpc\": \"2.0\",", + " \"id\": \"1\",", + " \"result\": \"1\"", + "}", + "", + "pm.test('Returns true (hardcoded)', function() {", + " pm.expect(pm.response.json()).to.be.deep.equal(expected)", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"net_version\",\n\t\"params\":[],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Returns the current network id.\r\n\r\n**Parameters**\r\n\r\nNone\r\n\r\n**Returns**\r\n\r\nSTRING - The current network id. One of BR \"1\": Ethereum Mainnet BR \"2\": Morden Testnet (deprecated) BR \"3\": Ropsten Testnet BR \"4\": Rinkeby Testnet BR \"42\": Kovan Testnet BR" + }, + "response": [] + }, + { + "name": "peerCount", + "event": [ + { + "listen": "test", + "script": { + "id": "985b79fb-0c36-421d-8dcf-cc1d619a11e3", + "exec": [ + "expected = {", + " \"jsonrpc\": \"2.0\",", + " \"id\": \"1\",", + " \"result\": \"0x19\"", + "}", + "", + "pm.test('Returns true (hardcoded)', function() {", + " expected.result = pm.response.json().result;", + " pm.expect(pm.response.json()).to.be.deep.equal(expected)", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"net_peerCount\",\n\t\"params\":[],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Returns number of peers currently connected to the client.\r\n\r\n**TODO**\r\n\r\nThis routine currently returns a hard coded value of '25'\r\n\r\n**Parameters**\r\n\r\nNone\r\n\r\n**Returns**\r\n\r\nQUANTITY - Integer of the number of connected peers" + }, + "response": [] + } + ], + "protocolProfileBehavior": {} + }, + { + "name": "eth", + "item": [ + { + "name": "blocks", + "item": [ + { + "name": "getBlockByNumber", + "event": [ + { + "listen": "test", + "script": { + "id": "438e5e99-267a-4a47-92f3-d7a9e675f183", + "exec": [ + "var expected = {", + " \"jsonrpc\": \"2.0\",", + " \"id\": \"1\",", + " \"result\": {", + " \"difficulty\": \"0xb5708d578a6\",", + " \"extraData\": \"0xd783010400844765746887676f312e352e31856c696e7578\",", + " \"gasLimit\": \"0x2fefd8\",", + " \"gasUsed\": \"0x14820\",", + " \"hash\": \"0x0b4c6fb75ded4b90218cf0346b0885e442878f104e1b60bf75d5b6860eeacd53\",", + " \"logsBloom\": \"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",", + " \"miner\": \"0x0c729be7c39543c3d549282a40395299d987cec2\",", + " \"mixHash\": \"0x1530cda332d86d5d7462e3a0eb585e22c88348dd796d29e6ef18196a78cdce07\",", + " \"nonce\": \"0x938e5630b060b7d3\",", + " \"number\": \"0xf4629\",", + " \"parentHash\": \"0x96810a6076e621e311a232468bfd3dcfac08f4803b255af0f00300f47981c10f\",", + " \"receiptsRoot\": \"0x075608bec75d988c52ea6750f4c2204fd60082eb1df32cf8f4732e8a591eef62\",", + " \"sha3Uncles\": \"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347\",", + " \"size\": \"0x3e1\",", + " \"stateRoot\": \"0xb3f9408d80048b6f206951c4e387f8da37fb8510eccc18527865fa746c47bbc5\",", + " \"timestamp\": \"0x56bff9bb\",", + " \"totalDifficulty\": \"0x6332227c16fd7c67\",", + " \"transactions\": [", + " \"0x730724cb08a6eb17bf6b3296359d261570d343ea7944a17a9d7287d77900db08\",", + " \"0xef2ea39c20ba09553b2f3cf02380406ac766039ca56612937eed5e7f3503fb3a\",", + " \"0x5352c80aa2073e21ce6c4aa5488c38455f3519955ece7dca5af3e326797bcc63\",", + " \"0x060e4cf9fa8d34a8b423b5b3691b2541255ff7974ff16699e104edcfb63bd521\"", + " ],", + " \"transactionsRoot\": \"0xb779480508401ddd57f1f1e83a54715dcafc6ccec4e4d842c1b68cb418e6560d\",", + " \"uncles\": []", + " }", + "}", + "", + "pm.test('Has correct result', function() {", + " var isErigon = pm.environment.get('HOST') == \"{{ERIGON}}\";", + " var jsonData = pm.response.json();", + " if (!isErigon) {", + " delete jsonData.result.author;", + " delete jsonData.result.sealFields;", + " }", + " pm.expect(jsonData).to.be.deep.equal(expected);", + "})", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"eth_getBlockByNumber\",\n\t\"params\":[\n\t\t\"0xf4629\", \n\t\tfalse\n\t],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Returns information about a block given the block's number.\r\n\r\n**Parameters**\r\n\r\nTAG - Integer block number or one of \"earliest\", \"latest\" or \"pending\"\r\n\r\nBoolean - If true it returns the full transaction objects, if false only the hashes of the transactions\r\n\r\n**Returns**\r\n\r\nObject - An object of type Block defined as:\r\n\r\nnumber: QUANTITY - The block number or null when pending\r\n\r\nhash: DATA, 32 Bytes - Hash of the block or null when pending\r\n\r\nparentHash: DATA, 32 Bytes - Hash of the parent block\r\n\r\nnonce: DATA, 8 bytes - Hash of the proof of work or null when pending\r\n\r\nsha3Uncles: DATA, 32 Bytes - SHA3 of the uncles data in the block\r\n\r\nlogsBloom: DATA, 256 Bytes - The bloom filter for the block's logs or null when pending\r\n\r\ntransactionsRoot: DATA, 32 Bytes - The root of the transaction trie of the block\r\n\r\nstateRoot: DATA, 32 Bytes - The root of the final state trie of the block\r\n\r\nreceiptsRoot: DATA, 32 Bytes - The root of the receipts trie of the block\r\n\r\nminer: DATA, 20 Bytes - The address of the beneficiary to whom the mining rewards were given\r\n\r\ndifficulty: QUANTITY - Integer of the difficulty for this block\r\n\r\ntotalDifficulty: QUANTITY - Integer of the total difficulty of the chain until this block\r\n\r\nextraData: DATA - The extra data field of this block\r\n\r\nsize: QUANTITY - Integer the size of this block in bytes\r\n\r\ngasLimit: QUANTITY - The maximum gas allowed in this block\r\n\r\ngasUsed: QUANTITY - The total used gas by all transactions in this block\r\n\r\ntimestamp: QUANTITY - The unix timestamp for when the block was collated\r\n\r\ntransactions: ARRAY - Array of transaction objects, or 32 Bytes transaction hashes depending on the last given parameter\r\n\r\nuncles: ARRAY - Array of uncle hashes\r\n\r\n" + }, + "response": [] + }, + { + "name": "getBlockByHash", + "event": [ + { + "listen": "test", + "script": { + "id": "7c760190-bb77-4b63-bba7-93c01a72bd2a", + "exec": [ + "var expected = {", + " \"jsonrpc\": \"2.0\",", + " \"id\": \"1\",", + " \"result\": {", + " \"difficulty\": \"0xb5708d578a6\",", + " \"extraData\": \"0xd783010400844765746887676f312e352e31856c696e7578\",", + " \"gasLimit\": \"0x2fefd8\",", + " \"gasUsed\": \"0x14820\",", + " \"hash\": \"0x0b4c6fb75ded4b90218cf0346b0885e442878f104e1b60bf75d5b6860eeacd53\",", + " \"logsBloom\": \"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",", + " \"miner\": \"0x0c729be7c39543c3d549282a40395299d987cec2\",", + " \"mixHash\": \"0x1530cda332d86d5d7462e3a0eb585e22c88348dd796d29e6ef18196a78cdce07\",", + " \"nonce\": \"0x938e5630b060b7d3\",", + " \"number\": \"0xf4629\",", + " \"parentHash\": \"0x96810a6076e621e311a232468bfd3dcfac08f4803b255af0f00300f47981c10f\",", + " \"receiptsRoot\": \"0x075608bec75d988c52ea6750f4c2204fd60082eb1df32cf8f4732e8a591eef62\",", + " \"sha3Uncles\": \"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347\",", + " \"size\": \"0x3e1\",", + " \"stateRoot\": \"0xb3f9408d80048b6f206951c4e387f8da37fb8510eccc18527865fa746c47bbc5\",", + " \"timestamp\": \"0x56bff9bb\",", + " \"totalDifficulty\": \"0x6332227c16fd7c67\",", + " \"transactions\": [", + " \"0x730724cb08a6eb17bf6b3296359d261570d343ea7944a17a9d7287d77900db08\",", + " \"0xef2ea39c20ba09553b2f3cf02380406ac766039ca56612937eed5e7f3503fb3a\",", + " \"0x5352c80aa2073e21ce6c4aa5488c38455f3519955ece7dca5af3e326797bcc63\",", + " \"0x060e4cf9fa8d34a8b423b5b3691b2541255ff7974ff16699e104edcfb63bd521\"", + " ],", + " \"transactionsRoot\": \"0xb779480508401ddd57f1f1e83a54715dcafc6ccec4e4d842c1b68cb418e6560d\",", + " \"uncles\": []", + " }", + "}", + "", + "pm.test('Has correct result', function() {", + " var isErigon = pm.environment.get('HOST') == \"{{ERIGON}}\";", + " var jsonData = pm.response.json();", + " if (!isErigon) {", + " delete jsonData.result.author;", + " delete jsonData.result.sealFields;", + " }", + " pm.expect(jsonData).to.be.deep.equal(expected);", + "})", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"eth_getBlockByHash\",\n\t\"params\":[\n\t\t\"0x0b4c6fb75ded4b90218cf0346b0885e442878f104e1b60bf75d5b6860eeacd53\", \n\t\tfalse\n\t],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Returns information about a block given the block's hash.\r\n\r\n**Parameters**\r\n\r\nDATA, 32 Bytes - Hash of a block\r\n\r\nBoolean - If true it returns the full transaction objects, if false only the hashes of the transactions\r\n\r\n**Returns**\r\n\r\nObject - An object of type Block as described at eth_getBlockByNumber, or null when no block was found" + }, + "response": [] + }, + { + "name": "getBlockTransactionCountByNumber", + "event": [ + { + "listen": "test", + "script": { + "id": "341676cb-5915-48b7-a2b2-146feb7b80a6", + "exec": [ + "pm.test('Has correct result', function() {", + " const jsonData = pm.response.json();", + " pm.expect(jsonData.result).to.be.equals(\"0x4\");", + "});", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"eth_getBlockTransactionCountByNumber\",\n\t\"params\":[\n\t\t\"0xf4629\"\n\t],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Returns the number of transactions in a block given the block's block number.\r\n\r\n**Parameters**\r\n\r\nTAG - Integer block number or one of \"earliest\", \"latest\" or \"pending\"\r\n\r\n**Returns**\r\n\r\nQUANTITY - Integer of the number of transactions in this block" + }, + "response": [] + }, + { + "name": "getBlockTransactionCountByHash", + "event": [ + { + "listen": "test", + "script": { + "id": "439ec2db-b271-4b15-8fc5-09e86aeed870", + "exec": [ + "pm.test('Has correct result', function() {", + " const jsonData = pm.response.json();", + " pm.expect(jsonData.result).to.be.equals('0x4');", + "});", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"eth_getBlockTransactionCountByHash\",\n\t\"params\":[\n\t\t\"0x0b4c6fb75ded4b90218cf0346b0885e442878f104e1b60bf75d5b6860eeacd53\"\n\t],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Returns the number of transactions in a block given the block's block hash.\r\n\r\n**Parameters**\r\n\r\nDATA, 32 Bytes - hash of a block\r\n\r\n**Returns**\r\n\r\nQUANTITY - Integer of the number of transactions in this block" + }, + "response": [] + } + ], + "protocolProfileBehavior": {}, + "_postman_isSubFolder": true + }, + { + "name": "txs", + "item": [ + { + "name": "getTransactionByHash", + "event": [ + { + "listen": "test", + "script": { + "id": "68b084bd-9b84-4018-bc45-e947bcf07f95", + "exec": [ + "var expected = {", + " \"jsonrpc\": \"2.0\",", + " \"id\": \"1\",", + " \"result\": {", + " \"blockHash\": \"0x785b221ec95c66579d5ae14eebe16284a769e948359615d580f02e646e93f1d5\",", + " \"blockNumber\": \"0x52a90b\",", + " \"from\": \"0x11b6a5fe2906f3354145613db0d99ceb51f604c9\",", + " \"gas\": \"0x6b6c\",", + " \"gasPrice\": \"0x11e1a300\",", + " \"hash\": \"0xb2fea9c4b24775af6990237aa90228e5e092c56bdaee74496992a53c208da1ee\",", + " \"input\": \"0x80dfa34a0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002e516d556558334448416654747442464a42315454384a617a67765744776a727a7342686973693473547532613551000000000000000000000000000000000000\",", + " \"nonce\": \"0x10\",", + " \"r\": \"0xacdf839bdcb6653da60900f739076a00ecbe0059fa046933348e9b68a62a222\",", + " \"s\": \"0x132a0517a4c52916e0c6b0e74b0479326891df2a9afd711482c7f3919b335ff6\",", + " \"to\": \"0xfa28ec7198028438514b49a3cf353bca5541ce1d\",", + " \"transactionIndex\": \"0x25\",", + " \"v\": \"0x26\",", + " \"value\": \"0x0\"", + " }", + "}", + "", + "pm.test('Has correct result', function() {", + " const jsonData = pm.response.json();", + " var keys = Object.keys(jsonData.result);", + " keys.map(function (k) {", + " var value = jsonData.result[k] ? jsonData.result[k] : null;", + " var expect = expected.result[k] ? expected.result[k] : null;", + " if (expect && typeof expect === 'object') {", + " jsonData.result[k].map(function (value, index) {", + " var expect = expected.result[k][index];", + " pm.expect(value).to.be.equal(expect)", + " })", + " } else {", + " pm.expect(value).to.be.equal(expect)", + " }", + " });", + "})", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"eth_getTransactionByHash\",\n\t\"params\":[\n\t\t\"0xb2fea9c4b24775af6990237aa90228e5e092c56bdaee74496992a53c208da1ee\"\n\t],\n\t\"id\":\"1\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Returns information about a transaction given the transaction's hash.\r\n\r\n**Parameters**\r\n\r\nDATA, 32 Bytes - hash of a transaction\r\n\r\n**Returns**\r\n\r\nObject - An object of type Transaction or null when no transaction was found\r\n\r\nhash: DATA, 32 Bytes - hash of the transaction\r\n\r\nnonce: QUANTITY - The number of transactions made by the sender prior to this one\r\n\r\nblockHash: DATA, 32 Bytes - hash of the block where this transaction was in. null when its pending\r\n\r\nblockNumber: QUANTITY - block number where this transaction was in. null when its pending\r\n\r\ntransactionIndex: QUANTITY - Integer of the transactions index position in the block. null when its pending\r\n\r\nfrom: DATA, 20 Bytes - address of the sender\r\n\r\nto: DATA, 20 Bytes - address of the receiver. null when its a contract creation transaction\r\n\r\nvalue: QUANTITY - value transferred in Wei\r\n\r\ngasPrice: QUANTITY - gas price provided by the sender in Wei\r\n\r\ngas: QUANTITY - gas provided by the sender\r\n\r\ninput: DATA - The data send along with the transaction" + }, + "response": [] + }, + { + "name": "getTransactionByBlockHashAndIndex", + "event": [ + { + "listen": "test", + "script": { + "id": "593d73f7-fea6-4fd0-bd02-ece07971cd58", + "exec": [ + "var expected = {", + " \"jsonrpc\": \"2.0\",", + " \"id\": \"1\",", + " \"result\": {", + " \"blockHash\": \"0x785b221ec95c66579d5ae14eebe16284a769e948359615d580f02e646e93f1d5\",", + " \"blockNumber\": \"0x52a90b\",", + " \"from\": \"0x11b6a5fe2906f3354145613db0d99ceb51f604c9\",", + " \"gas\": \"0x6b6c\",", + " \"gasPrice\": \"0x11e1a300\",", + " \"hash\": \"0xb2fea9c4b24775af6990237aa90228e5e092c56bdaee74496992a53c208da1ee\",", + " \"input\": \"0x80dfa34a0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002e516d556558334448416654747442464a42315454384a617a67765744776a727a7342686973693473547532613551000000000000000000000000000000000000\",", + " \"nonce\": \"0x10\",", + " \"r\": \"0xacdf839bdcb6653da60900f739076a00ecbe0059fa046933348e9b68a62a222\",", + " \"s\": \"0x132a0517a4c52916e0c6b0e74b0479326891df2a9afd711482c7f3919b335ff6\",", + " \"to\": \"0xfa28ec7198028438514b49a3cf353bca5541ce1d\",", + " \"transactionIndex\": \"0x25\",", + " \"v\": \"0x26\",", + " \"value\": \"0x0\"", + " }", + "}", + "", + "pm.test('Has correct result', function() {", + " const jsonData = pm.response.json();", + " var keys = Object.keys(jsonData.result);", + " keys.map(function (k) {", + " var value = jsonData.result[k] ? jsonData.result[k] : null;", + " var expect = expected.result[k] ? expected.result[k] : null;", + " if (expect && typeof expect === 'object') {", + " jsonData.result[k].map(function (value, index) {", + " var expect = expected.result[k][index];", + " pm.expect(value).to.be.equal(expect)", + " })", + " } else {", + " pm.expect(value).to.be.equal(expect)", + " }", + " });", + "})", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"eth_getTransactionByBlockHashAndIndex\",\n\t\"params\":[\n\t\t\"0x785b221ec95c66579d5ae14eebe16284a769e948359615d580f02e646e93f1d5\", \n\t\t\"0x25\"\n\t],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Returns information about a transaction given the block's hash and a transaction index.\r\n\r\n**Parameters**\r\n\r\nDATA, 32 Bytes - hash of a block\r\n\r\nQUANTITY - Integer of the transaction index position\r\n\r\n**Returns**\r\n\r\nObject - An object of type Transaction or null when no transaction was found. See eth_getTransactionByHash" + }, + "response": [] + }, + { + "name": "getTransactionByBlockNumberAndIndex", + "event": [ + { + "listen": "test", + "script": { + "id": "530d1490-3007-499c-ae23-f9fd26f1787b", + "exec": [ + "var expected = {", + " \"jsonrpc\": \"2.0\",", + " \"id\": \"1\",", + " \"result\": {", + " \"blockHash\": \"0x785b221ec95c66579d5ae14eebe16284a769e948359615d580f02e646e93f1d5\",", + " \"blockNumber\": \"0x52a90b\",", + " \"from\": \"0x11b6a5fe2906f3354145613db0d99ceb51f604c9\",", + " \"gas\": \"0x6b6c\",", + " \"gasPrice\": \"0x11e1a300\",", + " \"hash\": \"0xb2fea9c4b24775af6990237aa90228e5e092c56bdaee74496992a53c208da1ee\",", + " \"input\": \"0x80dfa34a0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002e516d556558334448416654747442464a42315454384a617a67765744776a727a7342686973693473547532613551000000000000000000000000000000000000\",", + " \"nonce\": \"0x10\",", + " \"r\": \"0xacdf839bdcb6653da60900f739076a00ecbe0059fa046933348e9b68a62a222\",", + " \"s\": \"0x132a0517a4c52916e0c6b0e74b0479326891df2a9afd711482c7f3919b335ff6\",", + " \"to\": \"0xfa28ec7198028438514b49a3cf353bca5541ce1d\",", + " \"transactionIndex\": \"0x25\",", + " \"v\": \"0x26\",", + " \"value\": \"0x0\"", + " }", + "}", + "", + "pm.test('Has correct result', function() {", + " const jsonData = pm.response.json();", + " var keys = Object.keys(jsonData.result);", + " keys.map(function (k) {", + " var value = jsonData.result[k] ? jsonData.result[k] : null;", + " var expect = expected.result[k] ? expected.result[k] : null;", + " if (expect && typeof expect === 'object') {", + " jsonData.result[k].map(function (value, index) {", + " var expect = expected.result[k][index];", + " pm.expect(value).to.be.equal(expect)", + " })", + " } else {", + " pm.expect(value).to.be.equal(expect)", + " }", + " });", + "})", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"eth_getTransactionByBlockNumberAndIndex\",\n\t\"params\":[\n\t\t\"0x52a90b\", \n\t\t\"0x25\"\n\t],\n\t\"id\":\"1\"\n}\n", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Returns information about a transaction given a block number and transaction index.\r\n\r\n**Parameters**\r\n\r\nTAG - Integer block number or one of \"earliest\", \"latest\" or \"pending\"\r\n\r\nQUANTITY - The transaction index position\r\n\r\n**Returns**\r\n\r\nObject - An object of type Transaction or null when no transaction was found. See eth_getTransactionByHash" + }, + "response": [] + }, + { + "name": "getTransactionReceipt", + "event": [ + { + "listen": "test", + "script": { + "id": "d49e47cb-cbdf-4cc1-83e2-e0ab6b860fd3", + "exec": [ + "var expected = {", + " \"jsonrpc\": \"2.0\",", + " \"id\": \"1\",", + " \"result\": {", + " \"blockHash\": \"0xf6084155ff2022773b22df3217d16e9df53cbc42689b27ca4789e06b6339beb2\",", + " \"blockNumber\": \"0x52a975\",", + " \"contractAddress\": null,", + " \"cumulativeGasUsed\": \"0x797db0\",", + " \"from\": \"0xd907941c8b3b966546fc408b8c942eb10a4f98df\",", + " \"gasUsed\": \"0x1308c\",", + " \"logs\": [", + " {", + " \"address\": \"0xd6df5935cd03a768b7b9e92637a01b25e24cb709\",", + " \"topics\": [", + " \"0x8940c4b8e215f8822c5c8f0056c12652c746cbc57eedbd2a440b175971d47a77\",", + " \"0x000000000000000000000000d907941c8b3b966546fc408b8c942eb10a4f98df\"", + " ],", + " \"data\": \"0x0000000000000000000000000000000000000000000000000000008bb2c97000\",", + " \"blockNumber\": \"0x52a975\",", + " \"transactionHash\": \"0xa3ece39ae137617669c6933b7578b94e705e765683f260fcfe30eaa41932610f\",", + " \"transactionIndex\": \"0x29\",", + " \"blockHash\": \"0xf6084155ff2022773b22df3217d16e9df53cbc42689b27ca4789e06b6339beb2\",", + " \"logIndex\": \"0x119\",", + " \"removed\": false", + " },", + " {", + " \"address\": \"0xd6df5935cd03a768b7b9e92637a01b25e24cb709\",", + " \"topics\": [", + " \"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef\",", + " \"0x0000000000000000000000000000000000000000000000000000000000000000\",", + " \"0x000000000000000000000000d907941c8b3b966546fc408b8c942eb10a4f98df\"", + " ],", + " \"data\": \"0x0000000000000000000000000000000000000000000000000000008bb2c97000\",", + " \"blockNumber\": \"0x52a975\",", + " \"transactionHash\": \"0xa3ece39ae137617669c6933b7578b94e705e765683f260fcfe30eaa41932610f\",", + " \"transactionIndex\": \"0x29\",", + " \"blockHash\": \"0xf6084155ff2022773b22df3217d16e9df53cbc42689b27ca4789e06b6339beb2\",", + " \"logIndex\": \"0x11a\",", + " \"removed\": false", + " }", + " ],", + " \"logsBloom\": \"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000020000000000000000000800000000000000004010000010100000000000000000000000000000000000000000000000000040000080000000000000080000000000000000000000000000000000000000000020000000000000000000000002000000000000000000000000000000000000000000000000000020000000010000000000000000000000000000000000000000000000000000000000\",", + " \"status\": \"0x1\",", + " \"to\": \"0xd6df5935cd03a768b7b9e92637a01b25e24cb709\",", + " \"transactionHash\": \"0xa3ece39ae137617669c6933b7578b94e705e765683f260fcfe30eaa41932610f\",", + " \"transactionIndex\": \"0x29\"", + " }", + "}", + "", + "pm.test('Has correct result', function() {", + " const jsonData = pm.response.json();", + " var keys = Object.keys(jsonData.result);", + " keys.map(function (k) {", + " var value = jsonData.result[k] ? jsonData.result[k] : null;", + " var expect = expected.result[k] ? expected.result[k] : null;", + " if (expect && typeof expect === 'object') {", + " if (k !== 'logs') {", + " jsonData.result[k].map(function (value, index) {", + " var expect = expected.result[k][index];", + " pm.expect(value).to.be.equal(expect)", + " })", + " }", + " } else {", + " pm.expect(value).to.be.equal(expect)", + " }", + " });", + "})", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"eth_getTransactionReceipt\",\n\t\"params\":[\n\t\t\"0xa3ece39ae137617669c6933b7578b94e705e765683f260fcfe30eaa41932610f\"\n\t],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Returns the receipt of a transaction given the transaction's hash.\r\n\r\n**Note**\r\n\r\nReceipts are not available for pending transactions.\r\n\r\n**Parameters**\r\n\r\nDATA, 32 Bytes - hash of a transaction\r\n\r\n**Returns**\r\n\r\nObject - An object of type TransactionReceipt or null when no receipt was found\r\n\r\ntransactionHash: DATA, 32 Bytes - hash of the transaction\r\n\r\ntransactionIndex: QUANTITY - Integer of the transactions index position in the block\r\n\r\nblockHash: DATA, 32 Bytes - hash of the block where this transaction was in\r\n\r\nblockNumber: QUANTITY - block number where this transaction was in\r\n\r\ncumulativeGasUsed: QUANTITY - The total amount of gas used when this transaction was executed in the block\r\n\r\ngasUsed: QUANTITY - The amount of gas used by this specific transaction alone\r\n\r\ncontractAddress: DATA, 20 Bytes - The contract address created, if the transaction was a contract creation, null otherwise\r\n\r\nlogs: Array - Array of log objects, which this transaction generated\r\n\r\nlogsBloom: DATA, 256 Bytes - Bloom filter for light clients to quickly retrieve related logs.\r\n\r\nroot: DATA 32 bytes - post-transaction stateroot (if the block is pre-Byzantium)\r\n\r\nstatus: QUANTITY - either 1 = success or 0 = failure (if block is Byzatnium or later)" + }, + "response": [] + } + ], + "protocolProfileBehavior": {}, + "_postman_isSubFolder": true + }, + { + "name": "uncles", + "item": [ + { + "name": "getUncleByBlockNumberAndIndex", + "event": [ + { + "listen": "test", + "script": { + "id": "bb80848b-3b1d-4d5a-8317-fe623c0be114", + "exec": [ + "var expected = {", + " \"jsonrpc\": \"2.0\",", + " \"id\": \"1\",", + " \"result\": {", + " \"difficulty\": \"0x3ff800000\",", + " \"extraData\": \"0x59617465732052616e64616c6c202d2045746865724e696e6a61\",", + " \"gasLimit\": \"0x1388\",", + " \"gasUsed\": \"0x0\",", + " \"hash\": \"0x5cd50096dbb856a6d1befa6de8f9c20decb299f375154427d90761dc0b101109\",", + " \"logsBloom\": \"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",", + " \"miner\": \"0xc8ebccc5f5689fa8659d83713341e5ad19349448\",", + " \"mixHash\": \"0xf8c94dfe61cf26dcdf8cffeda337cf6a903d65c449d7691a022837f6e2d99459\",", + " \"nonce\": \"0x68b769c5451a7aea\",", + " \"number\": \"0x1\",", + " \"parentHash\": \"0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3\",", + " \"receiptsRoot\": \"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\",", + " \"sha3Uncles\": \"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347\",", + " \"size\": \"0x21a\",", + " \"stateRoot\": \"0x1e6e030581fd1873b4784280859cd3b3c04aa85520f08c304cf5ee63d3935add\",", + " \"timestamp\": \"0x55ba4242\",", + " \"totalDifficulty\": \"0xffd003ffe\",", + " \"transactionsRoot\": \"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\",", + " \"uncles\": []", + " }", + "}", + "", + "pm.test('Has correct result', function() {", + " const jsonData = pm.response.json();", + " var keys = Object.keys(jsonData.result);", + " keys.map(function (k) {", + " var value = jsonData.result[k] ? jsonData.result[k] : null;", + " var expect = expected.result[k] ? expected.result[k] : null;", + " if (expect && typeof expect === 'object') {", + " jsonData.result[k].map(function (value, index) {", + " var expect = expected.result[k][index];", + " pm.expect(value).to.be.equal(expect)", + " })", + " } else {", + " pm.expect(value).to.be.equal(expect)", + " }", + " });", + "})", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"eth_getUncleByBlockNumberAndIndex\",\n\t\"params\":[\n\t\t\"0x3\",\n\t\t\"0x0\"\n\t],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Returns information about an uncle given a block's number and the index of the uncle.\r\n\r\n**Parameters**\r\n\r\nTAG - Integer block number or one of \"earliest\", \"latest\" or \"pending\"\r\n\r\nQUANTITY - The uncle's index position\r\n\r\n**Returns**\r\n\r\nObject - An object of type Block (with zero transactions), or null when no uncle was found. See eth_getBlockByHash" + }, + "response": [] + }, + { + "name": "getUncleByBlockHashAndIndex", + "event": [ + { + "listen": "test", + "script": { + "id": "3ba8cc46-cd5d-4b26-a618-a54ddc3d86c4", + "exec": [ + "var expected = {", + " \"jsonrpc\": \"2.0\",", + " \"id\": \"1\",", + " \"result\": {", + " \"difficulty\": \"0x3ff800000\",", + " \"extraData\": \"0x59617465732052616e64616c6c202d2045746865724e696e6a61\",", + " \"gasLimit\": \"0x1388\",", + " \"gasUsed\": \"0x0\",", + " \"hash\": \"0x5cd50096dbb856a6d1befa6de8f9c20decb299f375154427d90761dc0b101109\",", + " \"logsBloom\": \"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",", + " \"miner\": \"0xc8ebccc5f5689fa8659d83713341e5ad19349448\",", + " \"mixHash\": \"0xf8c94dfe61cf26dcdf8cffeda337cf6a903d65c449d7691a022837f6e2d99459\",", + " \"nonce\": \"0x68b769c5451a7aea\",", + " \"number\": \"0x1\",", + " \"parentHash\": \"0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3\",", + " \"receiptsRoot\": \"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\",", + " \"sha3Uncles\": \"0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347\",", + " \"size\": \"0x21a\",", + " \"stateRoot\": \"0x1e6e030581fd1873b4784280859cd3b3c04aa85520f08c304cf5ee63d3935add\",", + " \"timestamp\": \"0x55ba4242\",", + " \"totalDifficulty\": \"0xffd003ffe\",", + " \"transactionsRoot\": \"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\",", + " \"uncles\": []", + " }", + "}", + "", + "pm.test('Has correct result', function() {", + " const jsonData = pm.response.json();", + " var keys = Object.keys(jsonData.result);", + " keys.map(function (k) {", + " var value = jsonData.result[k] ? jsonData.result[k] : null;", + " var expect = expected.result[k] ? expected.result[k] : null;", + " if (expect && typeof expect === 'object') {", + " jsonData.result[k].map(function (value, index) {", + " var expect = expected.result[k][index];", + " pm.expect(value).to.be.equal(expect)", + " })", + " } else {", + " pm.expect(value).to.be.equal(expect)", + " }", + " });", + "})", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"eth_getUncleByBlockHashAndIndex\",\n\t\"params\":[\n\t\t\"0x3d6122660cc824376f11ee842f83addc3525e2dd6756b9bcf0affa6aa88cf741\", \n\t\t\"0x0\"\n\t],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Returns information about an uncle given a block's hash and the index of the uncle.\r\n\r\n**Parameters**\r\n\r\nDATA, 32 Bytes - Hash of the block holding the uncle\r\n\r\nQUANTITY - The uncle's index position\r\n\r\n**Returns**\r\n\r\nObject - An object of type Block (with zero transactions), or null when no uncle was found. See eth_getBlockByHash" + }, + "response": [] + }, + { + "name": "getUncleCountByBlockNumber", + "event": [ + { + "listen": "test", + "script": { + "id": "790ef142-b864-4ad6-a90c-7bece105c3f8", + "exec": [ + "var expected = {", + " \"jsonrpc\": \"2.0\",", + " \"result\": \"0x1\",", + " \"id\": \"1\"", + "}", + "", + "pm.test('Has correct result', function() {", + " var isErigon = pm.environment.get('HOST') == \"{{ERIGON}}\";", + " var jsonData = pm.response.json();", + " if (!isErigon) {", + " delete jsonData.result.author;", + " delete jsonData.result.sealFields;", + " }", + " pm.expect(jsonData).to.be.deep.equal(expected);", + "})", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"eth_getUncleCountByBlockNumber\",\n\t\"params\":[\n\t\t\"0x3\"\n ],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Returns the number of uncles in the block, if any.\r\n\r\n**Parameters**\r\n\r\nTAG - Integer block number or one of \"earliest\", \"latest\" or \"pending\"\r\n\r\n**Returns**\r\n\r\nQUANTITY - The number of uncles in the block, if any" + }, + "response": [] + }, + { + "name": "getUncleCountByBlockHash", + "event": [ + { + "listen": "test", + "script": { + "id": "d3fba91c-ae8f-4ced-b563-51f9b7e36144", + "exec": [ + "var expected = {", + " \"jsonrpc\": \"2.0\",", + " \"result\": \"0x1\",", + " \"id\": \"1\"", + "}", + "", + "pm.test('Has correct result', function() {", + " var isErigon = pm.environment.get('HOST') == \"{{ERIGON}}\";", + " var jsonData = pm.response.json();", + " if (!isErigon) {", + " delete jsonData.result.author;", + " delete jsonData.result.sealFields;", + " }", + " pm.expect(jsonData).to.be.deep.equal(expected);", + "})", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"eth_getUncleCountByBlockHash\",\n\t\"params\":[\n\t\t\"0x3d6122660cc824376f11ee842f83addc3525e2dd6756b9bcf0affa6aa88cf741\"\n\t],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Returns the number of uncles in the block, if any.\r\n\r\n**Parameters**\r\n\r\nDATA, 32 Bytes - Hash of the block containing the uncle\r\n\r\n**Returns**\r\n\r\nQUANTITY - The number of uncles in the block, if any" + }, + "response": [] + } + ], + "protocolProfileBehavior": {}, + "_postman_isSubFolder": true + }, + { + "name": "filters", + "item": [ + { + "name": "newPendingTransactionFilter", + "event": [ + { + "listen": "test", + "script": { + "id": "2bdda0a7-7cf2-4e02-ae19-7a575f2588a2", + "exec": ["utils.notImplemented(\"eth_newPendingTransactionFilter\", pm.response.json())", ""], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"eth_newPendingTransactionFilter\",\n\t\"params\":[],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Creates a pending transaction filter in the node. To check if the state has changed, call eth_getFilterChanges.\r\n\r\n**Parameters**\r\n\r\nNone\r\n\r\n**Returns**\r\n\r\nQUANTITY - A filter id" + }, + "response": [] + }, + { + "name": "newBlockFilter", + "event": [ + { + "listen": "test", + "script": { + "id": "a627cf51-a966-4f25-9447-fb3da185a3e0", + "exec": ["utils.notImplemented(\"eth_newBlockFilter\", pm.response.json())", ""], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"eth_newBlockFilter\",\n\t\"params\":[],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Creates a block filter in the node, to notify when a new block arrives. To check if the state has changed, call eth_getFilterChanges.\r\n\r\n**Parameters**\r\n\r\nNone\r\n\r\n**Returns**\r\n\r\nQUANTITY - A filter id" + }, + "response": [] + }, + { + "name": "newFilter", + "event": [ + { + "listen": "test", + "script": { + "id": "44d72ef7-022a-4ebf-94b6-9778bd6925d1", + "exec": ["utils.notImplemented(\"eth_newFilter\", pm.response.json())", ""], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"eth_newFilter\",\n\t\"params\": [\n {\n \"fromBlock\": \"0x1\",\n \"toBlock\": \"0x2\",\n \"address\": \" 0x8888f1f195afa192cfee860698584c030f4c9db1\",\n \"topics\": [\n \"0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b\",\n null,\n [\"0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b\", \"0x0000000000000000000000000aff3454fce5edbc8cca8697c15331677e6ebccc\"]\n ]\n }\n ],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Creates an arbitrary filter object, based on filter options, to notify when the state changes (logs). To check if the state has changed, call eth_getFilterChanges.\r\n\r\n**Example**\r\n\r\nA note on specifying topic filters\r\n\r\nTopics are order-dependent. A transaction with a log with topics [A, B] will be matched by the following topic filters\r\n\r\n[] \"anything\"\r\n\r\n[A] \"A in first position (and anything after)\"\r\n\r\n[null, B] \"anything in first position AND B in second position (and anything after)\"\r\n\r\n[A, B] \"A in first position AND B in second position (and anything after)\"\r\n\r\n[[A, B], [A, B]] \"(A OR B) in first position AND (A OR B) in second position (and anything after)\"\r\n\r\n**Parameters**\r\n\r\nObject - An object of type Filter\r\n\r\nQUANTITY|TAG - (optional, default \"latest\") Integer block number, or \"earliest\", \"latest\" or \"pending\" for not yet mined transactions\r\n\r\nQUANTITY|TAG - (optional, default \"latest\") Integer block number, or \"earliest\", \"latest\" or \"pending\" for not yet mined transactions\r\n\r\nDATA|Array of DATA, 20 Bytes - (optional) Contract address or a list of addresses from which logs should originate\r\n\r\nArray of DATA, - (optional) Array of 32 Bytes DATA topics. Topics are order-dependent. Each topic can also be an array of DATA with \"or\" options\r\n\r\n**Returns**\r\n\r\nQUANTITY - A filter id" + }, + "response": [] + }, + { + "name": "uninstallFilter", + "event": [ + { + "listen": "test", + "script": { + "id": "11a48bf8-6320-45ae-989c-ad4b889b5f0d", + "exec": ["utils.notImplemented(\"eth_uninstallFilter\", pm.response.json())", ""], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"eth_uninstallFilter\",\n\t\"params\":[\n\t\t\"0xdeadbeef\"\n\t],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Uninstalls a previously-created filter given the filter's id. Always uninstall filters when no longer needed.\r\n\r\n**Note**\r\n\r\nFilters timeout when they are not requested with eth_getFilterChanges for a period of time.\r\n\r\n**Parameters**\r\n\r\nQUANTITY - The filter id\r\n\r\n**Returns**\r\n\r\nBoolean - true if the filter was successfully uninstalled, false otherwise" + }, + "response": [] + }, + { + "name": "getFilterChanges", + "event": [ + { + "listen": "test", + "script": { + "id": "6e68517c-5d19-4843-b1bb-39c7a594d4a5", + "exec": ["utils.notImplemented(\"eth_getFilterChanges\", pm.response.json())", ""], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"eth_getFilterChanges\",\n\t\"params\":[\n\t\t\"0xdeadbeef\"\n\t],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Returns an array of objects of type Log, an array of block hashes (for eth_newBlockFilter) or an array of transaction hashes (for eth_newPendingTransactionFilter) or an empty array if nothing has changed since the last poll.\r\n\r\n**Note**\r\n\r\nIn solidity: The first topic is the hash of the signature of the event (if you have not declared the event anonymous.\r\n\r\n**Parameters**\r\n\r\nQUANTITY - The filter id\r\n\r\n**Returns**\r\n\r\nObject - An object of type FilterLog is defined as\r\n\r\nremoved: BOOLEAN - true when the log was removed, due to a chain reorganization. false if its a valid log\r\n\r\nlogIndex: QUANTITY - Integer of the log index position in the block. null when its pending log\r\n\r\ntransactionIndex: QUANTITY - Integer of the transactions index position log was created from. null when its pending log\r\n\r\ntransactionHash: DATA, 32 Bytes - hash of the transactions this log was created from. null when its pending log\r\n\r\nblockHash: DATA, 32 Bytes - hash of the block where this log was in. null when its pending. null when its pending log\r\n\r\nblockNumber: QUANTITY - The block number where this log was in. null when its pending. null when its pending log\r\n\r\naddress: DATA, 20 Bytes - address from which this log originated\r\n\r\ndata: DATA - contains one or more 32 Bytes non-indexed arguments of the log\r\n\r\ntopics: Array of DATA - Array of 0 to 4 32 Bytes DATA of indexed log arguments." + }, + "response": [] + }, + { + "name": "getLogs", + "event": [ + { + "listen": "test", + "script": { + "id": "3b0fee2d-9ef2-48d4-901b-7cab11dfbba2", + "exec": [ + "pm.test('Not tested', function() {", + " var tested = false;", + " pm.expect(tested).to.be.true", + "})", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"eth_getLogs\",\n\t\"params\":[{\n\t\t\"topics\":[\n\t\t\t\"0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b\"\n\t\t]\n\t}],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Returns an array of logs matching a given filter object.\r\n\r\n**Parameters**\r\n\r\nObject - An object of type Filter, see eth_newFilter parameters\r\n\r\n**Returns**\r\n\r\nObject - An object of type LogArray or an empty array if nothing has changed since last poll. See eth_getFilterChanges" + }, + "response": [] + } + ], + "protocolProfileBehavior": {}, + "_postman_isSubFolder": true + }, + { + "name": "accounts", + "item": [ + { + "name": "getBalance", + "event": [ + { + "listen": "test", + "script": { + "id": "2527ac10-fa47-47c1-a422-ac54f2067e83", + "exec": [ + "var expected = {", + " \"jsonrpc\": \"2.0\",", + " \"id\": \"1\",", + " \"result\": \"0x7a69\"", + "}", + "", + "pm.test('Has correct result', function() {", + " pm.expect(pm.response.json()).to.be.deep.equal(expected);", + "})", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"eth_getBalance\",\n\t\"params\":[\n\t\t\"0x5df9b87991262f6ba471f09758cde1c0fc1de734\", \n\t\t\"0xb443\"\n\t],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Returns the balance of an account for a given address.\r\n\r\n**Parameters**\r\n\r\nDATA, 20 Bytes - Address to check for balance\r\n\r\nTAG - Integer block number or one of \"earliest\", \"latest\" or \"pending\"\r\n\r\n**Returns**\r\n\r\nQUANTITY - Integer of the current balance in wei" + }, + "response": [] + }, + { + "name": "getTransactionCount", + "event": [ + { + "listen": "test", + "script": { + "id": "bcfa7ced-fa30-4936-ad0d-28c99c7a39c5", + "exec": [ + "var expected = {", + " \"jsonrpc\": \"2.0\",", + " \"id\": \"1\",", + " \"result\": \"0xa\"", + "}", + "", + "pm.test('Has correct result', function() {", + " pm.expect(pm.response.json()).to.be.deep.equal(expected);", + "})", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"eth_getTransactionCount\",\n\t\"params\":[\n\t\t\"0xfd2605a2bf58fdbb90db1da55df61628b47f9e8c\", \n\t\t\"0xc443\"\n\t],\n\t\"id\":\"1\"\n}\n", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Returns the number of transactions sent from an address (the nonce).\r\n\r\n**Parameters**\r\n\r\nDATA, 20 Bytes - Address from which to retrieve nonce\r\n\r\nTAG - Integer block number or one of \"earliest\", \"latest\" or \"pending\"\r\n\r\n**Returns**\r\n\r\nQUANTITY - Integer of the number of transactions sent from this address" + }, + "response": [] + }, + { + "name": "getCode", + "event": [ + { + "listen": "test", + "script": { + "id": "b1435da2-cfbc-48fd-97ac-24612fb6ee6d", + "exec": [ + "var expected = {", + " \"jsonrpc\": \"2.0\",", + " \"id\": \"1\",", + " \"result\": \"0x6060604052361561001f5760e060020a600035046372ea4b8c811461010c575b61011b3460008080670de0b6b3a764000084106101d557600180548101908190556003805433929081101561000257906000526020600020900160006101000a815481600160a060020a0302191690830217905550670de0b6b3a7640000840393508350670de0b6b3a76400006000600082828250540192505081905550600260016000505411151561011d5760038054829081101561000257906000526020600020900160009054906101000a9004600160a060020a0316600160a060020a03166000600060005054604051809050600060405180830381858888f150505080555060016002556101d5565b60018054016060908152602090f35b005b60018054600354910114156101d55760038054600254600101909102900392505b6003546002549003600119018310156101e357600380548490811015610002579082526040517fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b9190910154600160a060020a03169082906706f05b59d3b200009082818181858883f1505090546706f05b59d3b1ffff1901835550506001929092019161013e565b505060028054600101905550505b600080548501905550505050565b506002548154919250600190810190910460001901905b60035460025490036001190183101561029a576003805484908110156100025760009182526040517fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b9190910154600160a060020a03169190838504600019019082818181858883f1505081548486049003600190810190925550600290830183020460001901841415905061028e576001015b600192909201916101fa565b60038054600254810182018083559190829080158290116101c75760008390526101c7907fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b9081019083015b808211156102fa57600081556001016102e6565b509056\"", + "}", + "", + "pm.test('Has correct result', function() {", + " pm.expect(pm.response.json()).to.be.deep.equal(expected);", + "})", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"eth_getCode\",\n\t\"params\":[\n\t\t\"0x109c4f2ccc82c4d77bde15f306707320294aea3f\", \n\t\t\"0xc443\"\n\t],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Returns the byte code at a given address (if it's a smart contract).\r\n\r\n**Parameters**\r\n\r\nDATA, 20 Bytes - Address from which to retreive byte code\r\n\r\nTAG - Integer block number or one of \"earliest\", \"latest\" or \"pending\"\r\n\r\n**Returns**\r\n\r\nDATA - The byte code (if any) found at the given address" + }, + "response": [] + }, + { + "name": "getStorageAt", + "event": [ + { + "listen": "test", + "script": { + "id": "270e7931-1ec1-440a-a8e1-ba54f4f4e9a3", + "exec": [ + "var expected = {", + " \"jsonrpc\": \"2.0\",", + " \"id\": \"1\",", + " \"result\": \"0x0000000000000000000000000000000000000000000000001bc16d674ec80000\"", + "}", + "", + "pm.test('Has correct result', function() {", + " pm.expect(pm.response.json()).to.be.deep.equal(expected);", + "})", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\", \n\t\"method\": \"eth_getStorageAt\", \n\t\"params\": [\n\t\t\"0x109c4f2ccc82c4d77bde15f306707320294aea3f\", \n\t\t\"0x0\",\n\t\t\"0xc443\"\n\t], \n\t\"id\": \"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Returns the value from a storage position at a given address.\r\n\r\n**Parameters**\r\n\r\nDATA, 20 Bytes - Address of the contract whose storage to retreive\r\n\r\nQUANTITY - Integer of the position in the storage\r\n\r\nTAG - Integer block number or one of \"earliest\", \"latest\" or \"pending\"\r\n\r\n**Returns**\r\n\r\nDATA - The value at this storage position" + }, + "response": [] + } + ], + "protocolProfileBehavior": {}, + "_postman_isSubFolder": true + }, + { + "name": "system", + "item": [ + { + "name": "blockNumber", + "event": [ + { + "listen": "test", + "script": { + "id": "5e569618-0584-4849-9571-689ef1a79248", + "exec": ["utils.cannotTest(\"eth_blockNumber\", pm.response.json())", ""], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"eth_blockNumber\",\n\t\"params\":[],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Returns the block number of most recent block.\r\n\r\n**Parameters**\r\n\r\nNone\r\n\r\n**Returns**\r\n\r\nQUANTITY - Integer of the current highest block number the client is on" + }, + "response": [] + }, + { + "name": "syncing", + "event": [ + { + "listen": "test", + "script": { + "id": "8b16926e-2282-492c-9d84-48dd950ac85b", + "exec": [ + "// There's nothing really to test here. The node is always syncing", + "pm.test('Endpoint not tested', function() {", + " pm.expect(true).to.be.true;", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"eth_syncing\",\n\t\"params\":[],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Returns a data object detailing the status of the sync process or false if not syncing.\r\n\r\n**Parameters**\r\n\r\nNone\r\n\r\n**Returns**\r\n\r\nObject - An object of type Syncing or false if not syncing.\r\n\r\nstartingBlock: QUANTITY - The block at which the import started (will only be reset, after the sync reached his head)\r\n\r\ncurrentBlock: QUANTITY - The current block, same as eth_blockNumber\r\n\r\nhighestBlock: QUANTITY - The estimated highest block" + }, + "response": [] + }, + { + "name": "chainId", + "event": [ + { + "listen": "test", + "script": { + "id": "82448e71-a47e-4fee-9ba7-b6c0d211c075", + "exec": [ + "pm.test('Has correct result', function() {", + " const jsonData = pm.response.json();", + " pm.expect(jsonData.result).to.be.equals(\"0x1\")", + "});", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"eth_chainId\",\n\t\"params\":[],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Returns the current ethereum chainId.\r\n\r\n**Parameters**\r\n\r\nNone\r\n\r\n**Returns**\r\n\r\nQUANTITY - The current chainId" + }, + "response": [] + }, + { + "name": "protocolVersion", + "event": [ + { + "listen": "test", + "script": { + "id": "42dfa289-098b-43b0-9395-9ed18209fa20", + "exec": [ + "pm.test('Has correct result', function() {", + " var isParity = pm.environment.get('HOST') == \"{{PARITY}}\";", + " const jsonData = pm.response.json();", + " ", + " if (isParity) {", + " pm.expect(jsonData.result).to.be.equals(\"63\")", + " } else {", + " pm.expect(jsonData.result).to.be.equals(\"0x41\")", + " }", + "});", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"eth_protocolVersion\",\n\t\"params\":[],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Returns the current ethereum protocol version.\r\n\r\n**Parameters**\r\n\r\nNone\r\n\r\n**Returns**\r\n\r\nQUANTITY - The current ethereum protocol version" + }, + "response": [] + }, + { + "name": "gasPrice", + "event": [ + { + "listen": "test", + "script": { + "id": "50b5578b-4008-406c-a8f6-0459f258538d", + "exec": ["utils.cannotTest(\"eth_gasPrice\", pm.response.json())", ""], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"eth_gasPrice\",\n\t\"params\":[],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Returns the current price per gas in wei.\r\n\r\n**Parameters**\r\n\r\nNone\r\n\r\n**Returns**\r\n\r\nQUANTITY - Integer of the current gas price in wei" + }, + "response": [] + } + ], + "protocolProfileBehavior": {}, + "_postman_isSubFolder": true + }, + { + "name": "call", + "item": [ + { + "name": "call", + "event": [ + { + "listen": "test", + "script": { + "id": "3dde2a48-3bad-43c2-97a6-f4339f368992", + "exec": [ + "var expected = {", + " \"jsonrpc\": \"2.0\",", + " \"result\": \"0x0000000000000000000000000000000000000000000c685fa11e01ec6f000000\",", + " \"id\": \"1\"", + "}", + "", + "pm.test('Has correct result', function() {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData).to.be.deep.equal(expected);", + "})", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"eth_call\",\n\t\"params\":[\n {\n \"to\": \"0x08a2e41fb99a7599725190b9c970ad3893fa33cf\",\n \"data\": \"0x18160ddd\"\n },\n \"0xa2f2e0\"\n ],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Executes a new message call immediately without creating a transaction on the block chain.\r\n\r\n**Parameters**\r\n\r\nObject - An object of type Call\r\n\r\nDATA, 20 Bytes - (optional) The address the transaction is sent from\r\n\r\nDATA, 20 Bytes - The address the transaction is directed to\r\n\r\nQUANTITY - (optional) Integer of the gas provided for the transaction execution. eth_call consumes zero gas, but this parameter may be needed by some executions\r\n\r\nQUANTITY - (optional) Integer of the gasPrice used for each paid gas\r\n\r\nQUANTITY - (optional) Integer of the value sent with this transaction\r\n\r\nDATA - (optional) Hash of the method signature and encoded parameters. For details see Ethereum Contract ABI\r\n\r\nTAG - Integer block number or one of \"earliest\", \"latest\" or \"pending\"\r\n\r\n**Returns**\r\n\r\nDATA - The return value of executed contract" + }, + "response": [] + }, + { + "name": "estimateGas", + "event": [ + { + "listen": "test", + "script": { + "id": "61b5e2c2-b0c3-438c-a8cc-85bd6f058f75", + "exec": [ + "var expected = {", + " \"jsonrpc\": \"2.0\",", + " \"id\": \"1\",", + " \"result\": \"0x5208\"", + "}", + "", + "pm.test('Has correct result', function() {", + " pm.expect(pm.response.json()).to.be.deep.equal(expected);", + "})", + "", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"eth_estimateGas\",\n\t\"params\":[\n {\n \"to\": \"0x3d597789ea16054a084ac84ce87f50df9198f415\",\n \"from\": \"0x3d597789ea16054a084ac84ce87f50df9198f415\",\n \"value\": \"0x1\"\n }\n ],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Returns an estimate of how much gas is necessary to allow the transaction to complete. The transaction will not be added to the blockchain.\r\n\r\n**Note**\r\n\r\nThe estimate may be significantly more than the amount of gas actually used by the transaction for a variety of reasons including EVM mechanics and node performance.\r\n\r\n**Note**\r\n\r\nIf no gas limit is specified geth uses the block gas limit from the pending block as an upper bound. As a result the returned estimate might not be enough to executed the call/transaction when the amount of gas is higher than the pending block gas limit.\r\n\r\n**Parameters**\r\n\r\nObject - An object of type Call, see eth_call parameters, expect that all properties are optional\r\n\r\n**Returns**\r\n\r\nQUANTITY - The estimated amount of gas needed for the call" + }, + "response": [] + }, + { + "name": "sendTransaction", + "event": [ + { + "listen": "test", + "script": { + "id": "6099e6b6-bb38-45ed-8178-a2c148e4d2c5", + "exec": ["utils.notImplemented(\"eth_sendTransaction\", pm.response.json())", ""], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"eth_sendTransaction\",\n \"params\": [\n {\n \"from\": \" 0xb60e8dd61c5d32be8058bb8eb970870f07233155\",\n \"to\": \" 0xd46e8dd67c5d32be8058bb8eb970870f07244567\",\n \"gas\": \"0x76c0\",\n \"gasPrice\": \"0x9184e72a000\",\n \"value\": \"0x9184e72a\",\n \"data\": \"0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675\"\n }\n ],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Creates new message call transaction or a contract creation if the data field contains code.\r\n\r\n**Note**\r\n\r\nUse eth_getTransactionReceipt to get the contract address, after the transaction was mined, when you created a contract\r\n\r\n**Parameters**\r\n\r\nObject - An object of type SendTransaction\r\n\r\nDATA, 20 Bytes - The address the transaction is send from\r\n\r\nDATA, 20 Bytes - (optional when creating new contract) The address the transaction is directed to\r\n\r\nQUANTITY - (optional, default 90000) Integer of the gas provided for the transaction execution. It will return unused gas\r\n\r\nQUANTITY - (optional, default To-Be-Determined) Integer of the gasPrice used for each paid gas\r\n\r\nQUANTITY - (optional) Integer of the value sent with this transaction\r\n\r\nDATA - The compiled code of a contract OR the hash of the invoked method signature and encoded parameters. For details see Ethereum Contract ABI\r\n\r\nQUANTITY - (optional) Integer of a nonce. This allows to overwrite your own pending transactions that use the same nonce\r\n\r\n**Returns**\r\n\r\nDATA, 32 Bytes - The transaction hash, or the zero hash if the transaction is not yet available" + }, + "response": [] + }, + { + "name": "sendRawTransaction", + "event": [ + { + "listen": "test", + "script": { + "id": "3293bee1-893c-4d4c-bc5b-458235d2158b", + "exec": [ + "pm.test('Not tested', function() {", + " var tested = false;", + " pm.expect(tested).to.be.true", + "})", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"eth_sendRawTransaction\",\n\t\"params\":[\"0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675\"],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Creates new message call transaction or a contract creation for previously-signed transactions.\r\n\r\n**Note**\r\n\r\nUse eth_getTransactionReceipt to get the contract address, after the transaction was mined, when you created a contract.\r\n\r\n**Parameters**\r\n\r\nDATA - The signed transaction data\r\n\r\n**Returns**\r\n\r\nDATA, 32 Bytes - The transaction hash, or the zero hash if the transaction is not yet available" + }, + "response": [] + }, + { + "name": "getProof", + "event": [ + { + "listen": "test", + "script": { + "id": "3d8697ee-e17d-419f-b66a-1017f8f7ad22", + "exec": ["utils.notImplemented(\"eth_getProof\", pm.response.json())", ""], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"id\": \"1\",\n \"jsonrpc\": \"2.0\",\n \"method\": \"eth_getProof\",\n \"params\": [\n \"0x7F0d15C7FAae65896648C8273B6d7E43f58Fa842\",\n [ \"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\" ],\n \"latest\"\n ]\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "See this EIP of more information: https://github.com/ethereum/EIPs/issues/1186\r\n\r\nPossible implementation: https://github.com/vocdoni/eth-storage-proof\r\n\r\n**Parameters**\r\n\r\nDATA, 20 Bytes - The address of the storage locations being proved\r\n\r\nDATAARRAY - one or more storage locations to prove\r\n\r\nTAG - Integer block number or one of \"earliest\", \"latest\" or \"pending\"\r\n\r\n**Returns**\r\n\r\nDATA - The Merkel proof of the storage locations" + }, + "response": [] + } + ], + "event": [ + { + "listen": "prerequest", + "script": { + "id": "952dad06-2f84-4226-98c8-696d0fc84db6", + "type": "text/javascript", + "exec": [""] + } + }, + { + "listen": "test", + "script": { + "id": "e4208e7b-1dbd-4b84-9735-94dbf509f2e4", + "type": "text/javascript", + "exec": [""] + } + } + ], + "protocolProfileBehavior": {}, + "_postman_isSubFolder": true + }, + { + "name": "mining", + "item": [ + { + "name": "coinbase", + "event": [ + { + "listen": "test", + "script": { + "id": "6136a206-96bb-43f2-94bd-08f93303cf9a", + "exec": ["utils.notImplemented(\"eth_coinbase\", pm.response.json())", ""], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"eth_coinbase\",\n\t\"params\":[],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Returns the current client coinbase address.\r\n\r\n**Parameters**\r\n\r\nNone\r\n\r\n**Returns**\r\n\r\nDATA, 20 Bytes - The current coinbase address" + }, + "response": [] + }, + { + "name": "hashrate", + "event": [ + { + "listen": "test", + "script": { + "id": "9ac59f4f-7de3-4276-8e65-91cd0ad9c040", + "exec": ["utils.notImplemented(\"eth_hashrate\", pm.response.json())", ""], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"eth_hashrate\",\n\t\"params\":[],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Returns the number of hashes per second that the node is mining with.\r\n\r\n**Parameters**\r\n\r\nNone\r\n\r\n**Returns**\r\n\r\nQUANTITY - Number of hashes per second" + }, + "response": [] + }, + { + "name": "mining", + "event": [ + { + "listen": "test", + "script": { + "id": "8bdc9381-dbde-4419-b736-96e7914901e0", + "exec": [ + "var expected = {", + " \"jsonrpc\": \"2.0\",", + " \"id\": \"1\",", + " \"result\": false", + "}", + "", + "pm.test('Has correct result', function() {", + " pm.expect(pm.response.json()).to.be.deep.equal(expected);", + "})", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"eth_mining\",\n\t\"params\":[],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Returns true if client is actively mining new blocks.\r\n\r\n**Parameters**\r\n\r\nNone\r\n\r\n**Returns**\r\n\r\nBoolean - true if the client is mining, false otherwise" + }, + "response": [] + }, + { + "name": "getWork", + "event": [ + { + "listen": "test", + "script": { + "id": "99953248-ef11-4c01-92dc-26ce5ef38d9d", + "exec": ["utils.notImplemented(\"eth_getWork\", pm.response.json())", ""], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"eth_getWork\",\n\t\"params\":[],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Returns the hash of the current block, the seedHash, and the boundary condition to be met ('target').\r\n\r\n**Parameters**\r\n\r\nNone\r\n\r\n**Returns**\r\n\r\nObject - An object of type Work (an array of three hashes representing block header pow-hash, seed hash and boundary condition\r\n\r\ncurrent: DATA, 32 Bytes - current block header pow-hash\r\n\r\nseed: DATA, 32 Bytes - The seed hash used for the DAG\r\n\r\nboundary: DATA, 32 Bytes - The boundary condition ('target'), 2^256 / difficulty" + }, + "response": [] + }, + { + "name": "submitWork", + "event": [ + { + "listen": "test", + "script": { + "id": "db6d4657-a901-4ed5-9995-37f11ec9da6e", + "exec": ["utils.notImplemented(\"eth_submitWork\", pm.response.json())", ""], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\", \n\t\"method\":\"eth_submitWork\", \n\t\"params\":[\n\t\t\"0x1\", \n\t\t\"0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef\", \n\t\t\"0xD16E5700000000000000000000000000D16E5700000000000000000000000000\"\n\t],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Submits a proof-of-work solution to the blockchain.\r\n\r\n**Parameters**\r\n\r\nDATA, 8 Bytes - The nonce found (64 bits)\r\n\r\nDATA, 32 Bytes - The header's pow-hash (256 bits)\r\n\r\nDATA, 32 Bytes - The mix digest (256 bits)\r\n\r\n**Returns**\r\n\r\nBoolean - true if the provided solution is valid, false otherwise" + }, + "response": [] + }, + { + "name": "submitHashrate", + "event": [ + { + "listen": "test", + "script": { + "id": "394114d6-fffc-4cb8-a897-89e0bb6b0aa2", + "exec": ["utils.notImplemented(\"eth_submitHashrate\", pm.response.json())", ""], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\", \n\t\"method\":\"eth_submitHashrate\", \n\t\"params\":[\n\t\t\"0x0000000000000000000000000000000000000000000000000000000000500000\", \n\t\t\"0x59daa26581d0acd1fce254fb7e85952f4c09d0915afd33d3886cd914bc7d283c\"\n\t],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Submit the mining hashrate to the blockchain.\r\n\r\n**Parameters**\r\n\r\nDATA, 32 Bytes - a hexadecimal string representation of the hash rate\r\n\r\nString - A random hexadecimal ID identifying the client\r\n\r\n**Returns**\r\n\r\nBoolean - true if submitting went through succesfully, false otherwise" + }, + "response": [] + } + ], + "protocolProfileBehavior": {}, + "_postman_isSubFolder": true + } + ], + "protocolProfileBehavior": {} + }, + { + "name": "trace", + "item": [ + { + "name": "call", + "event": [ + { + "listen": "test", + "script": { + "id": "2e6a9c1c-38f4-4061-ae83-8fcc8a7511be", + "exec": ["utils.notImplemented(\"trace_call\", pm.response.json())", ""], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"jsonrpc\":\"2.0\",\n \"method\":\"trace_call\",\n \"params\":[\n {\n \"from\":\"0x407d73d8a49eeb85d32cf465507dd71d507100c1\",\n \"to\":\"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b\",\n \"value\":\"0x186a0\"\n },\n [\"trace\",\"vmTrace\"],\n \"latest\"\n ],\n \"id\": \"1\"\n}\n", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Executes the given call and returns a number of possible traces for it.\r\n\r\n**Parameters**\r\n\r\nObject - An object of type TraceCall\r\n\r\nfrom: DATA, 20 Bytes - (optional) 20 Bytes - The address the transaction is send from.\r\n\r\nto: DATA, 20 Bytes - (optional when creating new contract) 20 Bytes - The address the transaction is directed to.\r\n\r\ngas: QUANTITY - (optional) Integer formatted as a hex string of the gas provided for the transaction execution. eth_call consumes zero gas, but this parameter may be needed by some executions.\r\n\r\ngasPrice: QUANTITY - (optional) Integer formatted as a hex string of the gas price used for each paid gas.\r\n\r\nvalue: QUANTITY - (optional) Integer formatted as a hex string of the value sent with this transaction.\r\n\r\ndata: DATA - (optional) 4 byte hash of the method signature followed by encoded parameters. For details see Ethereum Contract ABI.\r\n\r\nSTRINGARRAY - An array of strings, one or more of: \"vmTrace\", \"trace\", \"stateDiff\".\r\n\r\nTAG - (optional) Integer of a block number, or the string 'earliest', 'latest' or 'pending'.\r\n\r\n**Returns**\r\n\r\nObject - An object of type BlockTraceArray" + }, + "response": [] + }, + { + "name": "callMany", + "event": [ + { + "listen": "test", + "script": { + "id": "fbec6f83-1a35-43dd-839b-8dea5ea39cfb", + "exec": ["utils.notImplemented(\"trace_callMany\", pm.response.json())", ""], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"trace_callMany\",\n \"params\": [\n [\n [\n {\n \"from\":\"0x407d73d8a49eeb85d32cf465507dd71d507100c1\",\n \"to\":\"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b\",\n \"value\":\"0x186a0\"\n },\n [\"trace\"]\n ],\n [\n {\n \"from\":\"0x407d73d8a49eeb85d32cf465507dd71d507100c1\",\n \"to\":\"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b\",\n \"value\":\"0x186a0\"\n },\n [\"trace\"]\n ]\n ],\n \"latest\"\n ],\n\t\"id\":\"1\"\n}\n", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Performs multiple call traces on top of the same block. i.e. transaction n will be executed on top of a pending block with all n-1 transactions applied (traced) first. Allows to trace dependent transactions.\r\n\r\n**Parameters**\r\n\r\nCALLARRAY - An array of Call objects plus strings, one or more of: \"vmTrace\", \"trace\", \"stateDiff\".\r\n\r\nTAG - (optional) integer block number, or the string 'latest', 'earliest' or 'pending', see the default block parameter.\r\n\r\n**Returns**\r\n\r\nObject - An object of type BlockTraceArray" + }, + "response": [] + }, + { + "name": "rawTransaction", + "event": [ + { + "listen": "test", + "script": { + "id": "a2465974-9dba-4410-a7bd-67b493703d29", + "exec": ["utils.notImplemented(\"trace_rawTransaction\", pm.response.json())", ""], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"trace_rawTransaction\",\n\t\"params\":[\"0x17104ac9d3312d8c136b7f44d4b8b47852618065ebfa534bd2d3b5ef218ca1f3\", [\"vmTrace\"]],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Traces a call to eth_sendRawTransaction without making the call, returning the traces\r\n\r\n**Parameters**\r\nDATA - Raw transaction data.\r\n\r\nSTRINGARRAY - Type of trace, one or more of: \"vmTrace\", \"trace\", \"stateDiff\".\r\n\r\n**Returns**\r\nObject - An object of type BlockTrace." + }, + "response": [] + }, + { + "name": "replayBlockTransactions", + "event": [ + { + "listen": "test", + "script": { + "id": "7ae64e81-7268-4743-ae25-98a2d53386c0", + "exec": ["utils.notImplemented(\"trace_replayBlockTransactions\", pm.response.json())", ""], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"trace_replayBlockTransactions\",\n\t\"params\":[\"0x2\",[\"trace\"]],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Replays all transactions in a block returning the requested traces for each transaction.\r\n\r\n**Parameters**\r\n\r\nTAG - Integer of a block number, or the string 'earliest', 'latest' or 'pending'.\r\n\r\nSTRINGARRAY - Type of trace, one or more of: \"vmTrace\", \"trace\", \"stateDiff\".\r\n\r\n**Returns**\r\n\r\nObject - An object of type BlockTraceArray." + }, + "response": [] + }, + { + "name": "replayTransaction", + "event": [ + { + "listen": "test", + "script": { + "id": "b60375bb-313f-47cc-9a7d-ff4abffebe99", + "exec": ["utils.notImplemented(\"trace_replayTransaction\", pm.response.json())", ""], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"trace_replayTransaction\",\n \"params\": [\n \"0x02d4a872e096445e80d05276ee756cefef7f3b376bcec14246469c0cd97dad8f\",\n [\"trace\"]\n ],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Replays a transaction, returning the traces.\r\n\r\n**Parameters**\r\nDATA, 32 Bytes - The transaction's hash.\r\n\r\nSTRINGARRAY - Type of trace, one or more of: \"vmTrace\", \"trace\", \"stateDiff\".\r\n\r\n**Returns**\r\nObject - An object of type BlockTrace." + }, + "response": [] + }, + { + "name": "transaction", + "event": [ + { + "listen": "test", + "script": { + "id": "de0d1c16-7bd3-4d6c-ae80-1001f994f1ed", + "exec": [ + "var expected = {", + " \"jsonrpc\": \"2.0\",", + " \"id\": \"1\",", + " \"result\": [", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0x83806d539d4ea1c140489a06660319c9a303f874\",", + " \"gas\": \"0x1a1f8\",", + " \"input\": \"0x\",", + " \"to\": \"0x1c39ba39e4735cb65978d4db400ddd70a72dc750\",", + " \"value\": \"0x7a16c911b4d00000\"", + " },", + " \"blockHash\": \"0x7eb25504e4c202cf3d62fd585d3e238f592c780cca82dacb2ed3cb5b38883add\",", + " \"blockNumber\": 3068185,", + " \"result\": {", + " \"gasUsed\": \"0x2982\",", + " \"output\": \"0x\"", + " },", + " \"subtraces\": 2,", + " \"traceAddress\": [],", + " \"transactionHash\": \"0x17104ac9d3312d8c136b7f44d4b8b47852618065ebfa534bd2d3b5ef218ca1f3\",", + " \"transactionPosition\": 2,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0x1c39ba39e4735cb65978d4db400ddd70a72dc750\",", + " \"gas\": \"0x13e99\",", + " \"input\": \"0x16c72721\",", + " \"to\": \"0x2bd2326c993dfaef84f696526064ff22eba5b362\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0x7eb25504e4c202cf3d62fd585d3e238f592c780cca82dacb2ed3cb5b38883add\",", + " \"blockNumber\": 3068185,", + " \"result\": {", + " \"gasUsed\": \"0x183\",", + " \"output\": \"0x0000000000000000000000000000000000000000000000000000000000000001\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [", + " 0", + " ],", + " \"transactionHash\": \"0x17104ac9d3312d8c136b7f44d4b8b47852618065ebfa534bd2d3b5ef218ca1f3\",", + " \"transactionPosition\": 2,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0x1c39ba39e4735cb65978d4db400ddd70a72dc750\",", + " \"gas\": \"0x8fc\",", + " \"input\": \"0x\",", + " \"to\": \"0x70faa28a6b8d6829a4b1e649d26ec9a2a39ba413\",", + " \"value\": \"0x7a16c911b4d00000\"", + " },", + " \"blockHash\": \"0x7eb25504e4c202cf3d62fd585d3e238f592c780cca82dacb2ed3cb5b38883add\",", + " \"blockNumber\": 3068185,", + " \"result\": {", + " \"gasUsed\": \"0x0\",", + " \"output\": \"0x\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [", + " 1", + " ],", + " \"transactionHash\": \"0x17104ac9d3312d8c136b7f44d4b8b47852618065ebfa534bd2d3b5ef218ca1f3\",", + " \"transactionPosition\": 2,", + " \"type\": \"call\"", + " }", + " ]", + "}", + "", + "pm.test('Has correct result', function() {", + " pm.expect(pm.response.json()).to.be.deep.equal(expected);", + "})", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"trace_transaction\",\n \"params\":[\"0x17104ac9d3312d8c136b7f44d4b8b47852618065ebfa534bd2d3b5ef218ca1f3\"],\n\t\"id\":\"1\"\n}\n", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Returns traces for the given transaction\r\n\r\n**Parameters**\r\n\r\nDATA, 32 Bytes - The transaction's hash\r\n\r\n**Returns**\r\n\r\nObject - An object of type AdhocTraceArray, see trace_filter." + }, + "response": [] + }, + { + "name": "get", + "event": [ + { + "listen": "test", + "script": { + "id": "c1d276a3-867a-43ba-8d82-629650317491", + "exec": [ + "var expected = {", + " \"jsonrpc\": \"2.0\",", + " \"id\": \"1\",", + " \"result\": {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0x1c39ba39e4735cb65978d4db400ddd70a72dc750\",", + " \"gas\": \"0x13e99\",", + " \"input\": \"0x16c72721\",", + " \"to\": \"0x2bd2326c993dfaef84f696526064ff22eba5b362\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0x7eb25504e4c202cf3d62fd585d3e238f592c780cca82dacb2ed3cb5b38883add\",", + " \"blockNumber\": 3068185,", + " \"result\": {", + " \"gasUsed\": \"0x183\",", + " \"output\": \"0x0000000000000000000000000000000000000000000000000000000000000001\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [", + " 0", + " ],", + " \"transactionHash\": \"0x17104ac9d3312d8c136b7f44d4b8b47852618065ebfa534bd2d3b5ef218ca1f3\",", + " \"transactionPosition\": 2,", + " \"type\": \"call\"", + " }", + "}", + "", + "pm.test('Has correct result', function() {", + " pm.expect(pm.response.json()).to.be.deep.equal(expected);", + "})", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"trace_get\",\n \"params\":[\n \"0x17104ac9d3312d8c136b7f44d4b8b47852618065ebfa534bd2d3b5ef218ca1f3\",\n [\"0x0\"]\n ],\n\t\"id\":\"1\"\n}\n", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Returns trace at given position.\r\n\r\n**Parameters**\r\n\r\nDATA, 32 Bytes - The transaction's hash.\r\n\r\nQUANTITYARRAY - The index position of the trace.\r\n\r\n**Returns**\r\n\r\nObject - An object of type AdhocTraceArray, see trace_filter." + }, + "response": [] + }, + { + "name": "block", + "event": [ + { + "listen": "test", + "script": { + "id": "0ab5009a-3398-4d25-a894-862f86e10785", + "exec": [ + "var expected = {", + " \"jsonrpc\": \"2.0\",", + " \"id\": \"1\",", + " \"result\": [", + " {", + " \"action\": {", + " \"author\": \"0x5088d623ba0fcf0131e0897a91734a4d83596aa0\",", + " \"rewardType\": \"block\",", + " \"value\": \"0x478eae0e571ba000\"", + " },", + " \"blockHash\": \"0x3d6122660cc824376f11ee842f83addc3525e2dd6756b9bcf0affa6aa88cf741\",", + " \"blockNumber\": 3,", + " \"result\": {},", + " \"subtraces\": 0,", + " \"traceAddress\": null,", + " \"transactionHash\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",", + " \"transactionPosition\": 0,", + " \"type\": \"reward\"", + " },", + " {", + " \"action\": {", + " \"author\": \"0xc8ebccc5f5689fa8659d83713341e5ad19349448\",", + " \"rewardType\": \"uncle\",", + " \"value\": \"0x340aad21b3b70000\"", + " },", + " \"blockHash\": \"0x3d6122660cc824376f11ee842f83addc3525e2dd6756b9bcf0affa6aa88cf741\",", + " \"blockNumber\": 3,", + " \"result\": {},", + " \"subtraces\": 0,", + " \"traceAddress\": null,", + " \"transactionHash\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",", + " \"transactionPosition\": 0,", + " \"type\": \"reward\"", + " }", + " ]", + "}", + "", + "pm.test('Has correct result', function() {", + " pm.expect(pm.response.json()).to.be.deep.equal(expected);", + "})" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"trace_block\",\n\t\"params\":[\"0x3\"],\n\t\"id\":\"1\"\n}\n", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Returns traces created at given block.\r\n\r\n**Parameters**\r\n\r\nTAG - Integer of a block number, or the string 'earliest', 'latest' or 'pending'.\r\n\r\n**Returns**\r\n\r\nObject - An object of type AdhocTraceArray." + }, + "response": [] + }, + { + "name": "filter", + "event": [ + { + "listen": "test", + "script": { + "id": "9b701d79-77b1-48fb-b8a7-4b38e6e63c5d", + "exec": [ + "var expected = {", + " \"jsonrpc\": \"2.0\",", + " \"id\": \"1\",", + " \"result\": [", + " {", + " \"action\": {", + " \"author\": \"0x5088d623ba0fcf0131e0897a91734a4d83596aa0\",", + " \"rewardType\": \"block\",", + " \"value\": \"0x478eae0e571ba000\"", + " },", + " \"blockHash\": \"0x3d6122660cc824376f11ee842f83addc3525e2dd6756b9bcf0affa6aa88cf741\",", + " \"blockNumber\": 3,", + " \"result\": {},", + " \"subtraces\": 0,", + " \"traceAddress\": null,", + " \"transactionHash\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",", + " \"transactionPosition\": 0,", + " \"type\": \"reward\"", + " },", + " {", + " \"action\": {", + " \"author\": \"0xc8ebccc5f5689fa8659d83713341e5ad19349448\",", + " \"rewardType\": \"uncle\",", + " \"value\": \"0x340aad21b3b70000\"", + " },", + " \"blockHash\": \"0x3d6122660cc824376f11ee842f83addc3525e2dd6756b9bcf0affa6aa88cf741\",", + " \"blockNumber\": 3,", + " \"result\": {},", + " \"subtraces\": 0,", + " \"traceAddress\": null,", + " \"transactionHash\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",", + " \"transactionPosition\": 0,", + " \"type\": \"reward\"", + " }", + " ]", + "}", + "", + "pm.test('Has correct result', function() {", + " pm.expect(pm.response.json()).to.be.deep.equal(expected);", + "})" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"trace_filter\",\n \"params\":[\n {\n \"fromBlock\":\"0x3\",\n \"toBlock\":\"0x3\"\n }\n ],\n\t\"id\":\"1\"\n}\n", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Returns traces matching given filter\r\n\r\n**Parameters**\r\n\r\nObject - An object of type TraceFilter\r\n\r\nfromBlock: TAG - (optional) From this block.\r\n\r\ntoBlock: TAG - (optional) To this block.\r\n\r\nfromAddress: DATA, 20 Bytes - (optional) Sent from these addresses.\r\n\r\ntoAddress: DATA, 20 Bytes - (optional) Sent to these addresses.\r\n\r\nafter: QUANTITY - (optional) The offset trace number\r\n\r\ncount: QUANTITY - (optional) Integer number of traces to display in a batch.\r\n\r\n**Returns**\r\nObject - An object of type AdHocTraceArray matching the given filter." + }, + "response": [] + } + ], + "protocolProfileBehavior": {} + }, + { + "name": "erigon", + "item": [ + { + "name": "forks", + "event": [ + { + "listen": "test", + "script": { + "id": "331402b4-0302-4516-b601-b160484292b3", + "exec": [ + "var expected = {", + " \"jsonrpc\": \"2.0\",", + " \"id\": \"1\",", + " \"result\": {", + " \"genesis\": \"0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3\",", + " \"forks\": [", + " 1150000,", + " 1920000,", + " 2463000,", + " 2675000,", + " 4370000,", + " 7280000,", + " 9069000,", + " 9200000", + " ]", + " }", + "}", + "", + "pm.test('Has correct result', function() {", + " pm.expect(pm.response.json()).to.be.deep.equal(expected);", + "})", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"erigon_forks\",\n\t\"params\":[],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Returns the genesis block hash and a sorted list of already passed fork block numbers as well as the next fork block (if applicable)\r\n\r\n**Parameters**\r\n\r\nNone\r\n\r\n**Returns**\r\n\r\nObject - An object of type Fork\r\n\r\ngenesis: DATA, 32 Bytes - The hash of the genesis block\r\n\r\npassed: ARRAY of QUANTITY - Array of block numbers passed by this client\r\n\r\nnext: QUANTITY - (optional) the next fork block" + }, + "response": [] + }, + { + "name": "getHeaderByNumber", + "event": [ + { + "listen": "test", + "script": { + "id": "8f7e9f2d-1508-4ce6-bb7e-ab697a69ce66", + "exec": [ + "var expected = {", + " \"jsonrpc\": \"2.0\",", + " \"id\": \"1\",", + " \"result\": {", + " \"parentHash\": \"0xb495a1d7e6663152ae92708da4843337b958146015a2802f4193a410044698c9\",", + " \"sha3Uncles\": \"0x6b17b938c6e4ef18b26ad81b9ca3515f27fd9c4e82aac56a1fd8eab288785e41\",", + " \"miner\": \"0x5088d623ba0fcf0131e0897a91734a4d83596aa0\",", + " \"stateRoot\": \"0x76ab0b899e8387436ff2658e2988f83cbf1af1590b9fe9feca3714f8d1824940\",", + " \"transactionsRoot\": \"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\",", + " \"receiptsRoot\": \"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\",", + " \"logsBloom\": \"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",", + " \"difficulty\": \"0x3fe802ffe\",", + " \"number\": \"0x3\",", + " \"gasLimit\": \"0x1388\",", + " \"gasUsed\": \"0x0\",", + " \"timestamp\": \"0x55ba4260\",", + " \"extraData\": \"0x476574682f76312e302e302d66633739643332642f6c696e75782f676f312e34\",", + " \"mixHash\": \"0x65e12eec23fe6555e6bcdb47aa25269ae106e5f16b54e1e92dcee25e1c8ad037\",", + " \"nonce\": \"0x2e9344e0cbde83ce\",", + " \"hash\": \"0x3d6122660cc824376f11ee842f83addc3525e2dd6756b9bcf0affa6aa88cf741\"", + " }", + "}", + "", + "pm.test('Has correct result', function() {", + " pm.expect(pm.response.json()).to.be.deep.equal(expected);", + "})", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"erigon_getHeaderByNumber\",\n\t\"params\":[\n\t\t\"0x3\"\n\t],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Returns a block's header given a block number ignoring the block's transaction and uncle list (may be faster).\r\n\r\n**Parameters**\r\n\r\nTAG - Integer block number or one of \"earliest\", \"latest\" or \"pending\"\r\n\r\n**Returns**\r\n\r\nObject - An object of type BlockHeader or null when no block was found. See eth_getBlockByHash" + }, + "response": [] + }, + { + "name": "getHeaderByHash", + "event": [ + { + "listen": "test", + "script": { + "id": "2ca80cf3-6a70-44ae-8741-3d8851096b65", + "exec": [ + "var expected = {", + " \"jsonrpc\": \"2.0\",", + " \"id\": \"1\",", + " \"result\": {", + " \"parentHash\": \"0xb495a1d7e6663152ae92708da4843337b958146015a2802f4193a410044698c9\",", + " \"sha3Uncles\": \"0x6b17b938c6e4ef18b26ad81b9ca3515f27fd9c4e82aac56a1fd8eab288785e41\",", + " \"miner\": \"0x5088d623ba0fcf0131e0897a91734a4d83596aa0\",", + " \"stateRoot\": \"0x76ab0b899e8387436ff2658e2988f83cbf1af1590b9fe9feca3714f8d1824940\",", + " \"transactionsRoot\": \"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\",", + " \"receiptsRoot\": \"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\",", + " \"logsBloom\": \"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",", + " \"difficulty\": \"0x3fe802ffe\",", + " \"number\": \"0x3\",", + " \"gasLimit\": \"0x1388\",", + " \"gasUsed\": \"0x0\",", + " \"timestamp\": \"0x55ba4260\",", + " \"extraData\": \"0x476574682f76312e302e302d66633739643332642f6c696e75782f676f312e34\",", + " \"mixHash\": \"0x65e12eec23fe6555e6bcdb47aa25269ae106e5f16b54e1e92dcee25e1c8ad037\",", + " \"nonce\": \"0x2e9344e0cbde83ce\",", + " \"hash\": \"0x3d6122660cc824376f11ee842f83addc3525e2dd6756b9bcf0affa6aa88cf741\"", + " }", + "}", + "", + "pm.test('Has correct result', function() {", + " pm.expect(pm.response.json()).to.be.deep.equal(expected);", + "})", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"erigon_getHeaderByHash\",\n\t\"params\":[\n\t\t\"0x3d6122660cc824376f11ee842f83addc3525e2dd6756b9bcf0affa6aa88cf741\"\n\t],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Returns a block's header given a block's hash.\r\n\r\n**Parameters**\r\n\r\nDATA, 32 Bytes - Hash of a block\r\n\r\n**Returns**\r\n\r\nObject - An object of type BlockHeader or null when no block was found. See eth_getBlockByHash" + }, + "response": [] + }, + { + "name": "getLogsByHash", + "event": [ + { + "listen": "test", + "script": { + "id": "6a55ab5e-fa04-4e14-b7f9-1b387ee51188", + "exec": [ + "var expected = [", + " null,", + " [", + " {", + " \"address\": \"0xb8c77482e45f1f44de1745f52c74426c631bdd52\",", + " \"topics\": [", + " \"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef\",", + " \"0x000000000000000000000000001866ae5b3de6caa5a51543fd9fb64f524f5478\",", + " \"0x00000000000000000000000016a9c11e229ce221578a9adb3e7c0a48482e8063\"", + " ],", + " \"data\": \"0x00000000000000000000000000000000000000000000021ea4a7ecbf3c280000\",", + " \"blockNumber\": \"0x3d0cec\",", + " \"transactionHash\": \"0x99f91752d50d0c2c92e681fda082843747e8284d846f8b623e4cd280fbd7bb65\",", + " \"transactionIndex\": \"0x2\",", + " \"blockHash\": \"0x2f244c154cbacb0305581295b80efa6dffb0224b60386a5fc6ae9585e2a140c4\",", + " \"logIndex\": \"0x0\",", + " \"removed\": false", + " }", + " ]", + "]", + "", + "pm.test('Has correct result', function() {", + " // We test just two log entries to keep the test case small", + " var jsonData = pm.response.json();", + " pm.expect(jsonData.result[0]).to.be.deep.equal(expected[0]);", + " pm.expect(jsonData.result[2]).to.be.deep.equal(expected[1]);", + "})", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"erigon_getLogsByHash\",\n\t\"params\":[\n\t\t\"0x2f244c154cbacb0305581295b80efa6dffb0224b60386a5fc6ae9585e2a140c4\"\n\t],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Returns an array of arrays of logs generated by the transactions in the block given by the block's hash.\r\n\r\n**Note**\r\n\r\nThe returned value is an array of arrays of log entries. There is an entry for each transaction in the block. BR BR If transaction X did not create any logs, the entry at result[X] will be null BR BR If transaction X generated N logs, the entry at position result[X] will be an array of N log objects\r\n\r\n**Parameters**\r\n\r\nDATA, 32 Bytes - Hash of block at which to retreive data\r\n\r\n**Returns**\r\n\r\nObject - An object of type LogArray some of which may be null found in the block. See eth_getFilterChanges" + }, + "response": [] + }, + { + "name": "issuance", + "event": [ + { + "listen": "test", + "script": { + "id": "b5a34317-4baa-4fb9-95a8-83f4f757c842", + "exec": [ + "var expected = {", + " \"jsonrpc\": \"2.0\",", + " \"id\": \"1\",", + " \"result\": {", + " \"blockReward\": \"0x478eae0e571ba000\",", + " \"uncleReward\": \"0x340aad21b3b70000\",", + " \"issuance\": \"0x7b995b300ad2a000\"", + " }", + "}", + "", + "pm.test('Has correct result', function() {", + " pm.expect(pm.response.json()).to.be.deep.equal(expected);", + "})", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"erigon_issuance\",\n\t\"params\":[\n\t\t\"0x3\"\n\t],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Returns the total issuance (block reward plus uncle reward) for the given block.\r\n\r\n**Parameters**\r\n\r\nTAG - Integer block number or one of \"earliest\", \"latest\" or \"pending\"\r\n\r\n**Returns**\r\n\r\nObject - An object of type Issuance\r\n\r\nblockReward: QUANTITY - The issuance to the miner of the block (includes nephew reward but not transaction fees)\r\n\r\nuncleReward: QUANTITY - The issuance to miners of included uncle (if any)\r\n\r\nissuance: QUANTITY - The sum of blockReward and uncleReward" + }, + "response": [] + } + ], + "protocolProfileBehavior": {} + }, + { + "name": "debug", + "item": [ + { + "name": "storageRangeAt", + "event": [ + { + "listen": "test", + "script": { + "id": "c4bcaf47-dd81-42af-9bbd-9256ba908426", + "exec": [ + "var isSilk = pm.environment.get('HOST') == \"{{SILKRPC}}\";", + "if (isSilk) {", + " utils.notImplemented(\"debug_storageRangeAt\", pm.response.json())", + " return;", + "}", + "var isErigon = pm.environment.get('HOST') == \"{{ERIGON}}\";", + "if (isErigon) {", + " utils.cannotTest(\"debug_accountRange\", pm.response.json())", + " return;", + "}", + "var expected = {", + " \"jsonrpc\": \"2.0\",", + " \"id\": \"1\",", + " \"result\": {", + " \"storage\": {", + " \"0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563\": {", + " \"key\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",", + " \"value\": \"0x000000000000000000000000ed2f1401f8994d3ff2b2a923e743c24c2914ab4f\"", + " },", + " \"0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6\": {", + " \"key\": \"0x0000000000000000000000000000000000000000000000000000000000000001\",", + " \"value\": \"0x000000000000000000000000739c71235a9669f6b900490ab1c95310c19abc71\"", + " }", + " },", + " \"nextKey\": \"0x0000000000000000000000000000000000000000000000000000000000000002\"", + " }", + "}", + "", + "pm.test('Has correct result', function() {", + " pm.expect(pm.response.json()).to.be.deep.equal(expected);", + "})", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"debug_storageRangeAt\",\n\t\"params\":[\n\t\t\"0xd3f1853788b02e31067f2c6e65cb0ae56729e23e3c92e2393af9396fa182701d\", \n 1,\n \"0xb734c74ff4087493373a27834074f80acbd32827\",\n\t\t\"0x00\",\n 2\n\t],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Returns information about a range of storage locations (if any) for the given address.\r\n\r\n**Parameters**\r\n\r\nDATA, 32 Bytes - Hash of block at which to retreive data\r\n\r\nQUANTITY, 8 bytes - Transaction index in the give block\r\n\r\nDATA, 20 Bytes - Contract address from which to retreive storage data\r\n\r\nDATA, 32 Bytes - Storage key to retreive\r\n\r\nQUANTITY, 8 bytes - The number of values to retreive\r\n\r\n**Returns**\r\n\r\nObject - An object of type StorageRangeResult which is defined as\r\n\r\npair: KEY/VALUE - A key value pair of the storage location\r\n\r\nnextKey: DATA, 32 Bytes - (optional) Hash pointing to next storage pair or empty" + }, + "response": [] + }, + { + "name": "accountRange", + "event": [ + { + "listen": "test", + "script": { + "id": "8fa3bd0b-1c56-4fd5-b46b-66d52a22d7fc", + "exec": [ + "var expected = {", + " \"jsonrpc\": \"2.0\",", + " \"id\": \"1\",", + " \"result\": {", + " \"root\": \"0x8d8f6ffa5f2e55c0f8f0b88c3421d647e497f3ee0d66825f3f7433d7e244dde8\",", + " \"accounts\": {", + " \"0x0000000000000000000000000000000000000001\": {", + " \"balance\": \"0\",", + " \"nonce\": 0,", + " \"root\": \"0000000000000000000000000000000000000000000000000000000000000000\",", + " \"codeHash\": \"c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470\"", + " }", + " },", + " \"next\": \"AAAAAAAAAAAAAAAAAAAAAAAAAAI=\"", + " }", + "}", + "", + "pm.test('Has correct result', function() {", + " pm.expect(pm.response.json()).to.be.deep.equal(expected);", + "})", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"debug_accountRange\",\n\t\"params\":[\n\t\t\"0xaaaaa\", \n\t\t[1],\n 1,\n true,\n true,\n true\n\t],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Returns a range of accounts involved in the given block range\r\n\r\n**Parameters**\r\n\r\nTAG - Integer block number or one of \"earliest\", \"latest\" or \"pending\"\r\n\r\nDATAARRAY - an array of prefixs against which to match account addresses (report only on accounts addresses that begin with this prefix, default matches all accounts)\r\n\r\nQUANTITY, 8 bytes - the maximum number of accounts to retreive\r\n\r\nBoolean - if true, do not return byte code from the address, if false return the byte code (if any)\r\n\r\nBoolean - if true, do not return storage from the address, if false return storage (if any)\r\n\r\nBoolean - if true, do not return missing preimages, if false do return them\r\n\r\n**Returns**\r\n\r\nObject - An object of type IteratorDump which is defined as\r\n\r\nroot: string - IteratorDump\r\n\r\naccounts: map[common.Address]DumpAccount - IteratorDump\r\n\r\nnext: []byte - IteratorDump\r\n\r\nbalance: string - DumpAccount\r\n\r\nnonce: uint64 - DumpAccount\r\n\r\nroot: string - DumpAccount\r\n\r\ncodeHash: string - DumpAccount\r\n\r\ncode: string - DumpAccount\r\n\r\nstorage: map[string]string - DumpAccount\r\n\r\naddress: common.Address - (optional) DumpAccount\r\n\r\nsecureKey: hexutil.Bytes - DumpAccount\r\n\r\n" + }, + "response": [] + }, + { + "name": "getModifiedAccountsByNumber", + "event": [ + { + "listen": "test", + "script": { + "id": "019465f3-a3d5-457c-bd86-4f50b02e518c", + "exec": [ + "var isSilk = pm.environment.get('HOST') == \"{{SILKRPC}}\";", + "if (isSilk) {", + " utils.notImplemented(\"debug_getModifiedAccountsByNumber\", pm.response.json())", + " return;", + "}", + "var expected = {", + " \"jsonrpc\": \"2.0\",", + " \"id\": \"1\",", + " \"result\": [", + " \"0x8764b360076809bba4635c4281c3f44c1677d013\",", + " \"0x1194e966965418c7d73a42cceeb254d875860356\",", + " \"0x42e6723a0c884e922240e56d7b618bec96f35800\",", + " \"0x52bc44d5378309ee2abf1539bf71de1b7d7be3b5\",", + " \"0xdf88d2cf450e1134e0cd794c3b89d648c3269ffc\",", + " \"0x2a65aca4d5fc5b5c859090a6c34d164135398226\",", + " \"0x68795c4aa09d6f4ed3e5deddf8c2ad3049a601da\",", + " \"0x8751355da8bb4854620e247904fc64c2dbff0484\"", + " ]", + "}", + "", + "pm.test('Has correct result', function() {", + " const jsonData = pm.response.json();", + " jsonData.result = jsonData.result.sort();", + " expected.result = expected.result.sort();", + " pm.expect(jsonData).to.be.deep.equal(expected);", + "})", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"debug_getModifiedAccountsByNumber\",\n\t\"params\":[\n\t\t\"0xccccd\",\n\t\t\"0xcccce\"\n\t],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Returns a list of accounts modified in the given block.\r\n\r\n**Parameters**\r\n\r\nTAG - Integer block number or one of \"earliest\", \"latest\" or \"pending\"\r\n\r\nTAG - Integer block number or one of \"earliest\", \"latest\" or \"pending\". Optional, defaults to startNum\r\n\r\n**Returns**\r\n\r\nArray of DATA, 20 Bytes - Array of addresses modifed in the given block range" + }, + "response": [] + }, + { + "name": "getModifiedAccountsByHash", + "event": [ + { + "listen": "test", + "script": { + "id": "bbbf909f-9ce2-4558-8e29-abc5ac1f5899", + "exec": [ + "var isSilk = pm.environment.get('HOST') == \"{{SILKRPC}}\";", + "if (isSilk) {", + " utils.notImplemented(\"debug_getModifiedAccountsByHash\", pm.response.json())", + " return;", + "}", + "var expected = {", + " \"jsonrpc\": \"2.0\",", + " \"id\": \"1\",", + " \"result\": [", + " \"0x8764b360076809bba4635c4281c3f44c1677d013\",", + " \"0x1194e966965418c7d73a42cceeb254d875860356\",", + " \"0x42e6723a0c884e922240e56d7b618bec96f35800\",", + " \"0x52bc44d5378309ee2abf1539bf71de1b7d7be3b5\",", + " \"0xdf88d2cf450e1134e0cd794c3b89d648c3269ffc\",", + " \"0x2a65aca4d5fc5b5c859090a6c34d164135398226\",", + " \"0x68795c4aa09d6f4ed3e5deddf8c2ad3049a601da\",", + " \"0x8751355da8bb4854620e247904fc64c2dbff0484\"", + " ]", + "}", + "", + "pm.test('Has correct result', function() {", + " const jsonData = pm.response.json();", + " jsonData.result = jsonData.result.sort();", + " expected.result = expected.result.sort();", + " pm.expect(jsonData).to.be.deep.equal(expected);", + "})", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"debug_getModifiedAccountsByHash\",\n\t\"params\":[\n\t\t\"0x2a1af018e33bcbd5015c96a356117a5251fcccf94a9c7c8f0148e25fdee37aec\",\n\t\t\"0x4e3d3e7eee350df0ee6e94a44471ee2d22cfb174db89bbf8e6c5f6aef7b360c5\"\n\t],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Returns a list of accounts modified in the given block.\r\n\r\n**Parameters**\r\n\r\nDATA, 32 Bytes - the first hash of block at which to retreive data\r\n\r\nDATA, 32 Bytes - the last hash of block at which to retreive data. Optional, defaults to startHash\r\n\r\n**Returns**\r\n\r\nArray of DATA, 20 Bytes - Array of addresses modifed in the given block range" + }, + "response": [] + }, + { + "name": "traceTransaction", + "event": [ + { + "listen": "test", + "script": { + "id": "a2e80bc5-85c6-4415-8e06-22ebe0d310cd", + "exec": [ + "var isSilk = pm.environment.get('HOST') == \"{{SILKRPC}}\";", + "if (isSilk) {", + " utils.notImplemented(\"debug_traceTransaction\", pm.response.json())", + " return;", + "}", + "var expected = [", + " {", + " \"pc\": 0,", + " \"op\": \"PUSH1\",", + " \"gas\": 179000,", + " \"gasCost\": 3,", + " \"depth\": 1,", + " \"stack\": [],", + " \"memory\": [],", + " \"storage\": {}", + " },", + " {", + " \"pc\": 2,", + " \"op\": \"PUSH1\",", + " \"gas\": 178997,", + " \"gasCost\": 3,", + " \"depth\": 1,", + " \"stack\": [", + " \"0000000000000000000000000000000000000000000000000000000000000060\"", + " ],", + " \"memory\": [],", + " \"storage\": {}", + " },", + " {", + " \"pc\": 284,", + " \"op\": \"STOP\",", + " \"gas\": 81142,", + " \"gasCost\": 0,", + " \"depth\": 1,", + " \"stack\": [],", + " \"memory\": [", + " \"0000000000000000000000000000000000000000000000000000000000000003\",", + " \"0000000000000000000000000000000000000000000000000000000000000000\",", + " \"0000000000000000000000000000000000000000000000000000000000000060\"", + " ],", + " \"storage\": {", + " \"0000000000000000000000000000000000000000000000000000000000000000\": \"0000000000000000000000000000000000000000000000000000000000000000\",", + " \"0000000000000000000000000000000000000000000000000000000000000001\": \"0000000000000000000000000000000000000000000000000000000000000001\",", + " \"0000000000000000000000000000000000000000000000000000000000000002\": \"0000000000000000000000000000000000000000000000000000000000000001\",", + " \"0000000000000000000000000000000000000000000000000000000000000003\": \"0000000000000000000000000000000000000000000000000000000000000006\",", + " \"c2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b\": \"000000000000000000000000881b0a4e9c55d08e31d8d3c022144d75a454211c\",", + " \"c2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85c\": \"000000000000000000000000fd2605a2bf58fdbb90db1da55df61628b47f9e8c\"", + " }", + " }", + "]", + "", + "pm.test('Has correct result', function() {", + " // because the returned data is pretty large, we only test the first two value and the last", + " var jsonData = pm.response.json()", + " pm.expect(jsonData.result.structLogs[0]).to.be.deep.equal(expected[0]);", + " pm.expect(jsonData.result.structLogs[1]).to.be.deep.equal(expected[1]);", + " pm.expect(jsonData.result.structLogs[jsonData.result.structLogs.length-1]).to.be.deep.equal(expected[2]);", + "})", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"debug_traceTransaction\",\n\t\"params\":[\n\t\t\"0x893c428fed019404f704cf4d9be977ed9ca01050ed93dccdd6c169422155586f\"\n\t],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Returns Geth style transaction traces.\r\n\r\n**Parameters**\r\n\r\nDATA, 32 Bytes - hash of transaction to trace.\r\n\r\n**Returns**\r\n\r\nSTACK_TRACE - An array of stack traces as per Geth" + }, + "response": [] + } + ], + "protocolProfileBehavior": {} + }, + { + "name": "deprecated", + "item": [ + { + "name": "eth", + "item": [ + { + "name": "accounts (deprecated)", + "event": [ + { + "listen": "test", + "script": { + "id": "49fab8c4-6858-4475-89f9-2c06a0acaaa0", + "exec": ["utils.isDeprecated(\"eth_accounts\", pm.response.json())", ""], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"eth_accounts\",\n\t\"params\":[],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Returns a list of addresses owned by the client.\r\n\r\n**Deprecated** This function will be removed in the future.\r\n\r\n**Parameters**\r\n\r\nNone\r\n\r\n**Returns**\r\n\r\nArray of DATA, 20 Bytes - addresses owned by the client" + }, + "response": [] + }, + { + "name": "getCompilers (deprecated)", + "event": [ + { + "listen": "test", + "script": { + "id": "71e1fac7-5027-4ec7-8a6f-b7ebba79ebc7", + "exec": ["utils.isDeprecated(\"eth_getCompilers\", pm.response.json())", ""], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"eth_getCompilers\",\n\t\"params\":[],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Returns a list of available compilers in the client.\r\n\r\n**Deprecated** This function will be removed in the future.\r\n\r\n**Parameters**\r\n\r\nNone\r\n\r\n**Returns**\r\n\r\nObject - An object of type StringArray of available compilers" + }, + "response": [] + }, + { + "name": "compileLLL (deprecated)", + "event": [ + { + "listen": "test", + "script": { + "id": "c143eb2a-869c-4d61-b77a-f1d96e35867d", + "exec": ["utils.isDeprecated(\"eth_compileLLL\", pm.response.json())", ""], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"eth_compileLLL\",\n\t\"params\":[\n\t\t\"(returnlll (suicide (caller)))\"\n\t],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Returns compiled LLL code.\r\n\r\n**Deprecated** This function will be removed in the future.\r\n\r\n**Parameters**\r\n\r\nString - The source code\r\n\r\n**Returns**\r\n\r\nDATA - The compiled source code" + }, + "response": [] + }, + { + "name": "compileSolidity (deprecated)", + "event": [ + { + "listen": "test", + "script": { + "id": "a225f789-727a-45b7-8233-b83fa9710f0b", + "exec": ["utils.isDeprecated(\"eth_compileSolidity\", pm.response.json())", ""], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"eth_compileSolidity\",\n\t\"params\":[\n\t\t\"contract test { function multiply(uint a) returns(uint d) { return a * 7; } }\"\n\t],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Returns compiled solidity code.\r\n\r\n**Deprecated** This function will be removed in the future.\r\n\r\n**Parameters**\r\n\r\nString - The source code\r\n\r\n**Returns**\r\n\r\nDATA - The compiled source code" + }, + "response": [] + }, + { + "name": "compileSerpent (deprecated)", + "event": [ + { + "listen": "test", + "script": { + "id": "281f3795-1854-47a9-b256-2e14f32ebff6", + "exec": ["utils.isDeprecated(\"eth_compileSerpent\", pm.response.json())", ""], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"eth_compileSerpent\",\n\t\"params\":[\"/* some serpent */\"],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Returns compiled serpent code.\r\n\r\n**Deprecated** This function will be removed in the future.\r\n\r\n**Parameters**\r\n\r\nString - The source code\r\n\r\n**Returns**\r\n\r\nDATA - The compiled source code" + }, + "response": [] + }, + { + "name": "sign (deprecated)", + "event": [ + { + "listen": "test", + "script": { + "id": "f3a959a5-3f2a-417b-ab6f-101ca25235ab", + "exec": ["utils.isDeprecated(\"eth_sign\", pm.response.json())", ""], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "id": "ccbe7bce-2ee4-4872-884d-884de423d002", + "exec": [ + "var isParity = pm.environment.get('HOST') == \"{{PARITY}}\";", + "if (isParity) {", + " pm.test.skip('Skipping for parity')", + "}" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"eth_sign\",\n\t\"params\":[\n\t\t\"0x9b2055d370f73ec7d8a03e965129118dc8f5bf83\", \n\t\t\"0xdeadbeef\"\n\t],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Calculates an Ethereum specific signature with: sign(keccak256(\"\\x19Ethereum Signed Message:\\n\" + len(message) + message))).\r\n\r\n**Deprecated** This function will be removed in the future.\r\n\r\n**Parameters**\r\n\r\nDATA, 20 Bytes - address\r\n\r\nDATA - message to sign\r\n\r\n**Returns**\r\n\r\nDATA - The signature" + }, + "response": [] + } + ], + "protocolProfileBehavior": {}, + "_postman_isSubFolder": true + }, + { + "name": "db", + "item": [ + { + "name": "getString (deprecated)", + "event": [ + { + "listen": "test", + "script": { + "id": "adc610c7-58da-4b14-86eb-5ad2b7e1bb42", + "exec": ["utils.isDeprecated(\"db_getString\", pm.response.json())", ""], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"db_getString\",\n\t\"params\":[\n\t\t\"testDB\",\n\t\t\"myKey\"\n\t],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Returns string from the local database.\r\n\r\n**Deprecated** This function will be removed in the future.\r\n\r\n**Parameters**\r\n\r\nString - Database name\r\n\r\nString - Key name\r\n\r\n**Returns**\r\n\r\nSTRING - The previously stored string" + }, + "response": [] + }, + { + "name": "putString (deprecated)", + "event": [ + { + "listen": "test", + "script": { + "id": "42952899-d220-432e-9c2f-5fd8b7f63a10", + "exec": ["utils.isDeprecated(\"db_putString\", pm.response.json())", ""], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "id": "765518a5-fcb0-4c40-bfd9-91a7dabaa24c", + "exec": [""], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"db_putString\",\n\t\"params\":[\n\t\t\"testDB\",\n\t\t\"myKey\",\n\t\t\"myString\"\n\t],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Stores a string in the local database.\r\n\r\n**Deprecated** This function will be removed in the future.\r\n\r\n**Parameters**\r\n\r\nString - Database name\r\n\r\nString - Key name\r\n\r\nString - String to store\r\n\r\n**Returns**\r\n\r\nBoolean - true if the value was stored, false otherwise" + }, + "response": [] + }, + { + "name": "getHex (deprecated)", + "event": [ + { + "listen": "test", + "script": { + "id": "1877532c-58ef-49e6-9adc-298e68e8e519", + "exec": ["utils.isDeprecated(\"db_getHex\", pm.response.json());"], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"db_getHex\"\n\t,\"params\":[\n\t\t\"testDB\",\n\t\t\"myKey\"\n\t],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Returns binary data from the local database.\r\n\r\n**Deprecated** This function will be removed in the future.\r\n\r\n**Parameters**\r\n\r\nString - Database name\r\n\r\nString - Key name\r\n\r\n**Returns**\r\n\r\nDATA - The previously stored data" + }, + "response": [] + }, + { + "name": "putHex (deprecated)", + "event": [ + { + "listen": "test", + "script": { + "id": "eb8f901f-11f6-40f1-96ba-db322d1bc017", + "exec": ["utils.isDeprecated(\"db_putHex\", pm.response.json())", ""], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"db_putHex\",\n\t\"params\":[\n\t\t\"testDB\",\n\t\t\"myKey\",\n\t\t\"0x68656c6c6f20776f726c64\"\n\t],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Stores binary data in the local database.\r\n\r\n**Deprecated** This function will be removed in the future.\r\n\r\n**Parameters**\r\n\r\nString - Database name\r\n\r\nString - Key name\r\n\r\nDATA - The data to store\r\n\r\n**Returns**\r\n\r\nBoolean - true if the value was stored, false otherwise" + }, + "response": [] + } + ], + "protocolProfileBehavior": {}, + "_postman_isSubFolder": true + }, + { + "name": "shh", + "item": [ + { + "name": "post (deprecated)", + "event": [ + { + "listen": "test", + "script": { + "id": "6f40e9ca-755e-42e3-9532-c629c98d7038", + "exec": ["utils.isDeprecated(\"shh_post\", pm.response.json());", ""], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"shh_post\",\n\t\"params\":[{\n\t\t\"from\":\"0xc931d93e97ab07fe42d923478ba2465f2..\",\n\t\t\"topics\": [\n\t\t\t\"0x68656c6c6f20776f726c64\"\n\t\t],\n\t\t\"payload\":\"0x68656c6c6f20776f726c64\",\n\t\t\"ttl\":\"0x64\",\n\t\t\"priority\":\"0x64\"\n\t}],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Sends a whisper message.\r\n\r\n**Deprecated** This function will be removed in the future.\r\n\r\n**Parameters**\r\n\r\nObject - An object of type Post\r\n\r\n**Returns**\r\n\r\nBoolean - true if the message was send, false otherwise" + }, + "response": [] + }, + { + "name": "version (deprecated)", + "event": [ + { + "listen": "test", + "script": { + "id": "4d2835ac-ef75-4a3e-ac48-8e6afa2508cb", + "exec": ["utils.isDeprecated(\"shh_version\", pm.response.json());", ""], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"shh_version\",\n\t\"params\":[],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Returns the current whisper protocol version.\r\n\r\n**Deprecated** This function will be removed in the future.\r\n\r\n**Parameters**\r\n\r\nNone\r\n\r\n**Returns**\r\n\r\nSTRING - The current whisper protocol version" + }, + "response": [] + }, + { + "name": "newIdentity (deprecated)", + "event": [ + { + "listen": "test", + "script": { + "id": "d5ca5bc1-1972-4479-a5cb-ea621c40c1f2", + "exec": ["utils.isDeprecated(\"shh_newIdentity\", pm.response.json());", ""], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"shh_newIdentity\",\n\t\"params\":[],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Creates new whisper identity in the client.\r\n\r\n**Deprecated** This function will be removed in the future.\r\n\r\n**Parameters**\r\n\r\nNone\r\n\r\n**Returns**\r\n\r\nDATA, 60 Bytes - The address of the new identiy" + }, + "response": [] + }, + { + "name": "hasIdentity (deprecated)", + "event": [ + { + "listen": "test", + "script": { + "id": "237a0212-f467-4bc7-825d-ce8eb97d02e7", + "exec": ["utils.isDeprecated(\"shh_hasIdentity\", pm.response.json());", ""], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"shh_hasIdentity\",\n\t\"params\":[\n\t\t\"0x04f96a5e25610293e42a73908e93ccc8c4d4dc0edcfa9fa872f50cb214e08ebf61a03e245533f97284d442460f2998cd41858798ddfd4d661997d3940272b717b1\"\n\t],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Checks if the client hold the private keys for a given identity.\r\n\r\n**Deprecated** This function will be removed in the future.\r\n\r\n**Parameters**\r\n\r\nDATA, 60 Bytes - The identity address to check\r\n\r\n**Returns**\r\n\r\nBoolean - true if the client holds the privatekey for that identity, false otherwise" + }, + "response": [] + }, + { + "name": "newGroup (deprecated)", + "event": [ + { + "listen": "test", + "script": { + "id": "498a4713-d7bf-4849-a794-bcb4ae1b13f6", + "exec": ["utils.isDeprecated(\"shh_newGroup\", pm.response.json());", ""], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"shh_newGroup\",\n\t\"params\":[],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Create a new group.\r\n\r\n**Deprecated** This function will be removed in the future.\r\n\r\n**Parameters**\r\n\r\nNone\r\n\r\n**Returns**\r\n\r\nDATA, 60 Bytes - The address of the new group" + }, + "response": [] + }, + { + "name": "addToGroup (deprecated)", + "event": [ + { + "listen": "test", + "script": { + "id": "59a5f8d0-6cb0-4948-9a94-a67494d56deb", + "exec": ["utils.isDeprecated(\"shh_addToGroup\", pm.response.json());", ""], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"shh_addToGroup\",\n\t\"params\":[\n\t\t\"0x04f96a5e25610293e42a73908e93ccc8c4d4dc0edcfa9fa872f50cb214e08ebf61a03e245533f97284d442460f2998cd41858798ddfd4d661997d3940272b717b1\"\n\t],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Add to a group.\r\n\r\n**Deprecated** This function will be removed in the future.\r\n\r\n**Parameters**\r\n\r\nDATA, 60 Bytes - The identity address to add to a group\r\n\r\n**Returns**\r\n\r\nBoolean - true if the identity was successfully added to the group, false otherwise" + }, + "response": [] + }, + { + "name": "newFilter (deprecated)", + "event": [ + { + "listen": "test", + "script": { + "id": "a3c1325c-f738-473f-b981-7a8f271377bd", + "exec": ["utils.isDeprecated(\"shh_newFilter\", pm.response.json());", ""], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"shh_newFilter\",\n\t\"params\":[{\n\t\t\"topics\": [\n\t\t\t\"0x12341234bf4b564f\"\n\t\t],\n\t\t\"to\": \"0x2341234bf4b2341234bf4b564f...\"\n\t}],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Creates filter to notify, when client receives whisper message matching the filter options.\r\n\r\n**Deprecated** This function will be removed in the future.\r\n\r\n**Parameters**\r\n\r\nObject - An object of type Filter\r\n\r\n**Returns**\r\n\r\nQUANTITY - The newly created filter id" + }, + "response": [] + }, + { + "name": "uninstallFilter (deprecated)", + "event": [ + { + "listen": "test", + "script": { + "id": "1f635382-7c93-456e-a4e0-6c9a31c3ff3e", + "exec": ["utils.isDeprecated(\"shh_uninstallFilter\", pm.response.json());", ""], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"shh_uninstallFilter\",\n\t\"params\":[\n\t\t\"0x7\"\n\t],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Uninstalls a filter with given id.\r\n\r\n**Deprecated** This function will be removed in the future.\r\n\r\n**Parameters**\r\n\r\nQUANTITY - The filter id\r\n\r\n**Returns**\r\n\r\nBoolean - true if the filter was successfully uninstalled, false otherwise" + }, + "response": [] + }, + { + "name": "getFilterChanges (deprecated)", + "event": [ + { + "listen": "test", + "script": { + "id": "1b86fec4-c310-4ad4-b87d-d6bcaa3e707c", + "exec": ["utils.isDeprecated(\"shh_getFilterChanges\", pm.response.json());", ""], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"shh_getFilterChanges\",\n\t\"params\":[\n\t\t\"0x7\"\n\t],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Polling method for whisper filters. Returns new messages since the last call of this method.\r\n\r\n**Deprecated** This function will be removed in the future.\r\n\r\n**Parameters**\r\n\r\nQUANTITY - The filter id\r\n\r\n**Returns**\r\n\r\nObject - An object of type MessageArray received since last poll" + }, + "response": [] + }, + { + "name": "getMessages (deprecated)", + "event": [ + { + "listen": "test", + "script": { + "id": "8cdf20b9-4b07-43ad-a96e-66d49cacb651", + "exec": ["utils.isDeprecated(\"shh_getMessages\", pm.response.json());", ""], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"shh_getMessages\",\n\t\"params\":[\n\t\t\"0x7\"\n\t],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": ["{{HOST}}"] + }, + "description": "Get all messages matching a filter. Unlike shh_getFilterChanges this returns all messages.\r\n\r\n**Deprecated** This function will be removed in the future.\r\n\r\n**Parameters**\r\n\r\nQUANTITY - The filter id\r\n\r\n**Returns**\r\n\r\nObject - An object of type MessageArray received since last poll" + }, + "response": [] + } + ], + "protocolProfileBehavior": {}, + "_postman_isSubFolder": true + } + ], + "description": "RPC commands in this group have been deprecated.", + "event": [ + { + "listen": "prerequest", + "script": { + "id": "f3715e8c-8219-4b4c-a797-283787c030da", + "type": "text/javascript", + "exec": [""] + } + }, + { + "listen": "test", + "script": { + "id": "b1b0fe57-01a2-480a-a5bf-fd11942fd43c", + "type": "text/javascript", + "exec": [""] + } + } + ], + "protocolProfileBehavior": {} + } + ], + "event": [ + { + "listen": "prerequest", + "script": { + "id": "28916081-d267-4803-b88f-38f0cfac83f3", + "type": "text/javascript", + "exec": [ + "utils = {", + " notImplemented: function(methodName, jsonData) {", + " var isErigon = pm.environment.get('HOST') == \"{{ERIGON}}\";", + " var isSilk = pm.environment.get('HOST') == \"{{SILKRPC}}\";", + " if (!isErigon && !isSilk) // only test erigon", + " return;", + "", + " var testNotImplemented = pm.globals.get('TEST_NOT_IMPLEMENTED') === 'true';", + " if (testNotImplemented) { // defaults to false, therefore don't test", + " pm.test('NOT IMPLEMENTED', function() {", + " pm.expect(false).to.be(true);", + " })", + " } else {", + " // pass unless user has explicitly told us to test not implemented", + " var expected = {", + " \"jsonrpc\": \"2.0\",", + " \"id\": \"1\",", + " \"error\": {", + " \"code\": -32000,", + " \"message\": \"the method is currently not implemented: \" + methodName", + " }", + " }", + " if (jsonData.error)", + " delete jsonData.error.data;", + " pm.test('NOT IMPLEMENTED', function() {", + " pm.expect(jsonData).to.deep.equals(expected);", + " })", + " }", + " },", + "", + " isDeprecated: function(methodName, jsonData) {", + " var isErigon = pm.environment.get('HOST') == \"{{ERIGON}}\";", + " var isSilk = pm.environment.get('HOST') == \"{{SILKRPC}}\";", + " if (!isErigon && !isSilk) // only test erigon", + " return;", + "", + " var testDeprecated = pm.globals.get('TEST_DEPRECATED') === 'true';", + " if (testDeprecated) { // defaults to false, therefore don't test", + " pm.test('DEPRECATED', function() {", + " console.log(\"testDeprecated2: \", testDeprecated)", + " pm.expect(false).to.be(true);", + " })", + " } else {", + " // pass unless user has explicitly told us to fail deprecated", + " var expected = {", + " \"jsonrpc\": \"2.0\",", + " \"id\": \"1\",", + " \"error\": {", + " \"code\": -32000,", + " \"message\": \"the method has been deprecated: \" + methodName", + " }", + " }", + " if (jsonData.error)", + " delete jsonData.error.data;", + " pm.test('DEPRECATED', function() {", + " pm.expect(jsonData).to.deep.equals(expected);", + " })", + " }", + " },", + "", + " cannotTest: function(methodName, jsonData) {", + " var isErigon = pm.environment.get('HOST') == \"{{ERIGON}}\";", + " var isSilk = pm.environment.get('HOST') == \"{{SILKRPC}}\";", + " if (!isErigon && !isSilk) // only test erigon", + " return;", + "", + " var expected = {", + " \"jsonrpc\": \"2.0\",", + " \"id\": \"1\",", + " \"result\": \"Cannot test - value changes\"", + " }", + " pm.test('VALUE CHANGES, CANNOT TEST: ' + methodName, function() {", + " jsonData.result = \"Cannot test - value changes\";", + " pm.expect(jsonData).to.deep.equals(expected);", + " })", + " },", + "};" + ] + } + }, + { + "listen": "test", + "script": { + "id": "be6e47aa-dcea-4eaf-941f-889669172f43", + "type": "text/javascript", + "exec": [ + "pm.test('Base tests', function() {", + " const jsonData = pm.response.json();", + " pm.response.to.have.status(200);", + " pm.expect(jsonData !== null)", + " jsonData.errors == null || pm.expect(jsonData.errors).to.be.empty;", + "})", + "" + ] + } + } + ], + "protocolProfileBehavior": {} +} diff --git a/cmd/rpcdaemon/postman/Trace_Testing.json b/cmd/rpcdaemon/postman/Trace_Testing.json new file mode 100644 index 0000000..74e7221 --- /dev/null +++ b/cmd/rpcdaemon/postman/Trace_Testing.json @@ -0,0 +1,7474 @@ +{ + "info": { + "_postman_id": "7b2a3a4b-0c75-4b99-8e8b-4237bcbd2494", + "name": "Trace Testing", + "description": "Tests related to tracing", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" + }, + "item": [ + { + "name": "trace_call", + "item": [ + { + "name": "trace_call - all", + "event": [ + { + "listen": "test", + "script": { + "id": "cad5e0e8-19aa-4c85-b322-fe4e9e40f0f7", + "exec": [ + "var expected = {", + " \"jsonrpc\": \"2.0\",", + " \"result\": {", + " \"output\": \"0x\",", + " \"stateDiff\": {", + " \"0x407d73d8a49eeb85d32cf465507dd71d507100c1\": {", + " \"balance\": {", + " \"+\": \"0x0\"", + " },", + " \"code\": {", + " \"+\": \"0x\"", + " },", + " \"nonce\": {", + " \"+\": \"0x1\"", + " },", + " \"storage\": {}", + " },", + " \"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b\": {", + " \"balance\": {", + " \"+\": \"0x186a0\"", + " },", + " \"code\": {", + " \"+\": \"0x\"", + " },", + " \"nonce\": {", + " \"+\": \"0x0\"", + " },", + " \"storage\": {}", + " }", + " },", + " \"trace\": [", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0x407d73d8a49eeb85d32cf465507dd71d507100c1\",", + " \"gas\": \"0x1dcd12f8\",", + " \"input\": \"0x\",", + " \"to\": \"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b\",", + " \"value\": \"0x186a0\"", + " },", + " \"result\": {", + " \"gasUsed\": \"0x0\",", + " \"output\": \"0x\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [],", + " \"type\": \"call\"", + " }", + " ],", + " \"vmTrace\": {", + " \"code\": \"0x\",", + " \"ops\": []", + " }", + " },", + " \"id\": \"1\"", + "}", + "", + "pm.test('Has correct result', function() {", + " pm.expect(pm.response.json()).to.be.deep.equal(expected);", + "})", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"jsonrpc\":\"2.0\",\n \"method\":\"trace_call\",\n \"params\":[\n {\n \"from\":\"0x407d73d8a49eeb85d32cf465507dd71d507100c1\",\n \"to\":\"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b\",\n \"value\":\"0x186a0\"\n },\n [\"trace\",\"vmTrace\",\"stateDiff\"],\n \"0x186a0\"\n ],\n \"id\": \"1\"\n}\n", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": [ + "{{HOST}}" + ] + } + }, + "response": [] + }, + { + "name": "trace_call - none", + "event": [ + { + "listen": "test", + "script": { + "id": "b5c127ba-f385-4ae5-a779-038281427a49", + "exec": [ + "var expected = {", + " \"jsonrpc\": \"2.0\",", + " \"result\": {", + " \"output\": \"0x\",", + " \"stateDiff\": null,", + " \"trace\": [],", + " \"vmTrace\": null", + " },", + " \"id\": \"1\"", + "}", + "", + "pm.test('Has correct result', function() {", + " pm.expect(pm.response.json()).to.be.deep.equal(expected);", + "})", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"jsonrpc\":\"2.0\",\n \"method\":\"trace_call\",\n \"params\":[\n {\n \"from\":\"0x407d73d8a49eeb85d32cf465507dd71d507100c1\",\n \"to\":\"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b\",\n \"value\":\"0x186a0\"\n },\n [],\n \"0x186a0\"\n ],\n \"id\": \"1\"\n}\n", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": [ + "{{HOST}}" + ] + } + }, + "response": [] + }, + { + "name": "trace_call - trace only", + "event": [ + { + "listen": "test", + "script": { + "id": "719796d3-02f9-499d-b22d-c7f42f9fa80a", + "exec": [ + "var expected = {", + " \"jsonrpc\": \"2.0\",", + " \"result\": {", + " \"output\": \"0x\",", + " \"stateDiff\": null,", + " \"trace\": [", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0x407d73d8a49eeb85d32cf465507dd71d507100c1\",", + " \"gas\": \"0x1dcd12f8\",", + " \"input\": \"0x\",", + " \"to\": \"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b\",", + " \"value\": \"0x186a0\"", + " },", + " \"result\": {", + " \"gasUsed\": \"0x0\",", + " \"output\": \"0x\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [],", + " \"type\": \"call\"", + " }", + " ],", + " \"vmTrace\": null", + " },", + " \"id\": \"1\"", + "}", + "", + "pm.test('Has correct result', function() {", + " pm.expect(pm.response.json()).to.be.deep.equal(expected);", + "})", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"jsonrpc\":\"2.0\",\n \"method\":\"trace_call\",\n \"params\":[\n {\n \"from\":\"0x407d73d8a49eeb85d32cf465507dd71d507100c1\",\n \"to\":\"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b\",\n \"value\":\"0x186a0\"\n },\n [\"trace\"],\n \"0x186a0\"\n ],\n \"id\": \"1\"\n}\n", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": [ + "{{HOST}}" + ] + } + }, + "response": [] + }, + { + "name": "trace_call - vmTrace only", + "event": [ + { + "listen": "test", + "script": { + "id": "bf873e95-ad20-42ef-b5da-71ef503f314c", + "exec": [ + "var expected = {", + " \"jsonrpc\": \"2.0\",", + " \"result\": {", + " \"output\": \"0x\",", + " \"stateDiff\": null,", + " \"trace\": [],", + " \"vmTrace\": {", + " \"code\": \"0x\",", + " \"ops\": []", + " }", + " },", + " \"id\": \"1\"", + "}", + "", + "pm.test('Has correct result', function() {", + " pm.expect(pm.response.json()).to.be.deep.equal(expected);", + "})", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"jsonrpc\":\"2.0\",\n \"method\":\"trace_call\",\n \"params\":[\n {\n \"from\":\"0x407d73d8a49eeb85d32cf465507dd71d507100c1\",\n \"to\":\"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b\",\n \"value\":\"0x186a0\"\n },\n [\"vmTrace\"],\n \"0x186a0\"\n ],\n \"id\": \"1\"\n}\n", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": [ + "{{HOST}}" + ] + } + }, + "response": [] + }, + { + "name": "trace_call - stateDiff only", + "event": [ + { + "listen": "test", + "script": { + "id": "eabf15c8-247b-4bfb-acfd-81c1851fa9d7", + "exec": [ + "var expected = {", + " \"jsonrpc\": \"2.0\",", + " \"result\": {", + " \"output\": \"0x\",", + " \"stateDiff\": {", + " \"0x407d73d8a49eeb85d32cf465507dd71d507100c1\": {", + " \"balance\": {", + " \"+\": \"0x0\"", + " },", + " \"code\": {", + " \"+\": \"0x\"", + " },", + " \"nonce\": {", + " \"+\": \"0x1\"", + " },", + " \"storage\": {}", + " },", + " \"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b\": {", + " \"balance\": {", + " \"+\": \"0x186a0\"", + " },", + " \"code\": {", + " \"+\": \"0x\"", + " },", + " \"nonce\": {", + " \"+\": \"0x0\"", + " },", + " \"storage\": {}", + " }", + " },", + " \"trace\": [],", + " \"vmTrace\": null", + " },", + " \"id\": \"1\"", + "}", + "", + "pm.test('Has correct result', function() {", + " pm.expect(pm.response.json()).to.be.deep.equal(expected);", + "})", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"jsonrpc\":\"2.0\",\n \"method\":\"trace_call\",\n \"params\":[\n {\n \"from\":\"0x407d73d8a49eeb85d32cf465507dd71d507100c1\",\n \"to\":\"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b\",\n \"value\":\"0x186a0\"\n },\n [\"stateDiff\"],\n \"0x186a0\"\n ],\n \"id\": \"1\"\n}\n", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": [ + "{{HOST}}" + ] + } + }, + "response": [] + } + ], + "protocolProfileBehavior": {} + }, + { + "name": "trace_callMany", + "item": [ + { + "name": "trace_callMany - all", + "event": [ + { + "listen": "test", + "script": { + "id": "7949387e-4c36-4942-a5a7-1759d7c43975", + "exec": [ + "var expected = {", + " \"jsonrpc\": \"2.0\",", + " \"result\": [", + " {", + " \"output\": \"0x\",", + " \"stateDiff\": {", + " \"0x407d73d8a49eeb85d32cf465507dd71d507100c1\": {", + " \"balance\": {", + " \"+\": \"0x0\"", + " },", + " \"code\": {", + " \"+\": \"0x\"", + " },", + " \"nonce\": {", + " \"+\": \"0x1\"", + " },", + " \"storage\": {}", + " },", + " \"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b\": {", + " \"balance\": {", + " \"+\": \"0x186a0\"", + " },", + " \"code\": {", + " \"+\": \"0x\"", + " },", + " \"nonce\": {", + " \"+\": \"0x0\"", + " },", + " \"storage\": {}", + " }", + " },", + " \"trace\": [", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0x407d73d8a49eeb85d32cf465507dd71d507100c1\",", + " \"gas\": \"0x1dcd12f8\",", + " \"input\": \"0x\",", + " \"to\": \"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b\",", + " \"value\": \"0x186a0\"", + " },", + " \"result\": {", + " \"gasUsed\": \"0x0\",", + " \"output\": \"0x\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [],", + " \"type\": \"call\"", + " }", + " ],", + " \"vmTrace\": {", + " \"code\": \"0x\",", + " \"ops\": []", + " }", + " },", + " {", + " \"output\": \"0x\",", + " \"stateDiff\": {", + " \"0x407d73d8a49eeb85d32cf465507dd71d507100c1\": {", + " \"balance\": \"=\",", + " \"code\": \"=\",", + " \"nonce\": {", + " \"*\": {", + " \"from\": \"0x1\",", + " \"to\": \"0x2\"", + " }", + " },", + " \"storage\": {}", + " },", + " \"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b\": {", + " \"balance\": {", + " \"*\": {", + " \"from\": \"0x186a0\",", + " \"to\": \"0x30d40\"", + " }", + " },", + " \"code\": \"=\",", + " \"nonce\": \"=\",", + " \"storage\": {}", + " }", + " },", + " \"trace\": [", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0x407d73d8a49eeb85d32cf465507dd71d507100c1\",", + " \"gas\": \"0x1dcd12f8\",", + " \"input\": \"0x\",", + " \"to\": \"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b\",", + " \"value\": \"0x186a0\"", + " },", + " \"result\": {", + " \"gasUsed\": \"0x0\",", + " \"output\": \"0x\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [],", + " \"type\": \"call\"", + " }", + " ],", + " \"vmTrace\": {", + " \"code\": \"0x\",", + " \"ops\": []", + " }", + " }", + " ],", + " \"id\": \"1\"", + "}", + "", + "pm.test('Has correct result', function() {", + " pm.expect(pm.response.json()).to.be.deep.equal(expected);", + "})", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"trace_callMany\",\n \"params\": [\n [\n [\n {\n \"from\":\"0x407d73d8a49eeb85d32cf465507dd71d507100c1\",\n \"to\":\"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b\",\n \"value\":\"0x186a0\"\n },\n [\"trace\",\"vmTrace\",\"stateDiff\"]\n ],\n [\n {\n \"from\":\"0x407d73d8a49eeb85d32cf465507dd71d507100c1\",\n \"to\":\"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b\",\n \"value\":\"0x186a0\"\n },\n [\"trace\",\"vmTrace\",\"stateDiff\"]\n ]\n ],\n \"0x186a0\"\n ],\n\t\"id\":\"1\"\n}\n", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": [ + "{{HOST}}" + ] + } + }, + "response": [] + }, + { + "name": "trace_callMany - none", + "event": [ + { + "listen": "test", + "script": { + "id": "1670fbac-fbed-4c5d-9e4f-cacf151fab86", + "exec": [ + "var expected = {", + " \"jsonrpc\": \"2.0\",", + " \"result\": [", + " {", + " \"output\": \"0x\",", + " \"stateDiff\": null,", + " \"trace\": [],", + " \"vmTrace\": null", + " },", + " {", + " \"output\": \"0x\",", + " \"stateDiff\": null,", + " \"trace\": [],", + " \"vmTrace\": null", + " }", + " ],", + " \"id\": \"1\"", + "}", + "", + "pm.test('Has correct result', function() {", + " pm.expect(pm.response.json()).to.be.deep.equal(expected);", + "})", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"trace_callMany\",\n \"params\": [\n [\n [\n {\n \"from\":\"0x407d73d8a49eeb85d32cf465507dd71d507100c1\",\n \"to\":\"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b\",\n \"value\":\"0x186a0\"\n },\n []\n ],\n [\n {\n \"from\":\"0x407d73d8a49eeb85d32cf465507dd71d507100c1\",\n \"to\":\"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b\",\n \"value\":\"0x186a0\"\n },\n []\n ]\n ],\n \"0x186a0\"\n ],\n\t\"id\":\"1\"\n}\n", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": [ + "{{HOST}}" + ] + } + }, + "response": [] + }, + { + "name": "trace_callMany - trace only", + "event": [ + { + "listen": "test", + "script": { + "id": "1e12f8e6-f089-458c-9b8f-9cc17d1f2828", + "exec": [ + "var expected = {", + " \"jsonrpc\": \"2.0\",", + " \"result\": [", + " {", + " \"output\": \"0x\",", + " \"stateDiff\": null,", + " \"trace\": [", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0x407d73d8a49eeb85d32cf465507dd71d507100c1\",", + " \"gas\": \"0x1dcd12f8\",", + " \"input\": \"0x\",", + " \"to\": \"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b\",", + " \"value\": \"0x186a0\"", + " },", + " \"result\": {", + " \"gasUsed\": \"0x0\",", + " \"output\": \"0x\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [],", + " \"type\": \"call\"", + " }", + " ],", + " \"vmTrace\": null", + " },", + " {", + " \"output\": \"0x\",", + " \"stateDiff\": null,", + " \"trace\": [", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0x407d73d8a49eeb85d32cf465507dd71d507100c1\",", + " \"gas\": \"0x1dcd12f8\",", + " \"input\": \"0x\",", + " \"to\": \"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b\",", + " \"value\": \"0x186a0\"", + " },", + " \"result\": {", + " \"gasUsed\": \"0x0\",", + " \"output\": \"0x\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [],", + " \"type\": \"call\"", + " }", + " ],", + " \"vmTrace\": null", + " }", + " ],", + " \"id\": \"1\"", + "}", + "", + "pm.test('Has correct result', function() {", + " pm.expect(pm.response.json()).to.be.deep.equal(expected);", + "})", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"trace_callMany\",\n \"params\": [\n [\n [\n {\n \"from\":\"0x407d73d8a49eeb85d32cf465507dd71d507100c1\",\n \"to\":\"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b\",\n \"value\":\"0x186a0\"\n },\n [\"trace\"]\n ],\n [\n {\n \"from\":\"0x407d73d8a49eeb85d32cf465507dd71d507100c1\",\n \"to\":\"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b\",\n \"value\":\"0x186a0\"\n },\n [\"trace\"]\n ]\n ],\n \"0x186a0\"\n ],\n\t\"id\":\"1\"\n}\n", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": [ + "{{HOST}}" + ] + } + }, + "response": [] + }, + { + "name": "trace_callMany - vmTrace only", + "event": [ + { + "listen": "test", + "script": { + "id": "27cc3046-2d7c-4b7a-ae7d-f1b11008fc4c", + "exec": [ + "var expected = {", + " \"jsonrpc\": \"2.0\",", + " \"result\": [", + " {", + " \"output\": \"0x\",", + " \"stateDiff\": null,", + " \"trace\": [],", + " \"vmTrace\": {", + " \"code\": \"0x\",", + " \"ops\": []", + " }", + " },", + " {", + " \"output\": \"0x\",", + " \"stateDiff\": null,", + " \"trace\": [],", + " \"vmTrace\": {", + " \"code\": \"0x\",", + " \"ops\": []", + " }", + " }", + " ],", + " \"id\": \"1\"", + "}", + "", + "pm.test('Has correct result', function() {", + " pm.expect(pm.response.json()).to.be.deep.equal(expected);", + "})", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"trace_callMany\",\n \"params\": [\n [\n [\n {\n \"from\":\"0x407d73d8a49eeb85d32cf465507dd71d507100c1\",\n \"to\":\"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b\",\n \"value\":\"0x186a0\"\n },\n [\"vmTrace\"]\n ],\n [\n {\n \"from\":\"0x407d73d8a49eeb85d32cf465507dd71d507100c1\",\n \"to\":\"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b\",\n \"value\":\"0x186a0\"\n },\n [\"vmTrace\"]\n ]\n ],\n \"0x186a0\"\n ],\n\t\"id\":\"1\"\n}\n", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": [ + "{{HOST}}" + ] + } + }, + "response": [] + }, + { + "name": "trace_callMany - stateDiff only", + "event": [ + { + "listen": "test", + "script": { + "id": "d944881a-3184-4b85-a047-a1ce1ec115cd", + "exec": [ + "var expected = {", + " \"jsonrpc\": \"2.0\",", + " \"result\": [", + " {", + " \"output\": \"0x\",", + " \"stateDiff\": {", + " \"0x407d73d8a49eeb85d32cf465507dd71d507100c1\": {", + " \"balance\": {", + " \"+\": \"0x0\"", + " },", + " \"code\": {", + " \"+\": \"0x\"", + " },", + " \"nonce\": {", + " \"+\": \"0x1\"", + " },", + " \"storage\": {}", + " },", + " \"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b\": {", + " \"balance\": {", + " \"+\": \"0x186a0\"", + " },", + " \"code\": {", + " \"+\": \"0x\"", + " },", + " \"nonce\": {", + " \"+\": \"0x0\"", + " },", + " \"storage\": {}", + " }", + " },", + " \"trace\": [],", + " \"vmTrace\": null", + " },", + " {", + " \"output\": \"0x\",", + " \"stateDiff\": {", + " \"0x407d73d8a49eeb85d32cf465507dd71d507100c1\": {", + " \"balance\": \"=\",", + " \"code\": \"=\",", + " \"nonce\": {", + " \"*\": {", + " \"from\": \"0x1\",", + " \"to\": \"0x2\"", + " }", + " },", + " \"storage\": {}", + " },", + " \"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b\": {", + " \"balance\": {", + " \"*\": {", + " \"from\": \"0x186a0\",", + " \"to\": \"0x30d40\"", + " }", + " },", + " \"code\": \"=\",", + " \"nonce\": \"=\",", + " \"storage\": {}", + " }", + " },", + " \"trace\": [],", + " \"vmTrace\": null", + " }", + " ],", + " \"id\": \"1\"", + "}", + "", + "pm.test('Has correct result', function() {", + " pm.expect(pm.response.json()).to.be.deep.equal(expected);", + "})", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"trace_callMany\",\n \"params\": [\n [\n [\n {\n \"from\":\"0x407d73d8a49eeb85d32cf465507dd71d507100c1\",\n \"to\":\"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b\",\n \"value\":\"0x186a0\"\n },\n [\"stateDiff\"]\n ],\n [\n {\n \"from\":\"0x407d73d8a49eeb85d32cf465507dd71d507100c1\",\n \"to\":\"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b\",\n \"value\":\"0x186a0\"\n },\n [\"stateDiff\"]\n ]\n ],\n \"0x1e8480\"\n ],\n\t\"id\":\"1\"\n}\n", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": [ + "{{HOST}}" + ] + } + }, + "response": [] + } + ], + "protocolProfileBehavior": {} + }, + { + "name": "trace_replayTransaction", + "item": [ + { + "name": "trace_replayTransaction - all", + "event": [ + { + "listen": "test", + "script": { + "id": "0df08365-de62-444f-a2a8-1585c6b2d9b1", + "exec": [ + "var expected = {", + " \"jsonrpc\": \"2.0\",", + " \"result\": {", + " \"output\": \"0x\",", + " \"stateDiff\": {", + " \"0x00a63d34051602b2cb268ea344d4b8bc4767f2d4\": {", + " \"balance\": {", + " \"*\": {", + " \"from\": \"0x52b7cb1385ccf49b2b\",", + " \"to\": \"0x5236bafcfeb4e73b2b\"", + " }", + " },", + " \"code\": \"=\",", + " \"nonce\": {", + " \"*\": {", + " \"from\": \"0xc6f\",", + " \"to\": \"0xc70\"", + " }", + " },", + " \"storage\": {}", + " },", + " \"0x1a060b0604883a99809eb3f798df71bef6c358f1\": {", + " \"balance\": {", + " \"*\": {", + " \"from\": \"0x6f9b59db405cf2c70\",", + " \"to\": \"0x6f9b71bb0e49d6c70\"", + " }", + " },", + " \"code\": \"=\",", + " \"nonce\": \"=\",", + " \"storage\": {}", + " },", + " \"0x87cc0d78ee64a9f11b5affdd9ea523872eae14e4\": {", + " \"balance\": {", + " \"*\": {", + " \"from\": \"0x3afccb788fcd0e00\",", + " \"to\": \"0xbc0b6402c90c2e00\"", + " }", + " },", + " \"code\": \"=\",", + " \"nonce\": \"=\",", + " \"storage\": {}", + " }", + " },", + " \"trace\": [", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0x00a63d34051602b2cb268ea344d4b8bc4767f2d4\",", + " \"gas\": \"0x0\",", + " \"input\": \"0x\",", + " \"to\": \"0x87cc0d78ee64a9f11b5affdd9ea523872eae14e4\",", + " \"value\": \"0x810e988a393f2000\"", + " },", + " \"result\": {", + " \"gasUsed\": \"0x0\",", + " \"output\": \"0x\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [],", + " \"type\": \"call\"", + " }", + " ],", + " \"vmTrace\": {", + " \"code\": \"0x\",", + " \"ops\": []", + " }", + " },", + " \"id\": \"1\"", + "}", + "", + "pm.test('Has correct result', function() {", + " pm.expect(pm.response.json()).to.be.deep.equal(expected);", + "})", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"trace_replayTransaction\",\n\t\"params\":[\n \"0x02d4a872e096445e80d05276ee756cefef7f3b376bcec14246469c0cd97dad8f\",\n [\"trace\",\"vmTrace\",\"stateDiff\"]\n ],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": [ + "{{HOST}}" + ] + } + }, + "response": [] + }, + { + "name": "trace_replayTransaction - none", + "event": [ + { + "listen": "test", + "script": { + "id": "5f84df2a-b6ab-45ca-9b18-f4f9534c1458", + "exec": [ + "var expected = {", + " \"jsonrpc\": \"2.0\",", + " \"result\": {", + " \"output\": \"0x\",", + " \"stateDiff\": null,", + " \"trace\": [],", + " \"vmTrace\": null", + " },", + " \"id\": \"1\"", + "}", + "", + "pm.test('Has correct result', function() {", + " pm.expect(pm.response.json()).to.be.deep.equal(expected);", + "})", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"trace_replayTransaction\",\n\t\"params\":[\n \"0x02d4a872e096445e80d05276ee756cefef7f3b376bcec14246469c0cd97dad8f\",\n []\n ],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": [ + "{{HOST}}" + ] + } + }, + "response": [] + }, + { + "name": "trace_replayTransaction - trace only", + "event": [ + { + "listen": "test", + "script": { + "id": "33278201-153b-490c-acb2-07b233baac25", + "exec": [ + "var expected = {", + " \"jsonrpc\": \"2.0\",", + " \"result\": {", + " \"output\": \"0x\",", + " \"stateDiff\": null,", + " \"trace\": [", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0x00a63d34051602b2cb268ea344d4b8bc4767f2d4\",", + " \"gas\": \"0x0\",", + " \"input\": \"0x\",", + " \"to\": \"0x87cc0d78ee64a9f11b5affdd9ea523872eae14e4\",", + " \"value\": \"0x810e988a393f2000\"", + " },", + " \"result\": {", + " \"gasUsed\": \"0x0\",", + " \"output\": \"0x\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [],", + " \"type\": \"call\"", + " }", + " ],", + " \"vmTrace\": null", + " },", + " \"id\": \"1\"", + "}", + "", + "pm.test('Has correct result', function() {", + " pm.expect(pm.response.json()).to.be.deep.equal(expected);", + "})", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"trace_replayTransaction\",\n\t\"params\":[\n \"0x02d4a872e096445e80d05276ee756cefef7f3b376bcec14246469c0cd97dad8f\",\n [\"trace\"]\n ],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": [ + "{{HOST}}" + ] + } + }, + "response": [] + }, + { + "name": "trace_replayTransaction - vmTrace only", + "event": [ + { + "listen": "test", + "script": { + "id": "a84b1a91-ee56-46ee-b4fa-231f7aad455e", + "exec": [ + "var expected = {", + " \"jsonrpc\": \"2.0\",", + " \"result\": {", + " \"output\": \"0x\",", + " \"stateDiff\": null,", + " \"trace\": [],", + " \"vmTrace\": {", + " \"code\": \"0x\",", + " \"ops\": []", + " }", + " },", + " \"id\": \"1\"", + "}", + "", + "pm.test('Has correct result', function() {", + " pm.expect(pm.response.json()).to.be.deep.equal(expected);", + "})", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"trace_replayTransaction\",\n\t\"params\":[\n \"0x02d4a872e096445e80d05276ee756cefef7f3b376bcec14246469c0cd97dad8f\",\n [\"vmTrace\"]\n ],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": [ + "{{HOST}}" + ] + } + }, + "response": [] + }, + { + "name": "trace_replayTransaction - stateDiff only", + "event": [ + { + "listen": "test", + "script": { + "id": "915e86b3-5172-44b3-87d9-9025c074ea5b", + "exec": [ + "var expected = {", + " \"jsonrpc\": \"2.0\",", + " \"result\": {", + " \"output\": \"0x\",", + " \"stateDiff\": {", + " \"0x00a63d34051602b2cb268ea344d4b8bc4767f2d4\": {", + " \"balance\": {", + " \"*\": {", + " \"from\": \"0x52b7cb1385ccf49b2b\",", + " \"to\": \"0x5236bafcfeb4e73b2b\"", + " }", + " },", + " \"code\": \"=\",", + " \"nonce\": {", + " \"*\": {", + " \"from\": \"0xc6f\",", + " \"to\": \"0xc70\"", + " }", + " },", + " \"storage\": {}", + " },", + " \"0x1a060b0604883a99809eb3f798df71bef6c358f1\": {", + " \"balance\": {", + " \"*\": {", + " \"from\": \"0x6f9b59db405cf2c70\",", + " \"to\": \"0x6f9b71bb0e49d6c70\"", + " }", + " },", + " \"code\": \"=\",", + " \"nonce\": \"=\",", + " \"storage\": {}", + " },", + " \"0x87cc0d78ee64a9f11b5affdd9ea523872eae14e4\": {", + " \"balance\": {", + " \"*\": {", + " \"from\": \"0x3afccb788fcd0e00\",", + " \"to\": \"0xbc0b6402c90c2e00\"", + " }", + " },", + " \"code\": \"=\",", + " \"nonce\": \"=\",", + " \"storage\": {}", + " }", + " },", + " \"trace\": [],", + " \"vmTrace\": null", + " },", + " \"id\": \"1\"", + "}", + "", + "pm.test('Has correct result', function() {", + " pm.expect(pm.response.json()).to.be.deep.equal(expected);", + "})", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"trace_replayTransaction\",\n\t\"params\":[\n \"0x02d4a872e096445e80d05276ee756cefef7f3b376bcec14246469c0cd97dad8f\",\n [\"stateDiff\"]\n ],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": [ + "{{HOST}}" + ] + } + }, + "response": [] + } + ], + "protocolProfileBehavior": {} + }, + { + "name": "trace_replayBlockTransactions", + "item": [ + { + "name": "trace_replayBlockTransactions - all", + "event": [ + { + "listen": "test", + "script": { + "id": "38dda4a1-afc6-4d61-ae10-d59496d10eb3", + "exec": [ + "var expected = {", + " \"jsonrpc\": \"2.0\",", + " \"result\": [", + " {", + " \"output\": \"0x\",", + " \"stateDiff\": {", + " \"0x104994f45d9d697ca104e5704a7b77d7fec3537c\": {", + " \"balance\": {", + " \"+\": \"0x821878651a4d70000\"", + " },", + " \"code\": {", + " \"+\": \"0x\"", + " },", + " \"nonce\": {", + " \"+\": \"0x0\"", + " },", + " \"storage\": {}", + " },", + " \"0x32be343b94f860124dc4fee278fdcbd38c102d88\": {", + " \"balance\": {", + " \"*\": {", + " \"from\": \"0x29dd8f1fcd55eef7fe5c\",", + " \"to\": \"0x29d56d960a08fbeb9e5c\"", + " }", + " },", + " \"code\": \"=\",", + " \"nonce\": {", + " \"*\": {", + " \"from\": \"0x1efc5\",", + " \"to\": \"0x1efc6\"", + " }", + " },", + " \"storage\": {}", + " },", + " \"0x61c808d82a3ac53231750dadc13c777b59310bd9\": {", + " \"balance\": {", + " \"*\": {", + " \"from\": \"0x16d21cbe94fc6c3ebf7\",", + " \"to\": \"0x16d21ce264b14f94bf7\"", + " }", + " },", + " \"code\": \"=\",", + " \"nonce\": \"=\",", + " \"storage\": {}", + " }", + " },", + " \"trace\": [", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0x32be343b94f860124dc4fee278fdcbd38c102d88\",", + " \"gas\": \"0x4c40d\",", + " \"input\": \"0x\",", + " \"to\": \"0x104994f45d9d697ca104e5704a7b77d7fec3537c\",", + " \"value\": \"0x821878651a4d70000\"", + " },", + " \"result\": {", + " \"gasUsed\": \"0x0\",", + " \"output\": \"0x\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [],", + " \"type\": \"call\"", + " }", + " ],", + " \"transactionHash\": \"0xc55e2b90168af6972193c1f86fa4d7d7b31a29c156665d15b9cd48618b5177ef\",", + " \"vmTrace\": {", + " \"code\": \"0x\",", + " \"ops\": []", + " }", + " }", + " ],", + " \"id\": \"1\"", + "}", + "", + "pm.test('Has correct result', function() {", + " pm.expect(pm.response.json()).to.be.deep.equal(expected);", + "})", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"trace_replayBlockTransactions\",\n\t\"params\":[\n \"0x1e8480\",\n [\"trace\",\"vmTrace\",\"stateDiff\"]\n ],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": [ + "{{HOST}}" + ] + } + }, + "response": [] + }, + { + "name": "trace_replayBlockTransactions - none", + "event": [ + { + "listen": "test", + "script": { + "id": "7ae24d9b-a87c-4e22-a604-9c20e6641ee5", + "exec": [ + "var expected = {", + " \"jsonrpc\": \"2.0\",", + " \"result\": [", + " {", + " \"output\": \"0x\",", + " \"stateDiff\": null,", + " \"trace\": [],", + " \"transactionHash\": \"0xc55e2b90168af6972193c1f86fa4d7d7b31a29c156665d15b9cd48618b5177ef\",", + " \"vmTrace\": null", + " }", + " ],", + " \"id\": \"1\"", + "}", + "", + "pm.test('Has correct result', function() {", + " pm.expect(pm.response.json()).to.be.deep.equal(expected);", + "})", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"trace_replayBlockTransactions\",\n\t\"params\":[\n \"0x1e8480\",\n []\n ],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": [ + "{{HOST}}" + ] + } + }, + "response": [] + }, + { + "name": "trace_replayBlockTransactions - trace only", + "event": [ + { + "listen": "test", + "script": { + "id": "ed4c941b-54ee-487d-8aff-7d0ecb750523", + "exec": [ + "var expected = {", + " \"jsonrpc\": \"2.0\",", + " \"result\": [", + " {", + " \"output\": \"0x\",", + " \"stateDiff\": null,", + " \"trace\": [", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0x32be343b94f860124dc4fee278fdcbd38c102d88\",", + " \"gas\": \"0x4c40d\",", + " \"input\": \"0x\",", + " \"to\": \"0x104994f45d9d697ca104e5704a7b77d7fec3537c\",", + " \"value\": \"0x821878651a4d70000\"", + " },", + " \"result\": {", + " \"gasUsed\": \"0x0\",", + " \"output\": \"0x\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [],", + " \"type\": \"call\"", + " }", + " ],", + " \"transactionHash\": \"0xc55e2b90168af6972193c1f86fa4d7d7b31a29c156665d15b9cd48618b5177ef\",", + " \"vmTrace\": null", + " }", + " ],", + " \"id\": \"1\"", + "}", + "", + "pm.test('Has correct result', function() {", + " pm.expect(pm.response.json()).to.be.deep.equal(expected);", + "})", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"trace_replayBlockTransactions\",\n\t\"params\":[\n \"0x1e8480\",\n [\"trace\"]\n ],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": [ + "{{HOST}}" + ] + } + }, + "response": [] + }, + { + "name": "trace_replayBlockTransactions - vmTrace only", + "event": [ + { + "listen": "test", + "script": { + "id": "b3703c29-7bb8-4d08-b757-efbb4de8243d", + "exec": [ + "var expected = {", + " \"jsonrpc\": \"2.0\",", + " \"result\": [", + " {", + " \"output\": \"0x\",", + " \"stateDiff\": null,", + " \"trace\": [],", + " \"transactionHash\": \"0xc55e2b90168af6972193c1f86fa4d7d7b31a29c156665d15b9cd48618b5177ef\",", + " \"vmTrace\": {", + " \"code\": \"0x\",", + " \"ops\": []", + " }", + " }", + " ],", + " \"id\": \"1\"", + "}", + "", + "pm.test('Has correct result', function() {", + " pm.expect(pm.response.json()).to.be.deep.equal(expected);", + "})", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"trace_replayBlockTransactions\",\n\t\"params\":[\n \"0x1e8480\",\n [\"vmTrace\"]\n ],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": [ + "{{HOST}}" + ] + } + }, + "response": [] + }, + { + "name": "trace_replayBlockTransactions - stateDiff only", + "event": [ + { + "listen": "test", + "script": { + "id": "ac907f46-3f6d-436e-b0fb-3ab294e6c33f", + "exec": [ + "utils.cannotTest(\"trace_rawTransaction - all\", pm.response.json())", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"trace_replayBlockTransactions\",\n\t\"params\":[\n \"0x1e8480\",\n [\"stateDiff\"]\n ],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": [ + "{{HOST}}" + ] + } + }, + "response": [] + } + ], + "protocolProfileBehavior": {} + }, + { + "name": "trace_rawTransaction", + "item": [ + { + "name": "trace_rawTransaction - all", + "event": [ + { + "listen": "test", + "script": { + "id": "daca0279-5627-47e0-abb3-b1d0e0e3e1ef", + "exec": [ + "utils.cannotTest(\"trace_rawTransaction - all\", pm.response.json())", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"trace_rawTransaction\",\n\t\"params\":[\n \"0xf86d09850cf032900f83030d4094109c4f2ccc82c4d77bde15f306707320294aea3f880de0b6b3a7640000801ca02da49aa24d7fa6fa876af59d77acfd60537eba478654934430b1b32893b65c85a02cdc152d81b71f25fd23e3e271c8c0b15a3a91ce104b6af35bd476d1e6d26fdf\",\n [\"trace\",\"vmTrace\",\"stateDiff\"]\n ],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": [ + "{{HOST}}" + ] + } + }, + "response": [] + }, + { + "name": "trace_rawTransaction - none", + "event": [ + { + "listen": "test", + "script": { + "id": "7a69f86d-f9db-4377-b650-e4fc0cf09253", + "exec": [ + "var expected = {", + " \"jsonrpc\": \"2.0\",", + " \"result\": {", + " \"output\": \"0x\",", + " \"stateDiff\": null,", + " \"trace\": [],", + " \"vmTrace\": null", + " },", + " \"id\": \"1\"", + "}", + "", + "pm.test('Has correct result', function() {", + " pm.expect(pm.response.json()).to.be.deep.equal(expected);", + "})", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"trace_rawTransaction\",\n\t\"params\":[\n \"0xf86d09850cf032900f83030d4094109c4f2ccc82c4d77bde15f306707320294aea3f880de0b6b3a7640000801ca02da49aa24d7fa6fa876af59d77acfd60537eba478654934430b1b32893b65c85a02cdc152d81b71f25fd23e3e271c8c0b15a3a91ce104b6af35bd476d1e6d26fdf\",\n []\n ],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": [ + "{{HOST}}" + ] + } + }, + "response": [] + }, + { + "name": "trace_rawTransaction - trace only", + "event": [ + { + "listen": "test", + "script": { + "id": "7ddd07c3-edfc-4a21-ba38-308efc7fb782", + "exec": [ + "var expected = {", + " \"jsonrpc\": \"2.0\",", + " \"result\": {", + " \"output\": \"0x\",", + " \"stateDiff\": null,", + " \"trace\": [", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xfd2605a2bf58fdbb90db1da55df61628b47f9e8c\",", + " \"gas\": \"0x2bb38\",", + " \"input\": \"0x\",", + " \"to\": \"0x109c4f2ccc82c4d77bde15f306707320294aea3f\",", + " \"value\": \"0xde0b6b3a7640000\"", + " },", + " \"result\": {", + " \"gasUsed\": \"0x9325\",", + " \"output\": \"0x\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [],", + " \"type\": \"call\"", + " }", + " ],", + " \"vmTrace\": null", + " },", + " \"id\": \"1\"", + "}", + "", + "pm.test('Has correct result', function() {", + " pm.expect(pm.response.json()).to.be.deep.equal(expected);", + "})", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"trace_rawTransaction\",\n\t\"params\":[\n \"0xf86d09850cf032900f83030d4094109c4f2ccc82c4d77bde15f306707320294aea3f880de0b6b3a7640000801ca02da49aa24d7fa6fa876af59d77acfd60537eba478654934430b1b32893b65c85a02cdc152d81b71f25fd23e3e271c8c0b15a3a91ce104b6af35bd476d1e6d26fdf\",\n [\"trace\"]\n ],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": [ + "{{HOST}}" + ] + } + }, + "response": [] + }, + { + "name": "trace_rawTransaction - vmTrace only", + "event": [ + { + "listen": "test", + "script": { + "id": "10371f18-4769-4d59-a46c-03d13a79a3c9", + "exec": [ + "var expected = {", + " \"jsonrpc\": \"2.0\",", + " \"result\": {", + " \"output\": \"0x\",", + " \"stateDiff\": null,", + " \"trace\": [],", + " \"vmTrace\": {", + " \"code\": \"0x6060604052361561001f5760e060020a600035046372ea4b8c811461010c575b61011b3460008080670de0b6b3a764000084106101d557600180548101908190556003805433929081101561000257906000526020600020900160006101000a815481600160a060020a0302191690830217905550670de0b6b3a7640000840393508350670de0b6b3a76400006000600082828250540192505081905550600260016000505411151561011d5760038054829081101561000257906000526020600020900160009054906101000a9004600160a060020a0316600160a060020a03166000600060005054604051809050600060405180830381858888f150505080555060016002556101d5565b60018054016060908152602090f35b005b60018054600354910114156101d55760038054600254600101909102900392505b6003546002549003600119018310156101e357600380548490811015610002579082526040517fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b9190910154600160a060020a03169082906706f05b59d3b200009082818181858883f1505090546706f05b59d3b1ffff1901835550506001929092019161013e565b505060028054600101905550505b600080548501905550505050565b506002548154919250600190810190910460001901905b60035460025490036001190183101561029a576003805484908110156100025760009182526040517fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b9190910154600160a060020a03169190838504600019019082818181858883f1505081548486049003600190810190925550600290830183020460001901841415905061028e576001015b600192909201916101fa565b60038054600254810182018083559190829080158290116101c75760008390526101c7907fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b9081019083015b808211156102fa57600081556001016102e6565b509056\",", + " \"ops\": [", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x60\"", + " ],", + " \"store\": null,", + " \"used\": 178997", + " },", + " \"pc\": 0,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x40\"", + " ],", + " \"store\": null,", + " \"used\": 178994", + " },", + " \"pc\": 2,", + " \"sub\": null", + " },", + " {", + " \"cost\": 12,", + " \"ex\": {", + " \"mem\": {", + " \"data\": \"0x0000000000000000000000000000000000000000000000000000000000000060\",", + " \"off\": 64", + " },", + " \"push\": [],", + " \"store\": null,", + " \"used\": 178982", + " },", + " \"pc\": 4,", + " \"sub\": null", + " },", + " {", + " \"cost\": 2,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x0\"", + " ],", + " \"store\": null,", + " \"used\": 178980", + " },", + " \"pc\": 5,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x1\"", + " ],", + " \"store\": null,", + " \"used\": 178977", + " },", + " \"pc\": 6,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x1f\"", + " ],", + " \"store\": null,", + " \"used\": 178974", + " },", + " \"pc\": 7,", + " \"sub\": null", + " },", + " {", + " \"cost\": 10,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [],", + " \"store\": null,", + " \"used\": 178964", + " },", + " \"pc\": 10,", + " \"sub\": null", + " },", + " {", + " \"cost\": 1,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [],", + " \"store\": null,", + " \"used\": 178963", + " },", + " \"pc\": 31,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x11b\"", + " ],", + " \"store\": null,", + " \"used\": 178960", + " },", + " \"pc\": 32,", + " \"sub\": null", + " },", + " {", + " \"cost\": 2,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0xde0b6b3a7640000\"", + " ],", + " \"store\": null,", + " \"used\": 178958", + " },", + " \"pc\": 35,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x0\"", + " ],", + " \"store\": null,", + " \"used\": 178955", + " },", + " \"pc\": 36,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x0\",", + " \"0x0\"", + " ],", + " \"store\": null,", + " \"used\": 178952", + " },", + " \"pc\": 38,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x0\",", + " \"0x0\"", + " ],", + " \"store\": null,", + " \"used\": 178949", + " },", + " \"pc\": 39,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0xde0b6b3a7640000\"", + " ],", + " \"store\": null,", + " \"used\": 178946", + " },", + " \"pc\": 40,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0xde0b6b3a7640000\",", + " \"0x0\",", + " \"0x0\",", + " \"0x0\",", + " \"0xde0b6b3a7640000\",", + " \"0xde0b6b3a7640000\"", + " ],", + " \"store\": null,", + " \"used\": 178943", + " },", + " \"pc\": 49,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x0\"", + " ],", + " \"store\": null,", + " \"used\": 178940", + " },", + " \"pc\": 50,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x1d5\"", + " ],", + " \"store\": null,", + " \"used\": 178937", + " },", + " \"pc\": 51,", + " \"sub\": null", + " },", + " {", + " \"cost\": 10,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [],", + " \"store\": null,", + " \"used\": 178927", + " },", + " \"pc\": 54,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x1\"", + " ],", + " \"store\": null,", + " \"used\": 178924", + " },", + " \"pc\": 55,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x1\",", + " \"0x1\"", + " ],", + " \"store\": null,", + " \"used\": 178921", + " },", + " \"pc\": 57,", + " \"sub\": null", + " },", + " {", + " \"cost\": 800,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x56\"", + " ],", + " \"store\": null,", + " \"used\": 178121", + " },", + " \"pc\": 58,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x1\",", + " \"0x56\",", + " \"0x1\"", + " ],", + " \"store\": null,", + " \"used\": 178118", + " },", + " \"pc\": 59,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x57\"", + " ],", + " \"store\": null,", + " \"used\": 178115", + " },", + " \"pc\": 60,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x57\",", + " \"0x1\"", + " ],", + " \"store\": null,", + " \"used\": 178112", + " },", + " \"pc\": 61,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x57\",", + " \"0x1\",", + " \"0x57\"", + " ],", + " \"store\": null,", + " \"used\": 178109", + " },", + " \"pc\": 62,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x57\",", + " \"0x1\"", + " ],", + " \"store\": null,", + " \"used\": 178106", + " },", + " \"pc\": 63,", + " \"sub\": null", + " },", + " {", + " \"cost\": 5000,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [],", + " \"store\": {", + " \"key\": \"0x1\",", + " \"val\": \"0x57\"", + " },", + " \"used\": 173106", + " },", + " \"pc\": 64,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x3\"", + " ],", + " \"store\": null,", + " \"used\": 173103", + " },", + " \"pc\": 65,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x3\",", + " \"0x3\"", + " ],", + " \"store\": null,", + " \"used\": 173100", + " },", + " \"pc\": 67,", + " \"sub\": null", + " },", + " {", + " \"cost\": 800,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x5b\"", + " ],", + " \"store\": null,", + " \"used\": 172300", + " },", + " \"pc\": 68,", + " \"sub\": null", + " },", + " {", + " \"cost\": 2,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0xfd2605a2bf58fdbb90db1da55df61628b47f9e8c\"", + " ],", + " \"store\": null,", + " \"used\": 172298", + " },", + " \"pc\": 69,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0xfd2605a2bf58fdbb90db1da55df61628b47f9e8c\",", + " \"0x3\",", + " \"0x5b\",", + " \"0x57\"", + " ],", + " \"store\": null,", + " \"used\": 172295", + " },", + " \"pc\": 70,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x57\",", + " \"0x5b\"", + " ],", + " \"store\": null,", + " \"used\": 172292", + " },", + " \"pc\": 71,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x57\",", + " \"0x5b\",", + " \"0x57\"", + " ],", + " \"store\": null,", + " \"used\": 172289", + " },", + " \"pc\": 72,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x1\"", + " ],", + " \"store\": null,", + " \"used\": 172286", + " },", + " \"pc\": 73,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x0\"", + " ],", + " \"store\": null,", + " \"used\": 172283", + " },", + " \"pc\": 74,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x2\"", + " ],", + " \"store\": null,", + " \"used\": 172280", + " },", + " \"pc\": 75,", + " \"sub\": null", + " },", + " {", + " \"cost\": 10,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [],", + " \"store\": null,", + " \"used\": 172270", + " },", + " \"pc\": 78,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x57\",", + " \"0x3\"", + " ],", + " \"store\": null,", + " \"used\": 172267", + " },", + " \"pc\": 79,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x0\"", + " ],", + " \"store\": null,", + " \"used\": 172264", + " },", + " \"pc\": 80,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": {", + " \"data\": \"0x0000000000000000000000000000000000000000000000000000000000000003\",", + " \"off\": 0", + " },", + " \"push\": [],", + " \"store\": null,", + " \"used\": 172261", + " },", + " \"pc\": 82,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x20\"", + " ],", + " \"store\": null,", + " \"used\": 172258", + " },", + " \"pc\": 83,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x0\"", + " ],", + " \"store\": null,", + " \"used\": 172255", + " },", + " \"pc\": 85,", + " \"sub\": null", + " },", + " {", + " \"cost\": 36,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0xc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b\"", + " ],", + " \"store\": null,", + " \"used\": 172219", + " },", + " \"pc\": 87,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0xc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b\",", + " \"0x57\"", + " ],", + " \"store\": null,", + " \"used\": 172216", + " },", + " \"pc\": 88,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0xc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f8b2\"", + " ],", + " \"store\": null,", + " \"used\": 172213", + " },", + " \"pc\": 89,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x0\"", + " ],", + " \"store\": null,", + " \"used\": 172210", + " },", + " \"pc\": 90,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x100\"", + " ],", + " \"store\": null,", + " \"used\": 172207", + " },", + " \"pc\": 92,", + " \"sub\": null", + " },", + " {", + " \"cost\": 10,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x1\"", + " ],", + " \"store\": null,", + " \"used\": 172197", + " },", + " \"pc\": 95,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0xc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f8b2\",", + " \"0x1\",", + " \"0xc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f8b2\"", + " ],", + " \"store\": null,", + " \"used\": 172194", + " },", + " \"pc\": 96,", + " \"sub\": null", + " },", + " {", + " \"cost\": 800,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x0\"", + " ],", + " \"store\": null,", + " \"used\": 171394", + " },", + " \"pc\": 97,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x1\",", + " \"0x0\",", + " \"0x1\"", + " ],", + " \"store\": null,", + " \"used\": 171391", + " },", + " \"pc\": 98,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x1\"", + " ],", + " \"store\": null,", + " \"used\": 171388", + " },", + " \"pc\": 99,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0xa0\"", + " ],", + " \"store\": null,", + " \"used\": 171385", + " },", + " \"pc\": 101,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x2\"", + " ],", + " \"store\": null,", + " \"used\": 171382", + " },", + " \"pc\": 103,", + " \"sub\": null", + " },", + " {", + " \"cost\": 60,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x10000000000000000000000000000000000000000\"", + " ],", + " \"store\": null,", + " \"used\": 171322", + " },", + " \"pc\": 105,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0xffffffffffffffffffffffffffffffffffffffff\"", + " ],", + " \"store\": null,", + " \"used\": 171319", + " },", + " \"pc\": 106,", + " \"sub\": null", + " },", + " {", + " \"cost\": 5,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0xffffffffffffffffffffffffffffffffffffffff\"", + " ],", + " \"store\": null,", + " \"used\": 171314", + " },", + " \"pc\": 107,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0xffffffffffffffffffffffff0000000000000000000000000000000000000000\"", + " ],", + " \"store\": null,", + " \"used\": 171311", + " },", + " \"pc\": 108,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x0\"", + " ],", + " \"store\": null,", + " \"used\": 171308", + " },", + " \"pc\": 109,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x0\",", + " \"0x1\"", + " ],", + " \"store\": null,", + " \"used\": 171305", + " },", + " \"pc\": 110,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0xfd2605a2bf58fdbb90db1da55df61628b47f9e8c\",", + " \"0xc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f8b2\",", + " \"0x0\",", + " \"0x1\",", + " \"0xfd2605a2bf58fdbb90db1da55df61628b47f9e8c\"", + " ],", + " \"store\": null,", + " \"used\": 171302", + " },", + " \"pc\": 111,", + " \"sub\": null", + " },", + " {", + " \"cost\": 5,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0xfd2605a2bf58fdbb90db1da55df61628b47f9e8c\"", + " ],", + " \"store\": null,", + " \"used\": 171297", + " },", + " \"pc\": 112,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0xfd2605a2bf58fdbb90db1da55df61628b47f9e8c\"", + " ],", + " \"store\": null,", + " \"used\": 171294", + " },", + " \"pc\": 113,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0xfd2605a2bf58fdbb90db1da55df61628b47f9e8c\",", + " \"0xc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f8b2\"", + " ],", + " \"store\": null,", + " \"used\": 171291", + " },", + " \"pc\": 114,", + " \"sub\": null", + " },", + " {", + " \"cost\": 20000,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [],", + " \"store\": {", + " \"key\": \"0xc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f8b2\",", + " \"val\": \"0xfd2605a2bf58fdbb90db1da55df61628b47f9e8c\"", + " },", + " \"used\": 151291", + " },", + " \"pc\": 115,", + " \"sub\": null", + " },", + " {", + " \"cost\": 2,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [],", + " \"store\": null,", + " \"used\": 151289", + " },", + " \"pc\": 116,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0xde0b6b3a7640000\"", + " ],", + " \"store\": null,", + " \"used\": 151286", + " },", + " \"pc\": 117,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0xde0b6b3a7640000\",", + " \"0x0\",", + " \"0x0\",", + " \"0x0\",", + " \"0xde0b6b3a7640000\",", + " \"0xde0b6b3a7640000\"", + " ],", + " \"store\": null,", + " \"used\": 151283", + " },", + " \"pc\": 126,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x0\"", + " ],", + " \"store\": null,", + " \"used\": 151280", + " },", + " \"pc\": 127,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x0\",", + " \"0x0\",", + " \"0x0\",", + " \"0x0\",", + " \"0xde0b6b3a7640000\"", + " ],", + " \"store\": null,", + " \"used\": 151277", + " },", + " \"pc\": 128,", + " \"sub\": null", + " },", + " {", + " \"cost\": 2,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [],", + " \"store\": null,", + " \"used\": 151275", + " },", + " \"pc\": 129,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x0\",", + " \"0x0\",", + " \"0x0\",", + " \"0x0\",", + " \"0x0\"", + " ],", + " \"store\": null,", + " \"used\": 151272", + " },", + " \"pc\": 130,", + " \"sub\": null", + " },", + " {", + " \"cost\": 2,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [],", + " \"store\": null,", + " \"used\": 151270", + " },", + " \"pc\": 131,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0xde0b6b3a7640000\"", + " ],", + " \"store\": null,", + " \"used\": 151267", + " },", + " \"pc\": 132,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x0\"", + " ],", + " \"store\": null,", + " \"used\": 151264", + " },", + " \"pc\": 141,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x0\"", + " ],", + " \"store\": null,", + " \"used\": 151261", + " },", + " \"pc\": 143,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0xde0b6b3a7640000\",", + " \"0x0\",", + " \"0x0\",", + " \"0xde0b6b3a7640000\"", + " ],", + " \"store\": null,", + " \"used\": 151258", + " },", + " \"pc\": 145,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x0\",", + " \"0x0\",", + " \"0xde0b6b3a7640000\",", + " \"0x0\"", + " ],", + " \"store\": null,", + " \"used\": 151255", + " },", + " \"pc\": 146,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x0\",", + " \"0xde0b6b3a7640000\",", + " \"0x0\",", + " \"0x0\"", + " ],", + " \"store\": null,", + " \"used\": 151252", + " },", + " \"pc\": 147,", + " \"sub\": null", + " },", + " {", + " \"cost\": 2,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [],", + " \"store\": null,", + " \"used\": 151250", + " },", + " \"pc\": 148,", + " \"sub\": null", + " },", + " {", + " \"cost\": 800,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x7ce66c50e91277e9\"", + " ],", + " \"store\": null,", + " \"used\": 150450", + " },", + " \"pc\": 149,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x8ac72304907677e9\"", + " ],", + " \"store\": null,", + " \"used\": 150447", + " },", + " \"pc\": 150,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x8ac72304907677e9\",", + " \"0x0\",", + " \"0x0\",", + " \"0xde0b6b3a7640000\"", + " ],", + " \"store\": null,", + " \"used\": 150444", + " },", + " \"pc\": 151,", + " \"sub\": null", + " },", + " {", + " \"cost\": 2,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [],", + " \"store\": null,", + " \"used\": 150442", + " },", + " \"pc\": 152,", + " \"sub\": null", + " },", + " {", + " \"cost\": 2,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [],", + " \"store\": null,", + " \"used\": 150440", + " },", + " \"pc\": 153,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x8ac72304907677e9\",", + " \"0x0\",", + " \"0x8ac72304907677e9\"", + " ],", + " \"store\": null,", + " \"used\": 150437", + " },", + " \"pc\": 154,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x8ac72304907677e9\",", + " \"0x0\"", + " ],", + " \"store\": null,", + " \"used\": 150434", + " },", + " \"pc\": 155,", + " \"sub\": null", + " },", + " {", + " \"cost\": 5000,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [],", + " \"store\": {", + " \"key\": \"0x0\",", + " \"val\": \"0x8ac72304907677e9\"", + " },", + " \"used\": 145434", + " },", + " \"pc\": 156,", + " \"sub\": null", + " },", + " {", + " \"cost\": 2,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [],", + " \"store\": null,", + " \"used\": 145432", + " },", + " \"pc\": 157,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x2\"", + " ],", + " \"store\": null,", + " \"used\": 145429", + " },", + " \"pc\": 158,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x1\"", + " ],", + " \"store\": null,", + " \"used\": 145426", + " },", + " \"pc\": 160,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x0\"", + " ],", + " \"store\": null,", + " \"used\": 145423", + " },", + " \"pc\": 162,", + " \"sub\": null", + " },", + " {", + " \"cost\": 2,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [],", + " \"store\": null,", + " \"used\": 145421", + " },", + " \"pc\": 164,", + " \"sub\": null", + " },", + " {", + " \"cost\": 800,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x57\"", + " ],", + " \"store\": null,", + " \"used\": 144621", + " },", + " \"pc\": 165,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x1\"", + " ],", + " \"store\": null,", + " \"used\": 144618", + " },", + " \"pc\": 166,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x0\"", + " ],", + " \"store\": null,", + " \"used\": 144615", + " },", + " \"pc\": 167,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x1\"", + " ],", + " \"store\": null,", + " \"used\": 144612", + " },", + " \"pc\": 168,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x11d\"", + " ],", + " \"store\": null,", + " \"used\": 144609", + " },", + " \"pc\": 169,", + " \"sub\": null", + " },", + " {", + " \"cost\": 10,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [],", + " \"store\": null,", + " \"used\": 144599", + " },", + " \"pc\": 172,", + " \"sub\": null", + " },", + " {", + " \"cost\": 1,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [],", + " \"store\": null,", + " \"used\": 144598", + " },", + " \"pc\": 285,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x1\"", + " ],", + " \"store\": null,", + " \"used\": 144595", + " },", + " \"pc\": 286,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x1\",", + " \"0x1\"", + " ],", + " \"store\": null,", + " \"used\": 144592", + " },", + " \"pc\": 288,", + " \"sub\": null", + " },", + " {", + " \"cost\": 800,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x57\"", + " ],", + " \"store\": null,", + " \"used\": 143792", + " },", + " \"pc\": 289,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x3\"", + " ],", + " \"store\": null,", + " \"used\": 143789", + " },", + " \"pc\": 290,", + " \"sub\": null", + " },", + " {", + " \"cost\": 800,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x5b\"", + " ],", + " \"store\": null,", + " \"used\": 142989", + " },", + " \"pc\": 292,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x5b\",", + " \"0x57\",", + " \"0x1\"", + " ],", + " \"store\": null,", + " \"used\": 142986", + " },", + " \"pc\": 293,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x58\"", + " ],", + " \"store\": null,", + " \"used\": 142983", + " },", + " \"pc\": 294,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x0\"", + " ],", + " \"store\": null,", + " \"used\": 142980", + " },", + " \"pc\": 295,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x1\"", + " ],", + " \"store\": null,", + " \"used\": 142977", + " },", + " \"pc\": 296,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x1d5\"", + " ],", + " \"store\": null,", + " \"used\": 142974", + " },", + " \"pc\": 297,", + " \"sub\": null", + " },", + " {", + " \"cost\": 10,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [],", + " \"store\": null,", + " \"used\": 142964", + " },", + " \"pc\": 300,", + " \"sub\": null", + " },", + " {", + " \"cost\": 1,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [],", + " \"store\": null,", + " \"used\": 142963", + " },", + " \"pc\": 469,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x0\"", + " ],", + " \"store\": null,", + " \"used\": 142960", + " },", + " \"pc\": 470,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x0\",", + " \"0x0\"", + " ],", + " \"store\": null,", + " \"used\": 142957", + " },", + " \"pc\": 472,", + " \"sub\": null", + " },", + " {", + " \"cost\": 800,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x8ac72304907677e9\"", + " ],", + " \"store\": null,", + " \"used\": 142157", + " },", + " \"pc\": 473,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x0\",", + " \"0x0\",", + " \"0x0\",", + " \"0x0\",", + " \"0x0\",", + " \"0x8ac72304907677e9\",", + " \"0x0\"", + " ],", + " \"store\": null,", + " \"used\": 142154", + " },", + " \"pc\": 474,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x8ac72304907677e9\"", + " ],", + " \"store\": null,", + " \"used\": 142151", + " },", + " \"pc\": 475,", + " \"sub\": null", + " },", + " {", + " \"cost\": 3,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [", + " \"0x8ac72304907677e9\",", + " \"0x0\"", + " ],", + " \"store\": null,", + " \"used\": 142148", + " },", + " \"pc\": 476,", + " \"sub\": null", + " },", + " {", + " \"cost\": 800,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [],", + " \"store\": {", + " \"key\": \"0x0\",", + " \"val\": \"0x8ac72304907677e9\"", + " },", + " \"used\": 141348", + " },", + " \"pc\": 477,", + " \"sub\": null", + " },", + " {", + " \"cost\": 2,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [],", + " \"store\": null,", + " \"used\": 141346", + " },", + " \"pc\": 478,", + " \"sub\": null", + " },", + " {", + " \"cost\": 2,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [],", + " \"store\": null,", + " \"used\": 141344", + " },", + " \"pc\": 479,", + " \"sub\": null", + " },", + " {", + " \"cost\": 2,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [],", + " \"store\": null,", + " \"used\": 141342", + " },", + " \"pc\": 480,", + " \"sub\": null", + " },", + " {", + " \"cost\": 2,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [],", + " \"store\": null,", + " \"used\": 141340", + " },", + " \"pc\": 481,", + " \"sub\": null", + " },", + " {", + " \"cost\": 8,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [],", + " \"store\": null,", + " \"used\": 141332", + " },", + " \"pc\": 482,", + " \"sub\": null", + " },", + " {", + " \"cost\": 1,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [],", + " \"store\": null,", + " \"used\": 141331", + " },", + " \"pc\": 283,", + " \"sub\": null", + " },", + " {", + " \"cost\": 0,", + " \"ex\": {", + " \"mem\": null,", + " \"push\": [],", + " \"store\": null,", + " \"used\": 141331", + " },", + " \"pc\": 284,", + " \"sub\": null", + " }", + " ]", + " }", + " },", + " \"id\": \"1\"", + "}", + "", + "pm.test('Has correct result', function() {", + " pm.expect(pm.response.json()).to.be.deep.equal(expected);", + "})", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"trace_rawTransaction\",\n\t\"params\":[\n \"0xf86d09850cf032900f83030d4094109c4f2ccc82c4d77bde15f306707320294aea3f880de0b6b3a7640000801ca02da49aa24d7fa6fa876af59d77acfd60537eba478654934430b1b32893b65c85a02cdc152d81b71f25fd23e3e271c8c0b15a3a91ce104b6af35bd476d1e6d26fdf\",\n [\"vmTrace\"]\n ],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": [ + "{{HOST}}" + ] + } + }, + "response": [] + }, + { + "name": "trace_rawTransaction - stateDiff only", + "event": [ + { + "listen": "test", + "script": { + "id": "9fd4f1d1-1c82-4d39-b47f-feeb33836056", + "exec": [ + "utils.cannotTest(\"trace_rawTransaction - stateDiff only\", pm.response.json())", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"trace_rawTransaction\",\n\t\"params\":[\n \"0xf86d09850cf032900f83030d4094109c4f2ccc82c4d77bde15f306707320294aea3f880de0b6b3a7640000801ca02da49aa24d7fa6fa876af59d77acfd60537eba478654934430b1b32893b65c85a02cdc152d81b71f25fd23e3e271c8c0b15a3a91ce104b6af35bd476d1e6d26fdf\",\n [\"stateDiff\"]\n ],\n\t\"id\":\"1\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": [ + "{{HOST}}" + ] + } + }, + "response": [] + } + ], + "protocolProfileBehavior": {} + }, + { + "name": "trace_get", + "item": [ + { + "name": "trace_get - trace 0", + "event": [ + { + "listen": "test", + "script": { + "id": "b13645b7-48a0-480f-99e5-be52aacae86d", + "exec": [ + "var expected = {", + " \"jsonrpc\": \"2.0\",", + " \"result\": {", + " \"action\": {", + " \"callType\": \"staticcall\",", + " \"from\": \"0x7a250d5630b4cf539739df2c5dacb4c659f2488d\",", + " \"gas\": \"0x40e8b\",", + " \"input\": \"0x0902f1ac\",", + " \"to\": \"0x6ebb1c40cd3789e6fc02f003b2416383ea5c96f4\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0x4d5e647b2d8d3a3c8c1561ebb88734bc5fc3c2941016f810cf218738c0ecd99e\",", + " \"blockNumber\": 11000000,", + " \"result\": {", + " \"gasUsed\": \"0x4b4\",", + " \"output\": \"0x00000000000000000000000000000000000000000000008f63f71a5f71f77323000000000000000000000000000000000000000000000008709d1f36bd0f2f83000000000000000000000000000000000000000000000000000000005f7befab\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [", + " 0", + " ],", + " \"transactionHash\": \"0x88162c6bcbb040fd8f6676fe336f83d7a27a5765b18bfce524beea2a0e107159\",", + " \"transactionPosition\": 26,", + " \"type\": \"call\"", + " },", + " \"id\": \"1\"", + "}", + "", + "pm.test('Has correct result', function() {", + " pm.expect(pm.response.json()).to.be.deep.equal(expected);", + "})", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"trace_get\",\n \"params\":[\n \"0x88162c6bcbb040fd8f6676fe336f83d7a27a5765b18bfce524beea2a0e107159\",\n [\"0x0\"]\n ],\n\t\"id\":\"1\"\n}\n", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": [ + "{{HOST}}" + ] + } + }, + "response": [] + }, + { + "name": "trace_get - trace 3", + "event": [ + { + "listen": "test", + "script": { + "id": "0c7a662c-06d5-45f2-85e8-6d0d30e07d64", + "exec": [ + "var expected = {", + " \"jsonrpc\": \"2.0\",", + " \"result\": {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0x7a250d5630b4cf539739df2c5dacb4c659f2488d\",", + " \"gas\": \"0x3d7ce\",", + " \"input\": \"0x23b872dd0000000000000000000000006795e7f4219a48e083157db6b52cf70002eced5f0000000000000000000000004a4354ffddb257671ac00cdcedef87503ac6b35200000000000000000000000000000000000000000000000001d1e7fc878ab04b\",", + " \"to\": \"0x5befbb272290dd5b8521d4a938f6c4757742c430\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0x4d5e647b2d8d3a3c8c1561ebb88734bc5fc3c2941016f810cf218738c0ecd99e\",", + " \"blockNumber\": 11000000,", + " \"result\": {", + " \"gasUsed\": \"0x5a30\",", + " \"output\": \"0x0000000000000000000000000000000000000000000000000000000000000001\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [", + " 3", + " ],", + " \"transactionHash\": \"0x88162c6bcbb040fd8f6676fe336f83d7a27a5765b18bfce524beea2a0e107159\",", + " \"transactionPosition\": 26,", + " \"type\": \"call\"", + " },", + " \"id\": \"1\"", + "}", + "", + "pm.test('Has correct result', function() {", + " pm.expect(pm.response.json()).to.be.deep.equal(expected);", + "})", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"trace_get\",\n \"params\":[\n \"0x88162c6bcbb040fd8f6676fe336f83d7a27a5765b18bfce524beea2a0e107159\",\n [\"0x3\"]\n ],\n\t\"id\":\"1\"\n}\n", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": [ + "{{HOST}}" + ] + } + }, + "response": [] + }, + { + "name": "trace_get - trace 5", + "event": [ + { + "listen": "test", + "script": { + "id": "f5431b3d-4824-4fb7-9172-483588363adc", + "exec": [ + "var expected = {", + " \"jsonrpc\": \"2.0\",", + " \"result\": {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0x7a250d5630b4cf539739df2c5dacb4c659f2488d\",", + " \"gas\": \"0x271a9\",", + " \"input\": \"0x022c0d9f00000000000000000000000000000000000000000000000003483b57f55165f500000000000000000000000000000000000000000000000000000000000000000000000000000000000000006ebb1c40cd3789e6fc02f003b2416383ea5c96f400000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000\",", + " \"to\": \"0x0d4a11d5eeaac28ec3f61d100daf4d40471f1852\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0x4d5e647b2d8d3a3c8c1561ebb88734bc5fc3c2941016f810cf218738c0ecd99e\",", + " \"blockNumber\": 11000000,", + " \"result\": {", + " \"gasUsed\": \"0xe1fa\",", + " \"output\": \"0x\"", + " },", + " \"subtraces\": 3,", + " \"traceAddress\": [", + " 5", + " ],", + " \"transactionHash\": \"0x88162c6bcbb040fd8f6676fe336f83d7a27a5765b18bfce524beea2a0e107159\",", + " \"transactionPosition\": 26,", + " \"type\": \"call\"", + " },", + " \"id\": \"1\"", + "}", + "", + "pm.test('Has correct result', function() {", + " pm.expect(pm.response.json()).to.be.deep.equal(expected);", + "})", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"trace_get\",\n \"params\":[\n \"0x88162c6bcbb040fd8f6676fe336f83d7a27a5765b18bfce524beea2a0e107159\",\n [\"0x5\"]\n ],\n\t\"id\":\"1\"\n}\n", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": [ + "{{HOST}}" + ] + } + }, + "response": [] + }, + { + "name": "trace_get - trace 10 (non-existant)", + "event": [ + { + "listen": "test", + "script": { + "id": "77a95092-2e76-4457-b024-78b2e57d7457", + "exec": [ + "var expected = {", + " \"jsonrpc\": \"2.0\",", + " \"result\": null,", + " \"id\": \"1\"", + "}", + "", + "pm.test('Has correct result', function() {", + " pm.expect(pm.response.json()).to.be.deep.equal(expected);", + "})", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"trace_get\",\n \"params\":[\n \"0x88162c6bcbb040fd8f6676fe336f83d7a27a5765b18bfce524beea2a0e107159\",\n [\"0xa\"]\n ],\n\t\"id\":\"1\"\n}\n", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": [ + "{{HOST}}" + ] + } + }, + "response": [] + } + ], + "protocolProfileBehavior": {} + }, + { + "name": "trace_transaction", + "event": [ + { + "listen": "test", + "script": { + "id": "d326776f-bac6-4630-82eb-d698fea4a4bf", + "exec": [ + "var expected = {", + " \"jsonrpc\": \"2.0\",", + " \"result\": [", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0x6795e7f4219a48e083157db6b52cf70002eced5f\",", + " \"gas\": \"0x42c8c\",", + " \"input\": \"0x8803dbee0000000000000000000000000000000000000000000000003782dace9d90000000000000000000000000000000000000000000000000000001d690b82191f53800000000000000000000000000000000000000000000000000000000000000a00000000000000000000000006795e7f4219a48e083157db6b52cf70002eced5f000000000000000000000000000000000000000000000000000000005f7bf45c00000000000000000000000000000000000000000000000000000000000000040000000000000000000000005befbb272290dd5b8521d4a938f6c4757742c430000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000001712aad2c773ee04bdc9114b32163c058321cd85\",", + " \"to\": \"0x7a250d5630b4cf539739df2c5dacb4c659f2488d\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0x4d5e647b2d8d3a3c8c1561ebb88734bc5fc3c2941016f810cf218738c0ecd99e\",", + " \"blockNumber\": 11000000,", + " \"result\": {", + " \"gasUsed\": \"0x3bafa\",", + " \"output\": \"0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000001d1e7fc878ab04b0000000000000000000000000000000000000000000000000000000004fe3dbb00000000000000000000000000000000000000000000000003483b57f55165f50000000000000000000000000000000000000000000000003782dace9d900000\"", + " },", + " \"subtraces\": 7,", + " \"traceAddress\": [],", + " \"transactionHash\": \"0x88162c6bcbb040fd8f6676fe336f83d7a27a5765b18bfce524beea2a0e107159\",", + " \"transactionPosition\": 26,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"staticcall\",", + " \"from\": \"0x7a250d5630b4cf539739df2c5dacb4c659f2488d\",", + " \"gas\": \"0x40e8b\",", + " \"input\": \"0x0902f1ac\",", + " \"to\": \"0x6ebb1c40cd3789e6fc02f003b2416383ea5c96f4\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0x4d5e647b2d8d3a3c8c1561ebb88734bc5fc3c2941016f810cf218738c0ecd99e\",", + " \"blockNumber\": 11000000,", + " \"result\": {", + " \"gasUsed\": \"0x4b4\",", + " \"output\": \"0x00000000000000000000000000000000000000000000008f63f71a5f71f77323000000000000000000000000000000000000000000000008709d1f36bd0f2f83000000000000000000000000000000000000000000000000000000005f7befab\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [", + " 0", + " ],", + " \"transactionHash\": \"0x88162c6bcbb040fd8f6676fe336f83d7a27a5765b18bfce524beea2a0e107159\",", + " \"transactionPosition\": 26,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"staticcall\",", + " \"from\": \"0x7a250d5630b4cf539739df2c5dacb4c659f2488d\",", + " \"gas\": \"0x3fc18\",", + " \"input\": \"0x0902f1ac\",", + " \"to\": \"0x0d4a11d5eeaac28ec3f61d100daf4d40471f1852\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0x4d5e647b2d8d3a3c8c1561ebb88734bc5fc3c2941016f810cf218738c0ecd99e\",", + " \"blockNumber\": 11000000,", + " \"result\": {", + " \"gasUsed\": \"0x4b4\",", + " \"output\": \"0x000000000000000000000000000000000000000000008c337fdddb8e693225210000000000000000000000000000000000000000000000000000d4a5c378ac6a000000000000000000000000000000000000000000000000000000005f7befad\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [", + " 1", + " ],", + " \"transactionHash\": \"0x88162c6bcbb040fd8f6676fe336f83d7a27a5765b18bfce524beea2a0e107159\",", + " \"transactionPosition\": 26,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"staticcall\",", + " \"from\": \"0x7a250d5630b4cf539739df2c5dacb4c659f2488d\",", + " \"gas\": \"0x3e9b8\",", + " \"input\": \"0x0902f1ac\",", + " \"to\": \"0x4a4354ffddb257671ac00cdcedef87503ac6b352\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0x4d5e647b2d8d3a3c8c1561ebb88734bc5fc3c2941016f810cf218738c0ecd99e\",", + " \"blockNumber\": 11000000,", + " \"result\": {", + " \"gasUsed\": \"0x4b4\",", + " \"output\": \"0x0000000000000000000000000000000000000000000000076bfdff5e26f7d67500000000000000000000000000000000000000000000000000000014716b4531000000000000000000000000000000000000000000000000000000005f7beebe\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [", + " 2", + " ],", + " \"transactionHash\": \"0x88162c6bcbb040fd8f6676fe336f83d7a27a5765b18bfce524beea2a0e107159\",", + " \"transactionPosition\": 26,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0x7a250d5630b4cf539739df2c5dacb4c659f2488d\",", + " \"gas\": \"0x3d7ce\",", + " \"input\": \"0x23b872dd0000000000000000000000006795e7f4219a48e083157db6b52cf70002eced5f0000000000000000000000004a4354ffddb257671ac00cdcedef87503ac6b35200000000000000000000000000000000000000000000000001d1e7fc878ab04b\",", + " \"to\": \"0x5befbb272290dd5b8521d4a938f6c4757742c430\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0x4d5e647b2d8d3a3c8c1561ebb88734bc5fc3c2941016f810cf218738c0ecd99e\",", + " \"blockNumber\": 11000000,", + " \"result\": {", + " \"gasUsed\": \"0x5a30\",", + " \"output\": \"0x0000000000000000000000000000000000000000000000000000000000000001\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [", + " 3", + " ],", + " \"transactionHash\": \"0x88162c6bcbb040fd8f6676fe336f83d7a27a5765b18bfce524beea2a0e107159\",", + " \"transactionPosition\": 26,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0x7a250d5630b4cf539739df2c5dacb4c659f2488d\",", + " \"gas\": \"0x36f24\",", + " \"input\": \"0x022c0d9f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004fe3dbb0000000000000000000000000d4a11d5eeaac28ec3f61d100daf4d40471f185200000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000\",", + " \"to\": \"0x4a4354ffddb257671ac00cdcedef87503ac6b352\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0x4d5e647b2d8d3a3c8c1561ebb88734bc5fc3c2941016f810cf218738c0ecd99e\",", + " \"blockNumber\": 11000000,", + " \"result\": {", + " \"gasUsed\": \"0xf2c2\",", + " \"output\": \"0x\"", + " },", + " \"subtraces\": 3,", + " \"traceAddress\": [", + " 4", + " ],", + " \"transactionHash\": \"0x88162c6bcbb040fd8f6676fe336f83d7a27a5765b18bfce524beea2a0e107159\",", + " \"transactionPosition\": 26,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0x4a4354ffddb257671ac00cdcedef87503ac6b352\",", + " \"gas\": \"0x33965\",", + " \"input\": \"0xa9059cbb0000000000000000000000000d4a11d5eeaac28ec3f61d100daf4d40471f18520000000000000000000000000000000000000000000000000000000004fe3dbb\",", + " \"to\": \"0xdac17f958d2ee523a2206206994597c13d831ec7\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0x4d5e647b2d8d3a3c8c1561ebb88734bc5fc3c2941016f810cf218738c0ecd99e\",", + " \"blockNumber\": 11000000,", + " \"result\": {", + " \"gasUsed\": \"0x4c91\",", + " \"output\": \"0x\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [", + " 4,", + " 0", + " ],", + " \"transactionHash\": \"0x88162c6bcbb040fd8f6676fe336f83d7a27a5765b18bfce524beea2a0e107159\",", + " \"transactionPosition\": 26,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"staticcall\",", + " \"from\": \"0x4a4354ffddb257671ac00cdcedef87503ac6b352\",", + " \"gas\": \"0x2e786\",", + " \"input\": \"0x70a082310000000000000000000000004a4354ffddb257671ac00cdcedef87503ac6b352\",", + " \"to\": \"0x5befbb272290dd5b8521d4a938f6c4757742c430\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0x4d5e647b2d8d3a3c8c1561ebb88734bc5fc3c2941016f810cf218738c0ecd99e\",", + " \"blockNumber\": 11000000,", + " \"result\": {", + " \"gasUsed\": \"0x4c2\",", + " \"output\": \"0x0000000000000000000000000000000000000000000000076dcfe75aae8286c0\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [", + " 4,", + " 1", + " ],", + " \"transactionHash\": \"0x88162c6bcbb040fd8f6676fe336f83d7a27a5765b18bfce524beea2a0e107159\",", + " \"transactionPosition\": 26,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"staticcall\",", + " \"from\": \"0x4a4354ffddb257671ac00cdcedef87503ac6b352\",", + " \"gas\": \"0x2dca4\",", + " \"input\": \"0x70a082310000000000000000000000004a4354ffddb257671ac00cdcedef87503ac6b352\",", + " \"to\": \"0xdac17f958d2ee523a2206206994597c13d831ec7\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0x4d5e647b2d8d3a3c8c1561ebb88734bc5fc3c2941016f810cf218738c0ecd99e\",", + " \"blockNumber\": 11000000,", + " \"result\": {", + " \"gasUsed\": \"0x97f\",", + " \"output\": \"0x000000000000000000000000000000000000000000000000000000146c6d0776\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [", + " 4,", + " 2", + " ],", + " \"transactionHash\": \"0x88162c6bcbb040fd8f6676fe336f83d7a27a5765b18bfce524beea2a0e107159\",", + " \"transactionPosition\": 26,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0x7a250d5630b4cf539739df2c5dacb4c659f2488d\",", + " \"gas\": \"0x271a9\",", + " \"input\": \"0x022c0d9f00000000000000000000000000000000000000000000000003483b57f55165f500000000000000000000000000000000000000000000000000000000000000000000000000000000000000006ebb1c40cd3789e6fc02f003b2416383ea5c96f400000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000\",", + " \"to\": \"0x0d4a11d5eeaac28ec3f61d100daf4d40471f1852\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0x4d5e647b2d8d3a3c8c1561ebb88734bc5fc3c2941016f810cf218738c0ecd99e\",", + " \"blockNumber\": 11000000,", + " \"result\": {", + " \"gasUsed\": \"0xe1fa\",", + " \"output\": \"0x\"", + " },", + " \"subtraces\": 3,", + " \"traceAddress\": [", + " 5", + " ],", + " \"transactionHash\": \"0x88162c6bcbb040fd8f6676fe336f83d7a27a5765b18bfce524beea2a0e107159\",", + " \"transactionPosition\": 26,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0x0d4a11d5eeaac28ec3f61d100daf4d40471f1852\",", + " \"gas\": \"0x23ffe\",", + " \"input\": \"0xa9059cbb0000000000000000000000006ebb1c40cd3789e6fc02f003b2416383ea5c96f400000000000000000000000000000000000000000000000003483b57f55165f5\",", + " \"to\": \"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0x4d5e647b2d8d3a3c8c1561ebb88734bc5fc3c2941016f810cf218738c0ecd99e\",", + " \"blockNumber\": 11000000,", + " \"result\": {", + " \"gasUsed\": \"0x3b3a\",", + " \"output\": \"0x0000000000000000000000000000000000000000000000000000000000000001\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [", + " 5,", + " 0", + " ],", + " \"transactionHash\": \"0x88162c6bcbb040fd8f6676fe336f83d7a27a5765b18bfce524beea2a0e107159\",", + " \"transactionPosition\": 26,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"staticcall\",", + " \"from\": \"0x0d4a11d5eeaac28ec3f61d100daf4d40471f1852\",", + " \"gas\": \"0x1fea6\",", + " \"input\": \"0x70a082310000000000000000000000000d4a11d5eeaac28ec3f61d100daf4d40471f1852\",", + " \"to\": \"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0x4d5e647b2d8d3a3c8c1561ebb88734bc5fc3c2941016f810cf218738c0ecd99e\",", + " \"blockNumber\": 11000000,", + " \"result\": {", + " \"gasUsed\": \"0x4d2\",", + " \"output\": \"0x000000000000000000000000000000000000000000008c337c95a03673e0bf2c\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [", + " 5,", + " 1", + " ],", + " \"transactionHash\": \"0x88162c6bcbb040fd8f6676fe336f83d7a27a5765b18bfce524beea2a0e107159\",", + " \"transactionPosition\": 26,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"staticcall\",", + " \"from\": \"0x0d4a11d5eeaac28ec3f61d100daf4d40471f1852\",", + " \"gas\": \"0x1f3b5\",", + " \"input\": \"0x70a082310000000000000000000000000d4a11d5eeaac28ec3f61d100daf4d40471f1852\",", + " \"to\": \"0xdac17f958d2ee523a2206206994597c13d831ec7\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0x4d5e647b2d8d3a3c8c1561ebb88734bc5fc3c2941016f810cf218738c0ecd99e\",", + " \"blockNumber\": 11000000,", + " \"result\": {", + " \"gasUsed\": \"0x97f\",", + " \"output\": \"0x0000000000000000000000000000000000000000000000000000d4a5c876ea25\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [", + " 5,", + " 2", + " ],", + " \"transactionHash\": \"0x88162c6bcbb040fd8f6676fe336f83d7a27a5765b18bfce524beea2a0e107159\",", + " \"transactionPosition\": 26,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0x7a250d5630b4cf539739df2c5dacb4c659f2488d\",", + " \"gas\": \"0x1875a\",", + " \"input\": \"0x022c0d9f0000000000000000000000000000000000000000000000003782dace9d90000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006795e7f4219a48e083157db6b52cf70002eced5f00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000\",", + " \"to\": \"0x6ebb1c40cd3789e6fc02f003b2416383ea5c96f4\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0x4d5e647b2d8d3a3c8c1561ebb88734bc5fc3c2941016f810cf218738c0ecd99e\",", + " \"blockNumber\": 11000000,", + " \"result\": {", + " \"gasUsed\": \"0x119aa\",", + " \"output\": \"0x\"", + " },", + " \"subtraces\": 3,", + " \"traceAddress\": [", + " 6", + " ],", + " \"transactionHash\": \"0x88162c6bcbb040fd8f6676fe336f83d7a27a5765b18bfce524beea2a0e107159\",", + " \"transactionPosition\": 26,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0x6ebb1c40cd3789e6fc02f003b2416383ea5c96f4\",", + " \"gas\": \"0x15958\",", + " \"input\": \"0xa9059cbb0000000000000000000000006795e7f4219a48e083157db6b52cf70002eced5f0000000000000000000000000000000000000000000000003782dace9d900000\",", + " \"to\": \"0x1712aad2c773ee04bdc9114b32163c058321cd85\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0x4d5e647b2d8d3a3c8c1561ebb88734bc5fc3c2941016f810cf218738c0ecd99e\",", + " \"blockNumber\": 11000000,", + " \"result\": {", + " \"gasUsed\": \"0x776b\",", + " \"output\": \"0x0000000000000000000000000000000000000000000000000000000000000001\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [", + " 6,", + " 0", + " ],", + " \"transactionHash\": \"0x88162c6bcbb040fd8f6676fe336f83d7a27a5765b18bfce524beea2a0e107159\",", + " \"transactionPosition\": 26,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"staticcall\",", + " \"from\": \"0x6ebb1c40cd3789e6fc02f003b2416383ea5c96f4\",", + " \"gas\": \"0xdcc0\",", + " \"input\": \"0x70a082310000000000000000000000006ebb1c40cd3789e6fc02f003b2416383ea5c96f4\",", + " \"to\": \"0x1712aad2c773ee04bdc9114b32163c058321cd85\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0x4d5e647b2d8d3a3c8c1561ebb88734bc5fc3c2941016f810cf218738c0ecd99e\",", + " \"blockNumber\": 11000000,", + " \"result\": {", + " \"gasUsed\": \"0x4fe\",", + " \"output\": \"0x00000000000000000000000000000000000000000000008f2c743f90d4677323\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [", + " 6,", + " 1", + " ],", + " \"transactionHash\": \"0x88162c6bcbb040fd8f6676fe336f83d7a27a5765b18bfce524beea2a0e107159\",", + " \"transactionPosition\": 26,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"staticcall\",", + " \"from\": \"0x6ebb1c40cd3789e6fc02f003b2416383ea5c96f4\",", + " \"gas\": \"0xd1a4\",", + " \"input\": \"0x70a082310000000000000000000000006ebb1c40cd3789e6fc02f003b2416383ea5c96f4\",", + " \"to\": \"0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0x4d5e647b2d8d3a3c8c1561ebb88734bc5fc3c2941016f810cf218738c0ecd99e\",", + " \"blockNumber\": 11000000,", + " \"result\": {", + " \"gasUsed\": \"0x4d2\",", + " \"output\": \"0x00000000000000000000000000000000000000000000000873e55a8eb2609578\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [", + " 6,", + " 2", + " ],", + " \"transactionHash\": \"0x88162c6bcbb040fd8f6676fe336f83d7a27a5765b18bfce524beea2a0e107159\",", + " \"transactionPosition\": 26,", + " \"type\": \"call\"", + " }", + " ],", + " \"id\": \"1\"", + "}", + "", + "pm.test('Has correct result', function() {", + " pm.expect(pm.response.json()).to.be.deep.equal(expected);", + "})", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"trace_transaction\",\n \"params\":[\"0x88162c6bcbb040fd8f6676fe336f83d7a27a5765b18bfce524beea2a0e107159\"],\n\t\"id\":\"1\"\n}\n", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": [ + "{{HOST}}" + ] + } + }, + "response": [] + }, + { + "name": "trace_block", + "event": [ + { + "listen": "test", + "script": { + "id": "181dcd6d-e8cd-4ab4-aae3-db15ad220580", + "exec": [ + "var expected = {", + " \"jsonrpc\": \"2.0\",", + " \"result\": [", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0x969837498944ae1dc0dcac2d0c65634c88729b2d\",", + " \"gas\": \"0x4782ec\",", + " \"input\": \"0xc4463c80000000000000000000000000000000000000000000000000000000000000003b000000000000000000000000b656b2a9c3b2416437a811e07466ca712f5a5b5a000000000000000000000000f835a0247b0063c04ef22006ebe57c5f11977cc40000000000000000000000000000000000000000000000000000000000000009000000000000000000000000f35e2cc8e6523d683ed44870f5b7cc785051a77d\",", + " \"to\": \"0xc0ee9db1a9e07ca63e4ff0d5fb6f86bf68d47b89\",", + " \"value\": \"0x775ec7b96add6c8f0\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x3ee428\",", + " \"output\": \"0x0000000000000000000000000000000000000000000000000000000000000001\"", + " },", + " \"subtraces\": 2,", + " \"traceAddress\": [],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xc0ee9db1a9e07ca63e4ff0d5fb6f86bf68d47b89\",", + " \"gas\": \"0x8fc\",", + " \"input\": \"0x\",", + " \"to\": \"0xf35e2cc8e6523d683ed44870f5b7cc785051a77d\",", + " \"value\": \"0x775ec7b96add6c8f0\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x0\",", + " \"output\": \"0x\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [", + " 0", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xc0ee9db1a9e07ca63e4ff0d5fb6f86bf68d47b89\",", + " \"gas\": \"0x4567ba\",", + " \"input\": \"0x82661dc4000000000000000000000000000000000000000000000000000000000000003b000000000000000000000000b656b2a9c3b2416437a811e07466ca712f5a5b5a\",", + " \"to\": \"0xbb9bc244d798123fde783fcc1c72d3bb8c189413\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x3d248a\",", + " \"output\": \"0x0000000000000000000000000000000000000000000000000000000000000001\"", + " },", + " \"subtraces\": 5,", + " \"traceAddress\": [", + " 1", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xbb9bc244d798123fde783fcc1c72d3bb8c189413\",", + " \"gas\": \"0x44f77f\",", + " \"input\": \"0xe2faf044000000000000000000000000b656b2a9c3b2416437a811e07466ca712f5a5b5a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000057870858\",", + " \"to\": \"0x4a574510c7014e4ae985403536074abe582adfc8\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x2b21c7\",", + " \"output\": \"0x000000000000000000000000304a554a310c7e546dfe434669c62820b7d83490\"", + " },", + " \"subtraces\": 1,", + " \"traceAddress\": [", + " 1,", + " 0", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"from\": \"0x4a574510c7014e4ae985403536074abe582adfc8\",", + " \"gas\": \"0x446e14\",", + " \"init\": \"0x606060405260405160c0806132c88339610120604052905160805160a051925160e0516101005193949293828282600f829055601083905560118054610100830261010060a860020a031990911617905560405130906001906101bc8061033e8339600160a060020a03909316908301526101408201526040519081900361016001906000f060128054600160a060020a031916919091179055505060038054600160a060020a03199081168917909155600e80549091168717905550600c84905560405130906000906101bc806104fa8339018083600160a060020a0316815260200182815260200192505050604051809103906000f0600760006101000a815481600160a060020a03021916908302179055503060006040516101bc806106b68339018083600160a060020a0316815260200182815260200192505050604051809103906000f060088054600160a060020a031916919091179055600754600160a060020a03166000141561017557610002565b600854600160a060020a03166000141561018e57610002565b426002556005600190815560008054828255829080158290116101ca57600e0281600e0283600052602060002091820191016101ca9190610245565b50505030600160a060020a03908116600090815260046020526040808220805460ff19908116600190811790925560035490941683529120805490921617905550505050505050612a56806108726000396000f35b5050600060098201819055600a820155600d81018054600160a060020a03191690556001015b8082111561033a578054600160a060020a03191681556000600182810182905560028381018054848255909281161561010002600019011604601f81901061030c57505b506000600383018190556004838101805461ffff19169055600584018290556006840182905560078401805460ff19169055600884018054838255908352602090922061021f929091028101905b8082111561033a5760008082556001820181815560028301919091556003919091018054600160a060020a03191690556102d7565b601f01602090049060005260206000209081019061028991905b8082111561033a5760008155600101610326565b50905660606040818152806101bc833960a090525160805160008054600160a060020a03191690921760a060020a60ff0219167401000000000000000000000000000000000000000090910217815561016290819061005a90396000f3606060405236156100405760e060020a60003504630221038a811461004d57806318bdc79a146100aa5780638da5cb5b146100be578063d2cc718f146100d0575b6100d96001805434019055565b6100db6004356024356000805433600160a060020a0390811691161415806100755750600034115b806100a05750805460a060020a900460ff1680156100a057508054600160a060020a03848116911614155b156100f757610002565b6100db60005460ff60a060020a9091041681565b6100ed600054600160a060020a031681565b6100db60015481565b005b60408051918252519081900360200190f35b6060908152602090f35b600160a060020a0383168260608381818185876185025a03f1925050501561015c57604080518381529051600160a060020a038516917f9735b0cb909f3d21d5c16bbcccd272d85fa11446f6d679f6ecb170d2dabfecfc919081900360200190a25060015b929150505660606040818152806101bc833960a090525160805160008054600160a060020a03191690921760a060020a60ff0219167401000000000000000000000000000000000000000090910217815561016290819061005a90396000f3606060405236156100405760e060020a60003504630221038a811461004d57806318bdc79a146100aa5780638da5cb5b146100be578063d2cc718f146100d0575b6100d96001805434019055565b6100db6004356024356000805433600160a060020a0390811691161415806100755750600034115b806100a05750805460a060020a900460ff1680156100a057508054600160a060020a03848116911614155b156100f757610002565b6100db60005460ff60a060020a9091041681565b6100ed600054600160a060020a031681565b6100db60015481565b005b60408051918252519081900360200190f35b6060908152602090f35b600160a060020a0383168260608381818185876185025a03f1925050501561015c57604080518381529051600160a060020a038516917f9735b0cb909f3d21d5c16bbcccd272d85fa11446f6d679f6ecb170d2dabfecfc919081900360200190a25060015b929150505660606040818152806101bc833960a090525160805160008054600160a060020a03191690921760a060020a60ff0219167401000000000000000000000000000000000000000090910217815561016290819061005a90396000f3606060405236156100405760e060020a60003504630221038a811461004d57806318bdc79a146100aa5780638da5cb5b146100be578063d2cc718f146100d0575b6100d96001805434019055565b6100db6004356024356000805433600160a060020a0390811691161415806100755750600034115b806100a05750805460a060020a900460ff1680156100a057508054600160a060020a03848116911614155b156100f757610002565b6100db60005460ff60a060020a9091041681565b6100ed600054600160a060020a031681565b6100db60015481565b005b60408051918252519081900360200190f35b6060908152602090f35b600160a060020a0383168260608381818185876185025a03f1925050501561015c57604080518381529051600160a060020a038516917f9735b0cb909f3d21d5c16bbcccd272d85fa11446f6d679f6ecb170d2dabfecfc919081900360200190a25060015b92915050566060604052361561020e5760e060020a6000350463013cf08b8114610247578063095ea7b3146102d05780630c3b7b96146103455780630e7082031461034e578063149acf9a1461036057806318160ddd146103725780631f2dc5ef1461037b57806321b5b8dd1461039b578063237e9492146103ad57806323b872dd1461040e5780632632bf2014610441578063341458081461047257806339d1f9081461047b5780634b6753bc146104935780634df6d6cc1461049c5780634e10c3ee146104b7578063590e1ae3146104ca578063612e45a3146104db578063643f7cdd1461057a578063674ed066146105925780636837ff1e1461059b57806370a08231146105e5578063749f98891461060b57806378524b2e1461062457806381f03fcb1461067e57806382661dc41461069657806382bf6464146106b75780638b15a605146106c95780638d7af473146106d257806396d7f3f5146106e1578063a1da2fb9146106ea578063a3912ec814610704578063a9059cbb1461070f578063b7bc2c841461073f578063baac53001461074b578063be7c29c1146107b1578063c9d27afe14610817578063cc9ae3f61461082d578063cdef91d014610841578063dbde198814610859578063dd62ed3e1461087e578063e33734fd146108b2578063e5962195146108c6578063e66f53b7146108de578063eceb2945146108f0578063f8c80d261461094f575b610966600f546000906234bc000142108015610239575060125433600160a060020a03908116911614155b156109785761098033610752565b6109866004356000805482908110156100025750808052600e8202600080516020612a3683398151915201905060038101546004820154600683015460018401548454600786015460058701546009880154600a890154600d8a0154600160a060020a039586169b509599600201989760ff81811698610100909204811697949691951693168c565b61096660043560243533600160a060020a03908116600081815260156020908152604080832094871680845294825280832086905580518681529051929493927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929181900390910190a35060015b92915050565b61096660105481565b610a7d600754600160a060020a031681565b610a7d600e54600160a060020a031681565b61096660165481565b6109665b60004262127500600f60005054031115610de557506014610983565b610a7d601254600160a060020a031681565b60408051602060248035600481810135601f810185900485028601850190965285855261096695813595919460449492939092019181908401838280828437509496505050505050506000600060006000600060003411156116a857610002565b6109666004356024356044355b60115460009060ff1680156104315750600f5442115b80156124e957506124e78461044b565b6109666000610980335b600160a060020a0381166000908152600b602052604081205481908114156129cb57610b99565b61096660065481565b6109665b600d5430600160a060020a03163103610983565b610966600f5481565b61096660043560046020526000908152604090205460ff1681565b61096660043560243560006124cb610831565b610a9a6000341115610ba457610002565b604080516020604435600481810135601f8101849004840285018401909552848452610966948135946024803595939460649492939101918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a01909352828252969897608497919650602491909101945090925082915084018382808284375094965050933593505060a435915050600060006110c1336105ec565b61096660043560096020526000908152604090205481565b61096660015481565b610a9a60043530600160a060020a031633600160a060020a03161415806105db5750600160a060020a03811660009081526004602052604090205460ff16155b156121cb576121c8565b6109666004355b600160a060020a0381166000908152601460205260409020545b919050565b6109666004356024356000600034111561259957610002565b610966600062e6b680420360026000505410806106505750600354600160a060020a0390811633909116145b80156106645750600254621274ff19420190105b156126145750426002908155600180549091028155610983565b610966600435600a6020526000908152604090205481565b610966600435602435600060006000600060006000341115611ba157610002565b610a7d600854600160a060020a031681565b610966600c5481565b61096660005460001901610983565b61096660025481565b61096660043560006000600060003411156121fc57610002565b6109665b6001610983565b6109666004356024355b60115460009060ff16801561072f5750600f5442115b801561248757506124853361044b565b61096660115460ff1681565b6109666004355b60006000600f600050544210801561076a5750600034115b80156107a457506011546101009004600160a060020a0316600014806107a457506011546101009004600160a060020a0390811633909116145b15610b9f57610a9c61037f565b610a7d600435600060006000508281548110156100025750508080527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e56b600e83020180548290811015610002575081526020902060030154600160a060020a0316610606565b61096660043560243560006000610e1b336105ec565b6109665b6000600034111561247c57610002565b61096660043560056020526000908152604090205481565b610966600435602435604435600061252f845b6000600060003411156127ac57610002565b610966600435602435600160a060020a0382811660009081526015602090815260408083209385168352929052205461033f565b610a9a600435600034111561254557610002565b610966600435600b6020526000908152604090205481565b610a7d600354600160a060020a031681565b604080516020606435600481810135601f81018490048402850184019095528484526109669481359460248035956044359560849492019190819084018382808284375094965050505050505060006000600034111561103257610002565b610a7d6011546101009004600160a060020a031681565b60408051918252519081900360200190f35b610980610708565b90505b90565b604051808d600160a060020a031681526020018c8152602001806020018b81526020018a815260200189815260200188815260200187815260200186815260200185815260200184815260200183600160a060020a0316815260200182810382528c818154600181600116156101000203166002900481526020019150805460018160011615610100020316600290048015610a635780601f10610a3857610100808354040283529160200191610a63565b820191906000526020600020905b815481529060010190602001808311610a4657829003601f168201915b50509d505050505050505050505050505060405180910390f35b60408051600160a060020a03929092168252519081900360200190f35b005b604051601254601434908102939093049350600160a060020a03169183900390600081818185876185025a03f150505050600160a060020a038316600081815260146020908152604080832080548601905560168054860190556013825291829020805434019055815184815291517fdbccb92686efceafb9bb7e0394df7f58f71b954061b81afb57109bf247d3d75a9281900390910190a260105460165410801590610b4c575060115460ff16155b15610b94576011805460ff1916600117905560165460408051918252517ff381a3e2428fdda36615919e8d9c35878d9eb0cf85ac6edf575088e80e4c147e9181900360200190a15b600191505b50919050565b610002565b600f5442118015610bb8575060115460ff16155b15610de357601260009054906101000a9004600160a060020a0316600160a060020a031663d2cc718f6040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100025750506040516012549051600160a060020a039190911631109050610cc9576040805160125460e060020a63d2cc718f0282529151600160a060020a039290921691630221038a913091849163d2cc718f91600482810192602092919082900301816000876161da5a03f11561000257505060408051805160e160020a63011081c5028252600160a060020a039490941660048201526024810193909352516044838101936020935082900301816000876161da5a03f115610002575050505b33600160a060020a0316600081815260136020526040808220549051909181818185876185025a03f19250505015610de35733600160a060020a03167fbb28353e4598c3b9199101a66e0989549b659a59a54d2c27fbb183f1932c8e6d6013600050600033600160a060020a03168152602001908152602001600020600050546040518082815260200191505060405180910390a26014600050600033600160a060020a0316815260200190815260200160002060005054601660008282825054039250508190555060006014600050600033600160a060020a031681526020019081526020016000206000508190555060006013600050600033600160a060020a03168152602001908152602001600020600050819055505b565b4262054600600f60005054031115610e13576201518062127500600f60005054034203046014019050610983565b50601e610983565b60001415610e2857610002565b6000341115610e3657610002565b6000805485908110156100025750600160a060020a03331681527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e56e600e8602908101602052604090912054600080516020612a3683398151915291909101915060ff1680610eb05750600c810160205260406000205460ff165b80610ebf575060038101544210155b15610ec957610002565b8215610f0f5733600160a060020a03166000908152601460209081526040808320546009850180549091019055600b84019091529020805460ff19166001179055610f4b565b33600160a060020a0316600090815260146020908152604080832054600a850180549091019055600c84019091529020805460ff191660011790555b33600160a060020a03166000908152600b60205260408120541415610f77576040600020849055610feb565b33600160a060020a03166000908152600b60205260408120548154811015610002579080527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e566600e909102015460038201541115610feb5733600160a060020a03166000908152600b602052604090208490555b60408051848152905133600160a060020a03169186917f86abfce99b7dd908bec0169288797f85049ec73cbe046ed9de818fab3a497ae09181900360200190a35092915050565b6000805487908110156100025750808052600e8702600080516020612a3683398151915201905090508484846040518084600160a060020a0316606060020a0281526014018381526020018280519060200190808383829060006004602084601f0104600f02600301f15090500193505050506040518091039020816005016000505414915050949350505050565b600014156110ce57610002565b82801561111857508660001415806110e857508451600014155b806111005750600354600160a060020a038981169116145b8061110b5750600034115b80611118575062093a8084105b1561112257610002565b8215801561114257506111348861115c565b158061114257506212750084105b156111fe57610002565b83546118e590600160a060020a03165b600160a060020a03811660009081526004602052604081205460ff16806111f15750601254600160a060020a039081169083161480156111f15750601260009054906101000a9004600160a060020a0316600160a060020a031663d2cc718f6040518160e060020a0281526004018090506020604051808303816000876161da5a03f115610002575050604051516006541190505b156129a157506001610606565b6249d40084111561120e57610002565b60115460ff1615806112215750600f5442105b806112365750600c5434108015611236575082155b1561124057610002565b42844201101561124f57610002565b30600160a060020a031633600160a060020a0316141561126e57610002565b60008054600181018083559091908280158290116112a557600e0281600e0283600052602060002091820191016112a5919061136a565b505060008054929450918491508110156100025750808052600e8302600080516020612a368339815191520190508054600160a060020a031916891781556001818101899055875160028084018054600082815260209081902096975091959481161561010002600019011691909104601f908101829004840193918b019083901061146257805160ff19168380011785555b5061149292915061144a565b5050600060098201819055600a820155600d81018054600160a060020a03191690556001015b8082111561145e578054600160a060020a03191681556000600182810182905560028084018054848255909281161561010002600019011604601f81901061143057505b506000600383018190556004808401805461ffff19169055600584018290556006840182905560078401805460ff191690556008840180548382559083526020909220611344929091028101905b8082111561145e57600080825560018201818155600283019190915560039091018054600160a060020a03191690556113fc565b601f0160209004906000526020600020908101906113ae91905b8082111561145e576000815560010161144a565b5090565b82800160010185558215611338579182015b82811115611338578251826000505591602001919060010190611474565b50508787866040518084600160a060020a0316606060020a0281526014018381526020018280519060200190808383829060006004602084601f0104600f02600301f150905001935050505060405180910390208160050160005081905550834201816003016000508190555060018160040160006101000a81548160ff02191690830217905550828160070160006101000a81548160ff02191690830217905550821561157857600881018054600181018083559091908280158290116115735760040281600402836000526020600020918201910161157391906113fc565b505050505b600d8082018054600160a060020a031916331790553460068301819055815401905560408051600160a060020a038a16815260208181018a9052918101859052608060608201818152895191830191909152885185937f5790de2c279e58269b93b12828f56fd5f2bc8ad15e61ce08572585c81a38756f938d938d938a938e93929160a084019185810191908190849082908590600090600490601f850104600f02600301f150905090810190601f1680156116485780820380516001836020036101000a031916815260200191505b509550505050505060405180910390a2509695505050505050565b6040805186815260208101839052815189927fdfc78bdca8e3e0b18c16c5c99323c6cb9eb5e00afde190b4e7273f5158702b07928290030190a25b5050505092915050565b6000805488908110156100025750808052600e8802600080516020612a36833981519152019050600781015490945060ff166116e757620d2f006116ec565b622398805b600485015490935060ff16801561170857506003840154830142115b15611716576117b887611890565b600384015442108061172d5750600484015460ff16155b806117ae57508360000160009054906101000a9004600160a060020a03168460010160005054876040518084600160a060020a0316606060020a0281526014018381526020018280519060200190808383829060006004602084601f0104600f02600301f15090500193505050506040518091039020846005016000505414155b1561114c57610002565b61169e565b60048401805461ff001916610100179055835460019550600160a060020a03908116309091161480159061180157508354600754600160a060020a03908116911614155b801561181d57506008548454600160a060020a03908116911614155b801561183957508354601254600160a060020a03908116911614155b801561185557506003548454600160a060020a03908116911614155b1561188b5760018401805430600160a060020a031660009081526005602052604090208054919091019055546006805490910190555b611663875b6000600060005082815481101561000257908052600e02600080516020612a36833981519152018150600481015490915060ff16156118d757600d80546006830154900390555b600401805460ff1916905550565b15156118f45761190087611890565b6001915061193161047f565b604051600d8501546006860154600160a060020a0391909116916000919082818181858883f193505050505061169e565b6001850154111561194157600091505b50600a8301546009840154865191019060049010801590611986575085600081518110156100025790602001015160f860020a900460f860020a02606860f860020a02145b80156119b6575085600181518110156100025790602001015160f860020a900460f860020a02603760f860020a02145b80156119e6575085600281518110156100025790602001015160f860020a900460f860020a0260ff60f860020a02145b8015611a16575085600381518110156100025790602001015160f860020a900460f860020a02601e60f860020a02145b8015611a45575030600160a060020a0316600090815260056020526040902054611a4290611a5d61047f565b81105b15611a4f57600091505b6001840154611a8090611a5f565b015b30600160a060020a03166000908152600560205260408120546129a961047f565b8110611ad457604051600d8501546006860154600160a060020a0391909116916000919082818181858883f193505050501515611abc57610002565b4260025560165460059004811115611ad45760056001555b6001840154611ae290611a5f565b8110158015611af85750600a8401546009850154115b8015611b015750815b1561188b578360000160009054906101000a9004600160a060020a0316600160a060020a0316846001016000505487604051808280519060200190808383829060006004602084601f0104600f02600301f150905090810190601f168015611b7d5780820380516001836020036101000a031916815260200191505b5091505060006040518083038185876185025a03f19250505015156117bd57610002565b611baa336105ec565b60001415611bb757610002565b60008054889081101561000257508052600e87027f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e566810154600080516020612a36833981519152919091019450421080611c1957506003840154622398800142115b80611c3257508354600160a060020a0390811690871614155b80611c425750600784015460ff16155b80611c68575033600160a060020a03166000908152600b8501602052604090205460ff16155b80611c9c575033600160a060020a03166000908152600b60205260409020548714801590611c9c5750604060009081205414155b15611ca657610002565b600884018054600090811015610002579081526020812060030154600160a060020a03161415611e1257611efc86604051600090600160a060020a038316907f9046fefd66f538ab35263248a44217dcb70e2eb2cd136629e141b8b8f9f03b60908390a260408051600e547fe2faf044000000000000000000000000000000000000000000000000000000008252600160a060020a03858116600484015260248301859052604483018590526223988042016064840152925192169163e2faf04491608480820192602092909190829003018187876161da5a03f1156100025750506040515191506106069050565b6008850180546000908110156100025781815260208082209390935530600160a060020a031681526005909252604082205481549092908110156100025790815260208120905060020155601654600885018054600090811015610002579081526020812090506001015560048401805461ff0019166101001790555b6008840180546000908110156100025781548282526020822060010154929190811015610002579081526020812090505433600160a060020a031660009081526014602052604081205460088801805493909102939093049550908110156100025790815260208120905060030154604080517fbaac530000000000000000000000000000000000000000000000000000000000815233600160a060020a0390811660048301529151929091169163baac53009186916024808301926020929190829003018185886185025a03f11561000257505060405151600014159150611f78905057610002565b60088501805460009081101561000257818152602081206003018054600160a060020a03191690931790925580549091908110156100025790815260208120905060030154600160a060020a031660001415611f5757610002565b600d5430600160a060020a0316311015611f7057610002565b611d9561047f565b6008840180546000908110156100025781548282526020822060010154929190811015610002579081526020812090506002015433600160a060020a0390811660009081526014602090815260408083205430909416835260058083528184205460099093529083205460088b018054969095029690960497509487020494508593929091908290811015610002575260208120815060030154600160a060020a0390811682526020828101939093526040918201600090812080549095019094553016835260059091529020548290101561205357610002565b30600160a060020a031660009081526005602052604081208054849003905560088501805483926009929091829081101561000257508152602080822060030154600160a060020a039081168352929052604080822080549094019093553090911681522054819010156120c657610002565b30600160a060020a0390811660009081526009602090815260408083208054869003905533909316808352601482528383205484519081529351929390927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929181900390910190a36121383361086c565b5033600160a060020a03166000908152601460209081526040808320805460168054919091039055839055600a9091528120556001945061169e565b30600160a060020a0390811660008181526005602090815260408083208054958716808552828520805490970190965584845283905560099091528082208054948352908220805490940190935590815290555b50565b604051600160a060020a0382811691309091163190600081818185876185025a03f192505050151561217457610002565b33600160a060020a03818116600090815260096020908152604080832054815160065460085460e060020a63d2cc718f028352935197995091969195929092169363d2cc718f936004848101949193929183900301908290876161da5a03f11561000257505050604051805190602001506005600050600033600160a060020a03168152602001908152602001600020600050540204101561229d57610002565b600160a060020a03338116600090815260096020908152604080832054815160065460085460e060020a63d2cc718f02835293519296909593169363d2cc718f93600483810194929383900301908290876161da5a03f11561000257505050604051805190602001506005600050600033600160a060020a0316815260200190815260200160002060005054020403905083156123ec57600860009054906101000a9004600160a060020a0316600160a060020a0316630221038a83600160a060020a0316630e7082036040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000257505060408051805160e160020a63011081c5028252600160a060020a031660048201526024810186905290516044808301935060209282900301816000876161da5a03f115610002575050604051511515905061245457610002565b6040805160085460e160020a63011081c5028252600160a060020a038581166004840152602483018590529251921691630221038a9160448082019260209290919082900301816000876161da5a03f115610002575050604051511515905061245457610002565b600160a060020a03331660009081526009602052604090208054909101905550600192915050565b6109803361086c565b155b80156124a257506124a23384845b6000600061293a856105ec565b80156124be57506124be83836000600034111561261c57610002565b15610b9f5750600161033f565b15156124d657610002565b6124e08383610719565b905061033f565b155b80156124fb57506124fb848484612495565b80156125185750612518848484600060003411156126c157610002565b15610b9f57506001612528565b90505b9392505050565b151561253a57610002565b61252584848461041b565b30600160a060020a031633600160a060020a031614158061258a575030600160a060020a031660009081526005602052604090205460649061258561047f565b010481115b1561259457610002565b600c55565b600354600160a060020a0390811633909116146125b557610002565b600160a060020a038316600081815260046020908152604091829020805460ff191686179055815185815291517f73ad2a153c8b67991df9459024950b318a609782cee8c7eeda47b905f9baa91f9281900390910190a250600161033f565b506000610983565b33600160a060020a03166000908152601460205260409020548290108015906126455750600082115b156126b957600160a060020a03338116600081815260146020908152604080832080548890039055938716808352918490208054870190558351868152935191937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929081900390910190a350600161033f565b50600061033f565b600160a060020a03841660009081526014602052604090205482901080159061270a5750601560209081526040600081812033600160a060020a03168252909252902054829010155b80156127165750600082115b156127a457600160a060020a03838116600081815260146020908152604080832080548801905588851680845281842080548990039055601583528184203390961684529482529182902080548790039055815186815291519293927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a3506001612528565b506000612528565b600160a060020a038381166000908152600a6020908152604080832054601654600754835160e060020a63d2cc718f02815293519296919591169363d2cc718f9360048181019492939183900301908290876161da5a03f11561000257505060405151905061281a866105ec565b0204101561282757610002565b600160a060020a038381166000908152600a6020908152604080832054601654600754835160e060020a63d2cc718f02815293519296919591169363d2cc718f9360048181019492939183900301908290876161da5a03f115610002575050604051519050612895866105ec565b0204039050600760009054906101000a9004600160a060020a0316600160a060020a0316630221038a84836040518360e060020a0281526004018083600160a060020a03168152602001828152602001925050506020604051808303816000876161da5a03f115610002575050604051511515905061291357610002565b600160a060020a0383166000908152600a6020526040902080548201905560019150610b99565b600160a060020a0386166000908152600a602052604090205480850291909104915081111561296857610002565b600160a060020a038581166000908152600a60205260408082208054859003905591861681522080548201905560019150509392505050565b506000610606565b0160030260166000505483020460016000505460166000505404019050610606565b600160a060020a0383166000908152600b6020526040812054815481101561000257818052600e02600080516020612a368339815191520190506003810154909150421115610b9457600160a060020a0383166000908152600b602052604081208190559150610b9956290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563000000000000000000000000b656b2a9c3b2416437a811e07466ca712f5a5b5a0000000000000000000000004a574510c7014e4ae985403536074abe582adfc8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000057870858000000000000000000000000bb9bc244d798123fde783fcc1c72d3bb8c189413\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"address\": \"0x304a554a310c7e546dfe434669c62820b7d83490\",", + " \"code\": \"0x6060604052361561020e5760e060020a6000350463013cf08b8114610247578063095ea7b3146102d05780630c3b7b96146103455780630e7082031461034e578063149acf9a1461036057806318160ddd146103725780631f2dc5ef1461037b57806321b5b8dd1461039b578063237e9492146103ad57806323b872dd1461040e5780632632bf2014610441578063341458081461047257806339d1f9081461047b5780634b6753bc146104935780634df6d6cc1461049c5780634e10c3ee146104b7578063590e1ae3146104ca578063612e45a3146104db578063643f7cdd1461057a578063674ed066146105925780636837ff1e1461059b57806370a08231146105e5578063749f98891461060b57806378524b2e1461062457806381f03fcb1461067e57806382661dc41461069657806382bf6464146106b75780638b15a605146106c95780638d7af473146106d257806396d7f3f5146106e1578063a1da2fb9146106ea578063a3912ec814610704578063a9059cbb1461070f578063b7bc2c841461073f578063baac53001461074b578063be7c29c1146107b1578063c9d27afe14610817578063cc9ae3f61461082d578063cdef91d014610841578063dbde198814610859578063dd62ed3e1461087e578063e33734fd146108b2578063e5962195146108c6578063e66f53b7146108de578063eceb2945146108f0578063f8c80d261461094f575b610966600f546000906234bc000142108015610239575060125433600160a060020a03908116911614155b156109785761098033610752565b6109866004356000805482908110156100025750808052600e8202600080516020612a3683398151915201905060038101546004820154600683015460018401548454600786015460058701546009880154600a890154600d8a0154600160a060020a039586169b509599600201989760ff81811698610100909204811697949691951693168c565b61096660043560243533600160a060020a03908116600081815260156020908152604080832094871680845294825280832086905580518681529051929493927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929181900390910190a35060015b92915050565b61096660105481565b610a7d600754600160a060020a031681565b610a7d600e54600160a060020a031681565b61096660165481565b6109665b60004262127500600f60005054031115610de557506014610983565b610a7d601254600160a060020a031681565b60408051602060248035600481810135601f810185900485028601850190965285855261096695813595919460449492939092019181908401838280828437509496505050505050506000600060006000600060003411156116a857610002565b6109666004356024356044355b60115460009060ff1680156104315750600f5442115b80156124e957506124e78461044b565b6109666000610980335b600160a060020a0381166000908152600b602052604081205481908114156129cb57610b99565b61096660065481565b6109665b600d5430600160a060020a03163103610983565b610966600f5481565b61096660043560046020526000908152604090205460ff1681565b61096660043560243560006124cb610831565b610a9a6000341115610ba457610002565b604080516020604435600481810135601f8101849004840285018401909552848452610966948135946024803595939460649492939101918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a01909352828252969897608497919650602491909101945090925082915084018382808284375094965050933593505060a435915050600060006110c1336105ec565b61096660043560096020526000908152604090205481565b61096660015481565b610a9a60043530600160a060020a031633600160a060020a03161415806105db5750600160a060020a03811660009081526004602052604090205460ff16155b156121cb576121c8565b6109666004355b600160a060020a0381166000908152601460205260409020545b919050565b6109666004356024356000600034111561259957610002565b610966600062e6b680420360026000505410806106505750600354600160a060020a0390811633909116145b80156106645750600254621274ff19420190105b156126145750426002908155600180549091028155610983565b610966600435600a6020526000908152604090205481565b610966600435602435600060006000600060006000341115611ba157610002565b610a7d600854600160a060020a031681565b610966600c5481565b61096660005460001901610983565b61096660025481565b61096660043560006000600060003411156121fc57610002565b6109665b6001610983565b6109666004356024355b60115460009060ff16801561072f5750600f5442115b801561248757506124853361044b565b61096660115460ff1681565b6109666004355b60006000600f600050544210801561076a5750600034115b80156107a457506011546101009004600160a060020a0316600014806107a457506011546101009004600160a060020a0390811633909116145b15610b9f57610a9c61037f565b610a7d600435600060006000508281548110156100025750508080527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e56b600e83020180548290811015610002575081526020902060030154600160a060020a0316610606565b61096660043560243560006000610e1b336105ec565b6109665b6000600034111561247c57610002565b61096660043560056020526000908152604090205481565b610966600435602435604435600061252f845b6000600060003411156127ac57610002565b610966600435602435600160a060020a0382811660009081526015602090815260408083209385168352929052205461033f565b610a9a600435600034111561254557610002565b610966600435600b6020526000908152604090205481565b610a7d600354600160a060020a031681565b604080516020606435600481810135601f81018490048402850184019095528484526109669481359460248035956044359560849492019190819084018382808284375094965050505050505060006000600034111561103257610002565b610a7d6011546101009004600160a060020a031681565b60408051918252519081900360200190f35b610980610708565b90505b90565b604051808d600160a060020a031681526020018c8152602001806020018b81526020018a815260200189815260200188815260200187815260200186815260200185815260200184815260200183600160a060020a0316815260200182810382528c818154600181600116156101000203166002900481526020019150805460018160011615610100020316600290048015610a635780601f10610a3857610100808354040283529160200191610a63565b820191906000526020600020905b815481529060010190602001808311610a4657829003601f168201915b50509d505050505050505050505050505060405180910390f35b60408051600160a060020a03929092168252519081900360200190f35b005b604051601254601434908102939093049350600160a060020a03169183900390600081818185876185025a03f150505050600160a060020a038316600081815260146020908152604080832080548601905560168054860190556013825291829020805434019055815184815291517fdbccb92686efceafb9bb7e0394df7f58f71b954061b81afb57109bf247d3d75a9281900390910190a260105460165410801590610b4c575060115460ff16155b15610b94576011805460ff1916600117905560165460408051918252517ff381a3e2428fdda36615919e8d9c35878d9eb0cf85ac6edf575088e80e4c147e9181900360200190a15b600191505b50919050565b610002565b600f5442118015610bb8575060115460ff16155b15610de357601260009054906101000a9004600160a060020a0316600160a060020a031663d2cc718f6040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100025750506040516012549051600160a060020a039190911631109050610cc9576040805160125460e060020a63d2cc718f0282529151600160a060020a039290921691630221038a913091849163d2cc718f91600482810192602092919082900301816000876161da5a03f11561000257505060408051805160e160020a63011081c5028252600160a060020a039490941660048201526024810193909352516044838101936020935082900301816000876161da5a03f115610002575050505b33600160a060020a0316600081815260136020526040808220549051909181818185876185025a03f19250505015610de35733600160a060020a03167fbb28353e4598c3b9199101a66e0989549b659a59a54d2c27fbb183f1932c8e6d6013600050600033600160a060020a03168152602001908152602001600020600050546040518082815260200191505060405180910390a26014600050600033600160a060020a0316815260200190815260200160002060005054601660008282825054039250508190555060006014600050600033600160a060020a031681526020019081526020016000206000508190555060006013600050600033600160a060020a03168152602001908152602001600020600050819055505b565b4262054600600f60005054031115610e13576201518062127500600f60005054034203046014019050610983565b50601e610983565b60001415610e2857610002565b6000341115610e3657610002565b6000805485908110156100025750600160a060020a03331681527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e56e600e8602908101602052604090912054600080516020612a3683398151915291909101915060ff1680610eb05750600c810160205260406000205460ff165b80610ebf575060038101544210155b15610ec957610002565b8215610f0f5733600160a060020a03166000908152601460209081526040808320546009850180549091019055600b84019091529020805460ff19166001179055610f4b565b33600160a060020a0316600090815260146020908152604080832054600a850180549091019055600c84019091529020805460ff191660011790555b33600160a060020a03166000908152600b60205260408120541415610f77576040600020849055610feb565b33600160a060020a03166000908152600b60205260408120548154811015610002579080527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e566600e909102015460038201541115610feb5733600160a060020a03166000908152600b602052604090208490555b60408051848152905133600160a060020a03169186917f86abfce99b7dd908bec0169288797f85049ec73cbe046ed9de818fab3a497ae09181900360200190a35092915050565b6000805487908110156100025750808052600e8702600080516020612a3683398151915201905090508484846040518084600160a060020a0316606060020a0281526014018381526020018280519060200190808383829060006004602084601f0104600f02600301f15090500193505050506040518091039020816005016000505414915050949350505050565b600014156110ce57610002565b82801561111857508660001415806110e857508451600014155b806111005750600354600160a060020a038981169116145b8061110b5750600034115b80611118575062093a8084105b1561112257610002565b8215801561114257506111348861115c565b158061114257506212750084105b156111fe57610002565b83546118e590600160a060020a03165b600160a060020a03811660009081526004602052604081205460ff16806111f15750601254600160a060020a039081169083161480156111f15750601260009054906101000a9004600160a060020a0316600160a060020a031663d2cc718f6040518160e060020a0281526004018090506020604051808303816000876161da5a03f115610002575050604051516006541190505b156129a157506001610606565b6249d40084111561120e57610002565b60115460ff1615806112215750600f5442105b806112365750600c5434108015611236575082155b1561124057610002565b42844201101561124f57610002565b30600160a060020a031633600160a060020a0316141561126e57610002565b60008054600181018083559091908280158290116112a557600e0281600e0283600052602060002091820191016112a5919061136a565b505060008054929450918491508110156100025750808052600e8302600080516020612a368339815191520190508054600160a060020a031916891781556001818101899055875160028084018054600082815260209081902096975091959481161561010002600019011691909104601f908101829004840193918b019083901061146257805160ff19168380011785555b5061149292915061144a565b5050600060098201819055600a820155600d81018054600160a060020a03191690556001015b8082111561145e578054600160a060020a03191681556000600182810182905560028084018054848255909281161561010002600019011604601f81901061143057505b506000600383018190556004808401805461ffff19169055600584018290556006840182905560078401805460ff191690556008840180548382559083526020909220611344929091028101905b8082111561145e57600080825560018201818155600283019190915560039091018054600160a060020a03191690556113fc565b601f0160209004906000526020600020908101906113ae91905b8082111561145e576000815560010161144a565b5090565b82800160010185558215611338579182015b82811115611338578251826000505591602001919060010190611474565b50508787866040518084600160a060020a0316606060020a0281526014018381526020018280519060200190808383829060006004602084601f0104600f02600301f150905001935050505060405180910390208160050160005081905550834201816003016000508190555060018160040160006101000a81548160ff02191690830217905550828160070160006101000a81548160ff02191690830217905550821561157857600881018054600181018083559091908280158290116115735760040281600402836000526020600020918201910161157391906113fc565b505050505b600d8082018054600160a060020a031916331790553460068301819055815401905560408051600160a060020a038a16815260208181018a9052918101859052608060608201818152895191830191909152885185937f5790de2c279e58269b93b12828f56fd5f2bc8ad15e61ce08572585c81a38756f938d938d938a938e93929160a084019185810191908190849082908590600090600490601f850104600f02600301f150905090810190601f1680156116485780820380516001836020036101000a031916815260200191505b509550505050505060405180910390a2509695505050505050565b6040805186815260208101839052815189927fdfc78bdca8e3e0b18c16c5c99323c6cb9eb5e00afde190b4e7273f5158702b07928290030190a25b5050505092915050565b6000805488908110156100025750808052600e8802600080516020612a36833981519152019050600781015490945060ff166116e757620d2f006116ec565b622398805b600485015490935060ff16801561170857506003840154830142115b15611716576117b887611890565b600384015442108061172d5750600484015460ff16155b806117ae57508360000160009054906101000a9004600160a060020a03168460010160005054876040518084600160a060020a0316606060020a0281526014018381526020018280519060200190808383829060006004602084601f0104600f02600301f15090500193505050506040518091039020846005016000505414155b1561114c57610002565b61169e565b60048401805461ff001916610100179055835460019550600160a060020a03908116309091161480159061180157508354600754600160a060020a03908116911614155b801561181d57506008548454600160a060020a03908116911614155b801561183957508354601254600160a060020a03908116911614155b801561185557506003548454600160a060020a03908116911614155b1561188b5760018401805430600160a060020a031660009081526005602052604090208054919091019055546006805490910190555b611663875b6000600060005082815481101561000257908052600e02600080516020612a36833981519152018150600481015490915060ff16156118d757600d80546006830154900390555b600401805460ff1916905550565b15156118f45761190087611890565b6001915061193161047f565b604051600d8501546006860154600160a060020a0391909116916000919082818181858883f193505050505061169e565b6001850154111561194157600091505b50600a8301546009840154865191019060049010801590611986575085600081518110156100025790602001015160f860020a900460f860020a02606860f860020a02145b80156119b6575085600181518110156100025790602001015160f860020a900460f860020a02603760f860020a02145b80156119e6575085600281518110156100025790602001015160f860020a900460f860020a0260ff60f860020a02145b8015611a16575085600381518110156100025790602001015160f860020a900460f860020a02601e60f860020a02145b8015611a45575030600160a060020a0316600090815260056020526040902054611a4290611a5d61047f565b81105b15611a4f57600091505b6001840154611a8090611a5f565b015b30600160a060020a03166000908152600560205260408120546129a961047f565b8110611ad457604051600d8501546006860154600160a060020a0391909116916000919082818181858883f193505050501515611abc57610002565b4260025560165460059004811115611ad45760056001555b6001840154611ae290611a5f565b8110158015611af85750600a8401546009850154115b8015611b015750815b1561188b578360000160009054906101000a9004600160a060020a0316600160a060020a0316846001016000505487604051808280519060200190808383829060006004602084601f0104600f02600301f150905090810190601f168015611b7d5780820380516001836020036101000a031916815260200191505b5091505060006040518083038185876185025a03f19250505015156117bd57610002565b611baa336105ec565b60001415611bb757610002565b60008054889081101561000257508052600e87027f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e566810154600080516020612a36833981519152919091019450421080611c1957506003840154622398800142115b80611c3257508354600160a060020a0390811690871614155b80611c425750600784015460ff16155b80611c68575033600160a060020a03166000908152600b8501602052604090205460ff16155b80611c9c575033600160a060020a03166000908152600b60205260409020548714801590611c9c5750604060009081205414155b15611ca657610002565b600884018054600090811015610002579081526020812060030154600160a060020a03161415611e1257611efc86604051600090600160a060020a038316907f9046fefd66f538ab35263248a44217dcb70e2eb2cd136629e141b8b8f9f03b60908390a260408051600e547fe2faf044000000000000000000000000000000000000000000000000000000008252600160a060020a03858116600484015260248301859052604483018590526223988042016064840152925192169163e2faf04491608480820192602092909190829003018187876161da5a03f1156100025750506040515191506106069050565b6008850180546000908110156100025781815260208082209390935530600160a060020a031681526005909252604082205481549092908110156100025790815260208120905060020155601654600885018054600090811015610002579081526020812090506001015560048401805461ff0019166101001790555b6008840180546000908110156100025781548282526020822060010154929190811015610002579081526020812090505433600160a060020a031660009081526014602052604081205460088801805493909102939093049550908110156100025790815260208120905060030154604080517fbaac530000000000000000000000000000000000000000000000000000000000815233600160a060020a0390811660048301529151929091169163baac53009186916024808301926020929190829003018185886185025a03f11561000257505060405151600014159150611f78905057610002565b60088501805460009081101561000257818152602081206003018054600160a060020a03191690931790925580549091908110156100025790815260208120905060030154600160a060020a031660001415611f5757610002565b600d5430600160a060020a0316311015611f7057610002565b611d9561047f565b6008840180546000908110156100025781548282526020822060010154929190811015610002579081526020812090506002015433600160a060020a0390811660009081526014602090815260408083205430909416835260058083528184205460099093529083205460088b018054969095029690960497509487020494508593929091908290811015610002575260208120815060030154600160a060020a0390811682526020828101939093526040918201600090812080549095019094553016835260059091529020548290101561205357610002565b30600160a060020a031660009081526005602052604081208054849003905560088501805483926009929091829081101561000257508152602080822060030154600160a060020a039081168352929052604080822080549094019093553090911681522054819010156120c657610002565b30600160a060020a0390811660009081526009602090815260408083208054869003905533909316808352601482528383205484519081529351929390927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929181900390910190a36121383361086c565b5033600160a060020a03166000908152601460209081526040808320805460168054919091039055839055600a9091528120556001945061169e565b30600160a060020a0390811660008181526005602090815260408083208054958716808552828520805490970190965584845283905560099091528082208054948352908220805490940190935590815290555b50565b604051600160a060020a0382811691309091163190600081818185876185025a03f192505050151561217457610002565b33600160a060020a03818116600090815260096020908152604080832054815160065460085460e060020a63d2cc718f028352935197995091969195929092169363d2cc718f936004848101949193929183900301908290876161da5a03f11561000257505050604051805190602001506005600050600033600160a060020a03168152602001908152602001600020600050540204101561229d57610002565b600160a060020a03338116600090815260096020908152604080832054815160065460085460e060020a63d2cc718f02835293519296909593169363d2cc718f93600483810194929383900301908290876161da5a03f11561000257505050604051805190602001506005600050600033600160a060020a0316815260200190815260200160002060005054020403905083156123ec57600860009054906101000a9004600160a060020a0316600160a060020a0316630221038a83600160a060020a0316630e7082036040518160e060020a0281526004018090506020604051808303816000876161da5a03f11561000257505060408051805160e160020a63011081c5028252600160a060020a031660048201526024810186905290516044808301935060209282900301816000876161da5a03f115610002575050604051511515905061245457610002565b6040805160085460e160020a63011081c5028252600160a060020a038581166004840152602483018590529251921691630221038a9160448082019260209290919082900301816000876161da5a03f115610002575050604051511515905061245457610002565b600160a060020a03331660009081526009602052604090208054909101905550600192915050565b6109803361086c565b155b80156124a257506124a23384845b6000600061293a856105ec565b80156124be57506124be83836000600034111561261c57610002565b15610b9f5750600161033f565b15156124d657610002565b6124e08383610719565b905061033f565b155b80156124fb57506124fb848484612495565b80156125185750612518848484600060003411156126c157610002565b15610b9f57506001612528565b90505b9392505050565b151561253a57610002565b61252584848461041b565b30600160a060020a031633600160a060020a031614158061258a575030600160a060020a031660009081526005602052604090205460649061258561047f565b010481115b1561259457610002565b600c55565b600354600160a060020a0390811633909116146125b557610002565b600160a060020a038316600081815260046020908152604091829020805460ff191686179055815185815291517f73ad2a153c8b67991df9459024950b318a609782cee8c7eeda47b905f9baa91f9281900390910190a250600161033f565b506000610983565b33600160a060020a03166000908152601460205260409020548290108015906126455750600082115b156126b957600160a060020a03338116600081815260146020908152604080832080548890039055938716808352918490208054870190558351868152935191937fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929081900390910190a350600161033f565b50600061033f565b600160a060020a03841660009081526014602052604090205482901080159061270a5750601560209081526040600081812033600160a060020a03168252909252902054829010155b80156127165750600082115b156127a457600160a060020a03838116600081815260146020908152604080832080548801905588851680845281842080548990039055601583528184203390961684529482529182902080548790039055815186815291519293927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a3506001612528565b506000612528565b600160a060020a038381166000908152600a6020908152604080832054601654600754835160e060020a63d2cc718f02815293519296919591169363d2cc718f9360048181019492939183900301908290876161da5a03f11561000257505060405151905061281a866105ec565b0204101561282757610002565b600160a060020a038381166000908152600a6020908152604080832054601654600754835160e060020a63d2cc718f02815293519296919591169363d2cc718f9360048181019492939183900301908290876161da5a03f115610002575050604051519050612895866105ec565b0204039050600760009054906101000a9004600160a060020a0316600160a060020a0316630221038a84836040518360e060020a0281526004018083600160a060020a03168152602001828152602001925050506020604051808303816000876161da5a03f115610002575050604051511515905061291357610002565b600160a060020a0383166000908152600a6020526040902080548201905560019150610b99565b600160a060020a0386166000908152600a602052604090205480850291909104915081111561296857610002565b600160a060020a038581166000908152600a60205260408082208054859003905591861681522080548201905560019150509392505050565b506000610606565b0160030260166000505483020460016000505460166000505404019050610606565b600160a060020a0383166000908152600b6020526040812054815481101561000257818052600e02600080516020612a368339815191520190506003810154909150421115610b9457600160a060020a0383166000908152600b602052604081208190559150610b9956290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563\",", + " \"gasUsed\": \"0x2a97ef\"", + " },", + " \"subtraces\": 3,", + " \"traceAddress\": [", + " 1,", + " 0,", + " 0", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"create\"", + " },", + " {", + " \"action\": {", + " \"from\": \"0x304a554a310c7e546dfe434669c62820b7d83490\",", + " \"gas\": \"0x433f5e\",", + " \"init\": \"0x60606040818152806101bc833960a090525160805160008054600160a060020a03191690921760a060020a60ff0219167401000000000000000000000000000000000000000090910217815561016290819061005a90396000f3606060405236156100405760e060020a60003504630221038a811461004d57806318bdc79a146100aa5780638da5cb5b146100be578063d2cc718f146100d0575b6100d96001805434019055565b6100db6004356024356000805433600160a060020a0390811691161415806100755750600034115b806100a05750805460a060020a900460ff1680156100a057508054600160a060020a03848116911614155b156100f757610002565b6100db60005460ff60a060020a9091041681565b6100ed600054600160a060020a031681565b6100db60015481565b005b60408051918252519081900360200190f35b6060908152602090f35b600160a060020a0383168260608381818185876185025a03f1925050501561015c57604080518381529051600160a060020a038516917f9735b0cb909f3d21d5c16bbcccd272d85fa11446f6d679f6ecb170d2dabfecfc919081900360200190a25060015b9291505056000000000000000000000000304a554a310c7e546dfe434669c62820b7d834900000000000000000000000000000000000000000000000000000000000000001\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"address\": \"0x914d1b8b43e92723e64fd0a06f5bdb8dd9b10c79\",", + " \"code\": \"0x606060405236156100405760e060020a60003504630221038a811461004d57806318bdc79a146100aa5780638da5cb5b146100be578063d2cc718f146100d0575b6100d96001805434019055565b6100db6004356024356000805433600160a060020a0390811691161415806100755750600034115b806100a05750805460a060020a900460ff1680156100a057508054600160a060020a03848116911614155b156100f757610002565b6100db60005460ff60a060020a9091041681565b6100ed600054600160a060020a031681565b6100db60015481565b005b60408051918252519081900360200190f35b6060908152602090f35b600160a060020a0383168260608381818185876185025a03f1925050501561015c57604080518381529051600160a060020a038516917f9735b0cb909f3d21d5c16bbcccd272d85fa11446f6d679f6ecb170d2dabfecfc919081900360200190a25060015b9291505056\",", + " \"gasUsed\": \"0x163e6\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [", + " 1,", + " 0,", + " 0,", + " 0", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"create\"", + " },", + " {", + " \"action\": {", + " \"from\": \"0x304a554a310c7e546dfe434669c62820b7d83490\",", + " \"gas\": \"0x405eab\",", + " \"init\": \"0x60606040818152806101bc833960a090525160805160008054600160a060020a03191690921760a060020a60ff0219167401000000000000000000000000000000000000000090910217815561016290819061005a90396000f3606060405236156100405760e060020a60003504630221038a811461004d57806318bdc79a146100aa5780638da5cb5b146100be578063d2cc718f146100d0575b6100d96001805434019055565b6100db6004356024356000805433600160a060020a0390811691161415806100755750600034115b806100a05750805460a060020a900460ff1680156100a057508054600160a060020a03848116911614155b156100f757610002565b6100db60005460ff60a060020a9091041681565b6100ed600054600160a060020a031681565b6100db60015481565b005b60408051918252519081900360200190f35b6060908152602090f35b600160a060020a0383168260608381818185876185025a03f1925050501561015c57604080518381529051600160a060020a038516917f9735b0cb909f3d21d5c16bbcccd272d85fa11446f6d679f6ecb170d2dabfecfc919081900360200190a25060015b9291505056000000000000000000000000304a554a310c7e546dfe434669c62820b7d834900000000000000000000000000000000000000000000000000000000000000000\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"address\": \"0xad3ecf23c0c8983b07163708be6d763b5f056193\",", + " \"code\": \"0x606060405236156100405760e060020a60003504630221038a811461004d57806318bdc79a146100aa5780638da5cb5b146100be578063d2cc718f146100d0575b6100d96001805434019055565b6100db6004356024356000805433600160a060020a0390811691161415806100755750600034115b806100a05750805460a060020a900460ff1680156100a057508054600160a060020a03848116911614155b156100f757610002565b6100db60005460ff60a060020a9091041681565b6100ed600054600160a060020a031681565b6100db60015481565b005b60408051918252519081900360200190f35b6060908152602090f35b600160a060020a0383168260608381818185876185025a03f1925050501561015c57604080518381529051600160a060020a038516917f9735b0cb909f3d21d5c16bbcccd272d85fa11446f6d679f6ecb170d2dabfecfc919081900360200190a25060015b9291505056\",", + " \"gasUsed\": \"0x163e6\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [", + " 1,", + " 0,", + " 0,", + " 1", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"create\"", + " },", + " {", + " \"action\": {", + " \"from\": \"0x304a554a310c7e546dfe434669c62820b7d83490\",", + " \"gas\": \"0x3e2e73\",", + " \"init\": \"0x60606040818152806101bc833960a090525160805160008054600160a060020a03191690921760a060020a60ff0219167401000000000000000000000000000000000000000090910217815561016290819061005a90396000f3606060405236156100405760e060020a60003504630221038a811461004d57806318bdc79a146100aa5780638da5cb5b146100be578063d2cc718f146100d0575b6100d96001805434019055565b6100db6004356024356000805433600160a060020a0390811691161415806100755750600034115b806100a05750805460a060020a900460ff1680156100a057508054600160a060020a03848116911614155b156100f757610002565b6100db60005460ff60a060020a9091041681565b6100ed600054600160a060020a031681565b6100db60015481565b005b60408051918252519081900360200190f35b6060908152602090f35b600160a060020a0383168260608381818185876185025a03f1925050501561015c57604080518381529051600160a060020a038516917f9735b0cb909f3d21d5c16bbcccd272d85fa11446f6d679f6ecb170d2dabfecfc919081900360200190a25060015b9291505056000000000000000000000000304a554a310c7e546dfe434669c62820b7d834900000000000000000000000000000000000000000000000000000000000000000\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"address\": \"0x1d29edb6997993a16c5086733cfd735d01df787c\",", + " \"code\": \"0x606060405236156100405760e060020a60003504630221038a811461004d57806318bdc79a146100aa5780638da5cb5b146100be578063d2cc718f146100d0575b6100d96001805434019055565b6100db6004356024356000805433600160a060020a0390811691161415806100755750600034115b806100a05750805460a060020a900460ff1680156100a057508054600160a060020a03848116911614155b156100f757610002565b6100db60005460ff60a060020a9091041681565b6100ed600054600160a060020a031681565b6100db60015481565b005b60408051918252519081900360200190f35b6060908152602090f35b600160a060020a0383168260608381818185876185025a03f1925050501561015c57604080518381529051600160a060020a038516917f9735b0cb909f3d21d5c16bbcccd272d85fa11446f6d679f6ecb170d2dabfecfc919081900360200190a25060015b9291505056\",", + " \"gasUsed\": \"0x163e6\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [", + " 1,", + " 0,", + " 0,", + " 2", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"create\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xbb9bc244d798123fde783fcc1c72d3bb8c189413\",", + " \"gas\": \"0x18a010\",", + " \"input\": \"0xbaac5300000000000000000000000000c0ee9db1a9e07ca63e4ff0d5fb6f86bf68d47b89\",", + " \"to\": \"0x304a554a310c7e546dfe434669c62820b7d83490\",", + " \"value\": \"0xdfd4116684423b208\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x124c9\",", + " \"output\": \"0x0000000000000000000000000000000000000000000000000000000000000001\"", + " },", + " \"subtraces\": 1,", + " \"traceAddress\": [", + " 1,", + " 1", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0x304a554a310c7e546dfe434669c62820b7d83490\",", + " \"gas\": \"0x181512\",", + " \"input\": \"0x\",", + " \"to\": \"0x914d1b8b43e92723e64fd0a06f5bdb8dd9b10c79\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x13f9\",", + " \"output\": \"0x\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [", + " 1,", + " 1,", + " 0", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xbb9bc244d798123fde783fcc1c72d3bb8c189413\",", + " \"gas\": \"0x171a62\",", + " \"input\": \"0xd2cc718f\",", + " \"to\": \"0xd2e16a20dd7b1ae54fb0312209784478d069c7b0\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x113\",", + " \"output\": \"0x00000000000000000000000000000000000000000000000000038d7ea4c68000\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [", + " 1,", + " 2", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xbb9bc244d798123fde783fcc1c72d3bb8c189413\",", + " \"gas\": \"0x17168c\",", + " \"input\": \"0xd2cc718f\",", + " \"to\": \"0xd2e16a20dd7b1ae54fb0312209784478d069c7b0\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x113\",", + " \"output\": \"0x00000000000000000000000000000000000000000000000000038d7ea4c68000\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [", + " 1,", + " 3", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xbb9bc244d798123fde783fcc1c72d3bb8c189413\",", + " \"gas\": \"0x171316\",", + " \"input\": \"0x0221038a000000000000000000000000c0ee9db1a9e07ca63e4ff0d5fb6f86bf68d47b89000000000000000000000000000000000000000000000000000000052aa8b9ab\",", + " \"to\": \"0xd2e16a20dd7b1ae54fb0312209784478d069c7b0\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0xea64e\",", + " \"output\": \"0x0000000000000000000000000000000000000000000000000000000000000001\"", + " },", + " \"subtraces\": 1,", + " \"traceAddress\": [", + " 1,", + " 4", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xd2e16a20dd7b1ae54fb0312209784478d069c7b0\",", + " \"gas\": \"0x169540\",", + " \"input\": \"0x\",", + " \"to\": \"0xc0ee9db1a9e07ca63e4ff0d5fb6f86bf68d47b89\",", + " \"value\": \"0x52aa8b9ab\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0xe8407\",", + " \"output\": \"0x0000000000000000000000000000000000000000000000000000000000000001\"", + " },", + " \"subtraces\": 2,", + " \"traceAddress\": [", + " 1,", + " 4,", + " 0", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xc0ee9db1a9e07ca63e4ff0d5fb6f86bf68d47b89\",", + " \"gas\": \"0x1632a8\",", + " \"input\": \"0x0e708203\",", + " \"to\": \"0xbb9bc244d798123fde783fcc1c72d3bb8c189413\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x15f\",", + " \"output\": \"0x000000000000000000000000d2e16a20dd7b1ae54fb0312209784478d069c7b0\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [", + " 1,", + " 4,", + " 0,", + " 0", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xc0ee9db1a9e07ca63e4ff0d5fb6f86bf68d47b89\",", + " \"gas\": \"0x161ae8\",", + " \"input\": \"0x82661dc4000000000000000000000000000000000000000000000000000000000000003b000000000000000000000000b656b2a9c3b2416437a811e07466ca712f5a5b5a\",", + " \"to\": \"0xbb9bc244d798123fde783fcc1c72d3bb8c189413\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0xe6afb\",", + " \"output\": \"0x0000000000000000000000000000000000000000000000000000000000000001\"", + " },", + " \"subtraces\": 4,", + " \"traceAddress\": [", + " 1,", + " 4,", + " 0,", + " 1", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xbb9bc244d798123fde783fcc1c72d3bb8c189413\",", + " \"gas\": \"0x159290\",", + " \"input\": \"0xbaac5300000000000000000000000000c0ee9db1a9e07ca63e4ff0d5fb6f86bf68d47b89\",", + " \"to\": \"0x304a554a310c7e546dfe434669c62820b7d83490\",", + " \"value\": \"0xdfd4116684423b208\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x5cdf\",", + " \"output\": \"0x0000000000000000000000000000000000000000000000000000000000000001\"", + " },", + " \"subtraces\": 1,", + " \"traceAddress\": [", + " 1,", + " 4,", + " 0,", + " 1,", + " 0", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0x304a554a310c7e546dfe434669c62820b7d83490\",", + " \"gas\": \"0x150792\",", + " \"input\": \"0x\",", + " \"to\": \"0x914d1b8b43e92723e64fd0a06f5bdb8dd9b10c79\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x13f9\",", + " \"output\": \"0x\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [", + " 1,", + " 4,", + " 0,", + " 1,", + " 0,", + " 0", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xbb9bc244d798123fde783fcc1c72d3bb8c189413\",", + " \"gas\": \"0x14d4cc\",", + " \"input\": \"0xd2cc718f\",", + " \"to\": \"0xd2e16a20dd7b1ae54fb0312209784478d069c7b0\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x113\",", + " \"output\": \"0x00000000000000000000000000000000000000000000000000038d7ea4c68000\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [", + " 1,", + " 4,", + " 0,", + " 1,", + " 1", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xbb9bc244d798123fde783fcc1c72d3bb8c189413\",", + " \"gas\": \"0x14d0f6\",", + " \"input\": \"0xd2cc718f\",", + " \"to\": \"0xd2e16a20dd7b1ae54fb0312209784478d069c7b0\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x113\",", + " \"output\": \"0x00000000000000000000000000000000000000000000000000038d7ea4c68000\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [", + " 1,", + " 4,", + " 0,", + " 1,", + " 2", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xbb9bc244d798123fde783fcc1c72d3bb8c189413\",", + " \"gas\": \"0x14cd7d\",", + " \"input\": \"0x0221038a000000000000000000000000c0ee9db1a9e07ca63e4ff0d5fb6f86bf68d47b89000000000000000000000000000000000000000000000000000000052aa8b9ab\",", + " \"to\": \"0xd2e16a20dd7b1ae54fb0312209784478d069c7b0\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0xcf3f8\",", + " \"output\": \"0x0000000000000000000000000000000000000000000000000000000000000001\"", + " },", + " \"subtraces\": 1,", + " \"traceAddress\": [", + " 1,", + " 4,", + " 0,", + " 1,", + " 3", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xd2e16a20dd7b1ae54fb0312209784478d069c7b0\",", + " \"gas\": \"0x144fa7\",", + " \"input\": \"0x\",", + " \"to\": \"0xc0ee9db1a9e07ca63e4ff0d5fb6f86bf68d47b89\",", + " \"value\": \"0x52aa8b9ab\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0xcd1b1\",", + " \"output\": \"0x0000000000000000000000000000000000000000000000000000000000000001\"", + " },", + " \"subtraces\": 2,", + " \"traceAddress\": [", + " 1,", + " 4,", + " 0,", + " 1,", + " 3,", + " 0", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xc0ee9db1a9e07ca63e4ff0d5fb6f86bf68d47b89\",", + " \"gas\": \"0x13ed0f\",", + " \"input\": \"0x0e708203\",", + " \"to\": \"0xbb9bc244d798123fde783fcc1c72d3bb8c189413\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x15f\",", + " \"output\": \"0x000000000000000000000000d2e16a20dd7b1ae54fb0312209784478d069c7b0\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [", + " 1,", + " 4,", + " 0,", + " 1,", + " 3,", + " 0,", + " 0", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xc0ee9db1a9e07ca63e4ff0d5fb6f86bf68d47b89\",", + " \"gas\": \"0x13d54f\",", + " \"input\": \"0x82661dc4000000000000000000000000000000000000000000000000000000000000003b000000000000000000000000b656b2a9c3b2416437a811e07466ca712f5a5b5a\",", + " \"to\": \"0xbb9bc244d798123fde783fcc1c72d3bb8c189413\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0xcb8a5\",", + " \"output\": \"0x0000000000000000000000000000000000000000000000000000000000000001\"", + " },", + " \"subtraces\": 4,", + " \"traceAddress\": [", + " 1,", + " 4,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xbb9bc244d798123fde783fcc1c72d3bb8c189413\",", + " \"gas\": \"0x134cf7\",", + " \"input\": \"0xbaac5300000000000000000000000000c0ee9db1a9e07ca63e4ff0d5fb6f86bf68d47b89\",", + " \"to\": \"0x304a554a310c7e546dfe434669c62820b7d83490\",", + " \"value\": \"0xdfd4116684423b208\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x5cdf\",", + " \"output\": \"0x0000000000000000000000000000000000000000000000000000000000000001\"", + " },", + " \"subtraces\": 1,", + " \"traceAddress\": [", + " 1,", + " 4,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 0", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0x304a554a310c7e546dfe434669c62820b7d83490\",", + " \"gas\": \"0x12c1f9\",", + " \"input\": \"0x\",", + " \"to\": \"0x914d1b8b43e92723e64fd0a06f5bdb8dd9b10c79\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x13f9\",", + " \"output\": \"0x\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [", + " 1,", + " 4,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 0,", + " 0", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xbb9bc244d798123fde783fcc1c72d3bb8c189413\",", + " \"gas\": \"0x128f33\",", + " \"input\": \"0xd2cc718f\",", + " \"to\": \"0xd2e16a20dd7b1ae54fb0312209784478d069c7b0\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x113\",", + " \"output\": \"0x00000000000000000000000000000000000000000000000000038d7ea4c68000\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [", + " 1,", + " 4,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 1", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xbb9bc244d798123fde783fcc1c72d3bb8c189413\",", + " \"gas\": \"0x128b5d\",", + " \"input\": \"0xd2cc718f\",", + " \"to\": \"0xd2e16a20dd7b1ae54fb0312209784478d069c7b0\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x113\",", + " \"output\": \"0x00000000000000000000000000000000000000000000000000038d7ea4c68000\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [", + " 1,", + " 4,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 2", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xbb9bc244d798123fde783fcc1c72d3bb8c189413\",", + " \"gas\": \"0x1287e4\",", + " \"input\": \"0x0221038a000000000000000000000000c0ee9db1a9e07ca63e4ff0d5fb6f86bf68d47b89000000000000000000000000000000000000000000000000000000052aa8b9ab\",", + " \"to\": \"0xd2e16a20dd7b1ae54fb0312209784478d069c7b0\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0xb41a2\",", + " \"output\": \"0x0000000000000000000000000000000000000000000000000000000000000001\"", + " },", + " \"subtraces\": 1,", + " \"traceAddress\": [", + " 1,", + " 4,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xd2e16a20dd7b1ae54fb0312209784478d069c7b0\",", + " \"gas\": \"0x120a0e\",", + " \"input\": \"0x\",", + " \"to\": \"0xc0ee9db1a9e07ca63e4ff0d5fb6f86bf68d47b89\",", + " \"value\": \"0x52aa8b9ab\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0xb1f5b\",", + " \"output\": \"0x0000000000000000000000000000000000000000000000000000000000000001\"", + " },", + " \"subtraces\": 2,", + " \"traceAddress\": [", + " 1,", + " 4,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xc0ee9db1a9e07ca63e4ff0d5fb6f86bf68d47b89\",", + " \"gas\": \"0x11a776\",", + " \"input\": \"0x0e708203\",", + " \"to\": \"0xbb9bc244d798123fde783fcc1c72d3bb8c189413\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x15f\",", + " \"output\": \"0x000000000000000000000000d2e16a20dd7b1ae54fb0312209784478d069c7b0\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [", + " 1,", + " 4,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 0", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xc0ee9db1a9e07ca63e4ff0d5fb6f86bf68d47b89\",", + " \"gas\": \"0x118fb6\",", + " \"input\": \"0x82661dc4000000000000000000000000000000000000000000000000000000000000003b000000000000000000000000b656b2a9c3b2416437a811e07466ca712f5a5b5a\",", + " \"to\": \"0xbb9bc244d798123fde783fcc1c72d3bb8c189413\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0xb064f\",", + " \"output\": \"0x0000000000000000000000000000000000000000000000000000000000000001\"", + " },", + " \"subtraces\": 4,", + " \"traceAddress\": [", + " 1,", + " 4,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xbb9bc244d798123fde783fcc1c72d3bb8c189413\",", + " \"gas\": \"0x11075e\",", + " \"input\": \"0xbaac5300000000000000000000000000c0ee9db1a9e07ca63e4ff0d5fb6f86bf68d47b89\",", + " \"to\": \"0x304a554a310c7e546dfe434669c62820b7d83490\",", + " \"value\": \"0xdfd4116684423b208\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x5cdf\",", + " \"output\": \"0x0000000000000000000000000000000000000000000000000000000000000001\"", + " },", + " \"subtraces\": 1,", + " \"traceAddress\": [", + " 1,", + " 4,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 0", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0x304a554a310c7e546dfe434669c62820b7d83490\",", + " \"gas\": \"0x107c60\",", + " \"input\": \"0x\",", + " \"to\": \"0x914d1b8b43e92723e64fd0a06f5bdb8dd9b10c79\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x13f9\",", + " \"output\": \"0x\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [", + " 1,", + " 4,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 0,", + " 0", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xbb9bc244d798123fde783fcc1c72d3bb8c189413\",", + " \"gas\": \"0x10499a\",", + " \"input\": \"0xd2cc718f\",", + " \"to\": \"0xd2e16a20dd7b1ae54fb0312209784478d069c7b0\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x113\",", + " \"output\": \"0x00000000000000000000000000000000000000000000000000038d7ea4c68000\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [", + " 1,", + " 4,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 1", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xbb9bc244d798123fde783fcc1c72d3bb8c189413\",", + " \"gas\": \"0x1045c4\",", + " \"input\": \"0xd2cc718f\",", + " \"to\": \"0xd2e16a20dd7b1ae54fb0312209784478d069c7b0\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x113\",", + " \"output\": \"0x00000000000000000000000000000000000000000000000000038d7ea4c68000\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [", + " 1,", + " 4,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 2", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xbb9bc244d798123fde783fcc1c72d3bb8c189413\",", + " \"gas\": \"0x10424b\",", + " \"input\": \"0x0221038a000000000000000000000000c0ee9db1a9e07ca63e4ff0d5fb6f86bf68d47b89000000000000000000000000000000000000000000000000000000052aa8b9ab\",", + " \"to\": \"0xd2e16a20dd7b1ae54fb0312209784478d069c7b0\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x98f4c\",", + " \"output\": \"0x0000000000000000000000000000000000000000000000000000000000000001\"", + " },", + " \"subtraces\": 1,", + " \"traceAddress\": [", + " 1,", + " 4,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xd2e16a20dd7b1ae54fb0312209784478d069c7b0\",", + " \"gas\": \"0xfc475\",", + " \"input\": \"0x\",", + " \"to\": \"0xc0ee9db1a9e07ca63e4ff0d5fb6f86bf68d47b89\",", + " \"value\": \"0x52aa8b9ab\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x96d05\",", + " \"output\": \"0x0000000000000000000000000000000000000000000000000000000000000001\"", + " },", + " \"subtraces\": 2,", + " \"traceAddress\": [", + " 1,", + " 4,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xc0ee9db1a9e07ca63e4ff0d5fb6f86bf68d47b89\",", + " \"gas\": \"0xf61dd\",", + " \"input\": \"0x0e708203\",", + " \"to\": \"0xbb9bc244d798123fde783fcc1c72d3bb8c189413\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x15f\",", + " \"output\": \"0x000000000000000000000000d2e16a20dd7b1ae54fb0312209784478d069c7b0\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [", + " 1,", + " 4,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 0", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xc0ee9db1a9e07ca63e4ff0d5fb6f86bf68d47b89\",", + " \"gas\": \"0xf4a1d\",", + " \"input\": \"0x82661dc4000000000000000000000000000000000000000000000000000000000000003b000000000000000000000000b656b2a9c3b2416437a811e07466ca712f5a5b5a\",", + " \"to\": \"0xbb9bc244d798123fde783fcc1c72d3bb8c189413\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x953f9\",", + " \"output\": \"0x0000000000000000000000000000000000000000000000000000000000000001\"", + " },", + " \"subtraces\": 4,", + " \"traceAddress\": [", + " 1,", + " 4,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xbb9bc244d798123fde783fcc1c72d3bb8c189413\",", + " \"gas\": \"0xec1c5\",", + " \"input\": \"0xbaac5300000000000000000000000000c0ee9db1a9e07ca63e4ff0d5fb6f86bf68d47b89\",", + " \"to\": \"0x304a554a310c7e546dfe434669c62820b7d83490\",", + " \"value\": \"0xdfd4116684423b208\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x5cdf\",", + " \"output\": \"0x0000000000000000000000000000000000000000000000000000000000000001\"", + " },", + " \"subtraces\": 1,", + " \"traceAddress\": [", + " 1,", + " 4,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 0", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0x304a554a310c7e546dfe434669c62820b7d83490\",", + " \"gas\": \"0xe36c7\",", + " \"input\": \"0x\",", + " \"to\": \"0x914d1b8b43e92723e64fd0a06f5bdb8dd9b10c79\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x13f9\",", + " \"output\": \"0x\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [", + " 1,", + " 4,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 0,", + " 0", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xbb9bc244d798123fde783fcc1c72d3bb8c189413\",", + " \"gas\": \"0xe0401\",", + " \"input\": \"0xd2cc718f\",", + " \"to\": \"0xd2e16a20dd7b1ae54fb0312209784478d069c7b0\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x113\",", + " \"output\": \"0x00000000000000000000000000000000000000000000000000038d7ea4c68000\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [", + " 1,", + " 4,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 1", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xbb9bc244d798123fde783fcc1c72d3bb8c189413\",", + " \"gas\": \"0xe002b\",", + " \"input\": \"0xd2cc718f\",", + " \"to\": \"0xd2e16a20dd7b1ae54fb0312209784478d069c7b0\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x113\",", + " \"output\": \"0x00000000000000000000000000000000000000000000000000038d7ea4c68000\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [", + " 1,", + " 4,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 2", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xbb9bc244d798123fde783fcc1c72d3bb8c189413\",", + " \"gas\": \"0xdfcb2\",", + " \"input\": \"0x0221038a000000000000000000000000c0ee9db1a9e07ca63e4ff0d5fb6f86bf68d47b89000000000000000000000000000000000000000000000000000000052aa8b9ab\",", + " \"to\": \"0xd2e16a20dd7b1ae54fb0312209784478d069c7b0\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x7dcf6\",", + " \"output\": \"0x0000000000000000000000000000000000000000000000000000000000000001\"", + " },", + " \"subtraces\": 1,", + " \"traceAddress\": [", + " 1,", + " 4,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xd2e16a20dd7b1ae54fb0312209784478d069c7b0\",", + " \"gas\": \"0xd7edc\",", + " \"input\": \"0x\",", + " \"to\": \"0xc0ee9db1a9e07ca63e4ff0d5fb6f86bf68d47b89\",", + " \"value\": \"0x52aa8b9ab\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x7baaf\",", + " \"output\": \"0x0000000000000000000000000000000000000000000000000000000000000001\"", + " },", + " \"subtraces\": 2,", + " \"traceAddress\": [", + " 1,", + " 4,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xc0ee9db1a9e07ca63e4ff0d5fb6f86bf68d47b89\",", + " \"gas\": \"0xd1c44\",", + " \"input\": \"0x0e708203\",", + " \"to\": \"0xbb9bc244d798123fde783fcc1c72d3bb8c189413\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x15f\",", + " \"output\": \"0x000000000000000000000000d2e16a20dd7b1ae54fb0312209784478d069c7b0\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [", + " 1,", + " 4,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 0", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xc0ee9db1a9e07ca63e4ff0d5fb6f86bf68d47b89\",", + " \"gas\": \"0xd0484\",", + " \"input\": \"0x82661dc4000000000000000000000000000000000000000000000000000000000000003b000000000000000000000000b656b2a9c3b2416437a811e07466ca712f5a5b5a\",", + " \"to\": \"0xbb9bc244d798123fde783fcc1c72d3bb8c189413\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x7a1a3\",", + " \"output\": \"0x0000000000000000000000000000000000000000000000000000000000000001\"", + " },", + " \"subtraces\": 4,", + " \"traceAddress\": [", + " 1,", + " 4,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xbb9bc244d798123fde783fcc1c72d3bb8c189413\",", + " \"gas\": \"0xc7c2c\",", + " \"input\": \"0xbaac5300000000000000000000000000c0ee9db1a9e07ca63e4ff0d5fb6f86bf68d47b89\",", + " \"to\": \"0x304a554a310c7e546dfe434669c62820b7d83490\",", + " \"value\": \"0xdfd4116684423b208\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x5cdf\",", + " \"output\": \"0x0000000000000000000000000000000000000000000000000000000000000001\"", + " },", + " \"subtraces\": 1,", + " \"traceAddress\": [", + " 1,", + " 4,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 0", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0x304a554a310c7e546dfe434669c62820b7d83490\",", + " \"gas\": \"0xbf12e\",", + " \"input\": \"0x\",", + " \"to\": \"0x914d1b8b43e92723e64fd0a06f5bdb8dd9b10c79\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x13f9\",", + " \"output\": \"0x\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [", + " 1,", + " 4,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 0,", + " 0", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xbb9bc244d798123fde783fcc1c72d3bb8c189413\",", + " \"gas\": \"0xbbe68\",", + " \"input\": \"0xd2cc718f\",", + " \"to\": \"0xd2e16a20dd7b1ae54fb0312209784478d069c7b0\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x113\",", + " \"output\": \"0x00000000000000000000000000000000000000000000000000038d7ea4c68000\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [", + " 1,", + " 4,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 1", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xbb9bc244d798123fde783fcc1c72d3bb8c189413\",", + " \"gas\": \"0xbba92\",", + " \"input\": \"0xd2cc718f\",", + " \"to\": \"0xd2e16a20dd7b1ae54fb0312209784478d069c7b0\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x113\",", + " \"output\": \"0x00000000000000000000000000000000000000000000000000038d7ea4c68000\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [", + " 1,", + " 4,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 2", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xbb9bc244d798123fde783fcc1c72d3bb8c189413\",", + " \"gas\": \"0xbb719\",", + " \"input\": \"0x0221038a000000000000000000000000c0ee9db1a9e07ca63e4ff0d5fb6f86bf68d47b89000000000000000000000000000000000000000000000000000000052aa8b9ab\",", + " \"to\": \"0xd2e16a20dd7b1ae54fb0312209784478d069c7b0\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x62aa0\",", + " \"output\": \"0x0000000000000000000000000000000000000000000000000000000000000001\"", + " },", + " \"subtraces\": 1,", + " \"traceAddress\": [", + " 1,", + " 4,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xd2e16a20dd7b1ae54fb0312209784478d069c7b0\",", + " \"gas\": \"0xb3943\",", + " \"input\": \"0x\",", + " \"to\": \"0xc0ee9db1a9e07ca63e4ff0d5fb6f86bf68d47b89\",", + " \"value\": \"0x52aa8b9ab\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x60859\",", + " \"output\": \"0x0000000000000000000000000000000000000000000000000000000000000001\"", + " },", + " \"subtraces\": 2,", + " \"traceAddress\": [", + " 1,", + " 4,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xc0ee9db1a9e07ca63e4ff0d5fb6f86bf68d47b89\",", + " \"gas\": \"0xad6ab\",", + " \"input\": \"0x0e708203\",", + " \"to\": \"0xbb9bc244d798123fde783fcc1c72d3bb8c189413\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x15f\",", + " \"output\": \"0x000000000000000000000000d2e16a20dd7b1ae54fb0312209784478d069c7b0\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [", + " 1,", + " 4,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 0", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xc0ee9db1a9e07ca63e4ff0d5fb6f86bf68d47b89\",", + " \"gas\": \"0xabeeb\",", + " \"input\": \"0x82661dc4000000000000000000000000000000000000000000000000000000000000003b000000000000000000000000b656b2a9c3b2416437a811e07466ca712f5a5b5a\",", + " \"to\": \"0xbb9bc244d798123fde783fcc1c72d3bb8c189413\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x5ef4d\",", + " \"output\": \"0x0000000000000000000000000000000000000000000000000000000000000001\"", + " },", + " \"subtraces\": 4,", + " \"traceAddress\": [", + " 1,", + " 4,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xbb9bc244d798123fde783fcc1c72d3bb8c189413\",", + " \"gas\": \"0xa3693\",", + " \"input\": \"0xbaac5300000000000000000000000000c0ee9db1a9e07ca63e4ff0d5fb6f86bf68d47b89\",", + " \"to\": \"0x304a554a310c7e546dfe434669c62820b7d83490\",", + " \"value\": \"0xdfd4116684423b208\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x5cdf\",", + " \"output\": \"0x0000000000000000000000000000000000000000000000000000000000000001\"", + " },", + " \"subtraces\": 1,", + " \"traceAddress\": [", + " 1,", + " 4,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 0", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0x304a554a310c7e546dfe434669c62820b7d83490\",", + " \"gas\": \"0x9ab95\",", + " \"input\": \"0x\",", + " \"to\": \"0x914d1b8b43e92723e64fd0a06f5bdb8dd9b10c79\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x13f9\",", + " \"output\": \"0x\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [", + " 1,", + " 4,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 0,", + " 0", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xbb9bc244d798123fde783fcc1c72d3bb8c189413\",", + " \"gas\": \"0x978cf\",", + " \"input\": \"0xd2cc718f\",", + " \"to\": \"0xd2e16a20dd7b1ae54fb0312209784478d069c7b0\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x113\",", + " \"output\": \"0x00000000000000000000000000000000000000000000000000038d7ea4c68000\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [", + " 1,", + " 4,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 1", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xbb9bc244d798123fde783fcc1c72d3bb8c189413\",", + " \"gas\": \"0x974f9\",", + " \"input\": \"0xd2cc718f\",", + " \"to\": \"0xd2e16a20dd7b1ae54fb0312209784478d069c7b0\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x113\",", + " \"output\": \"0x00000000000000000000000000000000000000000000000000038d7ea4c68000\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [", + " 1,", + " 4,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 2", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xbb9bc244d798123fde783fcc1c72d3bb8c189413\",", + " \"gas\": \"0x97180\",", + " \"input\": \"0x0221038a000000000000000000000000c0ee9db1a9e07ca63e4ff0d5fb6f86bf68d47b89000000000000000000000000000000000000000000000000000000052aa8b9ab\",", + " \"to\": \"0xd2e16a20dd7b1ae54fb0312209784478d069c7b0\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x4784a\",", + " \"output\": \"0x0000000000000000000000000000000000000000000000000000000000000001\"", + " },", + " \"subtraces\": 1,", + " \"traceAddress\": [", + " 1,", + " 4,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xd2e16a20dd7b1ae54fb0312209784478d069c7b0\",", + " \"gas\": \"0x8f3aa\",", + " \"input\": \"0x\",", + " \"to\": \"0xc0ee9db1a9e07ca63e4ff0d5fb6f86bf68d47b89\",", + " \"value\": \"0x52aa8b9ab\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x45603\",", + " \"output\": \"0x0000000000000000000000000000000000000000000000000000000000000001\"", + " },", + " \"subtraces\": 2,", + " \"traceAddress\": [", + " 1,", + " 4,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xc0ee9db1a9e07ca63e4ff0d5fb6f86bf68d47b89\",", + " \"gas\": \"0x89112\",", + " \"input\": \"0x0e708203\",", + " \"to\": \"0xbb9bc244d798123fde783fcc1c72d3bb8c189413\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x15f\",", + " \"output\": \"0x000000000000000000000000d2e16a20dd7b1ae54fb0312209784478d069c7b0\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [", + " 1,", + " 4,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 0", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xc0ee9db1a9e07ca63e4ff0d5fb6f86bf68d47b89\",", + " \"gas\": \"0x87952\",", + " \"input\": \"0x82661dc4000000000000000000000000000000000000000000000000000000000000003b000000000000000000000000b656b2a9c3b2416437a811e07466ca712f5a5b5a\",", + " \"to\": \"0xbb9bc244d798123fde783fcc1c72d3bb8c189413\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x43cf7\",", + " \"output\": \"0x0000000000000000000000000000000000000000000000000000000000000001\"", + " },", + " \"subtraces\": 4,", + " \"traceAddress\": [", + " 1,", + " 4,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xbb9bc244d798123fde783fcc1c72d3bb8c189413\",", + " \"gas\": \"0x7f0fa\",", + " \"input\": \"0xbaac5300000000000000000000000000c0ee9db1a9e07ca63e4ff0d5fb6f86bf68d47b89\",", + " \"to\": \"0x304a554a310c7e546dfe434669c62820b7d83490\",", + " \"value\": \"0xdfd4116684423b208\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x5cdf\",", + " \"output\": \"0x0000000000000000000000000000000000000000000000000000000000000001\"", + " },", + " \"subtraces\": 1,", + " \"traceAddress\": [", + " 1,", + " 4,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 0", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0x304a554a310c7e546dfe434669c62820b7d83490\",", + " \"gas\": \"0x765fc\",", + " \"input\": \"0x\",", + " \"to\": \"0x914d1b8b43e92723e64fd0a06f5bdb8dd9b10c79\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x13f9\",", + " \"output\": \"0x\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [", + " 1,", + " 4,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 0,", + " 0", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xbb9bc244d798123fde783fcc1c72d3bb8c189413\",", + " \"gas\": \"0x73336\",", + " \"input\": \"0xd2cc718f\",", + " \"to\": \"0xd2e16a20dd7b1ae54fb0312209784478d069c7b0\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x113\",", + " \"output\": \"0x00000000000000000000000000000000000000000000000000038d7ea4c68000\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [", + " 1,", + " 4,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 1", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xbb9bc244d798123fde783fcc1c72d3bb8c189413\",", + " \"gas\": \"0x72f60\",", + " \"input\": \"0xd2cc718f\",", + " \"to\": \"0xd2e16a20dd7b1ae54fb0312209784478d069c7b0\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x113\",", + " \"output\": \"0x00000000000000000000000000000000000000000000000000038d7ea4c68000\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [", + " 1,", + " 4,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 2", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xbb9bc244d798123fde783fcc1c72d3bb8c189413\",", + " \"gas\": \"0x72be7\",", + " \"input\": \"0x0221038a000000000000000000000000c0ee9db1a9e07ca63e4ff0d5fb6f86bf68d47b89000000000000000000000000000000000000000000000000000000052aa8b9ab\",", + " \"to\": \"0xd2e16a20dd7b1ae54fb0312209784478d069c7b0\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x2c5f4\",", + " \"output\": \"0x0000000000000000000000000000000000000000000000000000000000000001\"", + " },", + " \"subtraces\": 1,", + " \"traceAddress\": [", + " 1,", + " 4,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xd2e16a20dd7b1ae54fb0312209784478d069c7b0\",", + " \"gas\": \"0x6ae11\",", + " \"input\": \"0x\",", + " \"to\": \"0xc0ee9db1a9e07ca63e4ff0d5fb6f86bf68d47b89\",", + " \"value\": \"0x52aa8b9ab\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x2a3ad\",", + " \"output\": \"0x0000000000000000000000000000000000000000000000000000000000000001\"", + " },", + " \"subtraces\": 2,", + " \"traceAddress\": [", + " 1,", + " 4,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xc0ee9db1a9e07ca63e4ff0d5fb6f86bf68d47b89\",", + " \"gas\": \"0x64b79\",", + " \"input\": \"0x0e708203\",", + " \"to\": \"0xbb9bc244d798123fde783fcc1c72d3bb8c189413\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x15f\",", + " \"output\": \"0x000000000000000000000000d2e16a20dd7b1ae54fb0312209784478d069c7b0\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [", + " 1,", + " 4,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 0", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xc0ee9db1a9e07ca63e4ff0d5fb6f86bf68d47b89\",", + " \"gas\": \"0x633b9\",", + " \"input\": \"0x82661dc4000000000000000000000000000000000000000000000000000000000000003b000000000000000000000000b656b2a9c3b2416437a811e07466ca712f5a5b5a\",", + " \"to\": \"0xbb9bc244d798123fde783fcc1c72d3bb8c189413\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x28aa1\",", + " \"output\": \"0x0000000000000000000000000000000000000000000000000000000000000001\"", + " },", + " \"subtraces\": 4,", + " \"traceAddress\": [", + " 1,", + " 4,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xbb9bc244d798123fde783fcc1c72d3bb8c189413\",", + " \"gas\": \"0x5ab61\",", + " \"input\": \"0xbaac5300000000000000000000000000c0ee9db1a9e07ca63e4ff0d5fb6f86bf68d47b89\",", + " \"to\": \"0x304a554a310c7e546dfe434669c62820b7d83490\",", + " \"value\": \"0xdfd4116684423b208\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x5cdf\",", + " \"output\": \"0x0000000000000000000000000000000000000000000000000000000000000001\"", + " },", + " \"subtraces\": 1,", + " \"traceAddress\": [", + " 1,", + " 4,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 0", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0x304a554a310c7e546dfe434669c62820b7d83490\",", + " \"gas\": \"0x52063\",", + " \"input\": \"0x\",", + " \"to\": \"0x914d1b8b43e92723e64fd0a06f5bdb8dd9b10c79\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x13f9\",", + " \"output\": \"0x\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [", + " 1,", + " 4,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 0,", + " 0", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xbb9bc244d798123fde783fcc1c72d3bb8c189413\",", + " \"gas\": \"0x4ed9d\",", + " \"input\": \"0xd2cc718f\",", + " \"to\": \"0xd2e16a20dd7b1ae54fb0312209784478d069c7b0\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x113\",", + " \"output\": \"0x00000000000000000000000000000000000000000000000000038d7ea4c68000\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [", + " 1,", + " 4,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 1", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xbb9bc244d798123fde783fcc1c72d3bb8c189413\",", + " \"gas\": \"0x4e9c7\",", + " \"input\": \"0xd2cc718f\",", + " \"to\": \"0xd2e16a20dd7b1ae54fb0312209784478d069c7b0\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x113\",", + " \"output\": \"0x00000000000000000000000000000000000000000000000000038d7ea4c68000\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [", + " 1,", + " 4,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 2", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xbb9bc244d798123fde783fcc1c72d3bb8c189413\",", + " \"gas\": \"0x4e64e\",", + " \"input\": \"0x0221038a000000000000000000000000c0ee9db1a9e07ca63e4ff0d5fb6f86bf68d47b89000000000000000000000000000000000000000000000000000000052aa8b9ab\",", + " \"to\": \"0xd2e16a20dd7b1ae54fb0312209784478d069c7b0\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x1139e\",", + " \"output\": \"0x0000000000000000000000000000000000000000000000000000000000000001\"", + " },", + " \"subtraces\": 1,", + " \"traceAddress\": [", + " 1,", + " 4,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xd2e16a20dd7b1ae54fb0312209784478d069c7b0\",", + " \"gas\": \"0x46878\",", + " \"input\": \"0x\",", + " \"to\": \"0xc0ee9db1a9e07ca63e4ff0d5fb6f86bf68d47b89\",", + " \"value\": \"0x52aa8b9ab\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0xf157\",", + " \"output\": \"0x0000000000000000000000000000000000000000000000000000000000000001\"", + " },", + " \"subtraces\": 3,", + " \"traceAddress\": [", + " 1,", + " 4,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xc0ee9db1a9e07ca63e4ff0d5fb6f86bf68d47b89\",", + " \"gas\": \"0x405e0\",", + " \"input\": \"0x0e708203\",", + " \"to\": \"0xbb9bc244d798123fde783fcc1c72d3bb8c189413\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x15f\",", + " \"output\": \"0x000000000000000000000000d2e16a20dd7b1ae54fb0312209784478d069c7b0\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [", + " 1,", + " 4,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 0", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xc0ee9db1a9e07ca63e4ff0d5fb6f86bf68d47b89\",", + " \"gas\": \"0x4024b\",", + " \"input\": \"0x70a08231000000000000000000000000c0ee9db1a9e07ca63e4ff0d5fb6f86bf68d47b89\",", + " \"to\": \"0xbb9bc244d798123fde783fcc1c72d3bb8c189413\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x314\",", + " \"output\": \"0x00000000000000000000000000000000000000000000000dfd3f956d86e77600\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [", + " 1,", + " 4,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xc0ee9db1a9e07ca63e4ff0d5fb6f86bf68d47b89\",", + " \"gas\": \"0x3fe60\",", + " \"input\": \"0xa9059cbb000000000000000000000000f835a0247b0063c04ef22006ebe57c5f11977cc400000000000000000000000000000000000000000000000dfd3f956d86e77600\",", + " \"to\": \"0xbb9bc244d798123fde783fcc1c72d3bb8c189413\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0xd4fa\",", + " \"output\": \"0x0000000000000000000000000000000000000000000000000000000000000001\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [", + " 1,", + " 4,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 1,", + " 3,", + " 0,", + " 2", + " ],", + " \"transactionHash\": \"0x0ec3f2488a93839524add10ea229e773f6bc891b4eb4794c3337d4495263790b\",", + " \"transactionPosition\": 0,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0x2dd9d8e62af6e839b4ed0d869094198ee7e02bff\",", + " \"gas\": \"0x0\",", + " \"input\": \"0x\",", + " \"to\": \"0x46e943ad525b7fe18f8240d944028c7890da135c\",", + " \"value\": \"0xb1a2bc2ec50000\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x0\",", + " \"output\": \"0x\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [],", + " \"transactionHash\": \"0x61db76fc3fe109ad548d91d321daf76dc2ef2f683dc3c4006377d1da8629e274\",", + " \"transactionPosition\": 1,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0x286635c294b61bf10f416bbb7b579a0035379d33\",", + " \"gas\": \"0x10d88\",", + " \"input\": \"0x\",", + " \"to\": \"0x81d246bf10386b5702193202b865b0e45bd97f1a\",", + " \"value\": \"0x393ef1a5127c80000\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x0\",", + " \"output\": \"0x\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [],", + " \"transactionHash\": \"0x877db25210ca8be928280112b8b3b4a3afced1d35eb8cd795ac730c7e89d88a3\",", + " \"transactionPosition\": 2,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0xfecd1b8e3a1e21b304bfba7e5fb5241169e1fa1d\",", + " \"gas\": \"0x0\",", + " \"input\": \"0x\",", + " \"to\": \"0x7ed1e469fcb3ee19c0366d829e291451be638e59\",", + " \"value\": \"0x9e4e3e07f0b2fc00\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x0\",", + " \"output\": \"0x\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [],", + " \"transactionHash\": \"0xe7b3edd1d02b869b4d0eac0be43a67f0ac2f5b190f5a49f37ac59a98b17f56a3\",", + " \"transactionPosition\": 3,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0x0a869d79a7052c7f1b55a8ebabbea3420f0d1e13\",", + " \"gas\": \"0x74148\",", + " \"input\": \"0xf5537ede000000000000000000000000bb9bc244d798123fde783fcc1c72d3bb8c1894130000000000000000000000000a869d79a7052c7f1b55a8ebabbea3420f0d1e1300000000000000000000000000000000000000000000000000b1a2bc2ec50000\",", + " \"to\": \"0x447f914fee54e1f9dc1fc5276ae2572b9369ae5d\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x68eb\",", + " \"output\": \"0x\"", + " },", + " \"subtraces\": 1,", + " \"traceAddress\": [],", + " \"transactionHash\": \"0xe11112b361cc2ffdc4815513dcb337beb83be014bcc89cd39a984f3d458e668d\",", + " \"transactionPosition\": 4,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"callType\": \"call\",", + " \"from\": \"0x447f914fee54e1f9dc1fc5276ae2572b9369ae5d\",", + " \"gas\": \"0x6ddd9\",", + " \"input\": \"0xa9059cbb0000000000000000000000000a869d79a7052c7f1b55a8ebabbea3420f0d1e1300000000000000000000000000000000000000000000000000b1a2bc2ec50000\",", + " \"to\": \"0xbb9bc244d798123fde783fcc1c72d3bb8c189413\",", + " \"value\": \"0x0\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": {", + " \"gasUsed\": \"0x5fca\",", + " \"output\": \"0x0000000000000000000000000000000000000000000000000000000000000001\"", + " },", + " \"subtraces\": 0,", + " \"traceAddress\": [", + " 0", + " ],", + " \"transactionHash\": \"0xe11112b361cc2ffdc4815513dcb337beb83be014bcc89cd39a984f3d458e668d\",", + " \"transactionPosition\": 4,", + " \"type\": \"call\"", + " },", + " {", + " \"action\": {", + " \"author\": \"0xbcdfc35b86bedf72f0cda046a3c16829a2ef41d1\",", + " \"rewardType\": \"block\",", + " \"value\": \"0x4563918244f40000\"", + " },", + " \"blockHash\": \"0xcaaa13ce099342d5e1342b04d588d7733093591666af8ef756ce20cf13d16475\",", + " \"blockNumber\": 1718497,", + " \"result\": null,", + " \"subtraces\": 0,", + " \"traceAddress\": [],", + " \"transactionHash\": null,", + " \"transactionPosition\": null,", + " \"type\": \"reward\"", + " }", + " ],", + " \"id\": \"1\"", + "}", + "", + "pm.test('Has correct result', function() {", + " pm.expect(pm.response.json()).to.be.deep.equal(expected);", + "})" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"trace_block\",\n\t\"params\":[\"0x1a38e1\"],\n\t\"id\":\"1\"\n}\n", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": [ + "{{HOST}}" + ] + } + }, + "response": [] + }, + { + "name": "trace_filter", + "event": [ + { + "listen": "test", + "script": { + "id": "f524ed84-7851-4a5a-88f2-4d19a10e74cb", + "exec": [ + "var expected = {", + " \"jsonrpc\": \"2.0\",", + " \"result\": [", + " {", + " \"action\": {", + " \"author\": \"0x5088d623ba0fcf0131e0897a91734a4d83596aa0\",", + " \"rewardType\": \"block\",", + " \"value\": \"0x478eae0e571ba000\"", + " },", + " \"blockHash\": \"0x3d6122660cc824376f11ee842f83addc3525e2dd6756b9bcf0affa6aa88cf741\",", + " \"blockNumber\": 3,", + " \"result\": null,", + " \"subtraces\": 0,", + " \"traceAddress\": [],", + " \"transactionHash\": null,", + " \"transactionPosition\": null,", + " \"type\": \"reward\"", + " },", + " {", + " \"action\": {", + " \"author\": \"0xc8ebccc5f5689fa8659d83713341e5ad19349448\",", + " \"rewardType\": \"uncle\",", + " \"value\": \"0x340aad21b3b70000\"", + " },", + " \"blockHash\": \"0x3d6122660cc824376f11ee842f83addc3525e2dd6756b9bcf0affa6aa88cf741\",", + " \"blockNumber\": 3,", + " \"result\": null,", + " \"subtraces\": 0,", + " \"traceAddress\": [],", + " \"transactionHash\": null,", + " \"transactionPosition\": null,", + " \"type\": \"reward\"", + " }", + " ],", + " \"id\": \"1\"", + "}", + "pm.test('Has correct result', function() {", + " pm.expect(pm.response.json()).to.be.deep.equal(expected);", + "})" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n\t\"jsonrpc\":\"2.0\",\n\t\"method\":\"trace_filter\",\n \"params\":[\n {\n \"fromBlock\":\"0x3\",\n \"toBlock\":\"0x3\"\n }\n ],\n\t\"id\":\"1\"\n}\n", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{HOST}}", + "host": [ + "{{HOST}}" + ] + } + }, + "response": [] + } + ], + "event": [ + { + "listen": "prerequest", + "script": { + "id": "f660f521-60fc-4561-bacd-14ab00640a12", + "type": "text/javascript", + "exec": [ + "utils = {", + " notImplemented: function(methodName, jsonData) {", + " var isErigon = pm.environment.get('HOST') == \"{{ERIGON}}\";", + " var isSilk = pm.environment.get('HOST') == \"{{SILKRPC}}\";", + " if (!isErigon && !isSilk) // only test erigon", + " return;", + "", + " var testNotImplemented = pm.globals.get('TEST_NOT_IMPLEMENTED') === 'true';", + " if (testNotImplemented) { // defaults to false, therefore don't test", + " pm.test('NOT IMPLEMENTED', function() {", + " pm.expect(false).to.be(true);", + " })", + " } else {", + " // pass unless user has explicitly told us to test not implemented", + " var expected = {", + " \"jsonrpc\": \"2.0\",", + " \"id\": \"1\",", + " \"error\": {", + " \"code\": -32000,", + " \"message\": \"the method is currently not implemented: \" + methodName", + " }", + " }", + " if (jsonData.error)", + " delete jsonData.error.data;", + " pm.test('NOT IMPLEMENTED', function() {", + " pm.expect(jsonData).to.deep.equals(expected);", + " })", + " }", + " },", + "", + " isDeprecated: function(methodName, jsonData) {", + " var isErigon = pm.environment.get('HOST') == \"{{ERIGON}}\";", + " var isSilk = pm.environment.get('HOST') == \"{{SILKRPC}}\";", + " if (!isErigon && !isSilk) // only test erigon", + " return;", + "", + " var testDeprecated = pm.globals.get('TEST_DEPRECATED') === 'true';", + " if (testDeprecated) { // defaults to false, therefore don't test", + " pm.test('DEPRECATED', function() {", + " console.log(\"testDeprecated2: \", testDeprecated)", + " pm.expect(false).to.be(true);", + " })", + " } else {", + " // pass unless user has explicitly told us to fail deprecated", + " var expected = {", + " \"jsonrpc\": \"2.0\",", + " \"id\": \"1\",", + " \"error\": {", + " \"code\": -32000,", + " \"message\": \"the method has been deprecated: \" + methodName", + " }", + " }", + " if (jsonData.error)", + " delete jsonData.error.data;", + " pm.test('DEPRECATED', function() {", + " pm.expect(jsonData).to.deep.equals(expected);", + " })", + " }", + " },", + "", + " cannotTest: function(methodName, jsonData) {", + " var isErigon = pm.environment.get('HOST') == \"{{ERIGON}}\";", + " var isSilk = pm.environment.get('HOST') == \"{{SILKRPC}}\";", + " if (!isErigon && !isSilk) // only test erigon", + " return;", + "", + " var expected = {", + " \"jsonrpc\": \"2.0\",", + " \"id\": \"1\",", + " \"result\": \"Cannot test - value changes\"", + " }", + " pm.test('VALUE CHANGES, CANNOT TEST: ' + methodName, function() {", + " jsonData.result = \"Cannot test - value changes\";", + " pm.expect(jsonData).to.deep.equals(expected);", + " })", + " },", + "};" + ] + } + }, + { + "listen": "test", + "script": { + "id": "8e45cd97-14f5-42f7-9df7-fe5e2824be86", + "type": "text/javascript", + "exec": [ + "pm.test('Base tests', function() {", + " const jsonData = pm.response.json();", + " pm.response.to.have.status(200);", + " pm.expect(jsonData !== null)", + " jsonData.errors == null || pm.expect(jsonData.errors).to.be.empty;", + "})", + "" + ] + } + } + ], + "protocolProfileBehavior": {} +} \ No newline at end of file diff --git a/cmd/rpcdaemon/rpcdaemontest/test_util.go b/cmd/rpcdaemon/rpcdaemontest/test_util.go new file mode 100644 index 0000000..45aaf35 --- /dev/null +++ b/cmd/rpcdaemon/rpcdaemontest/test_util.go @@ -0,0 +1,321 @@ +package rpcdaemontest + +import ( + "context" + "crypto/ecdsa" + "encoding/binary" + "fmt" + "math/big" + "net" + "testing" + + "github.com/holiman/uint256" + "github.com/ledgerwatch/erigon-lib/gointerfaces/remote" + "github.com/ledgerwatch/erigon-lib/gointerfaces/txpool" + "github.com/ledgerwatch/erigon-lib/kv" + "github.com/ledgerwatch/erigon/accounts/abi/bind" + "github.com/ledgerwatch/erigon/accounts/abi/bind/backends" + "github.com/ledgerwatch/erigon/cmd/rpcdaemon/commands/contracts" + "github.com/ledgerwatch/erigon/common" + "github.com/ledgerwatch/erigon/consensus" + "github.com/ledgerwatch/erigon/consensus/ethash" + "github.com/ledgerwatch/erigon/core" + "github.com/ledgerwatch/erigon/core/types" + "github.com/ledgerwatch/erigon/crypto" + "github.com/ledgerwatch/erigon/ethdb/privateapi" + "github.com/ledgerwatch/erigon/params" + "github.com/ledgerwatch/erigon/turbo/snapshotsync" + "github.com/ledgerwatch/erigon/turbo/stages" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" + "google.golang.org/grpc/test/bufconn" +) + +func CreateTestKV(t *testing.T) kv.RwDB { + s, _, _ := CreateTestSentry(t) + return s.DB +} + +type testAddresses struct { + key *ecdsa.PrivateKey + key1 *ecdsa.PrivateKey + key2 *ecdsa.PrivateKey + address common.Address + address1 common.Address + address2 common.Address +} + +func makeTestAddresses() testAddresses { + var ( + key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + key1, _ = crypto.HexToECDSA("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee") + key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a") + address = crypto.PubkeyToAddress(key.PublicKey) + address1 = crypto.PubkeyToAddress(key1.PublicKey) + address2 = crypto.PubkeyToAddress(key2.PublicKey) + ) + + return testAddresses{ + key: key, + key1: key1, + key2: key2, + address: address, + address1: address1, + address2: address2, + } +} + +func CreateTestSentry(t *testing.T) (*stages.MockSentry, *core.ChainPack, []*core.ChainPack) { + addresses := makeTestAddresses() + var ( + key = addresses.key + address = addresses.address + address1 = addresses.address1 + address2 = addresses.address2 + ) + + var ( + gspec = &core.Genesis{ + Config: params.AllEthashProtocolChanges, + Alloc: core.GenesisAlloc{ + address: {Balance: big.NewInt(9000000000000000000)}, + address1: {Balance: big.NewInt(200000000000000000)}, + address2: {Balance: big.NewInt(300000000000000000)}, + }, + GasLimit: 10000000, + } + ) + m := stages.MockWithGenesis(t, gspec, key, false) + + contractBackend := backends.NewSimulatedBackendWithConfig(gspec.Alloc, gspec.Config, gspec.GasLimit) + defer contractBackend.Close() + + // Generate empty chain to have some orphaned blocks for tests + orphanedChain, err := core.GenerateChain(m.ChainConfig, m.Genesis, m.Engine, m.DB, 5, func(i int, block *core.BlockGen) { + }, true) + if err != nil { + t.Fatal(err) + } + + chain, err := getChainInstance(&addresses, m.ChainConfig, m.Genesis, m.Engine, m.DB, contractBackend) + if err != nil { + t.Fatal(err) + } + + if err = m.InsertChain(orphanedChain); err != nil { + t.Fatal(err) + } + if err = m.InsertChain(chain); err != nil { + t.Fatal(err) + } + + return m, chain, []*core.ChainPack{orphanedChain} +} + +var chainInstance *core.ChainPack + +func getChainInstance( + addresses *testAddresses, + config *params.ChainConfig, + parent *types.Block, + engine consensus.Engine, + db kv.RwDB, + contractBackend *backends.SimulatedBackend, +) (*core.ChainPack, error) { + var err error + if chainInstance == nil { + chainInstance, err = generateChain(addresses, config, parent, engine, db, contractBackend) + } + return chainInstance.Copy(), err +} + +func generateChain( + addresses *testAddresses, + config *params.ChainConfig, + parent *types.Block, + engine consensus.Engine, + db kv.RwDB, + contractBackend *backends.SimulatedBackend, +) (*core.ChainPack, error) { + var ( + key = addresses.key + key1 = addresses.key1 + key2 = addresses.key2 + address = addresses.address + address1 = addresses.address1 + address2 = addresses.address2 + theAddr = common.Address{1} + chainId = big.NewInt(1337) + // this code generates a log + signer = types.LatestSignerForChainID(nil) + ) + + transactOpts, _ := bind.NewKeyedTransactorWithChainID(key, chainId) + transactOpts1, _ := bind.NewKeyedTransactorWithChainID(key1, chainId) + transactOpts2, _ := bind.NewKeyedTransactorWithChainID(key2, chainId) + var poly *contracts.Poly + var tokenContract *contracts.Token + + // We generate the blocks without plain state because it's not supported in core.GenerateChain + return core.GenerateChain(config, parent, engine, db, 10, func(i int, block *core.BlockGen) { + var ( + txn types.Transaction + txs []types.Transaction + err error + ) + + ctx := context.Background() + switch i { + case 0: + txn, err = types.SignTx(types.NewTransaction(0, theAddr, uint256.NewInt(1000000000000000), 21000, new(uint256.Int), nil), *signer, key) + if err != nil { + panic(err) + } + err = contractBackend.SendTransaction(ctx, txn) + if err != nil { + panic(err) + } + case 1: + txn, err = types.SignTx(types.NewTransaction(1, theAddr, uint256.NewInt(1000000000000000), 21000, new(uint256.Int), nil), *signer, key) + if err != nil { + panic(err) + } + err = contractBackend.SendTransaction(ctx, txn) + if err != nil { + panic(err) + } + case 2: + _, txn, tokenContract, err = contracts.DeployToken(transactOpts, contractBackend, address1) + case 3: + txn, err = tokenContract.Mint(transactOpts1, address2, big.NewInt(10)) + case 4: + txn, err = tokenContract.Transfer(transactOpts2, address, big.NewInt(3)) + case 5: + // Multiple transactions sending small amounts of ether to various accounts + var j uint64 + var toAddr common.Address + nonce := block.TxNonce(address) + for j = 1; j <= 32; j++ { + binary.BigEndian.PutUint64(toAddr[:], j) + txn, err = types.SignTx(types.NewTransaction(nonce, toAddr, uint256.NewInt(1_000_000_000_000_000), 21000, new(uint256.Int), nil), *signer, key) + if err != nil { + panic(err) + } + err = contractBackend.SendTransaction(ctx, txn) + if err != nil { + panic(err) + } + txs = append(txs, txn) + nonce++ + } + case 6: + _, txn, tokenContract, err = contracts.DeployToken(transactOpts, contractBackend, address1) + if err != nil { + panic(err) + } + txs = append(txs, txn) + txn, err = tokenContract.Mint(transactOpts1, address2, big.NewInt(100)) + if err != nil { + panic(err) + } + txs = append(txs, txn) + // Multiple transactions sending small amounts of ether to various accounts + var j uint64 + var toAddr common.Address + for j = 1; j <= 32; j++ { + binary.BigEndian.PutUint64(toAddr[:], j) + txn, err = tokenContract.Transfer(transactOpts2, toAddr, big.NewInt(1)) + if err != nil { + panic(err) + } + txs = append(txs, txn) + } + case 7: + var toAddr common.Address + nonce := block.TxNonce(address) + binary.BigEndian.PutUint64(toAddr[:], 4) + txn, err = types.SignTx(types.NewTransaction(nonce, toAddr, uint256.NewInt(1000000000000000), 21000, new(uint256.Int), nil), *signer, key) + if err != nil { + panic(err) + } + err = contractBackend.SendTransaction(ctx, txn) + if err != nil { + panic(err) + } + txs = append(txs, txn) + binary.BigEndian.PutUint64(toAddr[:], 12) + txn, err = tokenContract.Transfer(transactOpts2, toAddr, big.NewInt(1)) + if err != nil { + panic(err) + } + txs = append(txs, txn) + case 8: + _, txn, poly, err = contracts.DeployPoly(transactOpts, contractBackend) + if err != nil { + panic(err) + } + txs = append(txs, txn) + case 9: + txn, err = poly.DeployAndDestruct(transactOpts, big.NewInt(0)) + if err != nil { + panic(err) + } + txs = append(txs, txn) + } + + if err != nil { + panic(err) + } + if txs == nil && txn != nil { + txs = append(txs, txn) + } + + for _, txn := range txs { + block.AddTx(txn) + } + contractBackend.Commit() + }, true) +} + +type IsMiningMock struct{} + +func (*IsMiningMock) IsMining() bool { return false } + +func CreateTestGrpcConn(t *testing.T, m *stages.MockSentry) (context.Context, *grpc.ClientConn) { //nolint + ctx, cancel := context.WithCancel(context.Background()) + + apis := m.Engine.APIs(nil) + if len(apis) < 1 { + t.Fatal("couldn't instantiate Engine api") + } + + ethashApi := apis[1].Service.(*ethash.API) + server := grpc.NewServer() + + remote.RegisterETHBACKENDServer(server, privateapi.NewEthBackendServer(ctx, nil, m.DB, m.Notifications.Events, snapshotsync.NewBlockReader(), nil, nil, nil, false)) + txpool.RegisterTxpoolServer(server, m.TxPoolGrpcServer) + txpool.RegisterMiningServer(server, privateapi.NewMiningServer(ctx, &IsMiningMock{}, ethashApi)) + listener := bufconn.Listen(1024 * 1024) + + dialer := func() func(context.Context, string) (net.Conn, error) { + go func() { + if err := server.Serve(listener); err != nil { + fmt.Printf("%v\n", err) + } + }() + return func(context.Context, string) (net.Conn, error) { + return listener.Dial() + } + } + + conn, err := grpc.DialContext(ctx, "", grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithContextDialer(dialer())) + if err != nil { + t.Fatal(err) + } + t.Cleanup(func() { + cancel() + conn.Close() + server.Stop() + }) + return ctx, conn +} diff --git a/cmd/rpcdaemon/rpcservices/eth_backend.go b/cmd/rpcdaemon/rpcservices/eth_backend.go new file mode 100644 index 0000000..f9a344b --- /dev/null +++ b/cmd/rpcdaemon/rpcservices/eth_backend.go @@ -0,0 +1,310 @@ +package rpcservices + +import ( + "bytes" + "context" + "encoding/json" + "errors" + "fmt" + "io" + "sync/atomic" + + "github.com/ledgerwatch/erigon-lib/gointerfaces" + "github.com/ledgerwatch/erigon-lib/gointerfaces/remote" + types2 "github.com/ledgerwatch/erigon-lib/gointerfaces/types" + "github.com/ledgerwatch/erigon-lib/kv" + "github.com/ledgerwatch/erigon/common" + "github.com/ledgerwatch/erigon/core/types" + "github.com/ledgerwatch/erigon/ethdb/privateapi" + "github.com/ledgerwatch/erigon/p2p" + "github.com/ledgerwatch/erigon/rlp" + "github.com/ledgerwatch/erigon/turbo/services" + "github.com/ledgerwatch/log/v3" + "google.golang.org/grpc" + "google.golang.org/grpc/status" + "google.golang.org/protobuf/types/known/emptypb" +) + +type RemoteBackend struct { + remoteEthBackend remote.ETHBACKENDClient + log log.Logger + version gointerfaces.Version + db kv.RoDB + blockReader services.FullBlockReader +} + +func NewRemoteBackend(client remote.ETHBACKENDClient, db kv.RoDB, blockReader services.FullBlockReader) *RemoteBackend { + return &RemoteBackend{ + remoteEthBackend: client, + version: gointerfaces.VersionFromProto(privateapi.EthBackendAPIVersion), + log: log.New("remote_service", "eth_backend"), + db: db, + blockReader: blockReader, + } +} + +func (back *RemoteBackend) EnsureVersionCompatibility() bool { + versionReply, err := back.remoteEthBackend.Version(context.Background(), &emptypb.Empty{}, grpc.WaitForReady(true)) + if err != nil { + + back.log.Error("getting Version", "err", err) + return false + } + if !gointerfaces.EnsureVersion(back.version, versionReply) { + back.log.Error("incompatible interface versions", "client", back.version.String(), + "server", fmt.Sprintf("%d.%d.%d", versionReply.Major, versionReply.Minor, versionReply.Patch)) + return false + } + back.log.Info("interfaces compatible", "client", back.version.String(), + "server", fmt.Sprintf("%d.%d.%d", versionReply.Major, versionReply.Minor, versionReply.Patch)) + return true +} + +func (back *RemoteBackend) Etherbase(ctx context.Context) (common.Address, error) { + res, err := back.remoteEthBackend.Etherbase(ctx, &remote.EtherbaseRequest{}) + if err != nil { + if s, ok := status.FromError(err); ok { + return common.Address{}, errors.New(s.Message()) + } + return common.Address{}, err + } + + return gointerfaces.ConvertH160toAddress(res.Address), nil +} + +func (back *RemoteBackend) NetVersion(ctx context.Context) (uint64, error) { + res, err := back.remoteEthBackend.NetVersion(ctx, &remote.NetVersionRequest{}) + if err != nil { + if s, ok := status.FromError(err); ok { + return 0, errors.New(s.Message()) + } + return 0, err + } + + return res.Id, nil +} + +func (back *RemoteBackend) NetPeerCount(ctx context.Context) (uint64, error) { + res, err := back.remoteEthBackend.NetPeerCount(ctx, &remote.NetPeerCountRequest{}) + if err != nil { + if s, ok := status.FromError(err); ok { + return 0, errors.New(s.Message()) + } + return 0, err + } + + return res.Count, nil +} + +func (back *RemoteBackend) ProtocolVersion(ctx context.Context) (uint64, error) { + res, err := back.remoteEthBackend.ProtocolVersion(ctx, &remote.ProtocolVersionRequest{}) + if err != nil { + if s, ok := status.FromError(err); ok { + return 0, errors.New(s.Message()) + } + return 0, err + } + + return res.Id, nil +} + +func (back *RemoteBackend) ClientVersion(ctx context.Context) (string, error) { + res, err := back.remoteEthBackend.ClientVersion(ctx, &remote.ClientVersionRequest{}) + if err != nil { + if s, ok := status.FromError(err); ok { + return "", errors.New(s.Message()) + } + return "", err + } + + return res.NodeName, nil +} + +func (back *RemoteBackend) Subscribe(ctx context.Context, onNewEvent func(*remote.SubscribeReply)) error { + subscription, err := back.remoteEthBackend.Subscribe(ctx, &remote.SubscribeRequest{}, grpc.WaitForReady(true)) + if err != nil { + if s, ok := status.FromError(err); ok { + return errors.New(s.Message()) + } + return err + } + for { + event, err := subscription.Recv() + if errors.Is(err, io.EOF) { + log.Debug("rpcdaemon: the subscription channel was closed") + break + } + if err != nil { + return err + } + + onNewEvent(event) + } + return nil +} + +func (back *RemoteBackend) SubscribeLogs(ctx context.Context, onNewLogs func(reply *remote.SubscribeLogsReply), requestor *atomic.Value) error { + subscription, err := back.remoteEthBackend.SubscribeLogs(ctx, grpc.WaitForReady(true)) + if err != nil { + if s, ok := status.FromError(err); ok { + return errors.New(s.Message()) + } + return err + } + requestor.Store(subscription.Send) + for { + logs, err := subscription.Recv() + if errors.Is(err, io.EOF) { + log.Info("rpcdaemon: the logs subscription channel was closed") + break + } + if err != nil { + return err + } + onNewLogs(logs) + } + return nil +} + +func (back *RemoteBackend) TxnLookup(ctx context.Context, tx kv.Getter, txnHash common.Hash) (uint64, bool, error) { + return back.blockReader.TxnLookup(ctx, tx, txnHash) +} +func (back *RemoteBackend) BlockWithSenders(ctx context.Context, tx kv.Getter, hash common.Hash, blockHeight uint64) (block *types.Block, senders []common.Address, err error) { + return back.blockReader.BlockWithSenders(ctx, tx, hash, blockHeight) +} +func (back *RemoteBackend) BodyWithTransactions(ctx context.Context, tx kv.Getter, hash common.Hash, blockHeight uint64) (body *types.Body, err error) { + return back.blockReader.BodyWithTransactions(ctx, tx, hash, blockHeight) +} +func (back *RemoteBackend) BodyRlp(ctx context.Context, tx kv.Getter, hash common.Hash, blockHeight uint64) (bodyRlp rlp.RawValue, err error) { + return back.blockReader.BodyRlp(ctx, tx, hash, blockHeight) +} +func (back *RemoteBackend) Body(ctx context.Context, tx kv.Getter, hash common.Hash, blockHeight uint64) (body *types.Body, txAmount uint32, err error) { + return back.blockReader.Body(ctx, tx, hash, blockHeight) +} +func (back *RemoteBackend) Header(ctx context.Context, tx kv.Getter, hash common.Hash, blockHeight uint64) (*types.Header, error) { + return back.blockReader.Header(ctx, tx, hash, blockHeight) +} +func (back *RemoteBackend) HeaderByNumber(ctx context.Context, tx kv.Getter, blockHeight uint64) (*types.Header, error) { + return back.blockReader.HeaderByNumber(ctx, tx, blockHeight) +} +func (back *RemoteBackend) HeaderByHash(ctx context.Context, tx kv.Getter, hash common.Hash) (*types.Header, error) { + return back.blockReader.HeaderByHash(ctx, tx, hash) +} +func (back *RemoteBackend) CanonicalHash(ctx context.Context, tx kv.Getter, blockHeight uint64) (common.Hash, error) { + return back.blockReader.CanonicalHash(ctx, tx, blockHeight) +} +func (back *RemoteBackend) TxnByIdxInBlock(ctx context.Context, tx kv.Getter, blockNum uint64, i int) (types.Transaction, error) { + return back.blockReader.TxnByIdxInBlock(ctx, tx, blockNum, i) +} + +func (back *RemoteBackend) EngineNewPayloadV1(ctx context.Context, payload *types2.ExecutionPayload) (res *remote.EnginePayloadStatus, err error) { + return back.remoteEthBackend.EngineNewPayloadV1(ctx, payload) +} + +func (back *RemoteBackend) EngineForkchoiceUpdatedV1(ctx context.Context, request *remote.EngineForkChoiceUpdatedRequest) (*remote.EngineForkChoiceUpdatedReply, error) { + return back.remoteEthBackend.EngineForkChoiceUpdatedV1(ctx, request) +} + +func (back *RemoteBackend) EngineGetPayloadV1(ctx context.Context, payloadId uint64) (res *types2.ExecutionPayload, err error) { + return back.remoteEthBackend.EngineGetPayloadV1(ctx, &remote.EngineGetPayloadRequest{ + PayloadId: payloadId, + }) +} + +func (back *RemoteBackend) NodeInfo(ctx context.Context, limit uint32) ([]p2p.NodeInfo, error) { + nodes, err := back.remoteEthBackend.NodeInfo(ctx, &remote.NodesInfoRequest{Limit: limit}) + if err != nil { + return nil, fmt.Errorf("nodes info request error: %w", err) + } + + if nodes == nil || len(nodes.NodesInfo) == 0 { + return nil, errors.New("empty nodesInfo response") + } + + ret := make([]p2p.NodeInfo, 0, len(nodes.NodesInfo)) + for _, node := range nodes.NodesInfo { + var rawProtocols map[string]json.RawMessage + if err = json.Unmarshal(node.Protocols, &rawProtocols); err != nil { + return nil, fmt.Errorf("cannot decode protocols metadata: %w", err) + } + + protocols := make(map[string]interface{}, len(rawProtocols)) + for k, v := range rawProtocols { + protocols[k] = v + } + + ret = append(ret, p2p.NodeInfo{ + Enode: node.Enode, + ID: node.Id, + IP: node.Enode, + ENR: node.Enr, + ListenAddr: node.ListenerAddr, + Name: node.Name, + Ports: struct { + Discovery int `json:"discovery"` + Listener int `json:"listener"` + }{ + Discovery: int(node.Ports.Discovery), + Listener: int(node.Ports.Listener), + }, + Protocols: protocols, + }) + } + + return ret, nil +} + +func (back *RemoteBackend) Peers(ctx context.Context) ([]*p2p.PeerInfo, error) { + rpcPeers, err := back.remoteEthBackend.Peers(ctx, &emptypb.Empty{}) + if err != nil { + return nil, fmt.Errorf("ETHBACKENDClient.Peers() error: %w", err) + } + + peers := make([]*p2p.PeerInfo, 0, len(rpcPeers.Peers)) + + for _, rpcPeer := range rpcPeers.Peers { + peer := p2p.PeerInfo{ + ENR: rpcPeer.Enr, + Enode: rpcPeer.Enode, + ID: rpcPeer.Id, + Name: rpcPeer.Name, + Caps: rpcPeer.Caps, + Network: struct { + LocalAddress string `json:"localAddress"` + RemoteAddress string `json:"remoteAddress"` + Inbound bool `json:"inbound"` + Trusted bool `json:"trusted"` + Static bool `json:"static"` + }{ + LocalAddress: rpcPeer.ConnLocalAddr, + RemoteAddress: rpcPeer.ConnRemoteAddr, + Inbound: rpcPeer.ConnIsInbound, + Trusted: rpcPeer.ConnIsTrusted, + Static: rpcPeer.ConnIsStatic, + }, + Protocols: nil, + } + + peers = append(peers, &peer) + } + + return peers, nil +} + +func (back *RemoteBackend) PendingBlock(ctx context.Context) (*types.Block, error) { + blockRlp, err := back.remoteEthBackend.PendingBlock(ctx, &emptypb.Empty{}) + if err != nil { + return nil, fmt.Errorf("ETHBACKENDClient.PendingBlock() error: %w", err) + } + if blockRlp == nil { + return nil, nil + } + + var block types.Block + err = rlp.Decode(bytes.NewReader(blockRlp.BlockRlp), &block) + if err != nil { + return nil, fmt.Errorf("decoding block from %x: %w", blockRlp, err) + } + + return &block, nil +} diff --git a/cmd/rpcdaemon/rpcservices/eth_mining.go b/cmd/rpcdaemon/rpcservices/eth_mining.go new file mode 100644 index 0000000..889b24d --- /dev/null +++ b/cmd/rpcdaemon/rpcservices/eth_mining.go @@ -0,0 +1,43 @@ +package rpcservices + +import ( + "context" + "fmt" + + "github.com/ledgerwatch/erigon-lib/gointerfaces" + "github.com/ledgerwatch/erigon-lib/gointerfaces/txpool" + "github.com/ledgerwatch/erigon/ethdb/privateapi" + "github.com/ledgerwatch/log/v3" + "google.golang.org/grpc" + "google.golang.org/protobuf/types/known/emptypb" +) + +type MiningService struct { + txpool.MiningClient + log log.Logger + version gointerfaces.Version +} + +func NewMiningService(client txpool.MiningClient) *MiningService { + return &MiningService{ + MiningClient: client, + version: gointerfaces.VersionFromProto(privateapi.MiningAPIVersion), + log: log.New("remote_service", "mining"), + } +} + +func (s *MiningService) EnsureVersionCompatibility() bool { + versionReply, err := s.Version(context.Background(), &emptypb.Empty{}, grpc.WaitForReady(true)) + if err != nil { + s.log.Error("getting Version", "err", err) + return false + } + if !gointerfaces.EnsureVersion(s.version, versionReply) { + s.log.Error("incompatible interface versions", "client", s.version.String(), + "server", fmt.Sprintf("%d.%d.%d", versionReply.Major, versionReply.Minor, versionReply.Patch)) + return false + } + s.log.Info("interfaces compatible", "client", s.version.String(), + "server", fmt.Sprintf("%d.%d.%d", versionReply.Major, versionReply.Minor, versionReply.Patch)) + return true +} diff --git a/cmd/rpcdaemon/rpcservices/eth_txpool.go b/cmd/rpcdaemon/rpcservices/eth_txpool.go new file mode 100644 index 0000000..670a77b --- /dev/null +++ b/cmd/rpcdaemon/rpcservices/eth_txpool.go @@ -0,0 +1,50 @@ +package rpcservices + +import ( + "context" + "fmt" + "time" + + "github.com/ledgerwatch/erigon-lib/gointerfaces" + "github.com/ledgerwatch/erigon-lib/gointerfaces/grpcutil" + txpooproto "github.com/ledgerwatch/erigon-lib/gointerfaces/txpool" + txpool2 "github.com/ledgerwatch/erigon-lib/txpool" + "github.com/ledgerwatch/log/v3" + "google.golang.org/grpc" + "google.golang.org/protobuf/types/known/emptypb" +) + +type TxPoolService struct { + txpooproto.TxpoolClient + log log.Logger + version gointerfaces.Version +} + +func NewTxPoolService(client txpooproto.TxpoolClient) *TxPoolService { + return &TxPoolService{ + TxpoolClient: client, + version: gointerfaces.VersionFromProto(txpool2.TxPoolAPIVersion), + log: log.New("remote_service", "tx_pool"), + } +} + +func (s *TxPoolService) EnsureVersionCompatibility() bool { +Start: + versionReply, err := s.Version(context.Background(), &emptypb.Empty{}, grpc.WaitForReady(true)) + if err != nil { + if grpcutil.ErrIs(err, txpool2.ErrPoolDisabled) { + time.Sleep(3 * time.Second) + goto Start + } + s.log.Error("ensure version", "err", err) + return false + } + if !gointerfaces.EnsureVersion(s.version, versionReply) { + s.log.Error("incompatible interface versions", "client", s.version.String(), + "server", fmt.Sprintf("%d.%d.%d", versionReply.Major, versionReply.Minor, versionReply.Patch)) + return false + } + s.log.Info("interfaces compatible", "client", s.version.String(), + "server", fmt.Sprintf("%d.%d.%d", versionReply.Major, versionReply.Minor, versionReply.Patch)) + return true +} diff --git a/cmd/rpcdaemon/test.http b/cmd/rpcdaemon/test.http new file mode 100644 index 0000000..cf6205c --- /dev/null +++ b/cmd/rpcdaemon/test.http @@ -0,0 +1,222 @@ + +### + +POST localhost:8545 +Content-Type: application/json + +{ + "jsonrpc": "2.0", + "method": "eth_syncing", + "params": [], + "id": 1 +} + +### + +POST localhost:8545 +Content-Type: application/json + +{ + "jsonrpc": "2.0", + "method": "eth_getBalance", + "params": [ + "0xfffa4763f94f7ad191b366a343092a5d1a47ed08", + "0xde84" + ], + "id": 1 +} + +### + +POST localhost:8545 +Content-Type: application/json + +{ + "jsonrpc": "2.0", + "method": "debug_accountRange", + "params": [ + "0x1e8480", + "", + 256, + false, + false, + false + ], + "id": 1 +} + +### + +# curl -X POST -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"eth_getTransactionByHash", "params": ["0x1302cc71b89c1482b18a97a6fa2c9c375f4bf7548122363b6e91528440272fde"], "id":1}' localhost:8545 +POST localhost:8545 +Content-Type: application/json + +{ + "jsonrpc": "2.0", + "method": "eth_getTransactionByHash", + "params": [ + "0x1302cc71b89c1482b18a97a6fa2c9c375f4bf7548122363b6e91528440272fde" + ], + "id": 1 +} + +### + + + +# curl -X POST -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"eth_getTransactionByHash", "params": ["0x1302cc71b89c1482b18a97a6fa2c9c375f4bf7548122363b6e91528440272fde"], "id":1}' localhost:8545 +POST localhost:8545 +Content-Type: application/json + +{ + "jsonrpc": "2.0", + "method": "eth_getBlockByNumber", + "params": [ + "0x4C4B40", + true + ], + "id": 1 +} + +### + +# curl -X POST -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"eth_getBlockByNumber", "params": ["0x1b4", true], "id":1}' localhost:8545 +POST localhost:8545 +Content-Type: application/json + +{ + "jsonrpc": "2.0", + "method": "eth_newHeader", + "params": [], + "id": 1 +} + +### + +POST localhost:8545 +Content-Type: application/json + +{ + "jsonrpc": "2.0", + "method": "eth_getBlockByNumber", + "params": [ + "0xf4240", + true + ], + "id": 2 +} + +### + +POST localhost:8545 +Content-Type: application/json + +{ + "jsonrpc": "2.0", + "method": "debug_storageRangeAt", + "params": [ + "0x4ced0bc30041f7f4e11ba9f341b54404770c7695dfdba6bb64b6ffeee2074177", + 99, + "0x33990122638b9132ca29c723bdf037f1a891a70c", + "0x0000000000000000000000000000000000000000000000000000000000000000", + 1024 + ], + "id": 537758 +} + +### > 60 + +### >20 +###{"jsonrpc":"2.0","method":"debug_storageRangeAt","params":["0x6e6ec30ba20b263d1bdf6d87a0b1b037ea595929ac10ad74f6b7e1890fdad744", 19,"0x793ae8c1b1a160bfc07bfb0d04f85eab1a71f4f2","0x0000000000000000000000000000000000000000000000000000000000000000",1024],"id":113911} + + +### {"jsonrpc":"2.0","mesthod":"debug_storageRangeAt","params":["0xbcb55dcb321899291d10818dd06eaaf939ff87a717ac40850b54c6b56e8936ff", 2,"0xca7c390f8f843a8c3036841fde755e5d0acb97da","0x0000000000000000000000000000000000000000000000000000000000000000",1024],"id":3836} + +###{"jsonrpc":"2.0","method":"debug_storageRangeAt","params":["0xf212a7655339852bf58f7e1d66f82256d22d13ccba3068a9c47a635738698c84", 0,"0xb278e4cb20dfbf97e78f27001f6b15288302f4d7","0x0000000000000000000000000000000000000000000000000000000000000000",1024],"id":8970} + +### + +POST 192.168.255.138:8545 +Content-Type: application/json + +{ + "jsonrpc": "2.0", + "method": "eth_getTransactionReceipt", + "params": [ + "0xc05ce241bec59900356ede868d170bc01d743c3cd5ecb129ca99596593022771" + ], + "id": 537758 +} + + +### + +#POST 192.168.255.138:8545 +POST localhost:8545 +Content-Type: application/json + +{ + "jsonrpc": "2.0", + "method": "erigon_getLogsByHash", + "params": [ + "0x343f85f13356e138152d77287fda5ae0818c514119119ad439f81d69c59fc2f6" + ], + "id": 537758 +} + + +### + +#POST 192.168.255.138:8545 +POST localhost:8545 +Content-Type: application/json + +{ + "jsonrpc": "2.0", + "method": "eth_getLogs", + "params": [ + { + "address": "0x6090a6e47849629b7245dfa1ca21d94cd15878ef", + "fromBlock": "0x3d0000", + "toBlock": "0x3d2600", + "topics": [ + null, + "0x374f3a049e006f36f6cf91b02a3b0ee16c858af2f75858733eb0e927b5b7126c" + ] + } + ], + "id": 537758 +} + +### + +#POST 192.168.255.138:8545 +POST localhost:8545 +Content-Type: application/json + +{ + "jsonrpc": "2.0", + "method": "eth_getWork", + "params": [], + "id": 537758 +} + + + +### + +POST localhost:8545 +Content-Type: application/json + +{ + "id": 1, + "method": "eth_estimateGas", + "params": [ + { + "to": "0x5fda30bb72b8dfe20e48a00dfc108d0915be9bb0", + "value": "0x1234" + }, + "latest" + ] +} + diff --git a/cmd/rpcdaemon/testdata/.gitignore b/cmd/rpcdaemon/testdata/.gitignore new file mode 100644 index 0000000..6ad2716 --- /dev/null +++ b/cmd/rpcdaemon/testdata/.gitignore @@ -0,0 +1,5 @@ +geth +parity +nethermind +turbogeth +erigon \ No newline at end of file diff --git a/cmd/rpcdaemon/testdata/sed_file b/cmd/rpcdaemon/testdata/sed_file new file mode 100644 index 0000000..777338a --- /dev/null +++ b/cmd/rpcdaemon/testdata/sed_file @@ -0,0 +1,22 @@ +s/,\"id\":\"1\"//g +s/\"result\":null,/\"result\":\{\},/g +s/suicide/selfdestruct/g +s/\"gasUsed\":\"0x0\",//g +s/,\"value\":\"0x0\"//g + +s/invalid argument 1: json: cannot unmarshal hex string \\\"0x\\\" into Go value of type hexutil.Uint64/Invalid params: Invalid index: cannot parse integer from empty string./ +s/invalid argument 1: json: cannot unmarshal number into Go value of type \[\]hexutil.Uint64/Invalid params: invalid type: integer `0`, expected a sequence./ +s/missing value for required argument 1/Invalid params: invalid length 1, expected a tuple of size 2./ +s/Invalid params: invalid type: string \\\"0x0\\\", expected a sequence./invalid argument 1: json: cannot unmarshal string into Go value of type \[\]hexutil.Uint64/ +s/Invalid params\: Invalid block number\: number too large to fit in target type./invalid argument 0: hex number > 64 bits/ +s/the method trace_junk12 does not exist\/is not available/Method not found/ + +s/,\"traceAddress\":null/,\"traceAddress\":[]/g +s/\"0x0000000000000000000000000000000000000000000000000000000000000000\"/\"0x\"/g +s/\"transactionHash\":\"0x\",\"transactionPosition\":0/\"transactionHash\":null,\"transactionPosition\":null/g +s/\"result\":null/\"result\":[]/g + +s/\"error\":{\"code\":-32000,\"message\":\"function trace_replayBlockTransactions not implemented\"}/\"result\":\[\]/ +s/\"error\":{\"code\":-32000,\"message\":\"function trace_replayTransaction not implemented\"}/\"result\":{\"output\":\"0x\",\"stateDiff\":null,\"trace\":\[\],\"vmTrace\":null}/ +s/\"error\":{\"code\":-32602,\"message\":\"invalid argument 0: json: cannot unmarshal array into Go value of type commands.CallParam\"}/\"result\":\[{\"output\":\"0x\",\"stateDiff\":null,\"trace\":\[\],\"vmTrace\":null},{\"output\":\"0x\",\"stateDiff\":null,\"trace\":\[\],\"vmTrace\":null}]/ +s/\"error\":{\"code\":-32602,\"message\":\"invalid argument 0: hex string has length 82, want 64 for common.Hash\"}/\"error\":{\"code\":-32602,\"data\":\"RlpIncorrectListLen\",\"message\":\"Couldn't parse parameters: Transaction is not valid RLP\"}/ diff --git a/cmd/rpcdaemon/testdata/trace_tests b/cmd/rpcdaemon/testdata/trace_tests new file mode 100644 index 0000000..0e89a8d --- /dev/null +++ b/cmd/rpcdaemon/testdata/trace_tests @@ -0,0 +1,76 @@ +005 trace_get fail ["0x17104ac9d3312d8c136b7f44d4b8b47852618065ebfa534bd2d3b5ef218ca1f3",0] +010 trace_get fail ["0x17104ac9d3312d8c136b7f44d4b8b47852618065ebfa534bd2d3b5ef218ca1f3","0x0"] +015 trace_get zero ["0x17104ac9d3312d8c136b7f44d4b8b47852618065ebfa534bd2d3b5ef218ca1f3",["0x0"]] +020 trace_get one ["0x17104ac9d3312d8c136b7f44d4b8b47852618065ebfa534bd2d3b5ef218ca1f3",["0x1"]] +025 trace_get both ["0x17104ac9d3312d8c136b7f44d4b8b47852618065ebfa534bd2d3b5ef218ca1f3",["0x0","0x1"]] +030 trace_get fail ["0x17104ac9d3312d8c136b7f44d4b8b47852618065ebfa534bd2d3b5ef218ca1f3"] +035 trace_get two ["0x5c504ed432cb51138bcf09aa5e8a410dd4a1e204ef84bfed1be16dfba1b22060",["0x2"]] +040 trace_get fail ["0x975994512b958b31608f5692a6dbacba359349533dfb4ba0facfb7291fbec48d",["0x"]] + +050 trace_transaction one ["0x17104ac9d3312d8c136b7f44d4b8b47852618065ebfa534bd2d3b5ef218ca1f3"] +055 trace_transaction two ["0x5c504ed432cb51138bcf09aa5e8a410dd4a1e204ef84bfed1be16dfba1b22060"] +060 trace_transaction three ["0x6afbe0f0ea3613edd6b84b71260836c03bddce81604f05c81a070cd671d3d765"] +065 trace_transaction four ["0x80926bb17ecdd526a2d901835482615eec87c4ca7fc30b96d8c6d6ab17bc721e"] +070 trace_transaction five ["0xb8ae0ab093fe1882249187b8f40dbe6e9285b419d096bd8028172d55b47ff3ce"] +075 trace_transaction six ["0xc2b831c051582f13dfaff6df648972e7e94aeeed1e85d23bd968a55b59f3cb5b"] +080 trace_transaction seven ["0xf9d426284bd20415a53991a004122b3a3a619b295ea98d1d88a5fd3a4125408b"] +085 trace_transaction cr_de ["0x343ba476313771d4431018d7d2e935eba2bfe26d5be3e6cb84af6817fd0e4309"] + +105 trace_block 0x23 ["0x2328"] +110 trace_block 0x10 ["0x100"] +115 trace_block 0x12 ["0x12"] +120 trace_block 0x12 ["0x121212"] +125 trace_block 0x2e ["0x2ed119"] +130 trace_block 0xa1 ["0xa18dcfbc639be11c353420ede9224d772c56eb9ff327eb73771f798cf42d0027"] +#135 trace_block 0xa6 ["0xa60f34"] +#140 trace_block 0xf4 ["0xf4629"] +#145 trace_block slow ["0x895441"] + +150 trace_filter good_1 [{"fromBlock":"0x2328","toBlock":"0x2328"}] +155 trace_filter range_1 [{"fromBlock":"0x2dcaa9","toBlock":"0x2dcaaa"}] +160 trace_filter block_3 [{"fromBlock":"0x3","toBlock":"0x3"}] +165 trace_filter first_tx [{"fromBlock":"0xb443","toBlock":"0xb443"}] +170 trace_filter from_doc [{"fromBlock":"0x2ed0c4","toBlock":"0x2ed128","toAddress":["0x8bbb73bcb5d553b5a556358d27625323fd781d37"],"after":1000,"count":100}] +175 trace_filter rem_a_o [{"fromBlock":"0x2ed0c4","toBlock":"0x2ed128","toAddress":["0x8bbb73bcb5d553b5a556358d27625323fd781d37"]}] +180 trace_filter count_1 [{"fromBlock":"0x2ed0c4","toBlock":"0x2ed128","toAddress":["0x8bbb73bcb5d553b5a556358d27625323fd781d37"],"count":1}] +185 trace_filter after_1 [{"fromBlock":"0x2ed0c4","toBlock":"0x2ed128","toAddress":["0x8bbb73bcb5d553b5a556358d27625323fd781d37"],"after":1,"count":4}] +190 trace_filter to_0xc02 [{"fromBlock":"0xa344e0","toBlock":"0xa344e0","toAddress":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"]}] +195 trace_filter fr_0xc3c [{"fromBlock":"0xa344e0","toBlock":"0xa344e0","fromAddress":["0xc3ca90684fd7b8c7e4be88c329269fc32111c4bd"]}] +200 trace_filter both [{"fromBlock":"0xa344e0","toBlock":"0xa344e0","fromAddress":["0xc3ca90684fd7b8c7e4be88c329269fc32111c4bd"],"toAddress":["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"]}] +205 trace_filter fail_2 [{"fromBlock":"0xa606ba","toBlock":"0x2dcaa9"}] +210 trace_filter bad_1 [{"fromBlock":"0x2328","toBlock":"0x2327"}] +#215 trace_filter slow_2 [{"fromBlock":"0xa606ba","toBlock":"0xa606ba"}] +#220 trace_filter 10700000 [{"fromBlock":"0xa344e0","toBlock":"0xa344e0"}] + +250 trace_replayBlockTransactions fail ["0x3", ["stateDiff"]] +300 trace_replayTransaction fail ["0x02d4a872e096445e80d05276ee756cefef7f3b376bcec14246469c0cd97dad8f", ["fail"]] +320_erigon trace_call fail [{"input":"0x0","nonce":"0x0","from":"0x02fcf30912b6fe2b6452ee19721c6068fe4c7b61","gas":"0xf4240","to":"0x37a9679c41e99db270bda88de8ff50c0cd23f326","gasPrice":"0x4a817c800","value":"0x0"},["fail"],"latest"] +340 trace_callMany fail [[[{"from":"0x407d73d8a49eeb85d32cf465507dd71d507100c1","to":"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b","value":"0x186a0"},["fail"]],[{"from":"0x407d73d8a49eeb85d32cf465507dd71d507100c1","to":"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b","value":"0x186a0"},["fail"]]],"latest"] +360 trace_rawTransaction fail ["0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675",["fail"]] +#255 trace_replayBlockTransactions ["0x1",["trace"]] +#250 trace_replayBlockTransactions ["0x1"] +#265 trace_replayBlockTransactions ["0x100"] +#260 trace_replayBlockTransactions ["0x895441",["trace"]] +#275 trace_replayBlockTransactions ["0x895441",["vmTrace"]] +#270 trace_replayBlockTransactions ["0xCF9BF",["trace"]] +#285 trace_replayBlockTransactions ["0xDBBA1",["trace"]] +#280 trace_replayBlockTransactions ["0xDBBA1",["vmTrace"]] +#285 trace_replayBlockTransactions ["CF9BF",["trace"]] +#290 trace_replayTransactions ["CF9BF",["trace"]] +#295trace_replayTransactions ["CF9BF",["trace"]] + +305 trace_junk12 no_rpc [] + +# custom, experimental stuff +405_erigon trace_blockReward rew_0 ["0x0"] +410_erigon trace_blockReward rew_1 ["0x1"] +415_erigon trace_blockReward rew_2 ["0x2"] +420_erigon trace_blockReward rew_3 ["0x3"] +425_erigon trace_uncleReward unc_0 ["0x0"] +430_erigon trace_uncleReward unc_1 ["0x1"] +435_erigon trace_uncleReward unc_2 ["0x2"] +440_erigon trace_uncleReward unc_3 ["0x3"] +445_erigon trace_issuance iss_0 ["0x0"] +450_erigon trace_issuance iss_1 ["0x1"] +455_erigon trace_issuance iss_2 ["0x2"] +460_erigon trace_issuance iss_3 ["0x3"] diff --git a/cmd/server/main.go b/cmd/server/main.go new file mode 100644 index 0000000..7e52aee --- /dev/null +++ b/cmd/server/main.go @@ -0,0 +1,69 @@ +package main + +import ( + "log" + "net/http" + "os" + "strings" + "time" + + "github.com/go-chi/chi/v5" + "github.com/go-chi/chi/v5/middleware" +) + +func main() { + root := "dist" + port := os.Getenv("PORT") + if port == "" { + port = "3001" + } + if os.Getenv("ROOTDIR") != "" { + root = os.Getenv("ROOTDIR") + } + if len(os.Args) > 1 { + if os.Args[1] != "" { + root = os.Args[1] + } + } + filesDir := http.Dir(root) + + r := chi.NewRouter() + r.Use(middleware.Logger) + r.Use(middleware.Recoverer) + r.Use(middleware.SetHeader("Access-Control-Allow-Origin", "*")) + + FileServer(r, "/", filesDir) + + s := http.Server{ + Addr: ":" + port, + Handler: r, + } + s.SetKeepAlivesEnabled(false) + s.ReadHeaderTimeout = 250 * time.Millisecond + s.MaxHeaderBytes = 8192 + + log.Println("static asset server running on " + port) + // Start the server. + if err := s.ListenAndServe(); err != nil { + log.Fatalf("error in ListenAndServe: %v", err) + } +} + +// FileServer conveniently sets up a http.FileServer handler to serve +// static files from a http.FileSystem. +func FileServer(r chi.Router, path string, root http.FileSystem) { + if strings.ContainsAny(path, "{}*") { + panic("FileServer does not permit any URL parameters.") + } + if path != "/" && path[len(path)-1] != '/' { + r.Get(path, http.RedirectHandler(path+"/", 301).ServeHTTP) + path += "/" + } + path += "*" + r.Get(path, func(w http.ResponseWriter, r *http.Request) { + rctx := chi.RouteContext(r.Context()) + pathPrefix := strings.TrimSuffix(rctx.RoutePattern(), "/*") + fs := http.StripPrefix(pathPrefix, http.FileServer(root)) + fs.ServeHTTP(w, r) + }) +} diff --git a/erigon_internal/debug/api.go b/erigon_internal/debug/api.go new file mode 100644 index 0000000..95d0213 --- /dev/null +++ b/erigon_internal/debug/api.go @@ -0,0 +1,239 @@ +// Copyright 2016 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +// Package debug interfaces Go runtime debugging facilities. +// This package is mostly glue code making these facilities available +// through the CLI and RPC subsystem. If you want to use them from Go code, +// use package runtime instead. +package debug + +import ( + "bytes" + "errors" + "io" + "os" + "os/user" + "path/filepath" + "runtime" + "runtime/debug" + "runtime/pprof" + "strings" + "sync" + "time" + + "github.com/ledgerwatch/erigon-lib/common" + "github.com/ledgerwatch/log/v3" +) + +// Handler is the global debugging handler. +var Handler = new(HandlerT) + +// HandlerT implements the debugging API. +// Do not create values of this type, use the one +// in the Handler variable instead. +type HandlerT struct { + mu sync.Mutex + cpuW io.WriteCloser + cpuFile string + traceW io.WriteCloser + traceFile string +} + +// Verbosity sets the log verbosity ceiling. The verbosity of individual packages +// and source files can be raised using Vmodule. +func (*HandlerT) Verbosity(level int) { + //glogger.Verbosity(log.Lvl(level)) +} + +// Vmodule sets the log verbosity pattern. See package log for details on the +// pattern syntax. +func (*HandlerT) Vmodule(pattern string) error { + //return glogger.Vmodule(pattern) + return nil +} + +// BacktraceAt sets the log backtrace location. See package log for details on +// the pattern syntax. +func (*HandlerT) BacktraceAt(location string) error { + //return glogger.BacktraceAt(location) + return nil +} + +// MemStats returns detailed runtime memory statistics. +func (*HandlerT) MemStats() *runtime.MemStats { + s := new(runtime.MemStats) + common.ReadMemStats(s) + return s +} + +// GcStats returns GC statistics. +func (*HandlerT) GcStats() *debug.GCStats { + s := new(debug.GCStats) + debug.ReadGCStats(s) + return s +} + +// CpuProfile turns on CPU profiling for nsec seconds and writes +// profile data to file. +func (h *HandlerT) CpuProfile(file string, nsec uint) error { + if err := h.StartCPUProfile(file); err != nil { + return err + } + time.Sleep(time.Duration(nsec) * time.Second) + _ = h.StopCPUProfile() + return nil +} + +// StartCPUProfile turns on CPU profiling, writing to the given file. +func (h *HandlerT) StartCPUProfile(file string) error { + h.mu.Lock() + defer h.mu.Unlock() + if h.cpuW != nil { + return errors.New("CPU profiling already in progress") + } + f, err := os.Create(expandHome(file)) + if err != nil { + return err + } + if err := pprof.StartCPUProfile(f); err != nil { + f.Close() + return err + } + h.cpuW = f + h.cpuFile = file + log.Info("CPU profiling started", "dump", h.cpuFile) + return nil +} + +// StopCPUProfile stops an ongoing CPU profile. +func (h *HandlerT) StopCPUProfile() error { + h.mu.Lock() + defer h.mu.Unlock() + pprof.StopCPUProfile() + if h.cpuW == nil { + return errors.New("CPU profiling not in progress") + } + log.Info("Done writing CPU profile", "dump", h.cpuFile) + h.cpuW.Close() + h.cpuW = nil + h.cpuFile = "" + return nil +} + +// GoTrace turns on tracing for nsec seconds and writes +// trace data to file. +func (h *HandlerT) GoTrace(file string, nsec uint) error { + if err := h.StartGoTrace(file); err != nil { + return err + } + time.Sleep(time.Duration(nsec) * time.Second) + _ = h.StopGoTrace() + return nil +} + +// BlockProfile turns on goroutine profiling for nsec seconds and writes profile data to +// file. It uses a profile rate of 1 for most accurate information. If a different rate is +// desired, set the rate and write the profile manually. +func (*HandlerT) BlockProfile(file string, nsec uint) error { + runtime.SetBlockProfileRate(1) + time.Sleep(time.Duration(nsec) * time.Second) + defer runtime.SetBlockProfileRate(0) + return writeProfile("block", file) +} + +// SetBlockProfileRate sets the rate of goroutine block profile data collection. +// rate 0 disables block profiling. +func (*HandlerT) SetBlockProfileRate(rate int) { + runtime.SetBlockProfileRate(rate) +} + +// WriteBlockProfile writes a goroutine blocking profile to the given file. +func (*HandlerT) WriteBlockProfile(file string) error { + return writeProfile("block", file) +} + +// MutexProfile turns on mutex profiling for nsec seconds and writes profile data to file. +// It uses a profile rate of 1 for most accurate information. If a different rate is +// desired, set the rate and write the profile manually. +func (*HandlerT) MutexProfile(file string, nsec uint) error { + runtime.SetMutexProfileFraction(1) + time.Sleep(time.Duration(nsec) * time.Second) + defer runtime.SetMutexProfileFraction(0) + return writeProfile("mutex", file) +} + +// SetMutexProfileFraction sets the rate of mutex profiling. +func (*HandlerT) SetMutexProfileFraction(rate int) { + runtime.SetMutexProfileFraction(rate) +} + +// WriteMutexProfile writes a goroutine blocking profile to the given file. +func (*HandlerT) WriteMutexProfile(file string) error { + return writeProfile("mutex", file) +} + +// WriteMemProfile writes an allocation profile to the given file. +// Note that the profiling rate cannot be set through the API, +// it must be set on the command line. +func (*HandlerT) WriteMemProfile(file string) error { + return writeProfile("heap", file) +} + +// Stacks returns a printed representation of the stacks of all goroutines. +func (*HandlerT) Stacks() string { + buf := new(bytes.Buffer) + _ = pprof.Lookup("goroutine").WriteTo(buf, 2) + return buf.String() +} + +// FreeOSMemory forces a garbage collection. +func (*HandlerT) FreeOSMemory() { + debug.FreeOSMemory() +} + +// SetGCPercent sets the garbage collection target percentage. It returns the previous +// setting. A negative value disables GC. +func (*HandlerT) SetGCPercent(v int) int { + return debug.SetGCPercent(v) +} + +func writeProfile(name, file string) error { + p := pprof.Lookup(name) + log.Info("Writing profile records", "count", p.Count(), "type", name, "dump", file) + f, err := os.Create(expandHome(file)) + if err != nil { + return err + } + defer f.Close() + return p.WriteTo(f, 0) +} + +// expands home directory in file paths. +// ~someuser/tmp will not be expanded. +func expandHome(p string) string { + if strings.HasPrefix(p, "~/") || strings.HasPrefix(p, "~\\") { + home := os.Getenv("HOME") + if home == "" { + if usr, err := user.Current(); err == nil { + home = usr.HomeDir + } + } + if home != "" { + p = home + p[1:] + } + } + return filepath.Clean(p) +} diff --git a/erigon_internal/debug/flags.go b/erigon_internal/debug/flags.go new file mode 100644 index 0000000..df30034 --- /dev/null +++ b/erigon_internal/debug/flags.go @@ -0,0 +1,217 @@ +// Copyright 2016 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package debug + +import ( + "fmt" + "net/http" + _ "net/http/pprof" //nolint:gosec + + metrics2 "github.com/VictoriaMetrics/metrics" + "github.com/ledgerwatch/erigon/common/fdlimit" + "github.com/ledgerwatch/erigon/metrics" + "github.com/ledgerwatch/erigon/metrics/exp" + "github.com/ledgerwatch/log/v3" + "github.com/spf13/cobra" + "github.com/urfave/cli" + "github.com/wmitsuda/otterscan/erigon_internal/logging" +) + +var ( + //nolint + vmoduleFlag = cli.StringFlag{ + Name: "vmodule", + Usage: "Per-module verbosity: comma-separated list of = (e.g. eth/*=5,p2p=4)", + Value: "", + } + metricsAddrFlag = cli.StringFlag{ + Name: "metrics.addr", + } + metricsPortFlag = cli.UintFlag{ + Name: "metrics.port", + Value: 6060, + } + pprofFlag = cli.BoolFlag{ + Name: "pprof", + Usage: "Enable the pprof HTTP server", + } + pprofPortFlag = cli.IntFlag{ + Name: "pprof.port", + Usage: "pprof HTTP server listening port", + Value: 6060, + } + pprofAddrFlag = cli.StringFlag{ + Name: "pprof.addr", + Usage: "pprof HTTP server listening interface", + Value: "127.0.0.1", + } + cpuprofileFlag = cli.StringFlag{ + Name: "pprof.cpuprofile", + Usage: "Write CPU profile to the given file", + } + traceFlag = cli.StringFlag{ + Name: "trace", + Usage: "Write execution trace to the given file", + } +) + +// Flags holds all command-line flags required for debugging. +var Flags = []cli.Flag{ + pprofFlag, pprofAddrFlag, pprofPortFlag, + cpuprofileFlag, traceFlag, +} + +func SetupCobra(cmd *cobra.Command) error { + RaiseFdLimit() + flags := cmd.Flags() + + _ = logging.GetLoggerCmd("debug", cmd) + + traceFile, err := flags.GetString(traceFlag.Name) + if err != nil { + return err + } + cpuFile, err := flags.GetString(cpuprofileFlag.Name) + if err != nil { + return err + } + + // profiling, tracing + if traceFile != "" { + if err2 := Handler.StartGoTrace(traceFile); err2 != nil { + return err2 + } + } + if cpuFile != "" { + if err2 := Handler.StartCPUProfile(cpuFile); err2 != nil { + return err2 + } + } + + go ListenSignals(nil) + pprof, err := flags.GetBool(pprofFlag.Name) + if err != nil { + return err + } + pprofAddr, err := flags.GetString(pprofAddrFlag.Name) + if err != nil { + return err + } + pprofPort, err := flags.GetInt(pprofPortFlag.Name) + if err != nil { + return err + } + + metricsAddr, err := flags.GetString(metricsAddrFlag.Name) + if err != nil { + return err + } + metricsPort, err := flags.GetInt(metricsPortFlag.Name) + if err != nil { + return err + } + + if metrics.Enabled && metricsAddr != "" { + address := fmt.Sprintf("%s:%d", metricsAddr, metricsPort) + exp.Setup(address) + } + + withMetrics := metrics.Enabled && metricsAddr == "" + if pprof { + // metrics and pprof server + StartPProf(fmt.Sprintf("%s:%d", pprofAddr, pprofPort), withMetrics) + } + return nil +} + +// Setup initializes profiling and logging based on the CLI flags. +// It should be called as early as possible in the program. +func Setup(ctx *cli.Context) error { + RaiseFdLimit() + + _ = logging.GetLoggerCtx("debug", ctx) + + if traceFile := ctx.String(traceFlag.Name); traceFile != "" { + if err := Handler.StartGoTrace(traceFile); err != nil { + return err + } + } + + if cpuFile := ctx.String(cpuprofileFlag.Name); cpuFile != "" { + if err := Handler.StartCPUProfile(cpuFile); err != nil { + return err + } + } + pprofEnabled := ctx.Bool(pprofFlag.Name) + metricsAddr := ctx.String(metricsAddrFlag.Name) + + if metrics.Enabled && (!pprofEnabled || metricsAddr != "") { + metricsPort := ctx.Int(metricsPortFlag.Name) + address := fmt.Sprintf("%s:%d", metricsAddr, metricsPort) + exp.Setup(address) + } + + // pprof server + if pprofEnabled { + pprofHost := ctx.String(pprofAddrFlag.Name) + pprofPort := ctx.Int(pprofPortFlag.Name) + address := fmt.Sprintf("%s:%d", pprofHost, pprofPort) + // This context value ("metrics.addr") represents the utils.MetricsHTTPFlag.Name. + // It cannot be imported because it will cause a cyclical dependency. + withMetrics := metrics.Enabled && metricsAddr == "" + StartPProf(address, withMetrics) + } + return nil +} + +func StartPProf(address string, withMetrics bool) { + // Hook go-metrics into expvar on any /debug/metrics request, load all vars + // from the registry into expvar, and execute regular expvar handler. + if withMetrics { + http.HandleFunc("/debug/metrics/prometheus", func(w http.ResponseWriter, req *http.Request) { + w.Header().Set("Access-Control-Allow-Origin", "*") + metrics2.WritePrometheus(w, true) + }) + } + cpuMsg := fmt.Sprintf("go tool pprof -lines -http=: http://%s/%s", address, "debug/pprof/profile?seconds=20") + heapMsg := fmt.Sprintf("go tool pprof -lines -http=: http://%s/%s", address, "debug/pprof/heap") + log.Info("Starting pprof server", "cpu", cpuMsg, "heap", heapMsg) + go func() { + if err := http.ListenAndServe(address, nil); err != nil { // nolint:gosec + log.Error("Failure in running pprof server", "err", err) + } + }() +} + +// Exit stops all running profiles, flushing their output to the +// respective file. +func Exit() { + _ = Handler.StopCPUProfile() + _ = Handler.StopGoTrace() +} + +// RaiseFdLimit raises out the number of allowed file handles per process +func RaiseFdLimit() { + limit, err := fdlimit.Maximum() + if err != nil { + log.Error("Failed to retrieve file descriptor allowance", "err", err) + return + } + if _, err = fdlimit.Raise(uint64(limit)); err != nil { + log.Error("Failed to raise file descriptor allowance", "err", err) + } +} diff --git a/erigon_internal/debug/loudpanic.go b/erigon_internal/debug/loudpanic.go new file mode 100644 index 0000000..3412d87 --- /dev/null +++ b/erigon_internal/debug/loudpanic.go @@ -0,0 +1,27 @@ +// Copyright 2016 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +//go:build go1.6 + +package debug + +import "runtime/debug" + +// LoudPanic panics in a way that gets all goroutine stacks printed on stderr. +func LoudPanic(x interface{}) { + debug.SetTraceback("all") + panic(x) +} diff --git a/erigon_internal/debug/loudpanic_fallback.go b/erigon_internal/debug/loudpanic_fallback.go new file mode 100644 index 0000000..a909f9d --- /dev/null +++ b/erigon_internal/debug/loudpanic_fallback.go @@ -0,0 +1,24 @@ +// Copyright 2016 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +//go:build !go1.6 + +package debug + +// LoudPanic panics in a way that gets all goroutine stacks printed on stderr. +func LoudPanic(x interface{}) { + panic(x) +} diff --git a/erigon_internal/debug/signal.go b/erigon_internal/debug/signal.go new file mode 100644 index 0000000..85e1088 --- /dev/null +++ b/erigon_internal/debug/signal.go @@ -0,0 +1,43 @@ +//go:build !windows + +package debug + +import ( + "io" + "os" + "os/signal" + "runtime/pprof" + + _debug "github.com/ledgerwatch/erigon/common/debug" + "github.com/ledgerwatch/log/v3" + "golang.org/x/sys/unix" +) + +func ListenSignals(stack io.Closer) { + sigc := make(chan os.Signal, 1) + signal.Notify(sigc, unix.SIGINT, unix.SIGTERM) + _debug.GetSigC(&sigc) + defer signal.Stop(sigc) + + usr1 := make(chan os.Signal, 1) + signal.Notify(usr1, unix.SIGUSR1) + for { + select { + case <-sigc: + log.Info("Got interrupt, shutting down...") + if stack != nil { + go stack.Close() + } + for i := 10; i > 0; i-- { + <-sigc + if i > 1 { + log.Warn("Already shutting down, interrupt more to panic.", "times", i-1) + } + } + Exit() // ensure trace and CPU profile data is flushed. + LoudPanic("boom") + case <-usr1: + pprof.Lookup("goroutine").WriteTo(os.Stdout, 1) + } + } +} diff --git a/erigon_internal/debug/signal_windows.go b/erigon_internal/debug/signal_windows.go new file mode 100644 index 0000000..ea731be --- /dev/null +++ b/erigon_internal/debug/signal_windows.go @@ -0,0 +1,33 @@ +//go:build windows + +package debug + +import ( + "io" + "os" + "os/signal" + + _debug "github.com/ledgerwatch/erigon/common/debug" + "github.com/ledgerwatch/log/v3" +) + +func ListenSignals(stack io.Closer) { + sigc := make(chan os.Signal, 1) + signal.Notify(sigc, os.Interrupt) + _debug.GetSigC(&sigc) + defer signal.Stop(sigc) + + <-sigc + log.Info("Got interrupt, shutting down...") + if stack != nil { + go stack.Close() + } + for i := 10; i > 0; i-- { + <-sigc + if i > 1 { + log.Warn("Already shutting down, interrupt more to panic.", "times", i-1) + } + } + Exit() // ensure trace and CPU profile data is flushed. + LoudPanic("boom") +} diff --git a/erigon_internal/debug/trace.go b/erigon_internal/debug/trace.go new file mode 100644 index 0000000..b9902e7 --- /dev/null +++ b/erigon_internal/debug/trace.go @@ -0,0 +1,63 @@ +// Copyright 2016 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +//go:build go1.5 + +package debug + +import ( + "errors" + "os" + "runtime/trace" + + "github.com/ledgerwatch/log/v3" +) + +// StartGoTrace turns on tracing, writing to the given file. +func (h *HandlerT) StartGoTrace(file string) error { + h.mu.Lock() + defer h.mu.Unlock() + if h.traceW != nil { + return errors.New("trace already in progress") + } + f, err := os.Create(expandHome(file)) + if err != nil { + return err + } + if err := trace.Start(f); err != nil { + f.Close() + return err + } + h.traceW = f + h.traceFile = file + log.Info("Go tracing started", "dump", h.traceFile) + return nil +} + +// StopTrace stops an ongoing trace. +func (h *HandlerT) StopGoTrace() error { + h.mu.Lock() + defer h.mu.Unlock() + trace.Stop() + if h.traceW == nil { + return errors.New("trace not in progress") + } + log.Info("Done writing Go trace", "dump", h.traceFile) + h.traceW.Close() + h.traceW = nil + h.traceFile = "" + return nil +} diff --git a/erigon_internal/debug/trace_fallback.go b/erigon_internal/debug/trace_fallback.go new file mode 100644 index 0000000..ffe506e --- /dev/null +++ b/erigon_internal/debug/trace_fallback.go @@ -0,0 +1,31 @@ +// Copyright 2016 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +//go:build !go1.5 + +// no-op implementation of tracing methods for Go < 1.5. + +package debug + +import "errors" + +func (*HandlerT) StartGoTrace(string) error { + return errors.New("tracing is not supported on Go < 1.5") +} + +func (*HandlerT) StopGoTrace() error { + return errors.New("tracing is not supported on Go < 1.5") +} diff --git a/erigon_internal/ethapi/api.go b/erigon_internal/ethapi/api.go new file mode 100644 index 0000000..2c8d96a --- /dev/null +++ b/erigon_internal/ethapi/api.go @@ -0,0 +1,1039 @@ +// Copyright 2015 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package ethapi + +import ( + "errors" + "fmt" + "math/big" + + "github.com/holiman/uint256" + "github.com/ledgerwatch/erigon/accounts/abi" + "github.com/ledgerwatch/erigon/common" + "github.com/ledgerwatch/erigon/common/hexutil" + "github.com/ledgerwatch/erigon/common/math" + "github.com/ledgerwatch/erigon/core" + "github.com/ledgerwatch/erigon/core/types" + "github.com/ledgerwatch/erigon/core/vm" + "github.com/ledgerwatch/log/v3" +) + +// CallArgs represents the arguments for a call. +type CallArgs struct { + From *common.Address `json:"from"` + To *common.Address `json:"to"` + Gas *hexutil.Uint64 `json:"gas"` + GasPrice *hexutil.Big `json:"gasPrice"` + MaxPriorityFeePerGas *hexutil.Big `json:"maxPriorityFeePerGas"` + MaxFeePerGas *hexutil.Big `json:"maxFeePerGas"` + Value *hexutil.Big `json:"value"` + Nonce *hexutil.Uint64 `json:"nonce"` + Data *hexutil.Bytes `json:"data"` + AccessList *types.AccessList `json:"accessList"` + ChainID *hexutil.Big `json:"chainId,omitempty"` +} + +// from retrieves the transaction sender address. +func (arg *CallArgs) from() common.Address { + if arg.From == nil { + return common.Address{} + } + return *arg.From +} + +// ToMessage converts CallArgs to the Message type used by the core evm +func (args *CallArgs) ToMessage(globalGasCap uint64, baseFee *uint256.Int) (types.Message, error) { + // Reject invalid combinations of pre- and post-1559 fee styles + if args.GasPrice != nil && (args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil) { + return types.Message{}, errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified") + } + // Set sender address or use zero address if none specified. + addr := args.from() + + // Set default gas & gas price if none were set + gas := globalGasCap + if gas == 0 { + gas = uint64(math.MaxUint64 / 2) + } + if args.Gas != nil { + gas = uint64(*args.Gas) + } + if globalGasCap != 0 && globalGasCap < gas { + log.Warn("Caller gas above allowance, capping", "requested", gas, "cap", globalGasCap) + gas = globalGasCap + } + + var ( + gasPrice *uint256.Int + gasFeeCap *uint256.Int + gasTipCap *uint256.Int + ) + if baseFee == nil { + // If there's no basefee, then it must be a non-1559 execution + gasPrice = new(uint256.Int) + if args.GasPrice != nil { + overflow := gasPrice.SetFromBig(args.GasPrice.ToInt()) + if overflow { + return types.Message{}, fmt.Errorf("args.GasPrice higher than 2^256-1") + } + } + gasFeeCap, gasTipCap = gasPrice, gasPrice + } else { + // A basefee is provided, necessitating 1559-type execution + if args.GasPrice != nil { + // User specified the legacy gas field, convert to 1559 gas typing + gasPrice = new(uint256.Int) + overflow := gasPrice.SetFromBig(args.GasPrice.ToInt()) + if overflow { + return types.Message{}, fmt.Errorf("args.GasPrice higher than 2^256-1") + } + gasFeeCap, gasTipCap = gasPrice, gasPrice + } else { + // User specified 1559 gas feilds (or none), use those + gasFeeCap = new(uint256.Int) + if args.MaxFeePerGas != nil { + overflow := gasFeeCap.SetFromBig(args.MaxFeePerGas.ToInt()) + if overflow { + return types.Message{}, fmt.Errorf("args.GasPrice higher than 2^256-1") + } + } + gasTipCap = new(uint256.Int) + if args.MaxPriorityFeePerGas != nil { + overflow := gasTipCap.SetFromBig(args.MaxPriorityFeePerGas.ToInt()) + if overflow { + return types.Message{}, fmt.Errorf("args.GasPrice higher than 2^256-1") + } + } + // Backfill the legacy gasPrice for EVM execution, unless we're all zeroes + gasPrice = new(uint256.Int) + if !gasFeeCap.IsZero() || !gasTipCap.IsZero() { + gasPrice = math.U256Min(new(uint256.Int).Add(gasTipCap, baseFee), gasFeeCap) + } + } + } + + value := new(uint256.Int) + if args.Value != nil { + overflow := value.SetFromBig(args.Value.ToInt()) + if overflow { + return types.Message{}, fmt.Errorf("args.Value higher than 2^256-1") + } + } + var data []byte + if args.Data != nil { + data = *args.Data + } + var accessList types.AccessList + if args.AccessList != nil { + accessList = *args.AccessList + } + + msg := types.NewMessage(addr, args.To, 0, value, gas, gasPrice, gasFeeCap, gasTipCap, data, accessList, false) + return msg, nil +} + +// account indicates the overriding fields of account during the execution of +// a message call. +// Note, state and stateDiff can't be specified at the same time. If state is +// set, message execution will only use the data in the given state. Otherwise +// if statDiff is set, all diff will be applied first and then execute the call +// message. +type Account struct { + Nonce *hexutil.Uint64 `json:"nonce"` + Code *hexutil.Bytes `json:"code"` + Balance **hexutil.Big `json:"balance"` + State *map[common.Hash]uint256.Int `json:"state"` + StateDiff *map[common.Hash]uint256.Int `json:"stateDiff"` +} + +func NewRevertError(result *core.ExecutionResult) *RevertError { + reason, errUnpack := abi.UnpackRevert(result.Revert()) + err := errors.New("execution reverted") + if errUnpack == nil { + err = fmt.Errorf("execution reverted: %v", reason) + } + return &RevertError{ + error: err, + reason: hexutil.Encode(result.Revert()), + } +} + +// RevertError is an API error that encompassas an EVM revertal with JSON error +// code and a binary data blob. +type RevertError struct { + error + reason string // revert reason hex encoded +} + +// ErrorCode returns the JSON error code for a revertal. +// See: https://github.com/ethereum/wiki/wiki/JSON-RPC-Error-Codes-Improvement-Proposal +func (e *RevertError) ErrorCode() int { + return 3 +} + +// ErrorData returns the hex encoded revert reason. +func (e *RevertError) ErrorData() interface{} { + return e.reason +} + +// ExecutionResult groups all structured logs emitted by the EVM +// while replaying a transaction in debug mode as well as transaction +// execution status, the amount of gas used and the return value +type ExecutionResult struct { + Gas uint64 `json:"gas"` + Failed bool `json:"failed"` + ReturnValue string `json:"returnValue"` + StructLogs []StructLogRes `json:"structLogs"` +} + +// StructLogRes stores a structured log emitted by the EVM while replaying a +// transaction in debug mode +type StructLogRes struct { + Pc uint64 `json:"pc"` + Op string `json:"op"` + Gas uint64 `json:"gas"` + GasCost uint64 `json:"gasCost"` + Depth int `json:"depth"` + Error error `json:"error,omitempty"` + Stack *[]string `json:"stack,omitempty"` + Memory *[]string `json:"memory,omitempty"` + Storage *map[string]string `json:"storage,omitempty"` +} + +// FormatLogs formats EVM returned structured logs for json output +func FormatLogs(logs []vm.StructLog) []StructLogRes { + formatted := make([]StructLogRes, len(logs)) + for index, trace := range logs { + formatted[index] = StructLogRes{ + Pc: trace.Pc, + Op: trace.Op.String(), + Gas: trace.Gas, + GasCost: trace.GasCost, + Depth: trace.Depth, + Error: trace.Err, + } + if trace.Stack != nil { + stack := make([]string, len(trace.Stack)) + for i, stackValue := range trace.Stack { + stack[i] = fmt.Sprintf("%x", math.PaddedBigBytes(stackValue, 32)) + } + formatted[index].Stack = &stack + } + if trace.Memory != nil { + memory := make([]string, 0, (len(trace.Memory)+31)/32) + for i := 0; i+32 <= len(trace.Memory); i += 32 { + memory = append(memory, fmt.Sprintf("%x", trace.Memory[i:i+32])) + } + formatted[index].Memory = &memory + } + if trace.Storage != nil { + storage := make(map[string]string) + for i, storageValue := range trace.Storage { + storage[fmt.Sprintf("%x", i)] = fmt.Sprintf("%x", storageValue) + } + formatted[index].Storage = &storage + } + } + return formatted +} + +// RPCMarshalHeader converts the given header to the RPC output . +func RPCMarshalHeader(head *types.Header) map[string]interface{} { + result := map[string]interface{}{ + "number": (*hexutil.Big)(head.Number), + "hash": head.Hash(), + "parentHash": head.ParentHash, + "nonce": head.Nonce, + "mixHash": head.MixDigest, + "sha3Uncles": head.UncleHash, + "logsBloom": head.Bloom, + "stateRoot": head.Root, + "miner": head.Coinbase, + "difficulty": (*hexutil.Big)(head.Difficulty), + "extraData": hexutil.Bytes(head.Extra), + "size": hexutil.Uint64(head.Size()), + "gasLimit": hexutil.Uint64(head.GasLimit), + "gasUsed": hexutil.Uint64(head.GasUsed), + "timestamp": hexutil.Uint64(head.Time), + "transactionsRoot": head.TxHash, + "receiptsRoot": head.ReceiptHash, + } + if head.BaseFee != nil { + result["baseFeePerGas"] = (*hexutil.Big)(head.BaseFee) + } + + return result +} + +// RPCMarshalBlock converts the given block to the RPC output which depends on fullTx. If inclTx is true transactions are +// returned. When fullTx is true the returned block contains full transaction details, otherwise it will only contain +// transaction hashes. +func RPCMarshalBlock(block *types.Block, inclTx bool, fullTx bool) (map[string]interface{}, error) { + return RPCMarshalBlockEx(block, inclTx, fullTx, nil, common.Hash{}) +} + +func RPCMarshalBlockEx(block *types.Block, inclTx bool, fullTx bool, borTx types.Transaction, borTxHash common.Hash) (map[string]interface{}, error) { + fields := RPCMarshalHeader(block.Header()) + fields["size"] = hexutil.Uint64(block.Size()) + if _, ok := fields["transactions"]; !ok { + fields["transactions"] = make([]interface{}, 0) + } + + if inclTx { + formatTx := func(tx types.Transaction, index int) (interface{}, error) { + return tx.Hash(), nil + } + if fullTx { + formatTx = func(tx types.Transaction, index int) (interface{}, error) { + return newRPCTransactionFromBlockAndTxGivenIndex(block, tx, uint64(index)), nil + } + } + txs := block.Transactions() + transactions := make([]interface{}, len(txs), len(txs)+1) + var err error + for i, tx := range txs { + if transactions[i], err = formatTx(tx, i); err != nil { + return nil, err + } + } + + if borTx != nil { + if fullTx { + transactions = append(transactions, newRPCBorTransaction(borTx, borTxHash, block.Hash(), block.NumberU64(), uint64(len(txs)), block.BaseFee())) + } else { + transactions = append(transactions, borTxHash) + } + } + + fields["transactions"] = transactions + } + uncles := block.Uncles() + uncleHashes := make([]common.Hash, len(uncles)) + for i, uncle := range uncles { + uncleHashes[i] = uncle.Hash() + } + fields["uncles"] = uncleHashes + + return fields, nil +} + +/* + +// rpcMarshalHeader uses the generalized output filler, then adds the total difficulty field, which requires +// a `PublicBlockchainAPI`. +func (s *PublicBlockChainAPI) rpcMarshalHeader(ctx context.Context, header *types.Header) map[string]interface{} { + fields := RPCMarshalHeader(header) + fields["totalDifficulty"] = (*hexutil.Big)(s.b.GetTd(ctx, header.Hash())) + return fields +} + +// rpcMarshalBlock uses the generalized output filler, then adds the total difficulty field, which requires +// a `PublicBlockchainAPI`. +func (s *PublicBlockChainAPI) rpcMarshalBlock(ctx context.Context, b *types.Block, inclTx bool, fullTx bool) (map[string]interface{}, error) { + fields, err := RPCMarshalBlock(b, inclTx, fullTx) + if err != nil { + return nil, err + } + if inclTx { + fields["totalDifficulty"] = (*hexutil.Big)(s.b.GetTd(ctx, b.Hash())) + } + return fields, err +} +*/ + +// RPCTransaction represents a transaction that will serialize to the RPC representation of a transaction +type RPCTransaction struct { + BlockHash *common.Hash `json:"blockHash"` + BlockNumber *hexutil.Big `json:"blockNumber"` + From common.Address `json:"from"` + Gas hexutil.Uint64 `json:"gas"` + GasPrice *hexutil.Big `json:"gasPrice,omitempty"` + Tip *hexutil.Big `json:"maxPriorityFeePerGas,omitempty"` + FeeCap *hexutil.Big `json:"maxFeePerGas,omitempty"` + Hash common.Hash `json:"hash"` + Input hexutil.Bytes `json:"input"` + Nonce hexutil.Uint64 `json:"nonce"` + To *common.Address `json:"to"` + TransactionIndex *hexutil.Uint64 `json:"transactionIndex"` + Value *hexutil.Big `json:"value"` + Type hexutil.Uint64 `json:"type"` + Accesses *types.AccessList `json:"accessList,omitempty"` + ChainID *hexutil.Big `json:"chainId,omitempty"` + V *hexutil.Big `json:"v"` + R *hexutil.Big `json:"r"` + S *hexutil.Big `json:"s"` +} + +// newRPCTransaction returns a transaction that will serialize to the RPC +// representation, with the given location metadata set (if available). +func newRPCTransaction(tx types.Transaction, blockHash common.Hash, blockNumber uint64, index uint64, baseFee *big.Int) *RPCTransaction { + // Determine the signer. For replay-protected transactions, use the most permissive + // signer, because we assume that signers are backwards-compatible with old + // transactions. For non-protected transactions, the homestead signer signer is used + // because the return value of ChainId is zero for those transactions. + chainId := uint256.NewInt(0) + result := &RPCTransaction{ + Type: hexutil.Uint64(tx.Type()), + Gas: hexutil.Uint64(tx.GetGas()), + Hash: tx.Hash(), + Input: hexutil.Bytes(tx.GetData()), + Nonce: hexutil.Uint64(tx.GetNonce()), + To: tx.GetTo(), + Value: (*hexutil.Big)(tx.GetValue().ToBig()), + } + switch t := tx.(type) { + case *types.LegacyTx: + chainId = types.DeriveChainId(&t.V) + result.ChainID = (*hexutil.Big)(chainId.ToBig()) + result.GasPrice = (*hexutil.Big)(t.GasPrice.ToBig()) + result.V = (*hexutil.Big)(t.V.ToBig()) + result.R = (*hexutil.Big)(t.R.ToBig()) + result.S = (*hexutil.Big)(t.S.ToBig()) + case *types.AccessListTx: + chainId.Set(t.ChainID) + result.ChainID = (*hexutil.Big)(chainId.ToBig()) + result.GasPrice = (*hexutil.Big)(t.GasPrice.ToBig()) + result.V = (*hexutil.Big)(t.V.ToBig()) + result.R = (*hexutil.Big)(t.R.ToBig()) + result.S = (*hexutil.Big)(t.S.ToBig()) + if len(t.AccessList) > 0 { + result.Accesses = &t.AccessList + } + case *types.DynamicFeeTransaction: + chainId.Set(t.ChainID) + result.ChainID = (*hexutil.Big)(chainId.ToBig()) + result.Tip = (*hexutil.Big)(t.Tip.ToBig()) + result.FeeCap = (*hexutil.Big)(t.FeeCap.ToBig()) + result.V = (*hexutil.Big)(t.V.ToBig()) + result.R = (*hexutil.Big)(t.R.ToBig()) + result.S = (*hexutil.Big)(t.S.ToBig()) + if len(t.AccessList) > 0 { + result.Accesses = &t.AccessList + } + // if the transaction has been mined, compute the effective gas price + if baseFee != nil && blockHash != (common.Hash{}) { + // price = min(tip, gasFeeCap - baseFee) + baseFee + price := math.BigMin(new(big.Int).Add(t.Tip.ToBig(), baseFee), t.FeeCap.ToBig()) + result.GasPrice = (*hexutil.Big)(price) + } else { + result.GasPrice = nil + } + } + signer := types.LatestSignerForChainID(chainId.ToBig()) + var err error + result.From, err = tx.Sender(*signer) + if err != nil { + log.Warn("sender recovery", "err", err) + } + if blockHash != (common.Hash{}) { + result.BlockHash = &blockHash + result.BlockNumber = (*hexutil.Big)(new(big.Int).SetUint64(blockNumber)) + result.TransactionIndex = (*hexutil.Uint64)(&index) + } + return result +} + +// newRPCBorTransaction returns a Bor transaction that will serialize to the RPC +// representation, with the given location metadata set (if available). +func newRPCBorTransaction(opaqueTx types.Transaction, txHash common.Hash, blockHash common.Hash, blockNumber uint64, index uint64, baseFee *big.Int) *RPCTransaction { + tx := opaqueTx.(*types.LegacyTx) + result := &RPCTransaction{ + Type: hexutil.Uint64(tx.Type()), + ChainID: (*hexutil.Big)(new(big.Int)), + GasPrice: (*hexutil.Big)(tx.GasPrice.ToBig()), + Gas: hexutil.Uint64(tx.GetGas()), + Hash: txHash, + Input: hexutil.Bytes(tx.GetData()), + Nonce: hexutil.Uint64(tx.GetNonce()), + From: common.Address{}, + To: tx.GetTo(), + Value: (*hexutil.Big)(tx.GetValue().ToBig()), + V: (*hexutil.Big)(big.NewInt(0)), + R: (*hexutil.Big)(big.NewInt(0)), + S: (*hexutil.Big)(big.NewInt(0)), + } + if blockHash != (common.Hash{}) { + result.BlockHash = &blockHash + result.BlockNumber = (*hexutil.Big)(new(big.Int).SetUint64(blockNumber)) + result.TransactionIndex = (*hexutil.Uint64)(&index) + } + return result +} + +/* +// newRPCPendingTransaction returns a pending transaction that will serialize to the RPC representation +func newRPCPendingTransaction(tx types.Transaction) *RPCTransaction { + return newRPCTransaction(tx, common.Hash{}, 0, 0) +} +*/ + +/* +// newRPCTransactionFromBlockIndex returns a transaction that will serialize to the RPC representation. +func newRPCTransactionFromBlockIndex(b *types.Block, index uint64) *RPCTransaction { + txs := b.Transactions() + if index >= uint64(len(txs)) { + return nil + } + return newRPCTransaction(txs[index], b.Hash(), b.NumberU64(), index, b.BaseFee()) +} +*/ + +// newRPCTransactionFromBlockAndTxGivenIndex returns a transaction that will serialize to the RPC representation. +func newRPCTransactionFromBlockAndTxGivenIndex(b *types.Block, tx types.Transaction, index uint64) *RPCTransaction { + return newRPCTransaction(tx, b.Hash(), b.NumberU64(), index, b.BaseFee()) +} + +/* +// newRPCRawTransactionFromBlockIndex returns the bytes of a transaction given a block and a transaction index. +func newRPCRawTransactionFromBlockIndex(b *types.Block, index uint64) hexutil.Bytes { + txs := b.Transactions() + if index >= uint64(len(txs)) { + return nil + } + var blob bytes.Buffer + if txs[index].Type() != types.LegacyTxType { + if err := blob.WriteByte(txs[index].Type()); err != nil { + panic(err) + } + } + if err := rlp.Encode(&blob, txs[index]); err != nil { + panic(err) + } + return blob.Bytes() +} +*/ + +/* +// newRPCTransactionFromBlockHash returns a transaction that will serialize to the RPC representation. +func newRPCTransactionFromBlockHash(b *types.Block, hash common.Hash) *RPCTransaction { + for idx, tx := range b.Transactions() { + if tx.Hash() == hash { + return newRPCTransactionFromBlockIndex(b, uint64(idx)) + } + } + return nil +} +*/ + +/* +// PublicTransactionPoolAPI exposes methods for the RPC interface +type PublicTransactionPoolAPI struct { + b Backend + nonceLock *AddrLocker + signer *types.Signer +} + +// NewPublicTransactionPoolAPI creates a new RPC service with methods specific for the transaction pool. +func NewPublicTransactionPoolAPI(b Backend, nonceLock *AddrLocker) *PublicTransactionPoolAPI { + // The signer used by the API should always be the 'latest' known one because we expect + // signers to be backwards-compatible with old transactions. + signer := types.LatestSigner(b.ChainConfig()) + return &PublicTransactionPoolAPI{b, nonceLock, signer} +} + +// GetBlockTransactionCountByNumber returns the number of transactions in the block with the given block number. +func (s *PublicTransactionPoolAPI) GetBlockTransactionCountByNumber(ctx context.Context, blockNr rpc.BlockNumber) *hexutil.Uint { + if block, _ := s.b.BlockByNumber(ctx, blockNr); block != nil { + n := hexutil.Uint(len(block.Transactions())) + return &n + } + return nil +} + +// GetBlockTransactionCountByHash returns the number of transactions in the block with the given hash. +func (s *PublicTransactionPoolAPI) GetBlockTransactionCountByHash(ctx context.Context, blockHash common.Hash) *hexutil.Uint { + if block, _ := s.b.BlockByHash(ctx, blockHash); block != nil { + n := hexutil.Uint(len(block.Transactions())) + return &n + } + return nil +} + +// GetTransactionByBlockNumberAndIndex returns the transaction for the given block number and index. +func (s *PublicTransactionPoolAPI) GetTransactionByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) *RPCTransaction { + if block, _ := s.b.BlockByNumber(ctx, blockNr); block != nil { + return newRPCTransactionFromBlockIndex(block, uint64(index)) + } + return nil +} + +// GetTransactionByBlockHashAndIndex returns the transaction for the given block hash and index. +func (s *PublicTransactionPoolAPI) GetTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) *RPCTransaction { + if block, _ := s.b.BlockByHash(ctx, blockHash); block != nil { + return newRPCTransactionFromBlockIndex(block, uint64(index)) + } + return nil +} + +// GetRawTransactionByBlockNumberAndIndex returns the bytes of the transaction for the given block number and index. +func (s *PublicTransactionPoolAPI) GetRawTransactionByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) hexutil.Bytes { + if block, _ := s.b.BlockByNumber(ctx, blockNr); block != nil { + return newRPCRawTransactionFromBlockIndex(block, uint64(index)) + } + return nil +} + +// GetRawTransactionByBlockHashAndIndex returns the bytes of the transaction for the given block hash and index. +func (s *PublicTransactionPoolAPI) GetRawTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) hexutil.Bytes { + if block, _ := s.b.BlockByHash(ctx, blockHash); block != nil { + return newRPCRawTransactionFromBlockIndex(block, uint64(index)) + } + return nil +} + +// GetTransactionCount returns the number of transactions the given address has sent for the given block number +func (s *PublicTransactionPoolAPI) GetTransactionCount(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (*hexutil.Uint64, error) { + // Ask transaction pool for the nonce which includes pending transactions + if blockNr, ok := blockNrOrHash.Number(); ok && blockNr == rpc.PendingBlockNumber { + nonce, err := s.b.GetPoolNonce(ctx, address) + if err != nil { + return nil, err + } + return (*hexutil.Uint64)(&nonce), nil + } + // Resolve block number and use its state to ask for the nonce + state, _, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash) + if state == nil || err != nil { + return nil, err + } + nonce := state.GetNonce(address) + return (*hexutil.Uint64)(&nonce), state.Error() +} + +// GetTransactionByHash returns the transaction for the given hash +func (s *PublicTransactionPoolAPI) GetTransactionByHash(ctx context.Context, hash common.Hash) (*RPCTransaction, error) { + // Try to return an already finalized transaction + tx, blockHash, blockNumber, index, err := s.b.GetTransaction(ctx, hash) + if err != nil { + return nil, err + } + if tx != nil { + return newRPCTransaction(tx, blockHash, blockNumber, index), nil + } + // No finalized transaction, try to retrieve it from the pool + if tx := s.b.GetPoolTransaction(hash); tx != nil { + return newRPCPendingTransaction(tx), nil + } + + // Transaction unknown, return as such + return nil, nil +} + +// GetRawTransactionByHash returns the bytes of the transaction for the given hash. +func (s *PublicTransactionPoolAPI) GetRawTransactionByHash(ctx context.Context, hash common.Hash) (hexutil.Bytes, error) { + // Retrieve a finalized transaction, or a pooled otherwise + tx, _, _, _, err := s.b.GetTransaction(ctx, hash) + if err != nil { + return nil, err + } + if tx == nil { + if tx = s.b.GetPoolTransaction(hash); tx == nil { + // Transaction not found anywhere, abort + return nil, nil + } + } + // Serialize to RLP and return + var blob bytes.Buffer + if tx.Type() != types.LegacyTxType { + if err := blob.WriteByte(tx.Type()); err != nil { + return nil, err + } + } + if err := rlp.Encode(&blob, tx); err != nil { + return nil, err + } + return blob.Bytes(), nil +} + +// GetTransactionReceipt returns the transaction receipt for the given transaction hash. +func (s *PublicTransactionPoolAPI) GetTransactionReceipt(ctx context.Context, hash common.Hash) (map[string]interface{}, error) { + tx, blockHash, blockNumber, index, err := s.b.GetTransaction(ctx, hash) + if err != nil { + return nil, nil + } + receipts, err := s.b.GetReceipts(ctx, blockHash) + if err != nil { + return nil, err + } + if len(receipts) <= int(index) { + return nil, nil + } + receipt := receipts[index] + + // Derive the sender. + signer := types.MakeSigner(s.b.ChainConfig(), blockNumber) + from, _ := tx.Sender(*signer) + + fields := map[string]interface{}{ + "blockHash": blockHash, + "blockNumber": hexutil.Uint64(blockNumber), + "transactionHash": hash, + "transactionIndex": hexutil.Uint64(index), + "from": from, + "to": tx.GetTo(), + "gasUsed": hexutil.Uint64(receipt.GasUsed), + "cumulativeGasUsed": hexutil.Uint64(receipt.CumulativeGasUsed), + "contractAddress": nil, + "logs": receipt.Logs, + "logsBloom": receipt.Bloom, + "type": hexutil.Uint(tx.Type()), + } + + // Assign receipt status or post state. + if len(receipt.PostState) > 0 { + fields["root"] = hexutil.Bytes(receipt.PostState) + } else { + fields["status"] = hexutil.Uint(receipt.Status) + } + if receipt.Logs == nil { + fields["logs"] = [][]*types.Log{} + } + // If the ContractAddress is 20 0x0 bytes, assume it is not a contract creation + if receipt.ContractAddress != (common.Address{}) { + fields["contractAddress"] = receipt.ContractAddress + } + return fields, nil +} + +// SendTxArgs represents the arguments to sumbit a new transaction into the transaction pool. +type SendTxArgs struct { + From common.Address `json:"from"` + To *common.Address `json:"to"` + Gas *hexutil.Uint64 `json:"gas"` + GasPrice *hexutil.Big `json:"gasPrice"` + MaxPriorityFeePerGas *hexutil.Big `json:"tip"` + MaxFeePerGas *hexutil.Big `json:"feeCap"` + Value *hexutil.Big `json:"value"` + Nonce *hexutil.Uint64 `json:"nonce"` + // We accept "data" and "input" for backwards-compatibility reasons. "input" is the + // newer name and should be preferred by clients. + Data *hexutil.Bytes `json:"data"` + Input *hexutil.Bytes `json:"input"` + + // For non-legacy transactions + AccessList *types.AccessList `json:"accessList,omitempty"` + ChainID *hexutil.Big `json:"chainId,omitempty"` +} + +// setDefaults fills in default values for unspecified tx fields. +func (args *SendTxArgs) setDefaults(ctx context.Context, b Backend) error { + if args.GasPrice == nil { + price, err := b.SuggestPrice(ctx) + if err != nil { + return err + } + args.GasPrice = (*hexutil.Big)(price) + } + if args.Value == nil { + args.Value = new(hexutil.Big) + } + if args.Nonce == nil { + nonce, err := b.GetPoolNonce(ctx, args.From) + if err != nil { + return err + } + args.Nonce = (*hexutil.Uint64)(&nonce) + } + if args.Data != nil && args.Input != nil && !bytes.Equal(*args.Data, *args.Input) { + return errors.New(`both "data" and "input" are set and not equal. Please use "input" to pass transaction call data`) + } + if args.To == nil { + // Contract creation + var input []byte + if args.Data != nil { + input = *args.Data + } else if args.Input != nil { + input = *args.Input + } + if len(input) == 0 { + return errors.New(`contract creation without any data provided`) + } + } + + // Estimate the gas usage if necessary. + if args.Gas == nil { + // For backwards-compatibility reason, we try both input and data + // but input is preferred. + input := args.Input + if input == nil { + input = args.Data + } + callArgs := CallArgs{ + From: &args.From, // From shouldn't be nil + To: args.To, + GasPrice: args.GasPrice, + Value: args.Value, + Data: input, + AccessList: args.AccessList, + } + pendingBlockNr := rpc.BlockNumberOrHashWithNumber(rpc.PendingBlockNumber) + estimated, err := DoEstimateGas(ctx, b, callArgs, pendingBlockNr, b.RPCGasCap()) + if err != nil { + return err + } + args.Gas = &estimated + log.Trace("Estimate gas usage automatically", "gas", args.Gas) + } + if args.ChainID == nil { + id := (*hexutil.Big)(b.ChainConfig().ChainID) + args.ChainID = id + } + return nil +} + +// toTransaction converts the arguments to a transaction. +// This assumes that setDefaults has been called. +func (args *SendTxArgs) toTransaction() types.Transaction { + var input []byte + if args.Input != nil { + input = *args.Input + } else if args.Data != nil { + input = *args.Data + } + + var tx types.Transaction + gasPrice, _ := uint256.FromBig((*big.Int)(args.GasPrice)) + value, _ := uint256.FromBig((*big.Int)(args.Value)) + if args.AccessList == nil { + tx = &types.LegacyTx{ + CommonTx: types.CommonTx{ + To: args.To, + Nonce: uint64(*args.Nonce), + Gas: uint64(*args.Gas), + Value: value, + Data: input, + }, + GasPrice: gasPrice, + } + } else { + chainId, _ := uint256.FromBig((*big.Int)(args.ChainID)) + if args.MaxFeePerGas == nil { + tx = &types.AccessListTx{ + LegacyTx: types.LegacyTx{ + CommonTx: types.CommonTx{ + To: args.To, + Nonce: uint64(*args.Nonce), + Gas: uint64(*args.Gas), + Value: value, + Data: input, + }, + GasPrice: gasPrice, + }, + ChainID: chainId, + AccessList: *args.AccessList, + } + } else { + tip, _ := uint256.FromBig((*big.Int)(args.MaxPriorityFeePerGas)) + feeCap, _ := uint256.FromBig((*big.Int)(args.MaxFeePerGas)) + tx = &types.DynamicFeeTransaction{ + CommonTx: types.CommonTx{ + To: args.To, + Nonce: uint64(*args.Nonce), + Gas: uint64(*args.Gas), + Value: value, + Data: input, + }, + MaxPriorityFeePerGas: tip, + MaxFeePerGas: feeCap, + ChainID: chainId, + AccessList: *args.AccessList, + } + } + } + return tx +} + +// SubmitTransaction is a helper function that submits tx to txPool and logs a message. +func SubmitTransaction(ctx context.Context, b Backend, tx types.Transaction) (common.Hash, error) { + // If the transaction fee cap is already specified, ensure the + // fee of the given transaction is _reasonable_. + if err := checkTxFee(tx.GetPrice().ToBig(), tx.GetGas(), b.RPCTxFeeCap()); err != nil { + return common.Hash{}, err + } + if !b.UnprotectedAllowed() && !tx.Protected() { + // Ensure only eip155 signed transactions are submitted if EIP155Required is set. + return common.Hash{}, errors.New("only replay-protected (EIP-155) transactions allowed over RPC") + } + if err := b.SendTx(ctx, tx); err != nil { + return common.Hash{}, err + } + // Print a log with full tx details for manual investigations and interventions + signer := types.MakeSigner(b.ChainConfig(), b.CurrentBlock().Number().Uint64()) + from, err := tx.Sender(*signer) + if err != nil { + return common.Hash{}, err + } + + if tx.GetTo() == nil { + addr := crypto.CreateAddress(from, tx.GetNonce()) + log.Info("Submitted contract creation", "hash", tx.Hash().Hex(), "from", from, "nonce", tx.GetNonce(), "contract", addr.Hex(), "value", tx.GetValue()) + } else { + log.Info("Submitted transaction", "hash", tx.Hash().Hex(), "from", from, "nonce", tx.GetNonce(), "recipient", tx.GetTo(), "value", tx.GetValue()) + } + return tx.Hash(), nil +} + +// FillTransaction fills the defaults (nonce, gas, gasPrice) on a given unsigned transaction, +// and returns it to the caller for further processing (signing + broadcast) +func (s *PublicTransactionPoolAPI) FillTransaction(ctx context.Context, args SendTxArgs) (*SignTransactionResult, error) { + // Set some sanity defaults and terminate on failure + if err := args.setDefaults(ctx, s.b); err != nil { + return nil, err + } + // Assemble the transaction and obtain rlp + tx := args.toTransaction() + var blob bytes.Buffer + if tx.Type() != types.LegacyTxType { + if err := blob.WriteByte(tx.Type()); err != nil { + return nil, err + } + } + if err := rlp.Encode(&blob, tx); err != nil { + return nil, err + } + return &SignTransactionResult{blob.Bytes(), tx}, nil +} + +// SendRawTransaction will add the signed transaction to the transaction pool. +// The sender is responsible for signing the transaction and using the correct nonce. +func (s *PublicTransactionPoolAPI) SendRawTransaction(ctx context.Context, input hexutil.Bytes) (common.Hash, error) { + tx, err := types.DecodeTransaction(rlp.NewStream(bytes.NewReader(input), 0)) + if err != nil { + return common.Hash{}, err + } + return SubmitTransaction(ctx, s.b, tx) +} + +// SignTransactionResult represents a RLP encoded signed transaction. +type SignTransactionResult struct { + Raw hexutil.Bytes `json:"raw"` + Tx types.Transaction `json:"tx"` +} + +// PublicDebugAPI is the collection of Ethereum APIs exposed over the public +// debugging endpoint. +type PublicDebugAPI struct { + b Backend +} + +// NewPublicDebugAPI creates a new API definition for the public debug methods +// of the Ethereum service. +func NewPublicDebugAPI(b Backend) *PublicDebugAPI { + return &PublicDebugAPI{b: b} +} + +// GetBlockRlp retrieves the RLP encoded for of a single block. +func (api *PublicDebugAPI) GetBlockRlp(ctx context.Context, number uint64) (string, error) { + block, _ := api.b.BlockByNumber(ctx, rpc.BlockNumber(number)) + if block == nil { + return "", fmt.Errorf("block #%d not found", number) + } + encoded, err := rlp.EncodeToBytes(block) + if err != nil { + return "", err + } + return fmt.Sprintf("%x", encoded), nil +} + +// PrintBlock retrieves a block and returns its pretty printed form. +func (api *PublicDebugAPI) PrintBlock(ctx context.Context, number uint64) (string, error) { + block, _ := api.b.BlockByNumber(ctx, rpc.BlockNumber(number)) + if block == nil { + return "", fmt.Errorf("block #%d not found", number) + } + return spew.Sdump(block), nil +} + +// SeedHash retrieves the seed hash of a block. +func (api *PublicDebugAPI) SeedHash(ctx context.Context, number uint64) (string, error) { + block, _ := api.b.BlockByNumber(ctx, rpc.BlockNumber(number)) + if block == nil { + return "", fmt.Errorf("block #%d not found", number) + } + return fmt.Sprintf("0x%x", ethash.SeedHash(number)), nil +} + +// PrivateDebugAPI is the collection of Ethereum APIs exposed over the private +// debugging endpoint. +type PrivateDebugAPI struct { + b Backend +} + +// NewPrivateDebugAPI creates a new API definition for the private debug methods +// of the Ethereum service. +func NewPrivateDebugAPI(b Backend) *PrivateDebugAPI { + return &PrivateDebugAPI{b: b} +} + +// ChaindbProperty returns properties of the chain database. +func (api *PrivateDebugAPI) ChaindbProperty(property string) (string, error) { + return "N/A", nil +} + +// ChaindbCompact flattens the entire key-value database into a single level, +// removing all unused slots and merging all keys. +func (api *PrivateDebugAPI) ChaindbCompact() error { + // Intentionally disabled in Erigon + return nil +} + +// SetHead rewinds the head of the blockchain to a previous block. +func (api *PrivateDebugAPI) SetHead(number hexutil.Uint64) { + api.b.SetHead(uint64(number)) +} + +// PublicNetAPI offers network related RPC methods +type PublicNetAPI struct { + net *p2p.Server + networkVersion uint64 +} + +// NewPublicNetAPI creates a new net API instance. +func NewPublicNetAPI(net *p2p.Server, networkVersion uint64) *PublicNetAPI { + return &PublicNetAPI{net, networkVersion} +} + +// Listening returns an indication if the node is listening for network connections. +func (s *PublicNetAPI) Listening() bool { + return true // always listening +} + +// PeerCount returns the number of connected peers +func (s *PublicNetAPI) PeerCount() hexutil.Uint { + return hexutil.Uint(s.net.PeerCount()) +} + +// Version returns the current ethereum protocol version. +func (s *PublicNetAPI) Version() string { + return fmt.Sprintf("%d", s.networkVersion) +} + +// checkTxFee is an internal function used to check whether the fee of +// the given transaction is _reasonable_(under the cap). +func checkTxFee(gasPrice *big.Int, gas uint64, cap float64) error { + // Short circuit if there is no cap for transaction fee at all. + if cap == 0 { + return nil + } + feeEth := new(big.Float).Quo(new(big.Float).SetInt(new(big.Int).Mul(gasPrice, new(big.Int).SetUint64(gas))), new(big.Float).SetInt(big.NewInt(params.Ether))) + feeFloat, _ := feeEth.Float64() + if feeFloat > cap { + return fmt.Errorf("tx fee (%.2f ether) exceeds the configured cap (%.2f ether)", feeFloat, cap) + } + return nil +} +*/ diff --git a/erigon_internal/ethapi/backend.go b/erigon_internal/ethapi/backend.go new file mode 100644 index 0000000..cef737c --- /dev/null +++ b/erigon_internal/ethapi/backend.go @@ -0,0 +1,56 @@ +// Copyright 2015 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +// Package ethapi implements the general Ethereum API functions. +package ethapi + +/* +func GetAPIs(apiBackend Backend) []rpc.API { + nonceLock := new(AddrLocker) + return []rpc.API{ + { + Namespace: "eth", + Version: "1.0", + Service: NewPublicEthereumAPI(apiBackend), + Public: true, + }, { + Namespace: "eth", + Version: "1.0", + Service: NewPublicBlockChainAPI(apiBackend), + Public: true, + }, { + Namespace: "eth", + Version: "1.0", + Service: NewPublicTransactionPoolAPI(apiBackend, nonceLock), + Public: true, + }, { + Namespace: "txpool", + Version: "1.0", + Service: NewPublicTxPoolAPI(apiBackend), + Public: true, + }, { + Namespace: "debug", + Version: "1.0", + Service: NewPublicDebugAPI(apiBackend), + Public: true, + }, { + Namespace: "debug", + Version: "1.0", + Service: NewPrivateDebugAPI(apiBackend), + }, + } +} +*/ diff --git a/erigon_internal/ethapi/get_proof.go b/erigon_internal/ethapi/get_proof.go new file mode 100644 index 0000000..6c45f59 --- /dev/null +++ b/erigon_internal/ethapi/get_proof.go @@ -0,0 +1,234 @@ +package ethapi + +import ( + "bytes" + + "github.com/ledgerwatch/erigon/common" + "github.com/ledgerwatch/erigon/common/hexutil" + "github.com/ledgerwatch/erigon/core/types/accounts" + "github.com/ledgerwatch/erigon/turbo/trie" +) + +// Result structs for GetProof +type AccountResult struct { + Address common.Address `json:"address"` + AccountProof []string `json:"accountProof"` + Balance *hexutil.Big `json:"balance"` + CodeHash common.Hash `json:"codeHash"` + Nonce hexutil.Uint64 `json:"nonce"` + StorageHash common.Hash `json:"storageHash"` + StorageProof []StorageResult `json:"storageProof"` +} +type StorageResult struct { + Key string `json:"key"` + Value *hexutil.Big `json:"value"` + Proof []string `json:"proof"` +} + +/*TODO: to support proofs +func (s *PublicBlockChainAPI) GetProof(ctx context.Context, address common.Address, storageKeys []string, blockNr rpc.BlockNumber) (*AccountResult, error) { + block := uint64(blockNr.Int64()) + 1 + db := s.b.ChainDb() + ts := dbutils.EncodeBlockNumber(block) + accountMap := make(map[string]*accounts.Account) + if err := changeset.Walk(db, dbutils.AccountChangeSetBucket, ts, 0, func(blockN uint64, a, v []byte) (bool, error) { + a, v = common.CopyBytes(a), common.CopyBytes(v) + var kHash, err = common.HashData(a) + if err != nil { + return false, err + } + k := kHash[:] + if _, ok := accountMap[string(k)]; !ok { + if len(v) > 0 { + var a accounts.Account + if innerErr := a.DecodeForStorage(v); innerErr != nil { + return false, innerErr + } + accountMap[string(k)] = &a + } else { + accountMap[string(k)] = nil + } + } + return true, nil + }); err != nil { + return nil, err + } + + storageMap := make(map[string][]byte) + if err := changeset.Walk(db, dbutils.AccountChangeSetBucket, ts, 0, func(blockN uint64, a, v []byte) (bool, error) { + a, v = common.CopyBytes(a), common.CopyBytes(v) + var kHash, err = common.HashData(a) + if err != nil { + return true, err + } + k := kHash[:] + if _, ok := storageMap[string(k)]; !ok { + storageMap[string(k)] = v + } + return true, nil + }); err != nil { + return nil, err + } + var unfurlList = make([]string, len(accountMap)+len(storageMap)) + unfurl := trie.NewRetainList(0) + i := 0 + for ks, acc := range accountMap { + unfurlList[i] = ks + i++ + unfurl.AddKey([]byte(ks)) + if acc != nil { + // Fill the code hashes + if acc.Incarnation > 0 && acc.IsEmptyCodeHash() { + if codeHash, err1 := db.Get(dbutils.ContractCodeBucket, dbutils.GenerateStoragePrefix([]byte(ks), acc.Incarnation)); err1 == nil { + copy(acc.CodeHash[:], codeHash) + } else { + return nil, err1 + } + } + } + } + for ks := range storageMap { + unfurlList[i] = ks + i++ + var sk [64]byte + copy(sk[:], []byte(ks)[:common.HashLength]) + copy(sk[common.HashLength:], []byte(ks)[common.HashLength+common.IncarnationLength:]) + unfurl.AddKey(sk[:]) + } + rl := trie.NewRetainList(0) + addrHash, err := common.HashData(address[:]) + if err != nil { + return nil, err + } + rl.AddKey(addrHash[:]) + unfurl.AddKey(addrHash[:]) + for _, key := range storageKeys { + keyAsHash := common.HexToHash(key) + if keyHash, err1 := common.HashData(keyAsHash[:]); err1 == nil { + trieKey := append(addrHash[:], keyHash[:]...) + rl.AddKey(trieKey) + unfurl.AddKey(trieKey) + } else { + return nil, err1 + } + } + sort.Strings(unfurlList) + loader := trie.NewFlatDBTrieLoader("checkRoots") + if err = loader.Reset(unfurl, nil, nil, false); err != nil { + panic(err) + } + r := &Receiver{defaultReceiver: trie.NewDefaultReceiver(), unfurlList: unfurlList, accountMap: accountMap, storageMap: storageMap} + r.defaultReceiver.Reset(rl, nil, false) + loader.SetStreamReceiver(r) + _, err = loader.CalcTrieRoot(db.(ethdb.HasTx).Tx().(ethdb.RwTx), []byte{}, nil) + if err != nil { + panic(err) + } + hash, err := rawdb.ReadCanonicalHash(db, block-1) + if err != nil { + return nil, err + } + header := rawdb.ReadHeader(db, hash, block-1) + tr := trie.New(header.Root) + if err = tr.HookSubTries(subTries, [][]byte{nil}); err != nil { + return nil, err + } + accountProof, err2 := tr.Prove(addrHash[:], 0, false) + if err2 != nil { + return nil, err2 + } + storageProof := make([]StorageResult, len(storageKeys)) + for i, key := range storageKeys { + keyAsHash := common.HexToHash(key) + if keyHash, err1 := common.HashData(keyAsHash[:]); err1 == nil { + trieKey := append(addrHash[:], keyHash[:]...) + if proof, err3 := tr.Prove(trieKey, 64 , true); err3 == nil { + v, _ := tr.Get(trieKey) + bv := new(big.Int) + bv.SetBytes(v) + storageProof[i] = StorageResult{key, (*hexutil.Big)(bv), toHexSlice(proof)} + } else { + return nil, err3 + } + } else { + return nil, err1 + } + } + acc, found := tr.GetAccount(addrHash[:]) + if !found { + return nil, nil + } + return &AccountResult{ + Address: address, + AccountProof: toHexSlice(accountProof), + Balance: (*hexutil.Big)(acc.Balance.ToBig()), + CodeHash: acc.CodeHash, + Nonce: hexutil.Uint64(acc.Nonce), + StorageHash: acc.Root, + StorageProof: storageProof, + }, nil + return &AccountResult{}, nil +} +*/ + +type Receiver struct { + defaultReceiver *trie.RootHashAggregator + accountMap map[string]*accounts.Account + storageMap map[string][]byte + unfurlList []string + currentIdx int +} + +func (r *Receiver) Root() common.Hash { panic("don't call me") } +func (r *Receiver) Receive( + itemType trie.StreamItem, + accountKey []byte, + storageKey []byte, + accountValue *accounts.Account, + storageValue []byte, + hash []byte, + hasTree bool, + cutoff int, +) error { + for r.currentIdx < len(r.unfurlList) { + ks := r.unfurlList[r.currentIdx] + k := []byte(ks) + var c int + switch itemType { + case trie.StorageStreamItem, trie.SHashStreamItem: + c = bytes.Compare(k, storageKey) + case trie.AccountStreamItem, trie.AHashStreamItem: + c = bytes.Compare(k, accountKey) + case trie.CutoffStreamItem: + c = -1 + } + if c > 0 { + return r.defaultReceiver.Receive(itemType, accountKey, storageKey, accountValue, storageValue, hash, hasTree, cutoff) + } + if len(k) > common.HashLength { + v := r.storageMap[ks] + if c <= 0 && len(v) > 0 { + if err := r.defaultReceiver.Receive(trie.StorageStreamItem, nil, k, nil, v, nil, hasTree, 0); err != nil { + return err + } + } + } else { + v := r.accountMap[ks] + if c <= 0 && v != nil { + if err := r.defaultReceiver.Receive(trie.AccountStreamItem, k, nil, v, nil, nil, hasTree, 0); err != nil { + return err + } + } + } + r.currentIdx++ + if c == 0 { + return nil + } + } + // We ran out of modifications, simply pass through + return r.defaultReceiver.Receive(itemType, accountKey, storageKey, accountValue, storageValue, hash, hasTree, cutoff) +} + +func (r *Receiver) Result() trie.SubTries { + return r.defaultReceiver.Result() +} diff --git a/erigon_internal/ethapi/state_overrides.go b/erigon_internal/ethapi/state_overrides.go new file mode 100644 index 0000000..d3159f3 --- /dev/null +++ b/erigon_internal/ethapi/state_overrides.go @@ -0,0 +1,50 @@ +package ethapi + +import ( + "fmt" + "math/big" + + "github.com/holiman/uint256" + "github.com/ledgerwatch/erigon/common" + "github.com/ledgerwatch/erigon/core/state" +) + +type StateOverrides map[common.Address]Account + +func (overrides *StateOverrides) Override(state *state.IntraBlockState) error { + + for addr, account := range *overrides { + // Override account nonce. + if account.Nonce != nil { + state.SetNonce(addr, uint64(*account.Nonce)) + } + // Override account(contract) code. + if account.Code != nil { + state.SetCode(addr, *account.Code) + } + // Override account balance. + if account.Balance != nil { + balance, overflow := uint256.FromBig((*big.Int)(*account.Balance)) + if overflow { + return fmt.Errorf("account.Balance higher than 2^256-1") + } + state.SetBalance(addr, balance) + } + if account.State != nil && account.StateDiff != nil { + return fmt.Errorf("account %s has both 'state' and 'stateDiff'", addr.Hex()) + } + // Replace entire state if caller requires. + if account.State != nil { + state.SetStorage(addr, *account.State) + } + // Apply state diff into specified accounts. + if account.StateDiff != nil { + for key, value := range *account.StateDiff { + key := key + state.SetState(addr, &key, value) + } + } + } + + return nil +} diff --git a/erigon_internal/logging/flags.go b/erigon_internal/logging/flags.go new file mode 100644 index 0000000..67d0fd9 --- /dev/null +++ b/erigon_internal/logging/flags.go @@ -0,0 +1,56 @@ +package logging + +import ( + "github.com/ledgerwatch/log/v3" + "github.com/urfave/cli" +) + +var ( + LogJsonFlag = cli.BoolFlag{ + Name: "log.json", + Usage: "Format console logs with JSON", + } + + LogConsoleJsonFlag = cli.BoolFlag{ + Name: "log.console.json", + Usage: "Format console logs with JSON", + } + + LogDirJsonFlag = cli.BoolFlag{ + Name: "log.dir.json", + Usage: "Format file logs with JSON", + } + + LogVerbosityFlag = cli.StringFlag{ + Name: "verbosity", + Usage: "Set the log level for console logs", + Value: log.LvlInfo.String(), + } + + LogConsoleVerbosityFlag = cli.StringFlag{ + Name: "log.console.verbosity", + Usage: "Set the log level for console logs", + Value: log.LvlInfo.String(), + } + + LogDirPathFlag = cli.StringFlag{ + Name: "log.dir.path", + Usage: "Path to store user and error logs to disk", + } + + LogDirVerbosityFlag = cli.StringFlag{ + Name: "log.dir.verbosity", + Usage: "Set the log verbosity for logs stored to disk", + Value: log.LvlDebug.String(), + } +) + +var Flags = []cli.Flag{ + LogJsonFlag, + LogConsoleJsonFlag, + LogDirJsonFlag, + LogVerbosityFlag, + LogConsoleVerbosityFlag, + LogDirPathFlag, + LogDirVerbosityFlag, +} diff --git a/erigon_internal/logging/logging.go b/erigon_internal/logging/logging.go new file mode 100644 index 0000000..7c83c2b --- /dev/null +++ b/erigon_internal/logging/logging.go @@ -0,0 +1,162 @@ +package logging + +import ( + "flag" + "os" + "path" + "strconv" + + "github.com/ledgerwatch/log/v3" + "github.com/spf13/cobra" + "github.com/urfave/cli" +) + +func GetLoggerCtx(filePrefix string, ctx *cli.Context) log.Logger { + var consoleJson = ctx.Bool(LogJsonFlag.Name) || ctx.Bool(LogConsoleJsonFlag.Name) + var dirJson = ctx.Bool(LogDirJsonFlag.Name) + + consoleLevel, lErr := tryGetLogLevel(ctx.String(LogConsoleVerbosityFlag.Name)) + if lErr != nil { + // try verbosity flag + consoleLevel, lErr = tryGetLogLevel(ctx.String(LogVerbosityFlag.Name)) + if lErr != nil { + consoleLevel = log.LvlInfo + } + } + + dirLevel, dErr := tryGetLogLevel(ctx.String(LogDirVerbosityFlag.Name)) + if dErr != nil { + dirLevel = log.LvlDebug + } + + dirPath := ctx.String(LogDirPathFlag.Name) + return initSeparatedLogging(filePrefix, dirPath, consoleLevel, dirLevel, consoleJson, dirJson) +} + +func GetLoggerCmd(filePrefix string, cmd *cobra.Command) log.Logger { + + logJsonVal, ljerr := cmd.Flags().GetBool(LogJsonFlag.Name) + if ljerr != nil { + logJsonVal = false + } + + logConsoleJsonVal, lcjerr := cmd.Flags().GetBool(LogConsoleJsonFlag.Name) + if lcjerr != nil { + logConsoleJsonVal = false + } + + var consoleJson = logJsonVal || logConsoleJsonVal + dirJson, djerr := cmd.Flags().GetBool(LogDirJsonFlag.Name) + if djerr != nil { + dirJson = false + } + + consoleLevel, lErr := tryGetLogLevel(cmd.Flags().Lookup(LogConsoleVerbosityFlag.Name).Value.String()) + if lErr != nil { + // try verbosity flag + consoleLevel, lErr = tryGetLogLevel(cmd.Flags().Lookup(LogVerbosityFlag.Name).Value.String()) + if lErr != nil { + consoleLevel = log.LvlInfo + } + } + + dirLevel, dErr := tryGetLogLevel(cmd.Flags().Lookup(LogDirVerbosityFlag.Name).Value.String()) + if dErr != nil { + dirLevel = log.LvlDebug + } + + dirPath := cmd.Flags().Lookup(LogDirPathFlag.Name).Value.String() + return initSeparatedLogging(filePrefix, dirPath, consoleLevel, dirLevel, consoleJson, dirJson) +} + +func GetLogger(filePrefix string) log.Logger { + var logConsoleVerbosity = flag.String(LogConsoleVerbosityFlag.Name, "", LogConsoleVerbosityFlag.Usage) + var logDirVerbosity = flag.String(LogDirVerbosityFlag.Name, "", LogDirVerbosityFlag.Usage) + var logDirPath = flag.String(LogDirPathFlag.Name, "", LogDirPathFlag.Usage) + var logVerbosity = flag.String(LogVerbosityFlag.Name, "", LogVerbosityFlag.Usage) + var logConsoleJson = flag.Bool(LogConsoleJsonFlag.Name, false, LogConsoleJsonFlag.Usage) + var logJson = flag.Bool(LogJsonFlag.Name, false, LogJsonFlag.Usage) + var logDirJson = flag.Bool(LogDirJsonFlag.Name, false, LogDirJsonFlag.Usage) + flag.Parse() + + var consoleJson = *logJson || *logConsoleJson + var dirJson = logDirJson + + consoleLevel, lErr := tryGetLogLevel(*logConsoleVerbosity) + if lErr != nil { + // try verbosity flag + consoleLevel, lErr = tryGetLogLevel(*logVerbosity) + if lErr != nil { + consoleLevel = log.LvlInfo + } + } + + dirLevel, dErr := tryGetLogLevel(*logDirVerbosity) + if dErr != nil { + dirLevel = log.LvlDebug + } + + return initSeparatedLogging(filePrefix, *logDirPath, consoleLevel, dirLevel, consoleJson, *dirJson) +} + +func initSeparatedLogging( + filePrefix string, + dirPath string, + consoleLevel log.Lvl, + dirLevel log.Lvl, + consoleJson bool, + dirJson bool) log.Logger { + + logger := log.Root() + + if consoleJson { + log.Root().SetHandler(log.LvlFilterHandler(consoleLevel, log.StreamHandler(os.Stderr, log.JsonFormat()))) + } else { + log.Root().SetHandler(log.LvlFilterHandler(consoleLevel, log.StderrHandler)) + } + + if len(dirPath) == 0 { + logger.Warn("no log dir set, console logging only") + return logger + } + + err := os.MkdirAll(dirPath, 0764) + if err != nil { + logger.Warn("failed to create log dir, console logging only") + return logger + } + + dirFormat := log.LogfmtFormat() + if dirJson { + dirFormat = log.JsonFormat() + } + + userLog, err := log.FileHandler(path.Join(dirPath, filePrefix+"-user.log"), dirFormat, 1<<27) // 128Mb + if err != nil { + logger.Warn("failed to open user log, console logging only") + return logger + } + errLog, err := log.FileHandler(path.Join(dirPath, filePrefix+"-error.log"), dirFormat, 1<<27) // 128Mb + if err != nil { + logger.Warn("failed to open error log, console logging only") + return logger + } + + mux := log.MultiHandler(logger.GetHandler(), log.LvlFilterHandler(dirLevel, userLog), log.LvlFilterHandler(log.LvlError, errLog)) + log.Root().SetHandler(mux) + logger.SetHandler(mux) + logger.Info("logging to file system", "log dir", dirPath, "file prefix", filePrefix, "log level", dirLevel, "json", dirJson) + return logger +} + +func tryGetLogLevel(s string) (log.Lvl, error) { + lvl, err := log.LvlFromString(s) + if err != nil { + l, err := strconv.Atoi(s) + if err != nil { + return 0, err + } + return log.Lvl(l), nil + } + return lvl, nil +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..51cd493 --- /dev/null +++ b/go.mod @@ -0,0 +1,149 @@ +module github.com/wmitsuda/otterscan + +go 1.19 + +replace github.com/tendermint/tendermint => github.com/bnb-chain/tendermint v0.31.12 + +require ( + github.com/RoaringBitmap/roaring v1.2.1 + github.com/VictoriaMetrics/metrics v1.22.2 + github.com/go-chi/chi/v5 v5.0.7 + github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d + github.com/holiman/uint256 v1.2.1 + github.com/ledgerwatch/erigon v1.9.7-0.20221024030055-592ad5792127 + github.com/ledgerwatch/erigon-lib v0.0.0-20221024030034-c1965e9c5ae3 + github.com/ledgerwatch/log/v3 v3.6.0 + github.com/spf13/cobra v1.5.0 + github.com/urfave/cli v1.22.9 + golang.org/x/sync v0.1.0 + golang.org/x/sys v0.1.0 + google.golang.org/grpc v1.50.1 + google.golang.org/protobuf v1.28.1 +) + +require ( + crawshaw.io/sqlite v0.3.3-0.20210127221821-98b1f83c5508 // indirect + github.com/VictoriaMetrics/fastcache v1.12.0 // indirect + github.com/ajwerner/btree v0.0.0-20211221152037-f427b3e689c0 // indirect + github.com/alecthomas/atomic v0.1.0-alpha2 // indirect + github.com/anacrolix/chansync v0.3.0 // indirect + github.com/anacrolix/dht/v2 v2.19.0 // indirect + github.com/anacrolix/envpprof v1.2.1 // indirect + github.com/anacrolix/generics v0.0.0-20220618083756-f99e35403a60 // indirect + github.com/anacrolix/go-libutp v1.2.0 // indirect + github.com/anacrolix/log v0.13.2-0.20220711050817-613cb738ef30 // indirect + github.com/anacrolix/missinggo v1.3.0 // indirect + github.com/anacrolix/missinggo/perf v1.0.0 // indirect + github.com/anacrolix/missinggo/v2 v2.7.0 // indirect + github.com/anacrolix/mmsg v1.0.0 // indirect + github.com/anacrolix/multiless v0.3.0 // indirect + github.com/anacrolix/stm v0.4.0 // indirect + github.com/anacrolix/sync v0.4.0 // indirect + github.com/anacrolix/torrent v1.47.0 // indirect + github.com/anacrolix/upnp v0.1.3-0.20220123035249-922794e51c96 // indirect + github.com/anacrolix/utp v0.1.0 // indirect + github.com/bahlo/generic-list-go v0.2.0 // indirect + github.com/benbjohnson/immutable v0.3.0 // indirect + github.com/benesch/cgosymbolizer v0.0.0-20190515212042-bec6fe6e597b // indirect + github.com/bits-and-blooms/bitset v1.2.2 // indirect + github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8 // indirect + github.com/btcsuite/btcd v0.22.0-beta // indirect + github.com/c2h5oh/datasize v0.0.0-20220606134207-859f65c6625b // indirect + github.com/cespare/xxhash/v2 v2.1.2 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect + github.com/crate-crypto/go-ipa v0.0.0-20220916134416-c5abbdbdf644 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/deckarep/golang-set v1.8.0 // indirect + github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91 // indirect + github.com/dop251/goja v0.0.0-20220405120441-9037c2b61cbf // indirect + github.com/dustin/go-humanize v1.0.0 // indirect + github.com/edsrzf/mmap-go v1.1.0 // indirect + github.com/emicklei/dot v1.0.0 // indirect + github.com/emirpasic/gods v1.18.1 // indirect + github.com/fjl/gencodec v0.0.0-20220412091415-8bb9e558978c // indirect + github.com/garslo/gogen v0.0.0-20170307003452-d6ebae628c7c // indirect + github.com/gballet/go-verkle v0.0.0-20220829125900-a702d458d33c // indirect + github.com/go-kit/kit v0.10.0 // indirect + github.com/go-logfmt/logfmt v0.5.1 // indirect + github.com/go-logr/logr v1.2.3 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect + github.com/go-stack/stack v1.8.1 // indirect + github.com/goccy/go-json v0.9.7 // indirect + github.com/gofrs/flock v0.8.1 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang-jwt/jwt/v4 v4.4.1 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/google/btree v1.1.2 // indirect + github.com/google/uuid v1.3.0 // indirect + github.com/gorilla/websocket v1.5.0 // indirect + github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect + github.com/huandu/xstrings v1.3.2 // indirect + github.com/huin/goupnp v1.0.3 // indirect + github.com/ianlancetaylor/cgosymbolizer v0.0.0-20220405231054-a1ae3e4bba26 // indirect + github.com/inconshreveable/mousetrap v1.0.0 // indirect + github.com/jackpal/go-nat-pmp v1.0.2 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/kevinburke/go-bindata v3.21.0+incompatible // indirect + github.com/ledgerwatch/erigon-snapshot v1.1.1-0.20221023043405-d157dec75e9a // indirect + github.com/ledgerwatch/secp256k1 v1.0.0 // indirect + github.com/lispad/go-generics-tools v1.1.0 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.16 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/mschoch/smat v0.2.0 // indirect + github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect + github.com/pelletier/go-toml/v2 v2.0.5 // indirect + github.com/pion/datachannel v1.5.2 // indirect + github.com/pion/dtls/v2 v2.1.5 // indirect + github.com/pion/ice/v2 v2.2.6 // indirect + github.com/pion/interceptor v0.1.11 // indirect + github.com/pion/logging v0.2.2 // indirect + github.com/pion/mdns v0.0.5 // indirect + github.com/pion/randutil v0.1.0 // indirect + github.com/pion/rtcp v1.2.9 // indirect + github.com/pion/rtp v1.7.13 // indirect + github.com/pion/sctp v1.8.2 // indirect + github.com/pion/sdp/v3 v3.0.5 // indirect + github.com/pion/srtp/v2 v2.0.9 // indirect + github.com/pion/stun v0.3.5 // indirect + github.com/pion/transport v0.13.1 // indirect + github.com/pion/turn/v2 v2.0.8 // indirect + github.com/pion/udp v0.1.1 // indirect + github.com/pion/webrtc/v3 v3.1.42 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/quasilyte/go-ruleguard/dsl v0.3.21 // indirect + github.com/rs/cors v1.8.2 // indirect + github.com/rs/dnscache v0.0.0-20211102005908-e0241e321417 // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/spaolacci/murmur3 v1.1.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/stretchr/testify v1.8.0 // indirect + github.com/tendermint/go-amino v0.14.1 // indirect + github.com/tendermint/tendermint v0.31.12 // indirect + github.com/tidwall/btree v1.3.1 // indirect + github.com/torquem-ch/mdbx-go v0.26.1 // indirect + github.com/ugorji/go/codec v1.1.13 // indirect + github.com/ugorji/go/codec/codecgen v1.1.13 // indirect + github.com/valyala/fastjson v1.6.3 // indirect + github.com/valyala/fastrand v1.1.0 // indirect + github.com/valyala/histogram v1.2.0 // indirect + github.com/xsleonard/go-merkle v1.1.0 // indirect + go.etcd.io/bbolt v1.3.6 // indirect + go.opentelemetry.io/otel v1.8.0 // indirect + go.opentelemetry.io/otel/trace v1.8.0 // indirect + go.uber.org/atomic v1.10.0 // indirect + golang.org/x/crypto v0.1.0 // indirect + golang.org/x/exp v0.0.0-20221018221608-02f3b879a704 // indirect + golang.org/x/mod v0.6.0 // indirect + golang.org/x/net v0.1.0 // indirect + golang.org/x/text v0.4.0 // indirect + golang.org/x/time v0.1.0 // indirect + golang.org/x/tools v0.2.0 // indirect + google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1 // indirect + google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.2.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..018e9a8 --- /dev/null +++ b/go.sum @@ -0,0 +1,889 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +crawshaw.io/iox v0.0.0-20181124134642-c51c3df30797 h1:yDf7ARQc637HoxDho7xjqdvO5ZA2Yb+xzv/fOnnvZzw= +crawshaw.io/iox v0.0.0-20181124134642-c51c3df30797/go.mod h1:sXBiorCo8c46JlQV3oXPKINnZ8mcqnye1EkVkqsectk= +crawshaw.io/sqlite v0.3.2/go.mod h1:igAO5JulrQ1DbdZdtVq48mnZUBAPOeFzer7VhDWNtW4= +crawshaw.io/sqlite v0.3.3-0.20210127221821-98b1f83c5508 h1:fILCBBFnjnrQ0whVJlGhfv1E/QiaFDNtGFBObEVRnYg= +crawshaw.io/sqlite v0.3.3-0.20210127221821-98b1f83c5508/go.mod h1:igAO5JulrQ1DbdZdtVq48mnZUBAPOeFzer7VhDWNtW4= +filippo.io/edwards25519 v1.0.0-rc.1 h1:m0VOOB23frXZvAOK44usCgLWvtsxIoMCTBGJZlpmGfU= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/RoaringBitmap/roaring v0.4.7/go.mod h1:8khRDP4HmeXns4xIj9oGrKSz7XTQiJx2zgh7AcNke4w= +github.com/RoaringBitmap/roaring v0.4.17/go.mod h1:D3qVegWTmfCaX4Bl5CrBE9hfrSrrXIr8KVNvRsDi1NI= +github.com/RoaringBitmap/roaring v0.4.23/go.mod h1:D0gp8kJQgE1A4LQ5wFLggQEyvDi06Mq5mKs52e1TwOo= +github.com/RoaringBitmap/roaring v1.2.1 h1:58/LJlg/81wfEHd5L9qsHduznOIhyv4qb1yWcSvVq9A= +github.com/RoaringBitmap/roaring v1.2.1/go.mod h1:icnadbWcNyfEHlYdr+tDlOTih1Bf/h+rzPpv4sbomAA= +github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= +github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= +github.com/VictoriaMetrics/fastcache v1.12.0 h1:vnVi/y9yKDcD9akmc4NqAoqgQhJrOwUF+j9LTgn4QDE= +github.com/VictoriaMetrics/fastcache v1.12.0/go.mod h1:tjiYeEfYXCqacuvYw/7UoDIeJaNxq6132xHICNP77w8= +github.com/VictoriaMetrics/metrics v1.22.2 h1:A6LsNidYwkAHetxsvNFaUWjtzu5ltdgNEoS6i7Bn+6I= +github.com/VictoriaMetrics/metrics v1.22.2/go.mod h1:rAr/llLpEnAdTehiNlUxKgnjcOuROSzpw0GvjpEbvFc= +github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= +github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= +github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= +github.com/ajwerner/btree v0.0.0-20211221152037-f427b3e689c0 h1:byYvvbfSo3+9efR4IeReh77gVs4PnNDR3AMOE9NJ7a0= +github.com/ajwerner/btree v0.0.0-20211221152037-f427b3e689c0/go.mod h1:q37NoqncT41qKc048STsifIt69LfUJ8SrWWcz/yam5k= +github.com/alecthomas/assert/v2 v2.0.0-alpha3 h1:pcHeMvQ3OMstAWgaeaXIAL8uzB9xMm2zlxt+/4ml8lk= +github.com/alecthomas/atomic v0.1.0-alpha2 h1:dqwXmax66gXvHhsOS4pGPZKqYOlTkapELkLb3MNdlH8= +github.com/alecthomas/atomic v0.1.0-alpha2/go.mod h1:zD6QGEyw49HIq19caJDc2NMXAy8rNi9ROrxtMXATfyI= +github.com/alecthomas/repr v0.0.0-20210801044451-80ca428c5142 h1:8Uy0oSf5co/NZXje7U1z8Mpep++QJOldL2hs/sBQf48= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8= +github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= +github.com/anacrolix/chansync v0.3.0 h1:lRu9tbeuw3wl+PhMu/r+JJCRu5ArFXIluOgdF0ao6/U= +github.com/anacrolix/chansync v0.3.0/go.mod h1:DZsatdsdXxD0WiwcGl0nJVwyjCKMDv+knl1q2iBjA2k= +github.com/anacrolix/dht/v2 v2.19.0 h1:A9oMHWRGbLmCyx1JlYzg79bDrur8V60+0ts8ZwEVYt4= +github.com/anacrolix/dht/v2 v2.19.0/go.mod h1:0h83KnnAQ2AUYhpQ/CkoZP45K41pjDAlPR9zGHgFjQE= +github.com/anacrolix/envpprof v0.0.0-20180404065416-323002cec2fa/go.mod h1:KgHhUaQMc8cC0+cEflSgCFNFbKwi5h54gqtVn8yhP7c= +github.com/anacrolix/envpprof v1.0.0/go.mod h1:KgHhUaQMc8cC0+cEflSgCFNFbKwi5h54gqtVn8yhP7c= +github.com/anacrolix/envpprof v1.1.0/go.mod h1:My7T5oSqVfEn4MD4Meczkw/f5lSIndGAKu/0SM/rkf4= +github.com/anacrolix/envpprof v1.2.1 h1:25TJe6t/i0AfzzldiGFKCpD+s+dk8lONBcacJZB2rdE= +github.com/anacrolix/envpprof v1.2.1/go.mod h1:My7T5oSqVfEn4MD4Meczkw/f5lSIndGAKu/0SM/rkf4= +github.com/anacrolix/generics v0.0.0-20220618083756-f99e35403a60 h1:k4/h2B1gGF+PJGyGHxs8nmHHt1pzWXZWBj6jn4OBlRc= +github.com/anacrolix/generics v0.0.0-20220618083756-f99e35403a60/go.mod h1:ff2rHB/joTV03aMSSn/AZNnaIpUw0h3njetGsaXcMy8= +github.com/anacrolix/go-libutp v1.2.0 h1:sjxoB+/ARiKUR7IK/6wLWyADIBqGmu1fm0xo+8Yy7u0= +github.com/anacrolix/go-libutp v1.2.0/go.mod h1:RrJ3KcaDcf9Jqp33YL5V/5CBEc6xMc7aJL8wXfuWL50= +github.com/anacrolix/log v0.3.0/go.mod h1:lWvLTqzAnCWPJA08T2HCstZi0L1y2Wyvm3FJgwU9jwU= +github.com/anacrolix/log v0.6.0/go.mod h1:lWvLTqzAnCWPJA08T2HCstZi0L1y2Wyvm3FJgwU9jwU= +github.com/anacrolix/log v0.10.0/go.mod h1:s5yBP/j046fm9odtUTbHOfDUq/zh1W8OkPpJtnX0oQI= +github.com/anacrolix/log v0.10.1-0.20220123034749-3920702c17f8/go.mod h1:GmnE2c0nvz8pOIPUSC9Rawgefy1sDXqposC2wgtBZE4= +github.com/anacrolix/log v0.13.2-0.20220711050817-613cb738ef30 h1:bAgFzUxN1K3U8KwOzqCOhiygOr5NqYO3kNlV9tvp2Rc= +github.com/anacrolix/log v0.13.2-0.20220711050817-613cb738ef30/go.mod h1:D4+CvN8SnruK6zIFS/xPoRJmtvtnxs+CSfDQ+BFxZ68= +github.com/anacrolix/lsan v0.0.0-20211126052245-807000409a62 h1:P04VG6Td13FHMgS5ZBcJX23NPC/fiC4cp9bXwYujdYM= +github.com/anacrolix/lsan v0.0.0-20211126052245-807000409a62/go.mod h1:66cFKPCO7Sl4vbFnAaSq7e4OXtdMhRSBagJGWgmpJbM= +github.com/anacrolix/missinggo v0.0.0-20180725070939-60ef2fbf63df/go.mod h1:kwGiTUTZ0+p4vAz3VbAI5a30t2YbvemcmspjKwrAz5s= +github.com/anacrolix/missinggo v1.1.0/go.mod h1:MBJu3Sk/k3ZfGYcS7z18gwfu72Ey/xopPFJJbTi5yIo= +github.com/anacrolix/missinggo v1.1.2-0.20190815015349-b888af804467/go.mod h1:MBJu3Sk/k3ZfGYcS7z18gwfu72Ey/xopPFJJbTi5yIo= +github.com/anacrolix/missinggo v1.2.1/go.mod h1:J5cMhif8jPmFoC3+Uvob3OXXNIhOUikzMt+uUjeM21Y= +github.com/anacrolix/missinggo v1.3.0 h1:06HlMsudotL7BAELRZs0yDZ4yVXsHXGi323QBjAVASw= +github.com/anacrolix/missinggo v1.3.0/go.mod h1:bqHm8cE8xr+15uVfMG3BFui/TxyB6//H5fwlq/TeqMc= +github.com/anacrolix/missinggo/perf v1.0.0 h1:7ZOGYziGEBytW49+KmYGTaNfnwUqP1HBsy6BqESAJVw= +github.com/anacrolix/missinggo/perf v1.0.0/go.mod h1:ljAFWkBuzkO12MQclXzZrosP5urunoLS0Cbvb4V0uMQ= +github.com/anacrolix/missinggo/v2 v2.2.0/go.mod h1:o0jgJoYOyaoYQ4E2ZMISVa9c88BbUBVQQW4QeRkNCGY= +github.com/anacrolix/missinggo/v2 v2.5.1/go.mod h1:WEjqh2rmKECd0t1VhQkLGTdIWXO6f6NLjp5GlMZ+6FA= +github.com/anacrolix/missinggo/v2 v2.5.2/go.mod h1:yNvsLrtZYRYCOI+KRH/JM8TodHjtIE/bjOGhQaLOWIE= +github.com/anacrolix/missinggo/v2 v2.7.0 h1:4fzOAAn/VCvfWGviLmh64MPMttrlYew81JdPO7nSHvI= +github.com/anacrolix/missinggo/v2 v2.7.0/go.mod h1:2IZIvmRTizALNYFYXsPR7ofXPzJgyBpKZ4kMqMEICkI= +github.com/anacrolix/mmsg v0.0.0-20180515031531-a4a3ba1fc8bb/go.mod h1:x2/ErsYUmT77kezS63+wzZp8E3byYB0gzirM/WMBLfw= +github.com/anacrolix/mmsg v1.0.0 h1:btC7YLjOn29aTUAExJiVUhQOuf/8rhm+/nWCMAnL3Hg= +github.com/anacrolix/mmsg v1.0.0/go.mod h1:x8kRaJY/dCrY9Al0PEcj1mb/uFHwP6GCJ9fLl4thEPc= +github.com/anacrolix/multiless v0.3.0 h1:5Bu0DZncjE4e06b9r1Ap2tUY4Au0NToBP5RpuEngSis= +github.com/anacrolix/multiless v0.3.0/go.mod h1:TrCLEZfIDbMVfLoQt5tOoiBS/uq4y8+ojuEVVvTNPX4= +github.com/anacrolix/stm v0.2.0/go.mod h1:zoVQRvSiGjGoTmbM0vSLIiaKjWtNPeTvXUSdJQA4hsg= +github.com/anacrolix/stm v0.4.0 h1:tOGvuFwaBjeu1u9X1eIh9TX8OEedEiEQ1se1FjhFnXY= +github.com/anacrolix/stm v0.4.0/go.mod h1:GCkwqWoAsP7RfLW+jw+Z0ovrt2OO7wRzcTtFYMYY5t8= +github.com/anacrolix/sync v0.0.0-20180808010631-44578de4e778/go.mod h1:s735Etp3joe/voe2sdaXLcqDdJSay1O0OPnM0ystjqk= +github.com/anacrolix/sync v0.3.0/go.mod h1:BbecHL6jDSExojhNtgTFSBcdGerzNc64tz3DCOj/I0g= +github.com/anacrolix/sync v0.4.0 h1:T+MdO/u87ir/ijWsTFsPYw5jVm0SMm4kVpg8t4KF38o= +github.com/anacrolix/sync v0.4.0/go.mod h1:BbecHL6jDSExojhNtgTFSBcdGerzNc64tz3DCOj/I0g= +github.com/anacrolix/tagflag v0.0.0-20180109131632-2146c8d41bf0/go.mod h1:1m2U/K6ZT+JZG0+bdMK6qauP49QT4wE5pmhJXOKKCHw= +github.com/anacrolix/tagflag v1.0.0/go.mod h1:1m2U/K6ZT+JZG0+bdMK6qauP49QT4wE5pmhJXOKKCHw= +github.com/anacrolix/tagflag v1.1.0/go.mod h1:Scxs9CV10NQatSmbyjqmqmeQNwGzlNe0CMUMIxqHIG8= +github.com/anacrolix/torrent v1.47.0 h1:aDUnhQZ8+kfStLICHiXOGGYVFgDENK+kz4q96linyRg= +github.com/anacrolix/torrent v1.47.0/go.mod h1:SYPxEUjMwqhDr3kWGzyQLkFMuAb1bgJ57JRMpuD3ZzE= +github.com/anacrolix/upnp v0.1.3-0.20220123035249-922794e51c96 h1:QAVZ3pN/J4/UziniAhJR2OZ9Ox5kOY2053tBbbqUPYA= +github.com/anacrolix/upnp v0.1.3-0.20220123035249-922794e51c96/go.mod h1:Wa6n8cYIdaG35x15aH3Zy6d03f7P728QfdcDeD/IEOs= +github.com/anacrolix/utp v0.1.0 h1:FOpQOmIwYsnENnz7tAGohA+r6iXpRjrq8ssKSre2Cp4= +github.com/anacrolix/utp v0.1.0/go.mod h1:MDwc+vsGEq7RMw6lr2GKOEqjWny5hO5OZXRVNaBJ2Dk= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= +github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= +github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= +github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= +github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= +github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= +github.com/benbjohnson/immutable v0.2.0/go.mod h1:uc6OHo6PN2++n98KHLxW8ef4W42ylHiQSENghE1ezxI= +github.com/benbjohnson/immutable v0.3.0 h1:TVRhuZx2wG9SZ0LRdqlbs9S5BZ6Y24hJEHTCgWHZEIw= +github.com/benbjohnson/immutable v0.3.0/go.mod h1:uc6OHo6PN2++n98KHLxW8ef4W42ylHiQSENghE1ezxI= +github.com/benesch/cgosymbolizer v0.0.0-20190515212042-bec6fe6e597b h1:5JgaFtHFRnOPReItxvhMDXbvuBkjSWE+9glJyF466yw= +github.com/benesch/cgosymbolizer v0.0.0-20190515212042-bec6fe6e597b/go.mod h1:eMD2XUcPsHYbakFEocKrWZp47G0MRJYoC60qFblGjpA= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= +github.com/bits-and-blooms/bitset v1.2.2 h1:J5gbX05GpMdBjCvQ9MteIg2KKDExr7DrgK+Yc15FvIk= +github.com/bits-and-blooms/bitset v1.2.2/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= +github.com/bnb-chain/tendermint v0.31.12 h1:g+blWaXkRw6iHa56lcRfRzPXHgURCWPmgIvaGBSV7Zc= +github.com/bnb-chain/tendermint v0.31.12/go.mod h1:j6XU7CArrhQ+9XBMRwdIz63iUxdVwSrZ8f7vP7gcCqg= +github.com/bradfitz/iter v0.0.0-20140124041915-454541ec3da2/go.mod h1:PyRFw1Lt2wKX4ZVSQ2mk+PeDa1rxyObEDlApuIsUKuo= +github.com/bradfitz/iter v0.0.0-20190303215204-33e6a9893b0c/go.mod h1:PyRFw1Lt2wKX4ZVSQ2mk+PeDa1rxyObEDlApuIsUKuo= +github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8 h1:GKTyiRCL6zVf5wWaqKnf+7Qs6GbEPfd4iMOitWzXJx8= +github.com/bradfitz/iter v0.0.0-20191230175014-e8f45d346db8/go.mod h1:spo1JLcs67NmW1aVLEgtA8Yy1elc+X8y5SRW1sFW4Og= +github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= +github.com/btcsuite/btcd v0.22.0-beta h1:LTDpDKUM5EeOFBPM8IXpinEcmZ6FWfNZbE3lfrfdnWo= +github.com/btcsuite/btcd v0.22.0-beta/go.mod h1:9n5ntfhhHQBIhUvlhDvD3Qg6fRUj4jkN0VB8L8svzOA= +github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= +github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= +github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce h1:YtWJF7RHm2pYCvA5t0RPmAaLUhREsKuKd+SLhxFbFeQ= +github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce/go.mod h1:0DVlHczLPewLcPGEIeUEzfOJhqGPQ0mJJRDBtD307+o= +github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= +github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= +github.com/btcsuite/goleveldb v1.0.0/go.mod h1:QiK9vBlgftBg6rWQIj6wFzbPfRjiykIEhBH4obrXJ/I= +github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= +github.com/btcsuite/snappy-go v1.0.0/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= +github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= +github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= +github.com/c2h5oh/datasize v0.0.0-20220606134207-859f65c6625b h1:6+ZFm0flnudZzdSE0JxlhR2hKnGPcNB35BjQf4RYQDY= +github.com/c2h5oh/datasize v0.0.0-20220606134207-859f65c6625b/go.mod h1:S/7n9copUssQ56c7aAgHqftWO4LTf4xY6CGWt8Bc+3M= +github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= +github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= +github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= +github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/crate-crypto/go-ipa v0.0.0-20220916134416-c5abbdbdf644 h1:1BOsVjUetPH2Lqv71Dh6uKLVj9WKdDr5KY57KZBbsWU= +github.com/crate-crypto/go-ipa v0.0.0-20220916134416-c5abbdbdf644/go.mod h1:gFnFS95y8HstDP6P9pPwzrxOOC5TRDkwbM+ao15ChAI= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/deckarep/golang-set v1.8.0 h1:sk9/l/KqpunDwP7pSjUg0keiOOLEnOBHzykLrsPppp4= +github.com/deckarep/golang-set v1.8.0/go.mod h1:5nI87KwE7wgsBU1F4GKAw2Qod7p5kyS383rP6+o6qqo= +github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91 h1:Izz0+t1Z5nI16/II7vuEo/nHjodOg0p7+OiDpjX5t1E= +github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= +github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/dop251/goja v0.0.0-20220405120441-9037c2b61cbf h1:Yt+4K30SdjOkRoRRm3vYNQgR+/ZIy0RmeUDZo7Y8zeQ= +github.com/dop251/goja v0.0.0-20220405120441-9037c2b61cbf/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk= +github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA7c8pLvoGndExHudxTDKZ84Pyvv+90pbBjbTz0Y= +github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v0.0.0-20180421182945-02af3965c54e/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= +github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= +github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= +github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= +github.com/edsrzf/mmap-go v1.1.0 h1:6EUwBLQ/Mcr1EYLE4Tn1VdW1A4ckqCQWZBw8Hr0kjpQ= +github.com/edsrzf/mmap-go v1.1.0/go.mod h1:19H/e8pUPLicwkyNgOykDXkJ9F0MHE+Z52B8EIth78Q= +github.com/emicklei/dot v1.0.0 h1:yyObALINBOuI1GdCRwVea2IPtGtVgh0NQgJDrE03Tqc= +github.com/emicklei/dot v1.0.0/go.mod h1:DeV7GvQtIw4h2u73RKBkkFdvVAz0D9fzeJrgPW6gy/s= +github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= +github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= +github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fjl/gencodec v0.0.0-20220412091415-8bb9e558978c h1:CndMRAH4JIwxbW8KYq6Q+cGWcGHz0FjGR3QqcInWcW0= +github.com/fjl/gencodec v0.0.0-20220412091415-8bb9e558978c/go.mod h1:AzA8Lj6YtixmJWL+wkKoBGsLWy9gFrAzi4g+5bCKwpY= +github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= +github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= +github.com/frankban/quicktest v1.9.0/go.mod h1:ui7WezCLWMWxVWr1GETZY3smRy0G4KWq9vcPtJmFl7Y= +github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= +github.com/garslo/gogen v0.0.0-20170307003452-d6ebae628c7c h1:uYNKzPntb8c6DKvP9EfrBjkLkU7pM4lM+uuHSIa8UtU= +github.com/garslo/gogen v0.0.0-20170307003452-d6ebae628c7c/go.mod h1:Q0X6pkwTILDlzrGEckF6HKjXe48EgsY/l7K7vhY4MW8= +github.com/gballet/go-verkle v0.0.0-20220829125900-a702d458d33c h1:zN3+0FLRcsoX/lVcgGC0EBtNcBvCXJWgMDmTbEz8pnw= +github.com/gballet/go-verkle v0.0.0-20220829125900-a702d458d33c/go.mod h1:o/XfIXWi4/GqbQirfRm5uTbXMG5NpqxkxblnbZ+QM9I= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE= +github.com/glycerine/go-unsnap-stream v0.0.0-20181221182339-f9677308dec2/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE= +github.com/glycerine/go-unsnap-stream v0.0.0-20190901134440-81cf024a9e0a/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE= +github.com/glycerine/goconvey v0.0.0-20180728074245-46e3a41ad493/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24= +github.com/glycerine/goconvey v0.0.0-20190315024820-982ee783a72e/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24= +github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24= +github.com/go-chi/chi/v5 v5.0.7 h1:rDTPXLDHGATaeHvVlLcR4Qe0zftYethFucbjVQ1PxU8= +github.com/go-chi/chi/v5 v5.0.7/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.10.0 h1:dXFJfIHVvUcpSgDOV+Ne6t7jXri8Tfv2uOLHUZ2XNuo= +github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= +github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA= +github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= +github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-sourcemap/sourcemap v2.1.3+incompatible h1:W1iEw64niKVGogNgBN3ePyLFfuisuzeidWPMPWmECqU= +github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= +github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw= +github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/goccy/go-json v0.9.7 h1:IcB+Aqpx/iMHu5Yooh7jEzJk1JZ7Pjtmys2ukPr7EeM= +github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= +github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= +github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-jwt/jwt/v4 v4.4.1 h1:pC5DB52sCeK48Wlb9oPcdhnjkz1TKt1D/P7WKJ0kUcQ= +github.com/golang-jwt/jwt/v4 v4.4.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/btree v0.0.0-20180124185431-e89373fe6b4a/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= +github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa h1:Q75Upo5UN4JbPFURXZ8nLKYUvF85dyFRop/vQ0Rv+64= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gopherjs/gopherjs v0.0.0-20190309154008-847fc94819f9/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= +github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw= +github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= +github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= +github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d h1:dg1dEPuWpEqDnvIw251EVy4zlP8gWbsGj4BsUKCRpYs= +github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= +github.com/holiman/uint256 v1.2.1 h1:XRtyuda/zw2l+Bq/38n5XUoEF72aSOu/77Thd9pPp2o= +github.com/holiman/uint256 v1.2.1/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/huandu/xstrings v1.0.0/go.mod h1:4qWG/gcEcfX4z/mBDHJ++3ReCw9ibxbsNJbcucJdbSo= +github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63UyNX5k4= +github.com/huandu/xstrings v1.3.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw= +github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= +github.com/huin/goupnp v1.0.3 h1:N8No57ls+MnjlB+JPiCVSOyy/ot7MJTqlo7rn+NYSqQ= +github.com/huin/goupnp v1.0.3/go.mod h1:ZxNlw5WqJj6wSsRK5+YfflQGXYfccj5VgQsMNixHM7Y= +github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= +github.com/ianlancetaylor/cgosymbolizer v0.0.0-20220405231054-a1ae3e4bba26 h1:UT3hQ6+5hwqUT83cKhKlY5I0W/kqsl6lpn3iFb3Gtqs= +github.com/ianlancetaylor/cgosymbolizer v0.0.0-20220405231054-a1ae3e4bba26/go.mod h1:DvXTE/K/RtHehxU8/GtDs4vFtfw64jJ3PaCnFri8CRg= +github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= +github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= +github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= +github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/kevinburke/go-bindata v3.21.0+incompatible h1:baK7hwFJDlAHrOqmE9U3u8tow1Uc5ihN9E/b7djcK2g= +github.com/kevinburke/go-bindata v3.21.0+incompatible/go.mod h1:/pEEZ72flUW2p0yi30bslSp9YqD9pysLxunQDdb2CPM= +github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v0.0.0-20170224010052-a616ab194758 h1:0D5M2HQSGD3PYPwICLl+/9oulQauOuETfgFvhBDffs0= +github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c= +github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= +github.com/ledgerwatch/erigon v1.9.7-0.20221024030055-592ad5792127 h1:6CpFRXkf6p3p1hUGNhjy3KaghtLxv/Q9aPFv0G1rXLU= +github.com/ledgerwatch/erigon v1.9.7-0.20221024030055-592ad5792127/go.mod h1:2uW5KjsMycyNF0KSiJKxKfdKFwlf91Hk0YDmRODFe3I= +github.com/ledgerwatch/erigon-lib v0.0.0-20221024030034-c1965e9c5ae3 h1:8Kf5Yi9F1Dcmr3KrqvIM02SrPEPMzD+f7aIFaaPrxGw= +github.com/ledgerwatch/erigon-lib v0.0.0-20221024030034-c1965e9c5ae3/go.mod h1:jv4jmffliy8Us1wXdT6Q1f/nrrmC6Xrr6V70JxZRp48= +github.com/ledgerwatch/erigon-snapshot v1.1.1-0.20221023043405-d157dec75e9a h1:5Lw7NR/KWxtAokY11DKaMnrI6Zb04OzX8BQMbF8Lu/w= +github.com/ledgerwatch/erigon-snapshot v1.1.1-0.20221023043405-d157dec75e9a/go.mod h1:3AuPxZc85jkehh/HA9h8gabv5MSi3kb/ddtzBsTVJFo= +github.com/ledgerwatch/log/v3 v3.6.0 h1:JBUSK1epPyutUrz7KYDTcJtQLEHnehECRpKbM1ugy5M= +github.com/ledgerwatch/log/v3 v3.6.0/go.mod h1:L+Sp+ma/h205EdCjviZECjGEvYUYEyXSdiuHNZzg+xQ= +github.com/ledgerwatch/secp256k1 v1.0.0 h1:Usvz87YoTG0uePIV8woOof5cQnLXGYa162rFf3YnwaQ= +github.com/ledgerwatch/secp256k1 v1.0.0/go.mod h1:SPmqJFciiF/Q0mPt2jVs2dTr/1TZBTIA+kPMmKgBAak= +github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= +github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= +github.com/lispad/go-generics-tools v1.1.0 h1:mbSgcxdFVmpoyso1X/MJHXbSbSL3dD+qhRryyxk+/XY= +github.com/lispad/go-generics-tools v1.1.0/go.mod h1:2csd1EJljo/gy5qG4khXol7ivCPptNjG5Uv2X8MgK84= +github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= +github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg= +github.com/mschoch/smat v0.2.0 h1:8imxQsjDm8yFEAVBe7azKmKSgzSkZXDuKkSq9374khM= +github.com/mschoch/smat v0.2.0/go.mod h1:kc9mz7DoBKqDyiRL7VZN8KvXQMWeTaVnttLRXOlotKw= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= +github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= +github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k= +github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= +github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/nxadm/tail v1.4.9-0.20211216163028-4472660a31a6 h1:iZ5rEHU561k2tdi/atkIsrP5/3AX3BjyhYtC96nJ260= +github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= +github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= +github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= +github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.17.0 h1:9Luw4uT5HTjHTN8+aNcSThgH1vdXnmdJ8xIfZ4wyTRE= +github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= +github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= +github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= +github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA= +github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= +github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= +github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= +github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= +github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= +github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= +github.com/pelletier/go-toml/v2 v2.0.5 h1:ipoSadvV8oGUjnUbMub59IDPPwfxF694nG/jwbMiyQg= +github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas= +github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= +github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= +github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= +github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pion/datachannel v1.5.2 h1:piB93s8LGmbECrpO84DnkIVWasRMk3IimbcXkTQLE6E= +github.com/pion/datachannel v1.5.2/go.mod h1:FTGQWaHrdCwIJ1rw6xBIfZVkslikjShim5yr05XFuCQ= +github.com/pion/dtls/v2 v2.1.3/go.mod h1:o6+WvyLDAlXF7YiPB/RlskRoeK+/JtuaZa5emwQcWus= +github.com/pion/dtls/v2 v2.1.5 h1:jlh2vtIyUBShchoTDqpCCqiYCyRFJ/lvf/gQ8TALs+c= +github.com/pion/dtls/v2 v2.1.5/go.mod h1:BqCE7xPZbPSubGasRoDFJeTsyJtdD1FanJYL0JGheqY= +github.com/pion/ice/v2 v2.2.6 h1:R/vaLlI1J2gCx141L5PEwtuGAGcyS6e7E0hDeJFq5Ig= +github.com/pion/ice/v2 v2.2.6/go.mod h1:SWuHiOGP17lGromHTFadUe1EuPgFh/oCU6FCMZHooVE= +github.com/pion/interceptor v0.1.11 h1:00U6OlqxA3FFB50HSg25J/8cWi7P6FbSzw4eFn24Bvs= +github.com/pion/interceptor v0.1.11/go.mod h1:tbtKjZY14awXd7Bq0mmWvgtHB5MDaRN7HV3OZ/uy7s8= +github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY= +github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms= +github.com/pion/mdns v0.0.5 h1:Q2oj/JB3NqfzY9xGZ1fPzZzK7sDSD8rZPOvcIQ10BCw= +github.com/pion/mdns v0.0.5/go.mod h1:UgssrvdD3mxpi8tMxAXbsppL3vJ4Jipw1mTCW+al01g= +github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA= +github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8= +github.com/pion/rtcp v1.2.9 h1:1ujStwg++IOLIEoOiIQ2s+qBuJ1VN81KW+9pMPsif+U= +github.com/pion/rtcp v1.2.9/go.mod h1:qVPhiCzAm4D/rxb6XzKeyZiQK69yJpbUDJSF7TgrqNo= +github.com/pion/rtp v1.7.13 h1:qcHwlmtiI50t1XivvoawdCGTP4Uiypzfrsap+bijcoA= +github.com/pion/rtp v1.7.13/go.mod h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko= +github.com/pion/sctp v1.8.0/go.mod h1:xFe9cLMZ5Vj6eOzpyiKjT9SwGM4KpK/8Jbw5//jc+0s= +github.com/pion/sctp v1.8.2 h1:yBBCIrUMJ4yFICL3RIvR4eh/H2BTTvlligmSTy+3kiA= +github.com/pion/sctp v1.8.2/go.mod h1:xFe9cLMZ5Vj6eOzpyiKjT9SwGM4KpK/8Jbw5//jc+0s= +github.com/pion/sdp/v3 v3.0.5 h1:ouvI7IgGl+V4CrqskVtr3AaTrPvPisEOxwgpdktctkU= +github.com/pion/sdp/v3 v3.0.5/go.mod h1:iiFWFpQO8Fy3S5ldclBkpXqmWy02ns78NOKoLLL0YQw= +github.com/pion/srtp/v2 v2.0.9 h1:JJq3jClmDFBPX/F5roEb0U19jSU7eUhyDqR/NZ34EKQ= +github.com/pion/srtp/v2 v2.0.9/go.mod h1:5TtM9yw6lsH0ppNCehB/EjEUli7VkUgKSPJqWVqbhQ4= +github.com/pion/stun v0.3.5 h1:uLUCBCkQby4S1cf6CGuR9QrVOKcvUwFeemaC865QHDg= +github.com/pion/stun v0.3.5/go.mod h1:gDMim+47EeEtfWogA37n6qXZS88L5V6LqFcf+DZA2UA= +github.com/pion/transport v0.12.2/go.mod h1:N3+vZQD9HlDP5GWkZ85LohxNsDcNgofQmyL6ojX5d8Q= +github.com/pion/transport v0.12.3/go.mod h1:OViWW9SP2peE/HbwBvARicmAVnesphkNkCVZIWJ6q9A= +github.com/pion/transport v0.13.0/go.mod h1:yxm9uXpK9bpBBWkITk13cLo1y5/ur5VQpG22ny6EP7g= +github.com/pion/transport v0.13.1 h1:/UH5yLeQtwm2VZIPjxwnNFxjS4DFhyLfS4GlfuKUzfA= +github.com/pion/transport v0.13.1/go.mod h1:EBxbqzyv+ZrmDb82XswEE0BjfQFtuw1Nu6sjnjWCsGg= +github.com/pion/turn/v2 v2.0.8 h1:KEstL92OUN3k5k8qxsXHpr7WWfrdp7iJZHx99ud8muw= +github.com/pion/turn/v2 v2.0.8/go.mod h1:+y7xl719J8bAEVpSXBXvTxStjJv3hbz9YFflvkpcGPw= +github.com/pion/udp v0.1.1 h1:8UAPvyqmsxK8oOjloDk4wUt63TzFe9WEJkg5lChlj7o= +github.com/pion/udp v0.1.1/go.mod h1:6AFo+CMdKQm7UiA0eUPA8/eVCTx8jBIITLZHc9DWX5M= +github.com/pion/webrtc/v3 v3.1.42 h1:wJEQFIXVanptnQcHOLTuIo4AtGB2+mG2x4OhIhnITOA= +github.com/pion/webrtc/v3 v3.1.42/go.mod h1:ffD9DulDrPxyWvDPUIPAOSAWx9GUlOExiJPf7cCcMLA= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= +github.com/prometheus/client_golang v1.5.1/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/procfs v0.0.11/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/quasilyte/go-ruleguard/dsl v0.3.21 h1:vNkC6fC6qMLzCOGbnIHOd5ixUGgTbp3Z4fGnUgULlDA= +github.com/quasilyte/go-ruleguard/dsl v0.3.21/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU= +github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= +github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg= +github.com/rs/cors v1.8.2 h1:KCooALfAYGs415Cwu5ABvv9n9509fSiG5SQJn/AQo4U= +github.com/rs/cors v1.8.2/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= +github.com/rs/dnscache v0.0.0-20211102005908-e0241e321417 h1:Lt9DzQALzHoDwMBGJ6v8ObDPR0dzr2a6sXTB1Fq7IHs= +github.com/rs/dnscache v0.0.0-20211102005908-e0241e321417/go.mod h1:qe5TWALJ8/a1Lqznoc5BDHpYX/8HU60Hm2AwRmqzxqA= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46 h1:GHRpF1pTW19a8tTFrMLUcfWwyC0pnifVo2ClaLq+hP8= +github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46/go.mod h1:uAQ5PCi+MFsC7HjREoAz1BU+Mq60+05gifQSsHSDG/8= +github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= +github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/assertions v0.0.0-20190215210624-980c5ac6f3ac/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= +github.com/smartystreets/goconvey v0.0.0-20190306220146-200a235640ff/go.mod h1:KSQcGKpxUMHk3nbYzs/tIBAM2iDooCn0BmttHOJEbLs= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= +github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU= +github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM= +github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/tendermint/go-amino v0.14.1 h1:o2WudxNfdLNBwMyl2dqOJxiro5rfrEaU0Ugs6offJMk= +github.com/tendermint/go-amino v0.14.1/go.mod h1:i/UKE5Uocn+argJJBb12qTZsCDBcAYMbR92AaJVmKso= +github.com/tidwall/btree v1.3.1 h1:636+tdVDs8Hjcf35Di260W2xCW4KuoXOKyk9QWOvCpA= +github.com/tidwall/btree v1.3.1/go.mod h1:LGm8L/DZjPLmeWGjv5kFrY8dL4uVhMmzmmLYmsObdKE= +github.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= +github.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= +github.com/tinylib/msgp v1.1.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= +github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/torquem-ch/mdbx-go v0.26.1 h1:28Rh8UHlhpgJ+mFlTcvNQF66maqTnOcv8sSLD2ydXbE= +github.com/torquem-ch/mdbx-go v0.26.1/go.mod h1:T2fsoJDVppxfAPTLd1svUgH1kpPmeXdPESmroSHcL1E= +github.com/ugorji/go v1.1.13/go.mod h1:jxau1n+/wyTGLQoCkjok9r5zFa/FxT6eI5HiHKQszjc= +github.com/ugorji/go/codec v1.1.13 h1:013LbFhocBoIqgHeIHKlV4JWYhqogATYWZhIcH0WHn4= +github.com/ugorji/go/codec v1.1.13/go.mod h1:oNVt3Dq+FO91WNQ/9JnHKQP2QJxTzoN7wCBFCq1OeuU= +github.com/ugorji/go/codec/codecgen v1.1.13 h1:rGpZ4Q63VcWA3DMBbIHvg+SQweUkfXBBa/f9X0W+tFg= +github.com/ugorji/go/codec/codecgen v1.1.13/go.mod h1:EhCxlc7Crov+HLygD4+hBCitXNrrGKRrRWj+pRsyJGg= +github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli v1.22.9 h1:cv3/KhXGBGjEXLC4bH0sLuJ9BewaAbpk5oyMOveu4pw= +github.com/urfave/cli v1.22.9/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/valyala/fastjson v1.6.3 h1:tAKFnnwmeMGPbwJ7IwxcTPCNr3uIzoIj3/Fh90ra4xc= +github.com/valyala/fastjson v1.6.3/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY= +github.com/valyala/fastrand v1.1.0 h1:f+5HkLW4rsgzdNoleUOB69hyT9IlD2ZQh9GyDMfb5G8= +github.com/valyala/fastrand v1.1.0/go.mod h1:HWqCzkrkg6QXT8V2EXWvXCoow7vLwOFN002oeRzjapQ= +github.com/valyala/histogram v1.2.0 h1:wyYGAZZt3CpwUiIb9AU/Zbllg1llXyrtApRS815OLoQ= +github.com/valyala/histogram v1.2.0/go.mod h1:Hb4kBwb4UxsaNbbbh+RRz8ZR6pdodR57tzWUS3BUzXY= +github.com/willf/bitset v1.1.9/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= +github.com/willf/bitset v1.1.10/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/xsleonard/go-merkle v1.1.0 h1:fHe1fuhJjGH22ZzVTAH0jqHLhTGhOq3wQjJN+8P0jQg= +github.com/xsleonard/go-merkle v1.1.0/go.mod h1:cW4z+UZ/4f2n9IJgIiyDCdYguchoDyDAPmpuOWGxdGg= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU= +go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= +go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= +go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= +go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opentelemetry.io/otel v1.8.0 h1:zcvBFizPbpa1q7FehvFiHbQwGzmPILebO0tyqIR5Djg= +go.opentelemetry.io/otel v1.8.0/go.mod h1:2pkj+iMj0o03Y+cW6/m8Y4WkRdYN3AvCXCnzRMp9yvM= +go.opentelemetry.io/otel/trace v1.8.0 h1:cSy0DF9eGI5WIfNwZ1q2iUyGj00tGzP24dE1lOlHrfY= +go.opentelemetry.io/otel/trace v1.8.0/go.mod h1:0Bt3PXY8w+3pheS3hQUt+wow8b1ojPaTBoTCh2zIFI4= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= +go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= +go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= +golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200115085410-6d4e4cb37c7d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220516162934-403b01795ae8/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU= +golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20221018221608-02f3b879a704 h1:qeTd8Mtg7Z9G839eB0/DhF2vU3ZeXcP6vwAY/IqVRPM= +golang.org/x/exp v0.0.0-20221018221608-02f3b879a704/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0 h1:b9gGHsz9/HhJ3HF5DHQytPpuwocVTChQJK3AvoLRD5I= +golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= +golang.org/x/net v0.0.0-20180524181706-dfa909b99c79/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201201195509-5d6afe98e0b7/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211201190559-0a0e4e1bb54c/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220401154927-543a649e0bdd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220531201128-c960675eff93/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0= +golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200413165638-669c56c373c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211020174200-9d6173849985/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220405052023-b1e9470b6e64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220608164250-635b8c9b7f68/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.1.0 h1:xYY+Bajn2a7VBmTM5GikTmnK8ZuX8YgnQCqZpbBNtmA= +golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.2.0 h1:G6AHpWxTMGY1KyEYoAQ5WTtIekUUvDNjan3ugu60JvE= +golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1 h1:b9mVrqYfq3P4bCdaLg1qtBnPzUYgglsIdjZkL/fQVOE= +google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.50.1 h1:DS/BukOZWp8s6p4Dt/tOaJaTQyPyOoCcrjroHuCeLzY= +google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.2.0 h1:TLkBREm4nIsEcexnCjgQd5GQWaHcqMzwQV0TX9pq8S0= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.2.0/go.mod h1:DNq5QpG7LJqD2AamLZ7zvKE0DEpVl2BSEVjFycAAjRY= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +pgregory.net/rapid v0.4.7 h1:MTNRktPuv5FNqOO151TM9mDTa+XHcX6ypYeISDVD14g= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= diff --git a/package.json b/package.json index f5b5fce..75a6e6b 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,10 @@ "scripts": { "start": "vite", "build": "tsc && vite build", + "postbuild": "cp -r chains dist && cp -r topic0 dist", "preview": "vite preview", + "dl-chains": "svn checkout https://github.com/ethereum-lists/chains/trunk/_data/chains && rm -rf chains/.svn", + "dl-topic0": "git clone https://github.com/wmitsuda/topic0 && rm -rf topic0/.git", "source-map-explorer": "source-map-explorer build/static/js/*.js", "assets-start": "docker run --rm -p 3001:80 --name otterscan-assets -d -v$(pwd)/4bytes/signatures:/usr/share/nginx/html/signatures/ -v$(pwd)/trustwallet/blockchains/ethereum/assets:/usr/share/nginx/html/assets/1 -v$(pwd)/topic0/with_parameter_names:/usr/share/nginx/html/topic0/ -v$(pwd)/chains/_data/chains:/usr/share/nginx/html/chains/ -v$(pwd)/nginx/nginx.conf:/etc/nginx/nginx.conf -v$(pwd)/nginx/conf.d/default.conf:/etc/nginx/conf.d/default.conf nginx:1.21.1-alpine", "assets-start-with-param-names": "docker run --rm -p 3001:80 --name otterscan-assets -d -v$(pwd)/4bytes/with_parameter_names:/usr/share/nginx/html/signatures/ -v$(pwd)/trustwallet/blockchains/ethereum/assets:/usr/share/nginx/html/assets/1 -v$(pwd)/topic0/with_parameter_names:/usr/share/nginx/html/topic0/ -v$(pwd)/chains/_data/chains:/usr/share/nginx/html/chains/ -v$(pwd)/nginx/nginx.conf:/etc/nginx/nginx.conf -v$(pwd)/nginx/conf.d/default.conf:/etc/nginx/conf.d/default.conf nginx:1.21.1-alpine", diff --git a/src/App.tsx b/src/App.tsx index bb8d9aa..a6417a5 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,5 +1,5 @@ import React, { Suspense } from "react"; -import { BrowserRouter as Router, Routes, Route } from "react-router-dom"; +import { HashRouter as Router, Routes, Route } from "react-router-dom"; import WarningHeader from "./WarningHeader"; import Home from "./Home"; import Main from "./Main";