-
Notifications
You must be signed in to change notification settings - Fork 843
test: query historical C-Chain state with Firewood #4809
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
e1265ab
ae5167b
d701cf1
727f451
d3ef71c
8f463e2
8e646fe
26b7d5c
f4d3f6b
dc23160
05e3bed
b8897c2
96b391b
8f49c2d
b6b88b7
3e8dfc5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,88 @@ | ||
| name: Firewood State Access Test | ||
|
|
||
| on: | ||
| workflow_dispatch: | ||
| inputs: | ||
| test: | ||
| description: 'Test name to run (e.g., firewood-archive-250k). Leave empty to use custom inputs below.' | ||
| default: '' | ||
| # Custom inputs (used when test is not provided) | ||
| start-block: | ||
| description: 'The start block for the test.' | ||
| default: '' | ||
| end-block: | ||
| description: 'The end block for the test.' | ||
| default: '' | ||
| current-state-dir-src: | ||
| description: 'The current state directory. Supports S3 directory/zip and local directories.' | ||
| default: '' | ||
| runner: | ||
| description: 'Runner to execute the state access test. Input to the runs-on field of the job.' | ||
| required: true | ||
| timeout-minutes: | ||
| description: 'Timeout in minutes for the job.' | ||
| default: '60' | ||
| schedule: | ||
| - cron: '0 9 * * *' # Runs every day at 09:00 UTC (04:00 EST) | ||
| # XXX: REMOVE BEFORE MERGING | ||
| pull_request: | ||
|
|
||
| jobs: | ||
| define-matrix: | ||
| runs-on: ubuntu-latest | ||
| outputs: | ||
| matrix: ${{ steps.define-matrix.outputs.matrix }} | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| - name: Define Matrix | ||
| id: define-matrix | ||
| shell: bash -x {0} | ||
| run: | | ||
| if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then | ||
| { | ||
| echo "matrix<<EOF" | ||
| printf '{ "include": [{ "test": "%s", "start-block": "%s", "end-block": "%s", "current-state-dir-src": "%s", "runner": "%s", "timeout-minutes": %s }] }\n' \ | ||
| "${{ github.event.inputs.test }}" \ | ||
| "${{ github.event.inputs.start-block }}" \ | ||
| "${{ github.event.inputs.end-block }}" \ | ||
| "${{ github.event.inputs.current-state-dir-src }}" \ | ||
| "${{ github.event.inputs.runner }}" \ | ||
| "${{ github.event.inputs.timeout-minutes }}" | ||
| echo EOF | ||
| } >> "$GITHUB_OUTPUT" | ||
| else | ||
| { | ||
| echo "matrix<<EOF" | ||
| echo '{ "include": [{ "test": "firewood-archive-250k" }] }' | ||
| echo EOF | ||
| } >> "$GITHUB_OUTPUT" | ||
| fi | ||
|
|
||
| firewood-state-access-test: | ||
| needs: define-matrix | ||
| strategy: | ||
| fail-fast: false | ||
| matrix: ${{ fromJSON(needs.define-matrix.outputs.matrix) }} | ||
| timeout-minutes: ${{ matrix.timeout-minutes || 60 }} | ||
| runs-on: ${{ matrix.runner || 'ubuntu-latest' }} | ||
| permissions: | ||
| id-token: write | ||
| contents: read | ||
| steps: | ||
| - uses: cachix/install-nix-action@02a151ada4993995686f9ed4f1be7cfbb229e56f #v31 | ||
| with: | ||
| github_access_token: ${{ secrets.GITHUB_TOKEN }} | ||
| - name: Configure AWS Credentials | ||
| uses: aws-actions/configure-aws-credentials@v4 | ||
| with: | ||
| role-to-assume: ${{ secrets.AWS_S3_READ_ONLY_ROLE }} | ||
| aws-region: 'us-east-2' | ||
| role-duration-seconds: '43200' | ||
| - uses: actions/checkout@v4 | ||
| - name: Run state access test with Firewood archive | ||
| shell: nix develop --impure --command bash -x {0} | ||
| run: ./scripts/run_task.sh test-firewood-state-access -- "${{ matrix.test || '' }}" | ||
| env: | ||
| START_BLOCK: ${{ matrix.start-block }} | ||
| END_BLOCK: ${{ matrix.end-block }} | ||
| CURRENT_STATE_DIR_SRC: ${{ matrix.current-state-dir-src }} | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've went with creating a new script rather than extending |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,104 @@ | ||
| #!/usr/bin/env bash | ||
|
|
||
| set -euo pipefail | ||
|
|
||
| # Firewood state access script | ||
| # | ||
| # Usage: | ||
| # ./tests.firewood_state_access.sh | ||
| # | ||
| # To see available tests, use `help` as the test name or invoke without a test | ||
| # name and without required env vars. | ||
| # | ||
| # Note: state access tests can only be run with Firewood archival states. | ||
| # | ||
| # Environment variables: | ||
| # Data sources (provide S3 sources OR local paths): | ||
| # CURRENT_STATE_DIR_SRC: S3 object key for state (triggers S3 import). | ||
| # CURRENT_STATE_DIR: Path to local current state directory. | ||
| # | ||
| # Required: | ||
| # START_BLOCK: The starting block height to query (inclusive). | ||
| # END_BLOCK: The ending block height to query (inclusive). | ||
|
|
||
| SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" | ||
|
|
||
| # CI-aware error function | ||
| error() { | ||
| if [[ "${GITHUB_ACTIONS:-}" == "true" ]]; then | ||
| echo "::error::$1" | ||
| else | ||
| echo "Error: $1" >&2 | ||
| fi | ||
| exit 1 | ||
| } | ||
|
|
||
| show_usage() { | ||
| cat <<EOF | ||
| Usage: $0 [test-name] | ||
|
|
||
| Available tests: | ||
| help - Show this help message | ||
|
|
||
| firewood-archive-250k - Query the first 250k blocks with Firewood archive. | ||
| EOF | ||
| } | ||
|
|
||
| # Set defaults based on test name (if provided) | ||
| TEST_NAME="${1:-}" | ||
| if [[ -n "$TEST_NAME" ]]; then | ||
| shift | ||
| case "$TEST_NAME" in | ||
| help) | ||
| show_usage | ||
| exit 0 | ||
| ;; | ||
| firewood-archive-250k) | ||
| CURRENT_STATE_DIR_SRC="${CURRENT_STATE_DIR_SRC:-cchain-current-state-firewood-archive-250k}" | ||
| START_BLOCK="${START_BLOCK:-0}" | ||
| END_BLOCK="${END_BLOCK:-250_000}" | ||
| ;; | ||
| *) | ||
| error "Unknown test '$TEST_NAME'" | ||
| ;; | ||
| esac | ||
| fi | ||
|
|
||
| # Determine data source: S3 import or local path | ||
| if [[ -n "${CURRENT_STATE_DIR_SRC:-}" ]]; then | ||
| # S3 mode - import data | ||
| TIMESTAMP=$(date '+%Y%m%d-%H%M%S') | ||
| EXECUTION_DATA_DIR="${EXECUTION_DATA_DIR:-/tmp/reexec-${TEST_NAME:-custom}-${TIMESTAMP}}" | ||
|
|
||
| CURRENT_STATE_DIR_SRC="${CURRENT_STATE_DIR_SRC}" \ | ||
| EXECUTION_DATA_DIR="${EXECUTION_DATA_DIR}" \ | ||
| "${SCRIPT_DIR}/import_cchain_data.sh" | ||
|
|
||
| CURRENT_STATE_DIR="${EXECUTION_DATA_DIR}/current-state" | ||
| elif [[ -z "${CURRENT_STATE_DIR:-}" ]]; then | ||
| show_usage | ||
| echo "" | ||
| echo "Env vars status:" | ||
| echo " S3 source:" | ||
| [[ -n "${CURRENT_STATE_DIR_SRC:-}" ]] && echo " CURRENT_STATE_DIR_SRC: ${CURRENT_STATE_DIR_SRC}" || echo " CURRENT_STATE_DIR_SRC: (not set)" | ||
| echo " Local path:" | ||
| [[ -n "${CURRENT_STATE_DIR:-}" ]] && echo " CURRENT_STATE_DIR: ${CURRENT_STATE_DIR}" || echo " CURRENT_STATE_DIR: (not set)" | ||
| echo " Block range:" | ||
| [[ -n "${START_BLOCK:-}" ]] && echo " START_BLOCK: ${START_BLOCK}" || echo " START_BLOCK: (not set)" | ||
| [[ -n "${END_BLOCK:-}" ]] && echo " END_BLOCK: ${END_BLOCK}" || echo " END_BLOCK: (not set)" | ||
| exit 1 | ||
| fi | ||
|
|
||
| # Validate block range | ||
| if [[ -z "${START_BLOCK:-}" || -z "${END_BLOCK:-}" ]]; then | ||
| error "START_BLOCK and END_BLOCK are required" | ||
| fi | ||
|
|
||
| echo "=== State Access Test: ${TEST_NAME:-custom} ===" | ||
| echo "Querying between: ${START_BLOCK} and ${END_BLOCK}" | ||
|
|
||
| echo "=== Running Test ===" | ||
| go run ./tests/reexecute/stateaccess \ | ||
| --current-state-dir="${CURRENT_STATE_DIR}" \ | ||
| --start-block="${START_BLOCK}" \ | ||
| --end-block="${END_BLOCK}" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,92 @@ | ||
| // Copyright (C) 2019, Ava Labs, Inc. All rights reserved. | ||
| // See the file LICENSE for licensing terms. | ||
|
|
||
| package main | ||
|
|
||
| import ( | ||
| "context" | ||
| "flag" | ||
| "math/big" | ||
| "net/http/httptest" | ||
| "path/filepath" | ||
|
|
||
| "github.com/ava-labs/libevm/common" | ||
| "github.com/ava-labs/libevm/ethclient" | ||
| "github.com/prometheus/client_golang/prometheus" | ||
| "github.com/stretchr/testify/require" | ||
|
|
||
| "github.com/ava-labs/avalanchego/api/metrics" | ||
| "github.com/ava-labs/avalanchego/database/leveldb" | ||
| "github.com/ava-labs/avalanchego/graft/coreth/plugin/evm" | ||
| "github.com/ava-labs/avalanchego/tests" | ||
| "github.com/ava-labs/avalanchego/tests/reexecute" | ||
| "github.com/ava-labs/avalanchego/utils/logging" | ||
| ) | ||
|
|
||
| var ( | ||
| currentStateDirArg string | ||
| startBlockArg uint64 | ||
| endBlockArg uint64 | ||
| ) | ||
|
|
||
| func init() { | ||
| evm.RegisterAllLibEVMExtras() | ||
|
|
||
| flag.StringVar(¤tStateDirArg, "current-state-dir", currentStateDirArg, "Current state directory including VM DB and Chain Data Directory.") | ||
| flag.Uint64Var(&startBlockArg, "start-block", 101, "Start block to begin execution (inclusive).") | ||
| flag.Uint64Var(&endBlockArg, "end-block", 200, "End block to end execution (inclusive).") | ||
| flag.Parse() | ||
| } | ||
|
|
||
| // main verifies that historical state is accessible for archival node by | ||
| // iterating over a range of blocks and querying the nonce of the zero address | ||
| // at each block height. This confirms the node can serve state queries for | ||
| // arbitrary historical blocks. | ||
| func main() { | ||
| tc := tests.NewTestContext(tests.NewDefaultLogger("state-access")) | ||
| defer tc.RecoverAndExit() | ||
|
|
||
| r := require.New(tc) | ||
| ctx := context.Background() | ||
|
|
||
| var ( | ||
| vmDBDir = filepath.Join(currentStateDirArg, "db") | ||
| chainDataDir = filepath.Join(currentStateDirArg, "chain-data-dir") | ||
| ) | ||
|
|
||
| db, err := leveldb.New(vmDBDir, nil, logging.NoLog{}, prometheus.NewRegistry()) | ||
| r.NoError(err) | ||
|
|
||
| firewoodArchiveConfig := `{ | ||
| "state-scheme": "firewood", | ||
| "snapshot-cache": 0, | ||
| "pruning-enabled": false, | ||
| "state-sync-enabled": false | ||
| }` | ||
|
|
||
| vm, err := reexecute.NewMainnetCChainVM( | ||
| ctx, | ||
| db, | ||
| chainDataDir, | ||
| []byte(firewoodArchiveConfig), | ||
| metrics.NewPrefixGatherer(), | ||
| prometheus.NewRegistry(), | ||
| ) | ||
| r.NoError(err) | ||
|
|
||
| handlers, err := vm.CreateHandlers(ctx) | ||
| r.NoError(err) | ||
|
|
||
| ethRPCEndpoint := "/rpc" | ||
| server := httptest.NewServer(handlers[ethRPCEndpoint]) | ||
| tc.DeferCleanup(server.Close) | ||
|
|
||
| client, err := ethclient.Dial(server.URL) | ||
| r.NoError(err) | ||
|
|
||
| for i := startBlockArg; i <= endBlockArg; i++ { | ||
| nonce, err := client.NonceAt(ctx, common.Address{}, big.NewInt(int64(i))) | ||
| r.NoErrorf(err, "failed to get nonce at block %d", i) | ||
| r.Zero(nonce) | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will remove before merging.