diff --git a/.github/workflows/compare-encoding-ethereum.yml b/.github/workflows/compare-encoding-ethereum.yml index 1b562e4..b92bbb5 100644 --- a/.github/workflows/compare-encoding-ethereum.yml +++ b/.github/workflows/compare-encoding-ethereum.yml @@ -19,6 +19,11 @@ concurrency: permissions: read-all +env: + # DEBUG/retest: encode this exact block in both encoders so the comparison is + # deterministic (no live-block race between the alloy and ethers jobs). + RETEST_BLOCK: '25463089' + jobs: setup: runs-on: ubuntu-24.04 @@ -65,13 +70,14 @@ jobs: run: | cargo build --release - - name: Execute for ${{ needs.setup.outputs.timeout-minutes }} minutes + - name: Encode target block ${{ env.RETEST_BLOCK }} timeout-minutes: ${{ fromJSON(needs.setup.outputs.step-timeout) }} working-directory: rust run: | ./target/release/encode-blocks \ --eth-rpc-url wss://mainnet.infura.io/ws/v3/${{ secrets.INFURA_ETHEREUM_RPC_KEY }} \ - --path-to-store-json /var/tmp/encoded-data/alloy/ + --path-to-store-json /var/tmp/encoded-data/alloy/ \ + --target-block "$RETEST_BLOCK" env: TIMEOUT_MINUTES: ${{ needs.setup.outputs.timeout-minutes }} @@ -114,12 +120,13 @@ jobs: - run: npm ci - run: npm run build --if-present - - name: Execute for ${{ needs.setup.outputs.timeout-minutes }} minutes + - name: Encode target block ${{ env.RETEST_BLOCK }} timeout-minutes: ${{ fromJSON(needs.setup.outputs.step-timeout) }} run: | node dist/bin/encode-blocks.js \ wss://blockchain.googleapis.com/v1/projects/creditcoin-test/locations/us-central1/endpoints/ethereum-mainnet/rpc?key=${{ secrets.GOOGLE_ETHEREUM_RPC_KEY }} \ - /var/tmp/encoded-data/ethers/ + /var/tmp/encoded-data/ethers/ \ + "$RETEST_BLOCK" env: TIMEOUT_MINUTES: ${{ needs.setup.outputs.timeout-minutes }} @@ -190,9 +197,9 @@ jobs: git status set -eo pipefail - # filter only modified content b/c between the 2 CI jobs we may not have - # encoded exactly the same set of blocks. Especially if cargo needs to - # recompile from scratch + # Both encoders were pointed at the SAME fixed block (${{ env.RETEST_BLOCK }}), + # so the modified-only filter now compares like-for-like tx files + # instead of racing potentially non-overlapping live blocks. git diff --diff-filter=M | colordiff # will exit non-zero in case of differences diff --git a/rust/bin/encode_blocks.rs b/rust/bin/encode_blocks.rs index a366ecd..fb3fc6e 100644 --- a/rust/bin/encode_blocks.rs +++ b/rust/bin/encode_blocks.rs @@ -25,6 +25,13 @@ pub struct CliArguments { #[arg(long, help = "Directory path to store JSON files", required = true)] pub path_to_store_json: String, + + #[arg( + long, + help = "Optional: encode exactly this block number then exit (deterministic retest mode). \ + When omitted, subscribe to live blocks for TIMEOUT_MINUTES." + )] + pub target_block: Option, } async fn encode_transaction( @@ -215,6 +222,20 @@ async fn main() -> Result<()> { .on_ws(WsConnect::new(args.eth_rpc_url)) .await?; + // Deterministic retest mode: encode exactly one fixed block then exit. This + // lets both CI encoders (alloy + ethers) operate on the identical block + // instead of racing live blocks that may not overlap between the two jobs. + if let Some(block_number) = args.target_block { + println!("=== encoding single block {block_number} then exiting ..."); + block_handler( + provider.clone(), + block_number, + args.path_to_store_json.clone(), + ) + .await?; + return Ok(()); + } + let subscriber = provider.subscribe_blocks().await?; let mut stream = subscriber.into_stream(); let mut last_seen_block: Option = None; diff --git a/src/bin/encode-blocks.ts b/src/bin/encode-blocks.ts index eb4f0fe..2990b3d 100644 --- a/src/bin/encode-blocks.ts +++ b/src/bin/encode-blocks.ts @@ -142,15 +142,41 @@ async function encodeBlocks(rpcUrl: string, pathToStoreJson: string): Promise { + console.log(`=== encoding single block ${blockNumber} then exiting ...`); + + mkdirSync(pathToStoreJson, { recursive: true }); + + const provider = new WebSocketProvider(rpcUrl); + try { + await blockHandler('block', provider, blockNumber, pathToStoreJson); + } finally { + await provider.destroy(); + } +} + if (process.argv.length < 4) { - console.error('node dist/bin/encode-blocks.js '); + console.error('node dist/bin/encode-blocks.js [targetBlockNumber]'); process.exit(1); } const rpcUrl = process.argv[2] || 'ws://127.0.0.1:8545'; const pathToStoreJson = process.argv[3]; +// Optional: when provided, encode exactly this one block and exit (deterministic +// retest mode). When omitted, subscribe to live blocks for TIMEOUT_MINUTES. +const targetBlockArg = process.argv[4]; + +const run = + targetBlockArg !== undefined + ? encodeSingleBlock(rpcUrl, pathToStoreJson, parseInt(targetBlockArg, 10)) + : encodeBlocks(rpcUrl, pathToStoreJson); -encodeBlocks(rpcUrl, pathToStoreJson).catch((reason) => { +run.catch((reason) => { console.error(reason); process.exit(1); });