Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
8971646
refactor(reexecute): export NewMainnetCChainVM()
RodrigoVillar Dec 17, 2025
4ec0964
test(reexecute): add firewood chaos test
RodrigoVillar Dec 15, 2025
5c7ec5c
chore: exponential => linear
RodrigoVillar Dec 16, 2025
9a893da
chore: add timeout when waiting for killed process to terminate
RodrigoVillar Dec 16, 2025
4e1b5ac
chore: ctx
RodrigoVillar Dec 17, 2025
7b6d057
chore: rebase nits
RodrigoVillar Dec 17, 2025
c8e8582
chore: remove unnecessary diff
RodrigoVillar Dec 17, 2025
506a2e3
chore: remove deps.go
RodrigoVillar Dec 17, 2025
004bc43
Merge branch 'master' into rodrigo/firewood-chaos-test
RodrigoVillar Dec 17, 2025
98273a0
chore: rename task
RodrigoVillar Dec 17, 2025
d989910
chore: nit
RodrigoVillar Dec 17, 2025
fd0d1e0
Merge branch 'master' into rodrigo/firewood-chaos-test
RodrigoVillar Jan 6, 2026
00a4852
refactor!: replace task logic with script
RodrigoVillar Jan 6, 2026
8b17166
chore: add archival test
RodrigoVillar Jan 6, 2026
8a239e6
fix: EOF
RodrigoVillar Jan 6, 2026
c84015d
fix: config
RodrigoVillar Jan 6, 2026
9b24d42
refactor: remove JSON
RodrigoVillar Jan 6, 2026
f1c7cf0
fix: config (again)
RodrigoVillar Jan 6, 2026
ef82e6a
chore: rename chaos test yml
RodrigoVillar Jan 6, 2026
c793199
refactor!: merge chaos script into reexecution script"
RodrigoVillar Jan 6, 2026
439dd59
Merge branch 'master' into rodrigo/firewood-chaos-test
RodrigoVillar Jan 6, 2026
b472805
chore: nits
RodrigoVillar Jan 6, 2026
219b24a
refactor!: address PR comments
RodrigoVillar Jan 6, 2026
59581a8
chore: defined tests set chaos defaults
RodrigoVillar Jan 6, 2026
c29a101
refactor: simplify chaos test validation conditional
RodrigoVillar Jan 6, 2026
ada0690
doc: make clear that chaos test works only with Firewood
RodrigoVillar Jan 6, 2026
6464738
Merge branch 'master' into rodrigo/firewood-chaos-test
RodrigoVillar Jan 6, 2026
4740b85
chore: license
RodrigoVillar Jan 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions .github/workflows/chaos-test.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"pull_request": {
"include": [
{
"start-block": "101",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also as per the example of #4761, please ensure that configuration required to run a test locally is defined outside of github actions - ideally execution would be something like task run-test test-name. That could mean that only test, runner and timeout-minutes would be defined in this file, and given that both the runner and the timeout are static, the value of this file would seem questionable.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also went ahead and removed the JSON file as suggested: 9b24d42

"end-block": "200000",
"block-dir-src": "cchain-mainnet-blocks-1m-ldb",
"current-state-dir-src": "cchain-current-state-firewood-100",
"min-wait-time": "120s",
"max-wait-time": "150s",
"runner": "ubuntu-latest",
"timeout-minutes": 60
}
]
},
"schedule": {
"include": [
{
"start-block": "101",
"end-block": "200000",
"block-dir-src": "cchain-mainnet-blocks-1m-ldb",
"current-state-dir-src": "cchain-current-state-firewood-100",
"min-wait-time": "120s",
"max-wait-time": "150s",
"runner": "ubuntu-latest",
"timeout-minutes": 60
}
]
}
}
108 changes: 108 additions & 0 deletions .github/workflows/chaos-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
name: Firewood Chaos Test

on:
workflow_dispatch:
inputs:
start-block:
description: 'The start block for the chaos test.'
default: ''
end-block:
description: 'The end block for the chaos test.'
default: ''
block-dir-src:
description: 'The source block directory. Supports S3 directory/zip and local directories.'
default: ''
current-state-dir-src:
description: 'The current state directory. Supports S3 directory/zip and local directories.'
default: ''
min-wait-time:
description: 'Minimum wait time before killing the process (e.g., 120s, 2m).'
default: '120s'
max-wait-time:
description: 'Maximum wait time before killing the process (e.g., 150s, 3m).'
default: '150s'
runner:
description: 'Runner to execute the chaos test. Input to the runs-on field of the job.'
required: true
timeout-minutes:
description: 'Timeout in minutes for the job.'
default: '60'
# XXX: remove this before merging
pull_request:
schedule:
- cron: '0 9 * * *' # Runs every day at 09:00 UTC (04:00 EST)

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": [{ "start-block": "%s", "end-block": "%s", "block-dir-src": "%s", "current-state-dir-src": "%s", "min-wait-time": "%s", "max-wait-time": "%s", "runner": "%s", "timeout-minutes": %s }] }\n' \
"${{ github.event.inputs.start-block }}" \
"${{ github.event.inputs.end-block }}" \
"${{ github.event.inputs.block-dir-src }}" \
"${{ github.event.inputs.current-state-dir-src }}" \
"${{ github.event.inputs.min-wait-time }}" \
"${{ github.event.inputs.max-wait-time }}" \
"${{ github.event.inputs.runner }}" \
"${{ github.event.inputs.timeout-minutes }}"
echo EOF
} >> "$GITHUB_OUTPUT"
else
json_string=$(jq -r ".\"${{ github.event_name }}\"" .github/workflows/chaos-test.json)
{
echo "matrix<<EOF"
echo "$json_string"
echo EOF
} >> "$GITHUB_OUTPUT"
fi

firewood-chaos-test:
needs: define-matrix
strategy:
fail-fast: false
matrix: ${{ fromJSON(needs.define-matrix.outputs.matrix) }}
timeout-minutes: ${{ matrix.timeout-minutes }}
runs-on: ${{ matrix.runner }}
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: Set task env
shell: bash
run: |
TIMESTAMP=$(date '+%Y%m%d-%H%M%S')
echo "EXECUTION_DATA_DIR=/tmp/reexecution-data-${TIMESTAMP}" >> "$GITHUB_ENV"
- name: Run chaos test with Firewood
shell: nix develop --impure --command bash -x {0}
run: |
TIMESTAMP=$(date +%s)
EXECUTION_DATA_DIR="/tmp/reexecution-data-${TIMESTAMP}"
./scripts/run_task.sh firewood-chaos-test-with-copied-data \
START_BLOCK=${{ matrix.start-block }} \
END_BLOCK=${{ matrix.end-block }} \
BLOCK_DIR_SRC=${{ matrix.block-dir-src }} \
EXECUTION_DATA_DIR=$EXECUTION_DATA_DIR \
CURRENT_STATE_DIR_SRC=${{ matrix.current-state-dir-src }} \
MIN_WAIT_TIME=${{ matrix.min-wait-time }} \
MAX_WAIT_TIME=${{ matrix.max-wait-time }}

39 changes: 39 additions & 0 deletions Taskfile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,45 @@ tasks:
cmds:
- cmd: bash -x ./scripts/copy_dir.sh {{.SRC}} {{.DST}}

firewood-chaos-test:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As per the example of #4761, var indirection as proposed below is best avoided. Instead, please prefer passing args directly so that any changes to the inputs don't require task modification:

  test-firewood-chaos:
    desc: ...
    cmd: go run ./tests/reexecute/chaos {{.CLI_ARGS}}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Followed the example of #4761 and moved the logic of test-firewood-chaos into it's own script: 00a4852

desc: Chaos test during reexecution test with Firewood
vars:
START_BLOCK: '{{.START_BLOCK}}'
END_BLOCK: '{{.END_BLOCK}}'
CURRENT_STATE_DIR: '{{.CURRENT_STATE_DIR}}'
BLOCK_DIR: '{{.BLOCK_DIR}}'
MIN_WAIT_TIME: '{{.MIN_WAIT_TIME}}'
MAX_WAIT_TIME: '{{.MAX_WAIT_TIME}}'
cmd: go run ./tests/reexecute/chaos --start-block={{.START_BLOCK}}
--end-block={{.END_BLOCK}} --current-state-dir={{.CURRENT_STATE_DIR}}
--block-dir={{.BLOCK_DIR}} --min-wait-time={{.MIN_WAIT_TIME}}
--max-wait-time={{.MAX_WAIT_TIME}}

firewood-chaos-test-with-copied-data:
desc: Combines import-cchain-reexecute-range and firewood-chaos-test
vars:
START_BLOCK: '{{.START_BLOCK}}'
END_BLOCK: '{{.END_BLOCK}}'
CURRENT_STATE_DIR_SRC: '{{.CURRENT_STATE_DIR_SRC}}'
BLOCK_DIR_SRC: '{{.BLOCK_DIR_SRC}}'
EXECUTION_DATA_DIR: '{{.EXECUTION_DATA_DIR}}'
MIN_WAIT_TIME: '{{.MIN_WAIT_TIME}}'
MAX_WAIT_TIME: '{{.MAX_WAIT_TIME}}'
cmds:
- task: import-cchain-reexecute-range
vars:
BLOCK_DIR_SRC: '{{.S3_BOOTSTRAP_BUCKET}}/{{.BLOCK_DIR_SRC}}/**'
CURRENT_STATE_DIR_SRC: '{{.S3_BOOTSTRAP_BUCKET}}/{{.CURRENT_STATE_DIR_SRC}}/**'
EXECUTION_DATA_DIR: '{{.EXECUTION_DATA_DIR}}'
- task: firewood-chaos-test
vars:
START_BLOCK: '{{.START_BLOCK}}'
END_BLOCK: '{{.END_BLOCK}}'
CURRENT_STATE_DIR: '{{.EXECUTION_DATA_DIR}}/current-state'
BLOCK_DIR: '{{.EXECUTION_DATA_DIR}}/blocks'
MIN_WAIT_TIME: '{{.MIN_WAIT_TIME}}'
MAX_WAIT_TIME: '{{.MAX_WAIT_TIME}}'

generate-mocks:
desc: Generates testing mocks
cmds:
Expand Down
103 changes: 1 addition & 102 deletions tests/reexecute/c/vm_reexecute.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,35 +22,15 @@ import (
"go.uber.org/zap"

"github.com/ava-labs/avalanchego/api/metrics"
"github.com/ava-labs/avalanchego/chains/atomic"
"github.com/ava-labs/avalanchego/database"
"github.com/ava-labs/avalanchego/database/leveldb"
"github.com/ava-labs/avalanchego/database/prefixdb"
"github.com/ava-labs/avalanchego/genesis"
"github.com/ava-labs/avalanchego/graft/coreth/plugin/evm"
"github.com/ava-labs/avalanchego/graft/coreth/plugin/factory"
"github.com/ava-labs/avalanchego/ids"
"github.com/ava-labs/avalanchego/snow"
"github.com/ava-labs/avalanchego/snow/engine/enginetest"
"github.com/ava-labs/avalanchego/snow/engine/snowman/block"
"github.com/ava-labs/avalanchego/snow/validators/validatorstest"
"github.com/ava-labs/avalanchego/tests"
"github.com/ava-labs/avalanchego/tests/fixture/tmpnet"
"github.com/ava-labs/avalanchego/tests/reexecute"
"github.com/ava-labs/avalanchego/upgrade"
"github.com/ava-labs/avalanchego/utils/constants"
"github.com/ava-labs/avalanchego/utils/crypto/bls/signer/localsigner"
"github.com/ava-labs/avalanchego/utils/logging"
"github.com/ava-labs/avalanchego/utils/perms"
"github.com/ava-labs/avalanchego/utils/timer"
"github.com/ava-labs/avalanchego/vms/metervm"
"github.com/ava-labs/avalanchego/vms/platformvm/warp"
)

var (
mainnetXChainID = ids.FromStringOrPanic("2oYMBNV4eNHyqk2fjjV5nVQLDbtmNJzq5s3qs3Lo6ftnC6FByM")
mainnetCChainID = ids.FromStringOrPanic("2q9e4r6Mu3U68nU1fYjgbR6JvwrRx36CohpAX5UQxse55x1Q5")
mainnetAvaxAssetID = ids.FromStringOrPanic("FvwEAhmxKfeiG8SnEvq42hc6whRyY3EFYAvebMqDNDGCgxN5Z")
)

var (
Expand Down Expand Up @@ -252,7 +232,7 @@ func benchmarkReexecuteRange(
r.NoError(db.Close())
}()

vm, err := newMainnetCChainVM(
vm, err := reexecute.NewMainnetCChainVM(
ctx,
db,
chainDataDir,
Expand Down Expand Up @@ -289,87 +269,6 @@ func benchmarkReexecuteRange(
}
}

func newMainnetCChainVM(
ctx context.Context,
vmAndSharedMemoryDB database.Database,
chainDataDir string,
configBytes []byte,
vmMultiGatherer metrics.MultiGatherer,
meterVMRegistry prometheus.Registerer,
) (block.ChainVM, error) {
factory := factory.Factory{}
vmIntf, err := factory.New(logging.NoLog{})
if err != nil {
return nil, fmt.Errorf("failed to create VM from factory: %w", err)
}
vm := vmIntf.(block.ChainVM)

blsKey, err := localsigner.New()
if err != nil {
return nil, fmt.Errorf("failed to create BLS key: %w", err)
}

blsPublicKey := blsKey.PublicKey()
warpSigner := warp.NewSigner(blsKey, constants.MainnetID, mainnetCChainID)

genesisConfig := genesis.GetConfig(constants.MainnetID)

sharedMemoryDB := prefixdb.New([]byte("sharedmemory"), vmAndSharedMemoryDB)
atomicMemory := atomic.NewMemory(sharedMemoryDB)

chainIDToSubnetID := map[ids.ID]ids.ID{
mainnetXChainID: constants.PrimaryNetworkID,
mainnetCChainID: constants.PrimaryNetworkID,
ids.Empty: constants.PrimaryNetworkID,
}

vm = metervm.NewBlockVM(vm, meterVMRegistry)

if err := vm.Initialize(
ctx,
&snow.Context{
NetworkID: constants.MainnetID,
SubnetID: constants.PrimaryNetworkID,
ChainID: mainnetCChainID,
NodeID: ids.GenerateTestNodeID(),
PublicKey: blsPublicKey,
NetworkUpgrades: upgrade.Mainnet,

XChainID: mainnetXChainID,
CChainID: mainnetCChainID,
AVAXAssetID: mainnetAvaxAssetID,

Log: tests.NewDefaultLogger("mainnet-vm-reexecution"),
SharedMemory: atomicMemory.NewSharedMemory(mainnetCChainID),
BCLookup: ids.NewAliaser(),
Metrics: vmMultiGatherer,

WarpSigner: warpSigner,

ValidatorState: &validatorstest.State{
GetSubnetIDF: func(_ context.Context, chainID ids.ID) (ids.ID, error) {
subnetID, ok := chainIDToSubnetID[chainID]
if ok {
return subnetID, nil
}
return ids.Empty, fmt.Errorf("unknown chainID: %s", chainID)
},
},
ChainDataDir: chainDataDir,
},
prefixdb.New([]byte("vm"), vmAndSharedMemoryDB),
[]byte(genesisConfig.CChainGenesis),
nil,
configBytes,
nil,
&enginetest.Sender{},
); err != nil {
return nil, fmt.Errorf("failed to initialize VM: %w", err)
}

return vm, nil
}

type vmExecutorConfig struct {
Log logging.Logger
// Registry is the registry to register the metrics with.
Expand Down
Loading