|
|
||
|---|---|---|
| .github/workflows | ||
| cmd | ||
| environments | ||
| monitoring | ||
| pkg | ||
| version | ||
| .gitignore | ||
| docker-compose.yml | ||
| Dockerfile | ||
| go.mod | ||
| go.sum | ||
| LICENSE | ||
| main.go | ||
| Makefile | ||
| README.md | ||
| startup_script.sh | ||
eth-statediff-service
standalone statediffing service on top of LevelDB
Purpose:
Stand up a statediffing service directly on top of a go-ethereum LevelDB instance. This service can serve historical state data over the same rpc interface as statediffing geth without needing to run a full node.
Setup
Build the binary:
make build
Configuration
An example config file:
[leveldb]
# LevelDB access mode <local | remote>
mode = "local" # LVLDB_MODE
# in local mode
# LevelDB paths
path = "/Users/user/Library/Ethereum/geth/chaindata" # LVLDB_PATH
ancient = "/Users/user/Library/Ethereum/geth/chaindata/ancient" # LVLDB_ANCIENT
# in remote mode
# URL for leveldb-ethdb-rpc endpoint
url = "http://127.0.0.1:8082/" # LVLDB_URL
[server]
ipcPath = ".ipc" # SERVICE_IPC_PATH
httpPath = "127.0.0.1:8545" # SERVICE_HTTP_PATH
[statediff]
prerun = true # STATEDIFF_PRERUN
serviceWorkers = 1 # STATEDIFF_SERVICE_WORKERS
workerQueueSize = 1024 # STATEDIFF_WORKER_QUEUE_SIZE
trieWorkers = 4 # STATEDIFF_TRIE_WORKERS
[prerun]
only = false # PRERUN_ONLY
# to perform prerun in a specific range (optional)
start = 0 # PRERUN_RANGE_START
stop = 100 # PRERUN_RANGE_STOP
# to perform prerun over multiple ranges (optional)
ranges = [
[101, 1000]
]
# statediffing params for prerun
[prerun.params]
intermediateStateNodes = true # PRERUN_INTERMEDIATE_STATE_NODES
intermediateStorageNodes = true # PRERUN_INTERMEDIATE_STORAGE_NODES
includeBlock = true # PRERUN_INCLUDE_BLOCK
includeReceipts = true # PRERUN_INCLUDE_RECEIPTS
includeTD = true # PRERUN_INCLUDE_TD
includeCode = true # PRERUN_INCLUDE_CODE
watchedAddresses = []
[log]
file = "" # LOG_FILE_PATH
level = "info" # LOG_LEVEL
[database]
# output type <postgres | file | dump>
type = "postgres"
# with postgres type
# db credentials
name = "vulcanize_test" # DATABASE_NAME
hostname = "localhost" # DATABASE_HOSTNAME
port = 5432 # DATABASE_PORT
user = "vulcanize" # DATABASE_USER
password = "..." # DATABASE_PASSWORD
driver = "sqlx" # DATABASE_DRIVER_TYPE <sqlx | pgx>
# with file type
# file mode <sql | csv>
fileMode = "csv" # DATABASE_FILE_MODE
# with SQL file mode
filePath = "" # DATABASE_FILE_PATH
# with CSV file mode
fileCsvDir = "output_dir" # DATABASE_FILE_CSV_DIR
# with dump type
# <stdout | stderr | discard>
dumpDestination = "" # DATABASE_DUMP_DST
[cache]
database = 1024 # DB_CACHE_SIZE_MB
trie = 1024 # TRIE_CACHE_SIZE_MB
[prom]
# prometheus metrics
metrics = true # PROM_METRICS
http = true # PROM_HTTP
httpAddr = "localhost" # PROM_HTTP_ADDR
httpPort = "8889" # PROM_HTTP_PORT
dbStats = true # PROM_DB_STATS
[ethereum]
# node info
nodeID = "" # ETH_NODE_ID
clientName = "eth-statediff-service" # ETH_CLIENT_NAME
networkID = 1 # ETH_NETWORK_ID
chainID = 1 # ETH_CHAIN_ID
genesisBlock = "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3" # ETH_GENESIS_BLOCK
# path to custom chain config file (optional)
# keep chainID same as that in chain config file
chainConfig = "./chain.json" # ETH_CHAIN_CONFIG
Local Setup
-
Create a chain config file
chain.jsonaccording to chain config in genesis json file used by local geth.Example:
{ "chainId": 41337, "homesteadBlock": 0, "eip150Block": 0, "eip150Hash": "0x0000000000000000000000000000000000000000000000000000000000000000", "eip155Block": 0, "eip158Block": 0, "byzantiumBlock": 0, "constantinopleBlock": 0, "petersburgBlock": 0, "istanbulBlock": 0, "clique": { "period": 5, "epoch": 30000 } }Provide the path to the above file in the config.
Usage
- Create / update the config file (refer to example config above).
serve
-
To serve the statediff RPC API:
./eth-statediff-service serve --config=<config path>Example:
./eth-statediff-service serve --config environments/config.toml -
Available RPC methods:
statediff_stateTrieAt()statediff_streamCodeAndCodeHash()statediff_stateDiffAt()statediff_writeStateDiffAt()statediff_writeStateDiffsInRange()
Example:
curl -X POST -H 'Content-Type: application/json' --data '{"jsonrpc":"2.0","method":"statediff_writeStateDiffsInRange","params":['"$BEGIN"', '"$END"', {"intermediateStateNodes":true,"intermediateStorageNodes":true,"includeBlock":true,"includeReceipts":true,"includeTD":true,"includeCode":true}],"id":1}' "$HOST":"$PORT" -
Prerun:
- The process can be configured locally with sets of ranges to process as a "prerun" to processing directed by the server endpoints.
- This is done by turning "prerun" on in the config (
statediff.prerun = true) and defining ranges and params in theprerunsection of the config. - Set the range using
prerun.startandprerun.stop. Useprerun.rangesif prerun on more than one range is required.
-
NOTE: Currently,
params.includeTDmust be set to / passed astrue.
Monitoring
- Enable metrics using config parameters
prom.metricsandprom.http. eth-statediff-serviceexposes following prometheus metrics at/metricsendpoint:ranges_queued: Number of range requests currently queued.loaded_height: The last block that was loaded for processing.processed_height: The last block that was processed.stats.t_block_load: Block loading time.stats.t_block_processing: Block (header, uncles, txs, rcts, tx trie, rct trie) processing time.stats.t_state_processing: State (state trie, storage tries, and code) processing time.stats.t_postgres_tx_commit: Postgres tx commit time.http.count: HTTP request count.http.duration: HTTP request duration.ipc.count: Unix socket connection count.
Tests
-
Run unit tests:
make test
Import output data in file mode into a database
-
When
eth-statediff-serviceis run in file mode (database.type) the output is in form of a SQL file or multiple CSV files. -
Assuming the output files are located in host's
./output_dirdirectory. -
Create a directory to store post-processed output:
mkdir -p output_dir/processed_output
SQL
-
De-duplicate data:
sort -u output_dir/statediff.sql -o output_dir/processed_output/deduped-statediff.sql -
Copy over the post-processed output files to the DB server (say in
/output_dir). -
Run the following to import data:
psql -U <DATABASE_USER> -h <DATABASE_HOSTNAME> -p <DATABASE_PORT> <DATABASE_NAME> --set ON_ERROR_STOP=on -f /output_dir/processed_output/deduped-statediff.sql
CSV
-
De-duplicate data and copy to post-processed output directory:
# public.blocks sort -u output_dir/public.blocks.csv -o output_dir/processed_output/deduped-public.blocks.csv # eth.header_cids sort -u output_dir/eth.header_cids.csv -o output_dir/processed_output/deduped-eth.header_cids.csv # eth.uncle_cids sort -u output_dir/eth.uncle_cids.csv -o output_dir/processed_output/deduped-eth.uncle_cids.csv # eth.transaction_cids sort -u output_dir/eth.transaction_cids.csv -o output_dir/processed_output/deduped-eth.transaction_cids.csv # eth.access_list_elements sort -u output_dir/eth.access_list_elements.csv -o output_dir/processed_output/deduped-eth.access_list_elements.csv # eth.receipt_cids sort -u output_dir/eth.receipt_cids.csv -o output_dir/processed_output/deduped-eth.receipt_cids.csv # eth.log_cids sort -u output_dir/eth.log_cids.csv -o output_dir/processed_output/deduped-eth.log_cids.csv # eth.state_cids sort -u output_dir/eth.state_cids.csv -o output_dir/processed_output/deduped-eth.state_cids.csv # eth.storage_cids sort -u output_dir/eth.storage_cids.csv -o output_dir/processed_output/deduped-eth.storage_cids.csv # eth.state_accounts sort -u output_dir/eth.state_accounts.csv -o output_dir/processed_output/deduped-eth.state_accounts.csv # public.nodes cp output_dir/public.nodes.csv output_dir/processed_output/public.nodes.csv -
Copy over the post-processed output files to the DB server (say in
/output_dir). -
Start
psqlto run the import commands:psql -U <DATABASE_USER> -h <DATABASE_HOSTNAME> -p <DATABASE_PORT> <DATABASE_NAME> -
Run the following to import data:
# public.nodes COPY public.nodes FROM '/output_dir/processed_output/public.nodes.csv' CSV; # public.nodes COPY public.blocks FROM '/output_dir/processed_output/deduped-public.blocks.csv' CSV; # eth.header_cids COPY eth.header_cids FROM '/output_dir/processed_output/deduped-eth.header_cids.csv' CSV; # eth.uncle_cids COPY eth.uncle_cids FROM '/output_dir/processed_output/deduped-eth.uncle_cids.csv' CSV; # eth.transaction_cids COPY eth.transaction_cids FROM '/output_dir/processed_output/deduped-eth.transaction_cids.csv' CSV FORCE NOT NULL dst; # eth.access_list_elements COPY eth.access_list_elements FROM '/output_dir/processed_output/deduped-eth.access_list_elements.csv' CSV; # eth.receipt_cids COPY eth.receipt_cids FROM '/output_dir/processed_output/deduped-eth.receipt_cids.csv' CSV FORCE NOT NULL post_state, contract, contract_hash; # eth.log_cids COPY eth.log_cids FROM '/output_dir/processed_output/deduped-eth.log_cids.csv' CSV FORCE NOT NULL topic0, topic1, topic2, topic3; # eth.state_cids COPY eth.state_cids FROM '/output_dir/processed_output/deduped-eth.state_cids.csv' CSV FORCE NOT NULL state_leaf_key; # eth.storage_cids COPY eth.storage_cids FROM '/output_dir/processed_output/deduped-eth.storage_cids.csv' CSV FORCE NOT NULL storage_leaf_key; # eth.state_accounts COPY eth.state_accounts FROM '/output_dir/processed_output/deduped-eth.state_accounts.csv' CSV; -
NOTE:
COPYcommand on CSVs inserts empty strings asNULLin the DB. PassingFORCE_NOT_NULL <COLUMN_NAME>forces it to insert empty strings instead. This is required to maintain compatibility of the imported statediff data with the data generated inpostgresmode. Reference: https://www.postgresql.org/docs/14/sql-copy.html