diff --git a/docker-compose.apphash-crash.yml b/docker-compose.apphash-crash.yml new file mode 100644 index 000000000..0d32c337a --- /dev/null +++ b/docker-compose.apphash-crash.yml @@ -0,0 +1,213 @@ +version: "3" + +services: + # -------------------------------------------------------------------------- + # Setup Service (Initialize Data) + # -------------------------------------------------------------------------- + setup: + build: + context: ../../../evm + dockerfile: contrib/images/evmd-env/Dockerfile + user: root + entrypoint: [] + command: | + sh -c " + # Initialize 4 nodes normally + evmd testnet init-files --validator-count 4 --output-dir /data --chain-id crash-test --keyring-backend test + + echo 'Enabling MemLogger...' + find /data -name app.toml -exec sed -i 's/enabled = false/enabled = true/g' {} + + + # Configure first 3 nodes normally + for i in 0 1 2; do + sed -i 's/127.0.0.1/0.0.0.0/g' /data/node$$i/evmd/config/config.toml + done + + echo 'Enabling MemLogger...' + find /data -name app.toml -exec sed -i 's/enabled = false/enabled = true/g' {} + + + # Node 3: Intentionally corrupt genesis to cause apphash mismatch + echo 'Corrupting node3 genesis to trigger apphash crash...' + # Change initial_height to cause state mismatch (match numeric value) + sed -i 's/\"initial_height\": 1,/\"initial_height\": 999,/' /data/node3/evmd/config/genesis.json + echo 'Changed initial_height from 1 to 999' + + chown -R 1025:1025 /data + " + volumes: + - ./crash-test-data:/data:Z + + # -------------------------------------------------------------------------- + # EVM Node 0 & Shipper 0 + # -------------------------------------------------------------------------- + evmdnode0: + container_name: evmdnode0 + build: + context: ../evm + dockerfile: contrib/images/evmd-env/Dockerfile + environment: + - DEBUG=0 + - ID=0 + - LOG=${LOG:-evmd.log} + depends_on: + setup: + condition: service_completed_successfully + command: start --chain-id crash-test --minimum-gas-prices 0atest --json-rpc.enable true --json-rpc.api eth,txpool,personal,net,debug,web3 + ports: + - "26656-26657:26656-26657" + - "1317:1317" + - "8545:8545" + volumes: + - ./crash-test-data:/data:Z + networks: + - localnet + + walship0: + container_name: walship0 + restart: always + build: + context: ../cosmos-analyzer-shipper + dockerfile: Dockerfile + depends_on: + - evmdnode0 + volumes: + # Mount the same data directory to access node config and WAL + - ./crash-test-data:/data:ro + environment: + # Point to the specific node's root directory inside the volume + - WALSHIP_ROOT=/data/node0/evmd + # Remote analytics backend URL + - WALSHIP_REMOTE_URL=${WALSHIP_REMOTE_URL:-http://host.docker.internal:8080/v1/ingest/wal-frames} + - WALSHIP_AUTH_KEY=${WALSHIP_AUTH_KEY:-dev-local-test-1234} + networks: + - localnet + + # -------------------------------------------------------------------------- + # EVM Node 1 & Shipper 1 + # -------------------------------------------------------------------------- + evmdnode1: + container_name: evmdnode1 + build: + context: ../evm + dockerfile: contrib/images/evmd-env/Dockerfile + environment: + - DEBUG=0 + - ID=1 + - LOG=${LOG:-evmd.log} + depends_on: + setup: + condition: service_completed_successfully + command: start --chain-id crash-test --minimum-gas-prices 0atest --json-rpc.enable true --json-rpc.api eth,txpool,personal,net,debug,web3 + ports: + - "26666-26667:26656-26657" + - "1318:1317" + - "8555:8545" + volumes: + - ./crash-test-data:/data:Z + networks: + - localnet + + walship1: + container_name: walship1 + restart: always + build: + context: ../cosmos-analyzer-shipper + dockerfile: Dockerfile + depends_on: + - evmdnode1 + volumes: + - ./crash-test-data:/data:ro + environment: + - WALSHIP_ROOT=/data/node1/evmd + - WALSHIP_REMOTE_URL=${WALSHIP_REMOTE_URL:-http://host.docker.internal:8080/v1/ingest/wal-frames} + - WALSHIP_AUTH_KEY=${WALSHIP_AUTH_KEY:-dev-local-test-1234} + networks: + - localnet + + # -------------------------------------------------------------------------- + # EVM Node 2 & Shipper 2 + # -------------------------------------------------------------------------- + evmdnode2: + container_name: evmdnode2 + build: + context: ../evm + dockerfile: contrib/images/evmd-env/Dockerfile + environment: + - DEBUG=0 + - ID=2 + - LOG=${LOG:-evmd.log} + depends_on: + setup: + condition: service_completed_successfully + command: start --chain-id crash-test --minimum-gas-prices 0atest --json-rpc.enable true --json-rpc.api eth,txpool,personal,net,debug,web3 + ports: + - "26676-26677:26656-26657" + - "1319:1317" + - "8565:8545" + volumes: + - ./crash-test-data:/data:Z + networks: + - localnet + + walship2: + container_name: walship2 + restart: always + build: + context: ../cosmos-analyzer-shipper + dockerfile: Dockerfile + depends_on: + - evmdnode2 + volumes: + - ./crash-test-data:/data:ro + environment: + - WALSHIP_ROOT=/data/node2/evmd + - WALSHIP_REMOTE_URL=${WALSHIP_REMOTE_URL:-http://host.docker.internal:8080/v1/ingest/wal-frames} + - WALSHIP_AUTH_KEY=${WALSHIP_AUTH_KEY:-dev-local-test-1234} + networks: + - localnet + + # -------------------------------------------------------------------------- + # EVM Node 3 & Shipper 3 + # -------------------------------------------------------------------------- + evmdnode3: + container_name: evmdnode3 + build: + context: ../evm + dockerfile: contrib/images/evmd-env/Dockerfile + environment: + - DEBUG=0 + - ID=3 + - LOG=${LOG:-evmd.log} + depends_on: + setup: + condition: service_completed_successfully + command: start --chain-id crash-test --minimum-gas-prices 0atest --json-rpc.enable true --json-rpc.api eth,txpool,personal,net,debug,web3 + ports: + - "26686-26687:26656-26657" + - "1320:1317" + - "8575:8545" + volumes: + - ./crash-test-data:/data:Z + networks: + - localnet + + walship3: + container_name: walship3 + restart: always + build: + context: ../cosmos-analyzer-shipper + dockerfile: Dockerfile + depends_on: + - evmdnode3 + volumes: + - ./crash-test-data:/data:ro + environment: + - WALSHIP_ROOT=/data/node3/evmd + - WALSHIP_REMOTE_URL=${WALSHIP_REMOTE_URL:-http://host.docker.internal:8080/v1/ingest/wal-frames} + - WALSHIP_AUTH_KEY=${WALSHIP_AUTH_KEY:-dev-local-test-1234} + networks: + - localnet + +networks: + localnet: + driver: bridge diff --git a/docker-compose.demo.yml b/docker-compose.demo.yml new file mode 100644 index 000000000..5b75fc049 --- /dev/null +++ b/docker-compose.demo.yml @@ -0,0 +1,220 @@ +version: "3" + +services: + # -------------------------------------------------------------------------- + # Setup Service (Initialize Data) + # -------------------------------------------------------------------------- + setup: + container_name: setup + build: + context: . + dockerfile: contrib/images/evmd-env/Dockerfile + user: root + entrypoint: [] + command: | + sh -c " + if [ ! -f /data/node0/evmd/config/genesis.json ]; then + echo 'Initializing testnet data...' + evmd testnet init-files --validator-count 4 --output-dir /data --chain-id ${CHAIN_ID:-local-test-1234} --keyring-backend test + + echo 'Configuring network binding...' + find /data -name config.toml -exec sed -i 's/127.0.0.1/0.0.0.0/g' {} + + + echo 'Enabling MemLogger...' + find /data -name app.toml -exec sed -i 's/enabled = false/enabled = true/g' {} + + + echo 'Configuring persistent peers...' + PEERS=\"\" + for i in 0 1 2 3; do + NODE_ID=$$(evmd comet show-node-id --home /data/node$$i/evmd) + PEER=\"$$NODE_ID@evmdnode$$i:26656\" + if [ -z \"$$PEERS\" ]; then PEERS=\"$$PEER\"; else PEERS=\"$$PEERS,$$PEER\"; fi + done + echo \"Peers: $$PEERS\" + for i in 0 1 2 3; do + sed -i \"s|^persistent_peers = .*|persistent_peers = \\\"$$PEERS\\\"|\" /data/node$$i/evmd/config/config.toml + done + + echo 'Fixing permissions...' + chown -R 1025:1025 /data + else + echo 'Testnet data already exists.' + fi + " + volumes: + - ./.testnets:/data:Z + + # -------------------------------------------------------------------------- + # EVM Node 0 & Shipper 0 + # -------------------------------------------------------------------------- + evmdnode0: + container_name: evmdnode0 + build: + context: . + dockerfile: contrib/images/evmd-env/Dockerfile + environment: + - DEBUG=0 + - ID=0 + - LOG=${LOG:-evmd.log} + depends_on: + setup: + condition: service_completed_successfully + command: start --chain-id ${CHAIN_ID:-local-test-1234} --minimum-gas-prices 0atest --json-rpc.enable true --json-rpc.api eth,txpool,personal,net,debug,web3 + ports: + - "26656-26657:26656-26657" + - "1317:1317" + - "8545:8545" + volumes: + - ./.testnets:/data:Z + networks: + - localnet + + walship0: + container_name: walship0 + restart: always + build: + context: ../cosmos-analyzer-shipper + dockerfile: Dockerfile + depends_on: + - evmdnode0 + volumes: + # Mount the same data directory to access node config and WAL + - ./.testnets:/data:ro + environment: + # Point to the specific node's root directory inside the volume + - WALSHIP_ROOT=/data/node0/evmd + # Remote analytics backend URL + - WALSHIP_REMOTE_URL=${WALSHIP_REMOTE_URL:-http://host.docker.internal:8080/v1/ingest/wal-frames} + - WALSHIP_AUTH_KEY=${WALSHIP_AUTH_KEY:-5a21c5c5dcf34b1aad1eafff1d0e6653} + networks: + - localnet + + # -------------------------------------------------------------------------- + # EVM Node 1 & Shipper 1 + # -------------------------------------------------------------------------- + evmdnode1: + container_name: evmdnode1 + build: + context: . + dockerfile: contrib/images/evmd-env/Dockerfile + environment: + - DEBUG=0 + - ID=1 + - LOG=${LOG:-evmd.log} + depends_on: + setup: + condition: service_completed_successfully + command: start --chain-id ${CHAIN_ID:-local-test-1234} --minimum-gas-prices 0atest --json-rpc.enable true --json-rpc.api eth,txpool,personal,net,debug,web3 + ports: + - "26666-26667:26656-26657" + - "1318:1317" + - "8555:8545" + volumes: + - ./.testnets:/data:Z + networks: + - localnet + + walship1: + container_name: walship1 + restart: always + build: + context: ../cosmos-analyzer-shipper + dockerfile: Dockerfile + depends_on: + - evmdnode1 + volumes: + - ./.testnets:/data:ro + environment: + - WALSHIP_ROOT=/data/node1/evmd + - WALSHIP_REMOTE_URL=${WALSHIP_REMOTE_URL:-http://host.docker.internal:8080/v1/ingest/wal-frames} + - WALSHIP_AUTH_KEY=${WALSHIP_AUTH_KEY:-5a21c5c5dcf34b1aad1eafff1d0e6653} + networks: + - localnet + + # -------------------------------------------------------------------------- + # EVM Node 2 & Shipper 2 + # -------------------------------------------------------------------------- + evmdnode2: + container_name: evmdnode2 + build: + context: . + dockerfile: contrib/images/evmd-env/Dockerfile + environment: + - DEBUG=0 + - ID=2 + - LOG=${LOG:-evmd.log} + depends_on: + setup: + condition: service_completed_successfully + command: start --chain-id ${CHAIN_ID:-local-test-1234} --minimum-gas-prices 0atest --json-rpc.enable true --json-rpc.api eth,txpool,personal,net,debug,web3 + ports: + - "26676-26677:26656-26657" + - "1319:1317" + - "8565:8545" + volumes: + - ./.testnets:/data:Z + networks: + - localnet + + walship2: + container_name: walship2 + restart: always + build: + context: ../cosmos-analyzer-shipper + dockerfile: Dockerfile + depends_on: + - evmdnode2 + volumes: + - ./.testnets:/data:ro + environment: + - WALSHIP_ROOT=/data/node2/evmd + - WALSHIP_REMOTE_URL=${WALSHIP_REMOTE_URL:-http://host.docker.internal:8080/v1/ingest/wal-frames} + - WALSHIP_AUTH_KEY=${WALSHIP_AUTH_KEY:-5a21c5c5dcf34b1aad1eafff1d0e6653} + networks: + - localnet + + # -------------------------------------------------------------------------- + # EVM Node 3 & Shipper 3 + # -------------------------------------------------------------------------- + evmdnode3: + container_name: evmdnode3 + build: + context: . + dockerfile: contrib/images/evmd-env/Dockerfile + environment: + - DEBUG=0 + - ID=3 + - LOG=${LOG:-evmd.log} + depends_on: + setup: + condition: service_completed_successfully + command: start --chain-id ${CHAIN_ID:-local-test-1234} --minimum-gas-prices 0atest --json-rpc.enable true --json-rpc.api eth,txpool,personal,net,debug,web3 + ports: + - "26686-26687:26656-26657" + - "1320:1317" + - "8575:8545" + volumes: + - ./.testnets:/data:Z + networks: + - localnet + + walship3: + container_name: walship3 + restart: always + build: + context: ../cosmos-analyzer-shipper + dockerfile: Dockerfile + depends_on: + - evmdnode3 + volumes: + - ./.testnets:/data:ro + environment: + - WALSHIP_ROOT=/data/node3/evmd + - WALSHIP_REMOTE_URL=${WALSHIP_REMOTE_URL:-http://host.docker.internal:8080/v1/ingest/wal-frames} + - WALSHIP_AUTH_KEY=${WALSHIP_AUTH_KEY:-5a21c5c5dcf34b1aad1eafff1d0e6653} + networks: + - localnet + +networks: + localnet: + driver: bridge diff --git a/evmd/go.mod b/evmd/go.mod index 1756e5e69..444261d9b 100644 --- a/evmd/go.mod +++ b/evmd/go.mod @@ -80,7 +80,7 @@ require ( github.com/cockroachdb/pebble v1.1.5 // indirect github.com/cockroachdb/redact v1.1.6 // indirect github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect - github.com/cometbft/cometbft-db v0.14.1 // indirect + github.com/cometbft/cometbft-db v1.0.1 // indirect github.com/consensys/gnark-crypto v0.18.0 // indirect github.com/cosmos/btcutil v1.0.5 // indirect github.com/cosmos/cosmos-proto v1.0.0-beta.5 // indirect @@ -98,8 +98,8 @@ require ( github.com/deckarep/golang-set/v2 v2.6.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect github.com/desertbit/timer v1.0.1 // indirect - github.com/dgraph-io/badger/v4 v4.2.0 // indirect - github.com/dgraph-io/ristretto v0.1.1 // indirect + github.com/dgraph-io/badger/v4 v4.5.1 // indirect + github.com/dgraph-io/ristretto/v2 v2.1.0 // indirect github.com/dlclark/regexp2 v1.7.0 // indirect github.com/dop251/goja v0.0.0-20230605162241-28ee0ee714f3 // indirect github.com/dustin/go-humanize v1.0.1 // indirect @@ -128,12 +128,11 @@ require ( github.com/gofrs/flock v0.12.1 // indirect github.com/gogo/googleapis v1.4.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/glog v1.2.5 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/golang/snappy v0.0.5-0.20231225225746-43d5d4cd4e0e // indirect github.com/google/btree v1.1.3 // indirect - github.com/google/flatbuffers v24.3.25+incompatible // indirect + github.com/google/flatbuffers v24.12.23+incompatible // indirect github.com/google/go-cmp v0.7.0 // indirect github.com/google/orderedcode v0.0.1 // indirect github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 // indirect @@ -174,7 +173,7 @@ require ( github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect github.com/lib/pq v1.10.9 // indirect - github.com/linxGnu/grocksdb v1.9.2 // indirect + github.com/linxGnu/grocksdb v1.9.3 // indirect github.com/manifoldco/promptui v0.9.0 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect @@ -275,6 +274,7 @@ require ( replace ( cosmossdk.io/log => github.com/bft-labs/cosmos-sdk/log v1.5.2-0.20251123071421-2a53c378ae57 cosmossdk.io/store => github.com/bft-labs/cosmos-sdk/store v1.10.0-rc.1.0.20251123071421-2a53c378ae57 + // use cosmos fork of keyring github.com/99designs/keyring => github.com/cosmos/keyring v1.2.0 github.com/cosmos/cosmos-sdk => github.com/bft-labs/cosmos-sdk v0.53.4-bft-labs-memlogger diff --git a/evmd/go.sum b/evmd/go.sum index 0b490da9a..7214c6ca3 100644 --- a/evmd/go.sum +++ b/evmd/go.sum @@ -841,8 +841,8 @@ github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1: github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= github.com/cometbft/cometbft v0.38.18 h1:1ZHYMdu0S75YxFM13LlPXnOwiIpUW5z9TKMQtTIALpw= github.com/cometbft/cometbft v0.38.18/go.mod h1:PlOQgf3jQorep+g6oVnJgtP65TJvBJoLiXjGaMdNxBE= -github.com/cometbft/cometbft-db v0.14.1 h1:SxoamPghqICBAIcGpleHbmoPqy+crij/++eZz3DlerQ= -github.com/cometbft/cometbft-db v0.14.1/go.mod h1:KHP1YghilyGV/xjD5DP3+2hyigWx0WTp9X+0Gnx0RxQ= +github.com/cometbft/cometbft-db v1.0.1 h1:SylKuLseMLQKw3+i8y8KozZyJcQSL98qEe2CGMCGTYE= +github.com/cometbft/cometbft-db v1.0.1/go.mod h1:EBrFs1GDRiTqrWXYi4v90Awf/gcdD5ExzdPbg4X8+mk= github.com/consensys/gnark-crypto v0.18.0 h1:vIye/FqI50VeAr0B3dx+YjeIvmc3LWz4yEfbWBpTUf0= github.com/consensys/gnark-crypto v0.18.0/go.mod h1:L3mXGFTe1ZN+RSJ+CLjUt9x7PNdx8ubaYfDROyp2Z8c= github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg= @@ -912,12 +912,11 @@ github.com/deepmap/oapi-codegen v1.6.0/go.mod h1:ryDa9AgbELGeB+YEXE1dR53yAjHwFvE github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f/go.mod h1:xH/i4TFMt8koVQZ6WFms69WAsDWr2XsYL3Hkl7jkoLE= github.com/desertbit/timer v1.0.1 h1:yRpYNn5Vaaj6QXecdLMPMJsW81JLiI1eokUft5nBmeo= github.com/desertbit/timer v1.0.1/go.mod h1:htRrYeY5V/t4iu1xCJ5XsQvp4xve8QulXXctAzxqcwE= -github.com/dgraph-io/badger/v4 v4.2.0 h1:kJrlajbXXL9DFTNuhhu9yCx7JJa4qpYWxtE8BzuWsEs= -github.com/dgraph-io/badger/v4 v4.2.0/go.mod h1:qfCqhPoWDFJRx1gp5QwwyGo8xk1lbHUxvK9nK0OGAak= -github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8= -github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA= +github.com/dgraph-io/badger/v4 v4.5.1 h1:7DCIXrQjo1LKmM96YD+hLVJ2EEsyyoWxJfpdd56HLps= +github.com/dgraph-io/badger/v4 v4.5.1/go.mod h1:qn3Be0j3TfV4kPbVoK0arXCD1/nr1ftth6sbL5jxdoA= +github.com/dgraph-io/ristretto/v2 v2.1.0 h1:59LjpOJLNDULHh8MC4UaegN52lC4JnO2dITsie/Pa8I= +github.com/dgraph-io/ristretto/v2 v2.1.0/go.mod h1:uejeqfYXpUomfse0+lO+13ATz4TypQYLJZzBSAemuB4= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= @@ -1076,8 +1075,6 @@ github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGw github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ= -github.com/golang/glog v1.2.5 h1:DrW6hGnjIhtvhOIiAKT6Psh/Kd/ldepEa81DKeiRJ5I= -github.com/golang/glog v1.2.5/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= 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-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -1125,8 +1122,8 @@ github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/flatbuffers v2.0.8+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= -github.com/google/flatbuffers v24.3.25+incompatible h1:CX395cjN9Kke9mmalRoL3d81AtFUxJM+yDthflgJGkI= -github.com/google/flatbuffers v24.3.25+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= +github.com/google/flatbuffers v24.12.23+incompatible h1:ubBKR94NR4pXUCY/MUsRVzd9umNW7ht7EG9hHfS9FX8= +github.com/google/flatbuffers v24.12.23+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= 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= @@ -1386,8 +1383,8 @@ github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= 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/linxGnu/grocksdb v1.9.2 h1:O3mzvO0wuzQ9mtlHbDrShixyVjVbmuqTjFrzlf43wZ8= -github.com/linxGnu/grocksdb v1.9.2/go.mod h1:QYiYypR2d4v63Wj1adOOfzglnoII0gLj3PNh4fZkcFA= +github.com/linxGnu/grocksdb v1.9.3 h1:s1cbPcOd0cU2SKXRG1nEqCOWYAELQjdqg3RVI2MH9ik= +github.com/linxGnu/grocksdb v1.9.3/go.mod h1:QYiYypR2d4v63Wj1adOOfzglnoII0gLj3PNh4fZkcFA= github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= github.com/lyft/protoc-gen-star v0.6.1/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= github.com/lyft/protoc-gen-star/v2 v2.0.1/go.mod h1:RcCdONR2ScXaYnQC5tUzxzlpA3WVYF7/opLeUgcQs/o= @@ -2122,7 +2119,6 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/evmd_broken_localnet.sh b/evmd_broken_localnet.sh new file mode 100755 index 000000000..497e414f7 --- /dev/null +++ b/evmd_broken_localnet.sh @@ -0,0 +1,508 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Multi-node localnet launcher with mixed binaries (normal + consensus-breaking) +# - setup: Builds both normal and broken evmd binaries +# - start: Runs 3 normal nodes + 1 broken node +# - stop: Stops all nodes +# - clean: Removes all test data +# +# Usage: +# ./evmd_localnet_mixed.sh setup # Build both binaries +# ./evmd_localnet_mixed.sh start # Start 4 nodes (3 normal, 1 broken) +# ./evmd_localnet_mixed.sh stop # Stop all nodes +# ./evmd_localnet_mixed.sh clean # Remove .testnets directory + +BASE_DIR_DEFAULT="./.testnets" +NODE_PREFIX_DEFAULT="node" +N_DEFAULT=4 +MIN_GAS_PRICES_DEFAULT="0atest" +SURGE_CMD_DEFAULT="surge faucet" +CHAIN_ID_DEFAULT="local-4221" +SINGLE_HOST_DEFAULT="true" +STARTING_IP_DEFAULT="127.0.0.1" + +# Cosmos SDK versions +COSMOS_SDK_NORMAL="github.com/bft-labs/cosmos-sdk v0.53.4-bft-labs-memlogger" +COSMOS_SDK_BROKEN="github.com/bft-labs/cosmos-sdk v0.53.4-bft-labs-memlogger-apphash-break-0" + +# Derive settings from env or defaults +BASE_DIR=${BASE_DIR:-$BASE_DIR_DEFAULT} +NODE_PREFIX=${NODE_PREFIX:-$NODE_PREFIX_DEFAULT} +N=${N:-$N_DEFAULT} +MIN_GAS_PRICES=${MIN_GAS_PRICES:-$MIN_GAS_PRICES_DEFAULT} +SURGE_CMD=${SURGE_CMD:-$SURGE_CMD_DEFAULT} +SURGE_ARGS=${SURGE_ARGS:-} +CHAIN_ID=${CHAIN_ID:-$CHAIN_ID_DEFAULT} +SINGLE_HOST=${SINGLE_HOST:-$SINGLE_HOST_DEFAULT} +STARTING_IP_ADDRESS=${STARTING_IP_ADDRESS:-$STARTING_IP_DEFAULT} + +# Binary paths +BUILDS_DIR="${BASE_DIR}/builds" +BINARY_NORMAL="${BUILDS_DIR}/evmd" +BINARY_BROKEN="${BUILDS_DIR}/broken_evmd" +BUILD_OUTPUT="./build/evmd" + +# Internal +PID_FILE="${BASE_DIR}/evmd_localnet_mixed.pids" +GO_MOD_BACKUP="${BASE_DIR}/go.mod.backup" +EVMD_GO_MOD_BACKUP="${BASE_DIR}/evmd_go.mod.backup" + +log() { echo "[evmd-localnet-mixed] $*"; } +err() { echo "[evmd-localnet-mixed:ERROR] $*" >&2; } + +setup_binaries() { + log "Setting up binaries in ${BUILDS_DIR}" + mkdir -p "$BUILDS_DIR" + mkdir -p "./build" + + # Backup original go.mod files if not already backed up + if [ ! -f "$GO_MOD_BACKUP" ]; then + log "Backing up go.mod" + cp go.mod "$GO_MOD_BACKUP" + fi + if [ ! -f "$EVMD_GO_MOD_BACKUP" ]; then + log "Backing up evmd/go.mod" + cp evmd/go.mod "$EVMD_GO_MOD_BACKUP" + fi + + # Build normal binary + log "Building normal evmd binary (cosmos-sdk ${COSMOS_SDK_NORMAL})..." + log "Updating go.mod files to use ${COSMOS_SDK_NORMAL}" + sed -i '' "s|github.com/cosmos/cosmos-sdk => github.com/bft-labs/cosmos-sdk v0.53.4-bft-labs-memlogger.*|github.com/cosmos/cosmos-sdk => ${COSMOS_SDK_NORMAL}|" go.mod + sed -i '' "s|github.com/cosmos/cosmos-sdk => github.com/bft-labs/cosmos-sdk v0.53.4-bft-labs-memlogger.*|github.com/cosmos/cosmos-sdk => ${COSMOS_SDK_NORMAL}|" evmd/go.mod + + log "Running go mod tidy in root..." + go mod tidy + log "Running go mod tidy in evmd/..." + cd evmd && go mod tidy && cd .. + + log "Building normal binary with go build..." + cd evmd && CGO_ENABLED="1" go build -tags "netgo" -ldflags '-w -s' -trimpath -o ../build/evmd ./cmd/evmd + cd .. + + if [ ! -f "$BUILD_OUTPUT" ]; then + err "Failed to build normal binary" + exit 1 + fi + cp "$BUILD_OUTPUT" "$BINARY_NORMAL" + log "Normal binary saved to ${BINARY_NORMAL}" + + # Build broken binary with consensus_break tag + log "Building broken evmd binary (cosmos-sdk ${COSMOS_SDK_BROKEN} + BUILD_TAGS=consensus_break)..." + log "Updating go.mod files to use ${COSMOS_SDK_BROKEN}" + sed -i '' "s|github.com/cosmos/cosmos-sdk => github.com/bft-labs/cosmos-sdk v0.53.4-bft-labs-memlogger.*|github.com/cosmos/cosmos-sdk => ${COSMOS_SDK_BROKEN}|" go.mod + sed -i '' "s|github.com/cosmos/cosmos-sdk => github.com/bft-labs/cosmos-sdk v0.53.4-bft-labs-memlogger.*|github.com/cosmos/cosmos-sdk => ${COSMOS_SDK_BROKEN}|" evmd/go.mod + + log "Running go mod tidy in root..." + go mod tidy + log "Running go mod tidy in evmd/..." + cd evmd && go mod tidy && cd .. + + log "Building broken binary with BUILD_TAGS=consensus_break..." + cd evmd && CGO_ENABLED="1" go build -tags "netgo,consensus_break" -ldflags '-w -s' -trimpath -o ../build/evmd ./cmd/evmd + cd .. + + if [ ! -f "$BUILD_OUTPUT" ]; then + err "Failed to build broken binary" + exit 1 + fi + cp "$BUILD_OUTPUT" "$BINARY_BROKEN" + log "Broken binary saved to ${BINARY_BROKEN}" + + # Restore original go.mod files + log "Restoring original go.mod files" + cp "$GO_MOD_BACKUP" go.mod + cp "$EVMD_GO_MOD_BACKUP" evmd/go.mod + + log "Running go mod tidy to restore dependencies..." + go mod tidy + cd evmd && go mod tidy && cd .. + + # Verify both binaries exist + if [ -f "$BINARY_NORMAL" ] && [ -f "$BINARY_BROKEN" ]; then + log "Setup complete! Binaries ready:" + log " Normal: ${BINARY_NORMAL}" + log " Broken: ${BINARY_BROKEN}" + else + err "Binary setup failed" + exit 1 + fi +} + +verify_binaries() { + if [ ! -f "$BINARY_NORMAL" ]; then + err "Normal binary not found at ${BINARY_NORMAL}" + err "Run './evmd_localnet_mixed.sh setup' first" + exit 1 + fi + if [ ! -f "$BINARY_BROKEN" ]; then + err "Broken binary not found at ${BINARY_BROKEN}" + err "Run './evmd_localnet_mixed.sh setup' first" + exit 1 + fi + log "Binaries verified: normal and broken evmd found" +} + +init_fresh() { + # Remove old testnet data (but preserve builds directory) + for ((i=0; i/dev/null | grep -q -- "--chain-id"; then + cmd+=(--chain-id "${CHAIN_ID}") + fi + if [ "${SINGLE_HOST}" = "true" ] && "$BINARY_NORMAL" testnet init-files --help 2>/dev/null | grep -q -- "--single-host"; then + cmd+=(--single-host=true) + fi + if [ "${SINGLE_HOST}" = "true" ] && "$BINARY_NORMAL" testnet init-files --help 2>/dev/null | grep -q -- "--starting-ip-address"; then + cmd+=(--starting-ip-address "${STARTING_IP_ADDRESS}") + fi + + printf '[evmd-localnet-mixed] Exec: ' + for a in "${cmd[@]}"; do printf '%s ' "$a"; done; printf '\n' + "${cmd[@]}" + + log "Init complete (chain-id: ${CHAIN_ID}). Genesis and configs under ${BASE_DIR}/${NODE_PREFIX}{0..$((N-1))}/evmd" + + # Fallback: patch genesis chain_id via jq if init-files doesn't support --chain-id + if ! "$BINARY_NORMAL" testnet init-files --help 2>/dev/null | grep -q -- "--chain-id"; then + if command -v jq >/dev/null 2>&1; then + for ((i=0; i "$tmp" && mv "$tmp" "$gi" + fi + done + log "Patched genesis chain_id to '${CHAIN_ID}' via jq (fallback path)." + else + log "jq not found; cannot patch genesis chain_id. Using defaults from init-files." + fi + fi +} + +adjust_ports_single_host() { + if [ "${SINGLE_HOST}" != "true" ]; then + log "SINGLE_HOST is not enabled; skipping port adjustments." + return 0 + fi + + toml_set_key_in_section() { + local file="$1" section="$2" key="$3" value="$4" + awk -v section="$section" -v key="$key" -v value="$value" ' + BEGIN { insec=0; done=0 } + /^[[:space:]]*\[/ { + if (insec && !done) { print key " = \"" value "\""; done=1 } + insec=0 + if ($0 ~ "^\\[" section "\\]") { insec=1 } + print; next + } + { + if (insec && $0 ~ "^[[:space:]]*" key "[[:space:]]*=") { + print key " = \"" value "\""; done=1; next + } + print + } + END { + if (insec && !done) { print key " = \"" value "\"" } + } + ' "$file" >"$file.tmp" && mv "$file.tmp" "$file" + } + + for ((i=0; i"$file.tmp" && mv "$file.tmp" "$file" + } + + toml_set_key_in_section_raw() { + local file="$1" section="$2" key="$3" rawvalue="$4" + awk -v section="$section" -v key="$key" -v rawvalue="$rawvalue" ' + BEGIN { insec=0; done=0 } + /^[[:space:]]*\[/ { + if (insec && !done) { print key " = " rawvalue; done=1 } + insec=0 + if ($0 ~ "^\\[" section "\\]") { insec=1 } + print; next + } + { + if (insec && $0 ~ "^[[:space:]]*" key "[[:space:]]*=") { + print key " = " rawvalue; done=1; next + } + print + } + END { + if (insec && !done) { print key " = " rawvalue } + } + ' "$file" >"$file.tmp" && mv "$file.tmp" "$file" + } + + toml_set_key_in_section "$APP_TOML" "memlogger" "enabled" "true" + toml_set_key_in_section "$APP_TOML" "memlogger" "interval" "2s" + toml_set_key_in_section_raw "$APP_TOML" "memlogger" "memory-bytes" "104857600" + done + log "Enabled memlogger for all nodes." +} + +apply_surge_and_replicate() { + local g0="${BASE_DIR}/${NODE_PREFIX}0/evmd/config/genesis.json" + if [ ! -f "$g0" ]; then + err "node0 genesis not found at $g0" + exit 1 + fi + + if [ -n "$SURGE_CMD" ]; then + local surge_bin + surge_bin=$(echo "$SURGE_CMD" | awk '{print $1}') + if ! command -v "$surge_bin" >/dev/null 2>&1; then + err "'$surge_bin' not found on PATH. Set SURGE_CMD='' to skip or install surge." + exit 1 + fi + printf '[evmd-localnet-mixed] Exec: %s %s %s\n' "$SURGE_CMD" "${SURGE_ARGS}" "$g0" + eval "$SURGE_CMD ${SURGE_ARGS} $g0" + else + log "SURGE_CMD empty; skipping surge faucet step." + fi + + for ((i=1; i/dev/null 2>&1 || true + fi + done +} + +build_peers_if_possible() { + if ! "$BINARY_NORMAL" comet --help >/dev/null 2>&1; then + log "'evmd comet' subcommand not found. Skipping persistent_peers injection." + return 0 + fi + + local peers="" + for ((i=0; i/dev/null); then + err "Failed to read node ID for ${NODE_PREFIX}${i}; skipping persistent_peers." + return 0 + fi + local p2p_port=$((16656 + i)) + local entry="${id}@127.0.0.1:${p2p_port}" + if [ -z "$peers" ]; then peers="$entry"; else peers+=",$entry"; fi + done + + log "persistent_peers=${peers}" + for ((i=0; i> "$cfg" + fi + fi + done +} + +start_nodes() { + mkdir -p "$(dirname "$PID_FILE")" + : > "$PID_FILE" + + for ((i=0; i/dev/null 2>&1 || true + + cmd=("$BINARY" start \ + --home "$home_dir" \ + --minimum-gas-prices "${MIN_GAS_PRICES}" \ + --evm.min-tip 0 \ + --json-rpc.api "eth,txpool,personal,net,debug,web3" \ + --chain-id "${CHAIN_ID}") + + printf '[evmd-localnet-mixed] Exec: ' + for arg in "${cmd[@]}"; do printf '%s ' "$arg"; done; printf '\n' + + ("${cmd[@]}" >"$log_file" 2>&1 & echo $! >> "$PID_FILE") + sleep 0.5 + done + + log "All nodes started. PIDs recorded in ${PID_FILE}" + log "Node0 (broken) running on: rpc=26657, http=8545" + log "Node1 (normal) running on: rpc=26658, http=8555" + log "Node2 (normal) running on: rpc=26659, http=8565" + log "Node3 (normal) running on: rpc=26660, http=8575" +} + +stop_nodes() { + if [ ! -f "$PID_FILE" ]; then + err "PID file not found: $PID_FILE" + exit 1 + fi + tac "$PID_FILE" | while read -r pid; do + if kill -0 "$pid" >/dev/null 2>&1; then + log "Stopping PID $pid" + kill "$pid" || true + fi + done + rm -f "$PID_FILE" + log "All nodes stopped." +} + +clean() { + if [ -d "$BASE_DIR" ]; then + log "Removing ${BASE_DIR}" + rm -rf "$BASE_DIR" + fi + log "Clean complete." +} + +cmd=${1:-start} +case "$cmd" in + setup) + setup_binaries + ;; + start) + verify_binaries + init_fresh + apply_surge_and_replicate + adjust_ports_single_host + tune_timeouts + adjust_memlogger + build_peers_if_possible + start_nodes + ;; + stop) + stop_nodes + ;; + clean) + clean + ;; + *) + echo "Usage: $0 {setup|start|stop|clean}" >&2 + echo "" >&2 + echo "Commands:" >&2 + echo " setup - Build both normal and broken evmd binaries" >&2 + echo " start - Initialize and start 4 nodes (1 broken, 3 normal)" >&2 + echo " stop - Stop all running nodes" >&2 + echo " clean - Remove all test data and binaries" >&2 + exit 1 + ;; +esac diff --git a/evmd_localnet.sh b/evmd_localnet.sh new file mode 100755 index 000000000..5c70bc7dd --- /dev/null +++ b/evmd_localnet.sh @@ -0,0 +1,418 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Simple multi-node localnet launcher for evmd +# - Initializes N validator nodes under BASE_DIR using `evmd testnet init-files --validator-count N --keyring-backend test` +# - Applies surge faucet to node0 genesis, then replicates the modified genesis to all nodes +# - Optionally computes persistent_peers via `evmd comet show-node-id` if available +# - Starts each node with its own home and port set by init-files +# +# Usage: +# scripts/evmd-localnet.sh start # init (if needed) and start N nodes +# scripts/evmd-localnet.sh stop # stop nodes started by this script (via PID file) +# scripts/evmd-localnet.sh clean # remove BASE_DIR + +BINARY_DEFAULT="evmd" # or override via BINARY env +BASE_DIR_DEFAULT="./.testnets" # or override via BASE_DIR env +NODE_PREFIX_DEFAULT="node" +N_DEFAULT=4 +# Start defaults (min gas aligned with local_node.sh) +MIN_GAS_PRICES_DEFAULT="0atest" +SURGE_CMD_DEFAULT="surge faucet" # or override via SURGE_CMD env; extra args via SURGE_ARGS +CHAIN_ID_DEFAULT="local-4221" # or override via CHAIN_ID env +SINGLE_HOST_DEFAULT="true" # allocate unique ports per node on one host +STARTING_IP_DEFAULT="127.0.0.1" # starting IP for init-files on single host + +# Derive settings from env or defaults +BINARY=${BINARY:-$BINARY_DEFAULT} +BASE_DIR=${BASE_DIR:-$BASE_DIR_DEFAULT} +NODE_PREFIX=${NODE_PREFIX:-$NODE_PREFIX_DEFAULT} +N=${N:-$N_DEFAULT} +MIN_GAS_PRICES=${MIN_GAS_PRICES:-$MIN_GAS_PRICES_DEFAULT} +SURGE_CMD=${SURGE_CMD:-$SURGE_CMD_DEFAULT} +SURGE_ARGS=${SURGE_ARGS:-} +CHAIN_ID=${CHAIN_ID:-$CHAIN_ID_DEFAULT} +SINGLE_HOST=${SINGLE_HOST:-$SINGLE_HOST_DEFAULT} +STARTING_IP_ADDRESS=${STARTING_IP_ADDRESS:-$STARTING_IP_DEFAULT} + +# Internal +PID_FILE="${BASE_DIR}/evmd_localnet.pids" + +log() { echo "[evmd-localnet] $*"; } +err() { echo "[evmd-localnet:ERROR] $*" >&2; } + +ensure_binary() { + if command -v "$BINARY" >/dev/null 2>&1; then + return 0 + fi + # Fallback to local build path + if [ -x "./build/evmd" ]; then + BINARY="./build/evmd" + return 0 + fi + err "Cannot find evmd binary. Put it on PATH or build via 'make build'." + exit 1 +} + +init_fresh() { + # Always initialize a fresh testnet as requested + rm -rf "$BASE_DIR" + log "Initializing ${N}-node testnet at ${BASE_DIR}…" + mkdir -p "$BASE_DIR" + + # Per request: use only validator-count and keyring-backend flags (+ output-dir to control location) + local cmd=("$BINARY" testnet init-files \ + --validator-count "${N}" \ + --keyring-backend test \ + --output-dir "${BASE_DIR}") + + # Add chain-id if supported by the subcommand + if "$BINARY" testnet init-files --help 2>/dev/null | grep -q -- "--chain-id"; then + cmd+=(--chain-id "${CHAIN_ID}") + fi + # Use single-host ports from generator if supported + if [ "${SINGLE_HOST}" = "true" ] && "$BINARY" testnet init-files --help 2>/dev/null | grep -q -- "--single-host"; then + cmd+=(--single-host=true) + fi + # Set starting IP address if supported (helps ensure 127.0.0.1 mapping) + if [ "${SINGLE_HOST}" = "true" ] && "$BINARY" testnet init-files --help 2>/dev/null | grep -q -- "--starting-ip-address"; then + cmd+=(--starting-ip-address "${STARTING_IP_ADDRESS}") + fi + + printf '[evmd-localnet] Exec: ' + for a in "${cmd[@]}"; do printf '%s ' "$a"; done; printf '\n' + "${cmd[@]}" + + log "Init complete (chain-id: ${CHAIN_ID}). Genesis and configs under ${BASE_DIR}/${NODE_PREFIX}{0..$((N-1))}/evmd" + + # Fallback: if init-files doesn't support --chain-id, patch genesis chain_id via jq + if ! "$BINARY" testnet init-files --help 2>/dev/null | grep -q -- "--chain-id"; then + if command -v jq >/dev/null 2>&1; then + for ((i=0; i< N; i++)); do + gi="${BASE_DIR}/${NODE_PREFIX}${i}/evmd/config/genesis.json" + if [ -f "$gi" ]; then + tmp="$gi.tmp" && jq --arg cid "$CHAIN_ID" '.chain_id=$cid' "$gi" > "$tmp" && mv "$tmp" "$gi" + fi + done + log "Patched genesis chain_id to '${CHAIN_ID}' via jq (fallback path)." + else + log "jq not found; cannot patch genesis chain_id. Using defaults from init-files." + fi + fi +} + +# Update per-node ports for single host to avoid conflicts +adjust_ports_single_host() { + if [ "${SINGLE_HOST}" != "true" ]; then + log "SINGLE_HOST is not enabled; skipping port adjustments." + return 0 + fi + + # Helper to set a key inside a specific TOML section + toml_set_key_in_section() { + local file="$1" section="$2" key="$3" value="$4" + awk -v section="$section" -v key="$key" -v value="$value" ' + BEGIN { insec=0; done=0 } + /^[[:space:]]*\[/ { + if (insec && !done) { print key " = \"" value "\""; done=1 } + insec=0 + if ($0 ~ "^\\[" section "\\]") { insec=1 } + print; next + } + { + if (insec && $0 ~ "^[[:space:]]*" key "[[:space:]]*=") { + print key " = \"" value "\""; done=1; next + } + print + } + END { + if (insec && !done) { print key " = \"" value "\"" } + } + ' "$file" >"$file.tmp" && mv "$file.tmp" "$file" + } + + for ((i=0; i< N; i++)); do + local home_dir="${BASE_DIR}/${NODE_PREFIX}${i}/evmd" + local cfg_tm="${home_dir}/config/config.toml" + local cfg_app="${home_dir}/config/app.toml" + + [ -f "$cfg_tm" ] || { err "Missing $cfg_tm"; continue; } + [ -f "$cfg_app" ] || { err "Missing $cfg_app"; continue; } + + # Compute unique ports + local rpc_port=$((26657 + i)) + local p2p_port=$((16656 + i)) + local pprof_port=$((6060 + i)) + local prom_port=$((26660 + i)) + local api_port=$((1317 + i)) + local grpc_port=$((9090 + i)) + local grpcweb_port=$((9091 + i)) + local http_port=$((8545 + i*10)) + local ws_port=$((8546 + i*10)) + + # Tendermint config.toml + toml_set_key_in_section "$cfg_tm" "rpc" "laddr" "tcp://127.0.0.1:${rpc_port}" + toml_set_key_in_section "$cfg_tm" "rpc" "pprof_laddr" "localhost:${pprof_port}" + toml_set_key_in_section "$cfg_tm" "p2p" "laddr" "tcp://127.0.0.1:${p2p_port}" + toml_set_key_in_section "$cfg_tm" "instrumentation" "prometheus_listen_addr" ":${prom_port}" + + # Application app.toml + toml_set_key_in_section "$cfg_app" "api" "address" "tcp://127.0.0.1:${api_port}" + toml_set_key_in_section "$cfg_app" "grpc" "address" "127.0.0.1:${grpc_port}" + toml_set_key_in_section "$cfg_app" "grpc-web" "address" "127.0.0.1:${grpcweb_port}" + toml_set_key_in_section "$cfg_app" "json-rpc" "address" "127.0.0.1:${http_port}" + toml_set_key_in_section "$cfg_app" "json-rpc" "ws-address" "127.0.0.1:${ws_port}" + + log "Configured ${NODE_PREFIX}${i} ports: rpc:${rpc_port} p2p:${p2p_port} api:${api_port} http:${http_port} ws:${ws_port} grpc:${grpc_port}/${grpcweb_port}" + done +} + +# Apply consensus timeout adjustments similar to local_node.sh +tune_timeouts() { + for ((i=0; i< N; i++)); do + local CONFIG_TOML="${BASE_DIR}/${NODE_PREFIX}${i}/evmd/config/config.toml" + if [ ! -f "$CONFIG_TOML" ]; then + err "Missing $CONFIG_TOML" + continue + fi + # Logging: debug level and json format + sed -i.bak 's/log_level = "info"/log_level = "debug"/g' "$CONFIG_TOML" + sed -i.bak 's/log_format = "plain"/log_format = "json"/g' "$CONFIG_TOML" + sed -i.bak 's/timeout_propose = "3s"/timeout_propose = "2s"/g' "$CONFIG_TOML" + sed -i.bak 's/timeout_propose_delta = "500ms"/timeout_propose_delta = "200ms"/g' "$CONFIG_TOML" + sed -i.bak 's/timeout_prevote = "1s"/timeout_prevote = "500ms"/g' "$CONFIG_TOML" + sed -i.bak 's/timeout_prevote_delta = "500ms"/timeout_prevote_delta = "200ms"/g' "$CONFIG_TOML" + sed -i.bak 's/timeout_precommit = "1s"/timeout_precommit = "500ms"/g' "$CONFIG_TOML" + sed -i.bak 's/timeout_precommit_delta = "500ms"/timeout_precommit_delta = "200ms"/g' "$CONFIG_TOML" + sed -i.bak 's/timeout_commit = "5s"/timeout_commit = "1s"/g' "$CONFIG_TOML" + sed -i.bak 's/timeout_broadcast_tx_commit = "10s"/timeout_broadcast_tx_commit = "5s"/g' "$CONFIG_TOML" + done + log "Applied consensus timeout adjustments to all nodes." +} + +# Adjust memlogger settings in app.toml for each node +adjust_memlogger() { + for ((i=0; i< N; i++)); do + local APP_TOML="${BASE_DIR}/${NODE_PREFIX}${i}/evmd/config/app.toml" + if [ ! -f "$APP_TOML" ]; then + err "Missing $APP_TOML" + continue + fi + + # Helpers local to this function + toml_set_key_in_section() { + local file="$1" section="$2" key="$3" value="$4" + awk -v section="$section" -v key="$key" -v value="$value" ' + BEGIN { insec=0; done=0 } + /^[[:space:]]*\[/ { + if (insec && !done) { print key " = \"" value "\""; done=1 } + insec=0 + if ($0 ~ "^\\[" section "\\]") { insec=1 } + print; next + } + { + if (insec && $0 ~ "^[[:space:]]*" key "[[:space:]]*=") { + print key " = \"" value "\""; done=1; next + } + print + } + END { + if (insec && !done) { print key " = \"" value "\"" } + } + ' "$file" >"$file.tmp" && mv "$file.tmp" "$file" + } + + toml_set_key_in_section_raw() { + local file="$1" section="$2" key="$3" rawvalue="$4" + awk -v section="$section" -v key="$key" -v rawvalue="$rawvalue" ' + BEGIN { insec=0; done=0 } + /^[[:space:]]*\[/ { + if (insec && !done) { print key " = " rawvalue; done=1 } + insec=0 + if ($0 ~ "^\\[" section "\\]") { insec=1 } + print; next + } + { + if (insec && $0 ~ "^[[:space:]]*" key "[[:space:]]*=") { + print key " = " rawvalue; done=1; next + } + print + } + END { + if (insec && !done) { print key " = " rawvalue } + } + ' "$file" >"$file.tmp" && mv "$file.tmp" "$file" + } + + # interval: set to 3m (string) + toml_set_key_in_section "$APP_TOML" "memlogger" "interval" "3m" + # max-bytes: set to 2GB (2147483648) numeric + toml_set_key_in_section_raw "$APP_TOML" "memlogger" "max-bytes" "2147483648" + + log "Adjusted memlogger for ${NODE_PREFIX}${i}: interval=3m, max-bytes=2147483648" + done +} + +apply_surge_and_replicate() { + # Apply surge faucet on node0 genesis, then copy to other nodes + local g0="${BASE_DIR}/${NODE_PREFIX}0/evmd/config/genesis.json" + if [ ! -f "$g0" ]; then + err "node0 genesis not found at $g0" + exit 1 + fi + + # Run surge faucet if available/desired + if [ -n "$SURGE_CMD" ]; then + local surge_bin + surge_bin=$(echo "$SURGE_CMD" | awk '{print $1}') + if ! command -v "$surge_bin" >/dev/null 2>&1; then + err "'$surge_bin' not found on PATH. Set SURGE_CMD='' to skip or install surge." + exit 1 + fi + # Echo the exact command + printf '[evmd-localnet] Exec: %s %s %s\n' "$SURGE_CMD" "${SURGE_ARGS}" "$g0" + # Execute with optional extra args + eval "$SURGE_CMD ${SURGE_ARGS} $g0" + else + log "SURGE_CMD empty; skipping surge faucet step." + fi + + # Replicate node0 genesis to all other nodes + for ((i=1; i< N; i++)); do + local gi="${BASE_DIR}/${NODE_PREFIX}${i}/evmd/config/genesis.json" + if [ -f "$gi" ]; then + cp "$g0" "$gi" + fi + done + + # Validate genesis for all nodes (best-effort) + for ((i=0; i< N; i++)); do + local home_dir="${BASE_DIR}/${NODE_PREFIX}${i}/evmd" + if [ -d "$home_dir" ]; then + "$BINARY" genesis validate-genesis --home "$home_dir" >/dev/null 2>&1 || true + fi + done +} + +build_peers_if_possible() { + # Try to gather node IDs using `evmd comet show-node-id` if the subcommand exists. + if ! "$BINARY" comet --help >/dev/null 2>&1; then + log "'evmd comet' subcommand not found. Skipping persistent_peers injection (nodes should still connect with generated configs)." + return 0 + fi + + local peers="" + for ((i=0; i< N; i++)); do + local home_dir="${BASE_DIR}/${NODE_PREFIX}${i}/evmd" + local id + if ! id=$("$BINARY" comet show-node-id --home "$home_dir" 2>/dev/null); then + err "Failed to read node ID for ${NODE_PREFIX}${i}; skipping persistent_peers." + return 0 + fi + # Ports per init-files when --single-host is used: + # - P2P starts at 16656 and increments by +1 per node + local p2p_port=$((16656 + i)) + local entry="${id}@127.0.0.1:${p2p_port}" + if [ -z "$peers" ]; then peers="$entry"; else peers+="",$entry; fi + done + + log "persistent_peers=${peers}" + # Inject into each node's config.toml + for ((i=0; i< N; i++)); do + local cfg="${BASE_DIR}/${NODE_PREFIX}${i}/evmd/config/config.toml" + if [ -f "$cfg" ]; then + # Replace existing line or append if missing + if grep -q '^persistent_peers\s*=\s*"' "$cfg"; then + sed -i.bak -E "s|^persistent_peers\s*=\s*\".*\"|persistent_peers = \"${peers}\"|" "$cfg" + else + echo "persistent_peers = \"${peers}\"" >> "$cfg" + fi + fi + done +} + +start_nodes() { + mkdir -p "$(dirname "$PID_FILE")" + : > "$PID_FILE" + + for ((i=0; i< N; i++)); do + local home_dir="${BASE_DIR}/${NODE_PREFIX}${i}/evmd" + local log_file="${home_dir}/evmd.log" + + # Compute display ports that init-files configure for single-host: + local rpc_port=$((26657 + i)) + local p2p_port=$((16656 + i)) + local api_port=$((1317 + i)) + local http_port=$((8545 + i*10)) + local ws_port=$((8546 + i*10)) + + log "Starting ${NODE_PREFIX}${i} (rpc:${rpc_port}, p2p:${p2p_port}, api:${api_port}, http:${http_port}, ws:${ws_port})" + + # Ensure client chain-id is set for this home (useful for CLI interactions) + "$BINARY" config set client chain-id "${CHAIN_ID}" --home "$home_dir" >/dev/null 2>&1 || true + + # Build start command (aligned with local_node.sh gas defaults) and echo it for reproducibility + cmd=("$BINARY" start \ + --home "$home_dir" \ + --minimum-gas-prices "${MIN_GAS_PRICES}" \ + --evm.min-tip 0 \ + --json-rpc.api "eth,txpool,personal,net,debug,web3" \ + --chain-id "${CHAIN_ID}" + --memlog=true) + + printf '[evmd-localnet] Exec: ' + for arg in "${cmd[@]}"; do printf '%s ' "$arg"; done; printf '\n' + + # Start in background, capture PID + ("${cmd[@]}" >"$log_file" 2>&1 & echo $! >> "$PID_FILE") + sleep 0.5 + done + + log "All nodes started. PIDs recorded in ${PID_FILE}" +} + +stop_nodes() { + if [ ! -f "$PID_FILE" ]; then + err "PID file not found: $PID_FILE" + exit 1 + fi + tac "$PID_FILE" | while read -r pid; do + if kill -0 "$pid" >/dev/null 2>&1; then + log "Stopping PID $pid" + kill "$pid" || true + fi + done + rm -f "$PID_FILE" + log "All nodes stopped." +} + +clean() { + if [ -d "$BASE_DIR" ]; then + log "Removing ${BASE_DIR}" + rm -rf "$BASE_DIR" + fi +} + +cmd=${1:-start} +case "$cmd" in + start) + ensure_binary + init_fresh + apply_surge_and_replicate + adjust_ports_single_host + tune_timeouts + adjust_memlogger + build_peers_if_possible + start_nodes + ;; + stop) + stop_nodes + ;; + clean) + clean + ;; + *) + echo "Usage: $0 {start|stop|clean}" >&2 + exit 1 + ;; +esac diff --git a/go.mod b/go.mod index 1134a228e..da9f34743 100644 --- a/go.mod +++ b/go.mod @@ -35,7 +35,7 @@ require ( github.com/hashicorp/go-metrics v0.5.4 github.com/holiman/uint256 v1.3.2 github.com/improbable-eng/grpc-web v0.15.0 - github.com/linxGnu/grocksdb v1.9.2 + github.com/linxGnu/grocksdb v1.9.3 github.com/onsi/ginkgo/v2 v2.23.4 github.com/onsi/gomega v1.38.0 github.com/pkg/errors v0.9.1 @@ -104,7 +104,7 @@ require ( github.com/cockroachdb/pebble v1.1.5 // indirect github.com/cockroachdb/redact v1.1.6 // indirect github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect - github.com/cometbft/cometbft-db v0.14.1 // indirect + github.com/cometbft/cometbft-db v1.0.1 // indirect github.com/consensys/gnark-crypto v0.18.0 // indirect github.com/cosmos/btcutil v1.0.5 // indirect github.com/cosmos/gogogateway v1.2.0 // indirect @@ -118,8 +118,8 @@ require ( github.com/deckarep/golang-set/v2 v2.6.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect github.com/desertbit/timer v1.0.1 // indirect - github.com/dgraph-io/badger/v4 v4.2.0 // indirect - github.com/dgraph-io/ristretto v0.1.1 // indirect + github.com/dgraph-io/badger/v4 v4.5.1 // indirect + github.com/dgraph-io/ristretto/v2 v2.1.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/dvsekhvalnov/jose2go v1.7.0 // indirect github.com/emicklei/dot v1.6.2 // indirect @@ -144,11 +144,10 @@ require ( github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect github.com/gofrs/flock v0.12.1 // indirect github.com/gogo/googleapis v1.4.1 // indirect - github.com/golang/glog v1.2.5 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/snappy v0.0.5-0.20231225225746-43d5d4cd4e0e // indirect github.com/google/btree v1.1.3 // indirect - github.com/google/flatbuffers v24.3.25+incompatible // indirect + github.com/google/flatbuffers v24.12.23+incompatible // indirect github.com/google/go-cmp v0.7.0 // indirect github.com/google/orderedcode v0.0.1 // indirect github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 // indirect @@ -269,6 +268,7 @@ require ( ) replace ( + cosmossdk.io/log => github.com/bft-labs/cosmos-sdk/log v1.5.2-0.20251123071421-2a53c378ae57 cosmossdk.io/store => github.com/bft-labs/cosmos-sdk/store v1.10.0-rc.1.0.20251123071421-2a53c378ae57 // use cosmos fork of keyring github.com/99designs/keyring => github.com/cosmos/keyring v1.2.0 diff --git a/go.sum b/go.sum index db7592081..7f0eae1f5 100644 --- a/go.sum +++ b/go.sum @@ -626,8 +626,6 @@ cosmossdk.io/depinject v1.2.1 h1:eD6FxkIjlVaNZT+dXTQuwQTKZrFZ4UrfCq1RKgzyhMw= cosmossdk.io/depinject v1.2.1/go.mod h1:lqQEycz0H2JXqvOgVwTsjEdMI0plswI7p6KX+MVqFOM= cosmossdk.io/errors v1.0.2 h1:wcYiJz08HThbWxd/L4jObeLaLySopyyuUFB5w4AGpCo= cosmossdk.io/errors v1.0.2/go.mod h1:0rjgiHkftRYPj//3DrD6y8hcm40HcPv/dR4R/4efr0k= -cosmossdk.io/log v1.6.1 h1:YXNwAgbDwMEKwDlCdH8vPcoggma48MgZrTQXCfmMBeI= -cosmossdk.io/log v1.6.1/go.mod h1:gMwsWyyDBjpdG9u2avCFdysXqxq28WJapJvu+vF1y+E= cosmossdk.io/math v1.5.3 h1:WH6tu6Z3AUCeHbeOSHg2mt9rnoiUWVWaQ2t6Gkll96U= cosmossdk.io/math v1.5.3/go.mod h1:uqcZv7vexnhMFJF+6zh9EWdm/+Ylyln34IvPnBauPCQ= cosmossdk.io/schema v1.1.0 h1:mmpuz3dzouCoyjjcMcA/xHBEmMChN+EHh8EHxHRHhzE= @@ -721,6 +719,8 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bft-labs/cosmos-sdk v0.53.4-bft-labs-memlogger h1:5pRPFmW3HddXynFY41gT0pGW8VK+lATJTDYS2Be9uUE= github.com/bft-labs/cosmos-sdk v0.53.4-bft-labs-memlogger/go.mod h1:SICzd8okv4I/osxz6esxbcQiHimH0CYIP6SBK8CfR7c= +github.com/bft-labs/cosmos-sdk/log v1.5.2-0.20251123071421-2a53c378ae57 h1:lu67DO6o5HkwXpM+foswKUMiiaKuV/as6SC/Luv0Gm4= +github.com/bft-labs/cosmos-sdk/log v1.5.2-0.20251123071421-2a53c378ae57/go.mod h1:/nr+xEg1LA3FHTsBBwwzrft0oQXsoFfdAwuSNXBQn0U= github.com/bft-labs/cosmos-sdk/store v1.10.0-rc.1.0.20251123071421-2a53c378ae57 h1:isQ928HvH1wP9SS2fr8cGoALSMg6crdiOfX/bFflwYM= github.com/bft-labs/cosmos-sdk/store v1.10.0-rc.1.0.20251123071421-2a53c378ae57/go.mod h1:i2O3FQWKx1kawKvwQ5dTOdYEfh2SKvPVrgMP154uqPE= github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d h1:xDfNPAt8lFiC1UJrqV3uuy861HCTo708pDMbjHHdCas= @@ -838,8 +838,8 @@ github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1: github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= github.com/cometbft/cometbft v0.38.18 h1:1ZHYMdu0S75YxFM13LlPXnOwiIpUW5z9TKMQtTIALpw= github.com/cometbft/cometbft v0.38.18/go.mod h1:PlOQgf3jQorep+g6oVnJgtP65TJvBJoLiXjGaMdNxBE= -github.com/cometbft/cometbft-db v0.14.1 h1:SxoamPghqICBAIcGpleHbmoPqy+crij/++eZz3DlerQ= -github.com/cometbft/cometbft-db v0.14.1/go.mod h1:KHP1YghilyGV/xjD5DP3+2hyigWx0WTp9X+0Gnx0RxQ= +github.com/cometbft/cometbft-db v1.0.1 h1:SylKuLseMLQKw3+i8y8KozZyJcQSL98qEe2CGMCGTYE= +github.com/cometbft/cometbft-db v1.0.1/go.mod h1:EBrFs1GDRiTqrWXYi4v90Awf/gcdD5ExzdPbg4X8+mk= github.com/consensys/gnark-crypto v0.18.0 h1:vIye/FqI50VeAr0B3dx+YjeIvmc3LWz4yEfbWBpTUf0= github.com/consensys/gnark-crypto v0.18.0/go.mod h1:L3mXGFTe1ZN+RSJ+CLjUt9x7PNdx8ubaYfDROyp2Z8c= github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg= @@ -909,12 +909,11 @@ github.com/deepmap/oapi-codegen v1.6.0/go.mod h1:ryDa9AgbELGeB+YEXE1dR53yAjHwFvE github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f/go.mod h1:xH/i4TFMt8koVQZ6WFms69WAsDWr2XsYL3Hkl7jkoLE= github.com/desertbit/timer v1.0.1 h1:yRpYNn5Vaaj6QXecdLMPMJsW81JLiI1eokUft5nBmeo= github.com/desertbit/timer v1.0.1/go.mod h1:htRrYeY5V/t4iu1xCJ5XsQvp4xve8QulXXctAzxqcwE= -github.com/dgraph-io/badger/v4 v4.2.0 h1:kJrlajbXXL9DFTNuhhu9yCx7JJa4qpYWxtE8BzuWsEs= -github.com/dgraph-io/badger/v4 v4.2.0/go.mod h1:qfCqhPoWDFJRx1gp5QwwyGo8xk1lbHUxvK9nK0OGAak= -github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8= -github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA= +github.com/dgraph-io/badger/v4 v4.5.1 h1:7DCIXrQjo1LKmM96YD+hLVJ2EEsyyoWxJfpdd56HLps= +github.com/dgraph-io/badger/v4 v4.5.1/go.mod h1:qn3Be0j3TfV4kPbVoK0arXCD1/nr1ftth6sbL5jxdoA= +github.com/dgraph-io/ristretto/v2 v2.1.0 h1:59LjpOJLNDULHh8MC4UaegN52lC4JnO2dITsie/Pa8I= +github.com/dgraph-io/ristretto/v2 v2.1.0/go.mod h1:uejeqfYXpUomfse0+lO+13ATz4TypQYLJZzBSAemuB4= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= @@ -1063,8 +1062,6 @@ github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGw github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ= -github.com/golang/glog v1.2.5 h1:DrW6hGnjIhtvhOIiAKT6Psh/Kd/ldepEa81DKeiRJ5I= -github.com/golang/glog v1.2.5/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= 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-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -1112,8 +1109,8 @@ github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/flatbuffers v2.0.8+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= -github.com/google/flatbuffers v24.3.25+incompatible h1:CX395cjN9Kke9mmalRoL3d81AtFUxJM+yDthflgJGkI= -github.com/google/flatbuffers v24.3.25+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= +github.com/google/flatbuffers v24.12.23+incompatible h1:ubBKR94NR4pXUCY/MUsRVzd9umNW7ht7EG9hHfS9FX8= +github.com/google/flatbuffers v24.12.23+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= 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= @@ -1371,8 +1368,8 @@ github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= 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/linxGnu/grocksdb v1.9.2 h1:O3mzvO0wuzQ9mtlHbDrShixyVjVbmuqTjFrzlf43wZ8= -github.com/linxGnu/grocksdb v1.9.2/go.mod h1:QYiYypR2d4v63Wj1adOOfzglnoII0gLj3PNh4fZkcFA= +github.com/linxGnu/grocksdb v1.9.3 h1:s1cbPcOd0cU2SKXRG1nEqCOWYAELQjdqg3RVI2MH9ik= +github.com/linxGnu/grocksdb v1.9.3/go.mod h1:QYiYypR2d4v63Wj1adOOfzglnoII0gLj3PNh4fZkcFA= github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= github.com/lyft/protoc-gen-star v0.6.1/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= github.com/lyft/protoc-gen-star/v2 v2.0.1/go.mod h1:RcCdONR2ScXaYnQC5tUzxzlpA3WVYF7/opLeUgcQs/o= @@ -2107,7 +2104,6 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/local_node.sh b/memlogger-experiment.sh similarity index 95% rename from local_node.sh rename to memlogger-experiment.sh index a7e410825..ea6d2e49f 100755 --- a/local_node.sh +++ b/memlogger-experiment.sh @@ -273,6 +273,11 @@ if [[ $overwrite == "y" || $overwrite == "Y" ]]; then sed -i.bak 's/enabled = false/enabled = true/g' "$APP_TOML" sed -i.bak 's/enable = false/enable = true/g' "$APP_TOML" + # loggers + sed -i.bak 's/log_level = "info"/log_level = "debug"/g' "$CONFIG_TOML" + sed -i.bak 's/log_format = "plain"/log_format = "json"/g' "$CONFIG_TOML" + + # --------- maybe generate additional users --------- # start with provided/default list final_mnemonics=("${dev_mnemonics[@]}") @@ -337,12 +342,25 @@ if [[ $overwrite == "y" || $overwrite == "Y" ]]; then fi fi + # Start the node -evmd start "$TRACE" \ - --pruning nothing \ - --log_level $LOGLEVEL \ - --minimum-gas-prices=0atest \ - --evm.min-tip=0 \ - --home "$CHAINDIR" \ - --json-rpc.api eth,txpool,personal,net,debug,web3 \ - --chain-id "$CHAINID" +# Echo the full command with all parameters for transparency (no shell-escaping) +cmd=(evmd start) +if [[ -n "$TRACE" ]]; then + cmd+=("$TRACE") +fi +cmd+=( + --pruning nothing + --log_level "$LOGLEVEL" + --minimum-gas-prices=0atest + --evm.min-tip=0 + --home "$CHAINDIR" + --json-rpc.api "eth,txpool,personal,net,debug,web3" + --chain-id "$CHAINID" + --memlog=true +) +printf 'Executing: ' +for arg in "${cmd[@]}"; do + printf '%s ' "$arg" +done +printf '\n' diff --git a/start-testnet.sh b/start-testnet.sh new file mode 100755 index 000000000..6172a4cce --- /dev/null +++ b/start-testnet.sh @@ -0,0 +1,230 @@ +#!/bin/bash + +# Interactive script to start a new testnet with apphash.io integration +set -e + +# Parse arguments +NODE_COUNT=4 +SERVICE_BASE="http://host.docker.internal:8080" +AUTH_KEY="" +CUSTOM_CHAIN_ID="" + +while [[ $# -gt 0 ]]; do + case $1 in + --nodes|-n) + NODE_COUNT="$2" + shift 2 + ;; + --url|-u) + SERVICE_BASE="$2" + shift 2 + ;; + --chain-id|-c) + CUSTOM_CHAIN_ID="$2" + shift 2 + ;; + --auth-key|-k) + AUTH_KEY="$2" + shift 2 + ;; + *) + NODE_COUNT="$1" + shift + ;; + esac +done + +echo "=============================================" +echo " EVM Testnet Launcher with apphash.io" +echo "=============================================" +echo "" + +# Step 1: Configure Chain ID +if [ -n "$CUSTOM_CHAIN_ID" ]; then + CHAIN_ID="$CUSTOM_CHAIN_ID" +else + DEFAULT_CHAIN_ID="testnet-$(date +%s)" + if [ -n "$AUTH_KEY" ]; then + CHAIN_ID="$DEFAULT_CHAIN_ID" + else + echo "Step 1: Configure Chain ID" + echo "" + read -p "Enter Chain ID (default: $DEFAULT_CHAIN_ID): " USER_CHAIN_ID + CHAIN_ID="${USER_CHAIN_ID:-$DEFAULT_CHAIN_ID}" + echo "" + fi +fi + +echo "Using Chain ID: $CHAIN_ID" +echo "" + +COMPOSE_FILE="docker-compose.${CHAIN_ID}.yml" + +# Step 2: Get Auth Key (if not provided) +if [ -z "$AUTH_KEY" ]; then + echo "=============================================" + echo "Step 2: Create project on apphash.io" + echo "=============================================" + echo "" + echo " 1. Go to: https://apphash.io" + echo " 2. Click 'New Project'" + echo " 3. Enter Chain ID: $CHAIN_ID" + echo " 4. Copy the generated Auth Key" + echo "" + read -p "Paste the Auth Key here: " AUTH_KEY + + if [ -z "$AUTH_KEY" ]; then + echo "Error: Auth Key cannot be empty" + exit 1 + fi + echo "" +fi + +# Step 3: Clean up old data +echo "Step 3: Cleaning up old data..." +docker compose -f "$COMPOSE_FILE" down -v 2>/dev/null || true +rm -rf .testnets +mkdir -p .testnets +echo "" + +# Step 4: Generate docker-compose and start testnet +echo "Step 4: Generating docker-compose and starting testnet..." +echo " Chain ID: $CHAIN_ID" +echo " Validators: $NODE_COUNT" +echo "" + +# Generate docker-compose.yml with init + setup + nodes + shippers +cat > "$COMPOSE_FILE" <> "$COMPOSE_FILE" <> "$COMPOSE_FILE" <> "$COMPOSE_FILE" <&1 | grep -v "View in Docker Desktop" | grep -v "View Config" | grep -v "Enable Watch" + +echo "" +echo "=============================================" +echo " Testnet is running!" +echo "=============================================" +echo "" +echo "Chain ID: $CHAIN_ID" +echo "Nodes: $NODE_COUNT" +echo "Auth Key: ${AUTH_KEY:0:8}...${AUTH_KEY: -8}" +echo "" +echo "Monitor your testnet:" +echo " https://apphash.io" +echo "" +echo "View logs:" +echo " docker compose -f $COMPOSE_FILE logs -f" +echo "" +echo "Stop testnet:" +echo " docker compose -f $COMPOSE_FILE down" +echo "" +echo "Clean up all data:" +echo " docker compose -f $COMPOSE_FILE down -v && rm -rf .testnets" +echo ""