Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
21 changes: 14 additions & 7 deletions .github/workflows/compare-encoding-ethereum.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 }}

Expand Down Expand Up @@ -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 }}

Expand Down Expand Up @@ -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
Expand Down
21 changes: 21 additions & 0 deletions rust/bin/encode_blocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<u64>,
}

async fn encode_transaction(
Expand Down Expand Up @@ -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<u64> = None;
Expand Down
30 changes: 28 additions & 2 deletions src/bin/encode-blocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,15 +142,41 @@ async function encodeBlocks(rpcUrl: string, pathToStoreJson: string): Promise<vo
});
}

/**
* Encode a single, fixed block then exit. Used to deterministically re-test
* alloy-vs-ethers encoding on the exact same block across both CI jobs, rather
* than racing live blocks that may not overlap between the two encoders.
*/
async function encodeSingleBlock(rpcUrl: string, pathToStoreJson: string, blockNumber: number): Promise<void> {
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 <ws://ethRpcUrl> <pathToStoreJson>');
console.error('node dist/bin/encode-blocks.js <ws://ethRpcUrl> <pathToStoreJson> [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);
});
Loading