Skip to content

Commit 998801f

Browse files
rakanalhmattsse
andauthored
fix: respect disableCode flag in diff mode for PreStateTracer (#362)
The disableCode flag was not being respected in diff mode for the PreStateTracer. When disableCode was set to true, code was correctly filtered from the pre state but was still appearing in the post state. This fix ensures that when disableCode is true, the code field is set to None for both pre and post states in diff mode, matching the expected behavior from Geth. Added test coverage to verify the fix works correctly in both cases (disableCode=true and disableCode=false). Co-authored-by: Matthias Seitz <[email protected]>
1 parent 8736651 commit 998801f

File tree

1 file changed

+143
-0
lines changed

1 file changed

+143
-0
lines changed

tests/it/geth.rs

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -504,3 +504,146 @@ fn test_geth_calltracer_nested_revert() {
504504
assert!(top_call.error.is_some(), "Top call should have an error");
505505
assert!(top_call.revert_reason.is_some(), "Top call should have a revert reason");
506506
}
507+
508+
#[test]
509+
fn test_geth_prestate_disable_code_in_diff_mode() {
510+
/*
511+
Test that verifies the disableCode flag works correctly in diff mode for PreStateTracer.
512+
When disableCode is true, code should be excluded from both pre and post states.
513+
*/
514+
let mut evm = Context::mainnet().with_db(CacheDB::new(EmptyDB::default())).build_mainnet();
515+
516+
// Deploy a simple contract
517+
let code = hex!("608060405234801561001057600080fd5b506103ac806100206000396000f3fe60806040526004361061003f5760003560e01c80630332ed131461014d5780636ae1ad40146101625780638384a00214610177578063de7eb4f31461018c575b60405134815233906000805160206103578339815191529060200160405180910390a2306001600160a01b0316636ae1ad406040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561009d57600080fd5b505af19250505080156100ae575060015b50306001600160a01b0316630332ed136040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156100ea57600080fd5b505af19250505080156100fb575060015b50306001600160a01b0316638384a0026040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561013757600080fd5b505af115801561014b573d6000803e3d6000fd5b005b34801561015957600080fd5b5061014b6101a1565b34801561016e57600080fd5b5061014b610253565b34801561018357600080fd5b5061014b6102b7565b34801561019857600080fd5b5061014b6102dd565b306001600160a01b031663de7eb4f36040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156101dc57600080fd5b505af11580156101f0573d6000803e3d6000fd5b505060405162461bcd60e51b8152602060048201526024808201527f6e6573746564456d6974576974684661696c75726541667465724e6573746564604482015263115b5a5d60e21b6064820152608401915061024a9050565b60405180910390fd5b6040516000815233906000805160206103578339815191529060200160405180910390a260405162461bcd60e51b81526020600482015260156024820152746e6573746564456d6974576974684661696c75726560581b604482015260640161024a565b6040516000815233906000805160206103578339815191529060200160405180910390a2565b6040516000815233906000805160206103578339815191529060200160405180910390a2306001600160a01b0316638384a0026040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561033c57600080fd5b505af1158015610350573d6000803e3d6000fd5b5050505056fef950957d2407bed19dc99b718b46b4ce6090c05589006dfb86fd22c34865b23ea2646970667358221220090a696b9fbd22c7d1cc2a0b6d4a48c32d3ba892480713689a3145b73cfeb02164736f6c63430008130033");
518+
let deployer = Address::ZERO;
519+
let addr =
520+
deploy_contract(&mut evm, code.into(), deployer, SpecId::LONDON).created_address().unwrap();
521+
522+
// Test with diff_mode=true and disable_code=true
523+
let prestate_config_no_code = PreStateConfig {
524+
diff_mode: Some(true),
525+
disable_code: Some(true),
526+
disable_storage: Some(false),
527+
};
528+
529+
let mut insp = TracingInspector::new(TracingInspectorConfig::from_geth_prestate_config(
530+
&prestate_config_no_code,
531+
));
532+
533+
let db = evm.ctx.db().clone();
534+
let res = {
535+
let mut evm_with_insp = evm.with_inspector(&mut insp);
536+
evm_with_insp
537+
.inspect_tx(TxEnv {
538+
caller: deployer,
539+
gas_limit: 1000000,
540+
kind: TransactTo::Call(addr),
541+
data: hex!("8384a002").into(), // nestedEmitWithSuccess() selector
542+
nonce: 1,
543+
..Default::default()
544+
})
545+
.unwrap()
546+
};
547+
assert!(res.result.is_success());
548+
549+
let frame = insp
550+
.with_transaction_gas_used(res.result.gas_used())
551+
.geth_builder()
552+
.geth_prestate_traces(&res, &prestate_config_no_code, db)
553+
.unwrap();
554+
555+
// Verify that code is not present in either pre or post states when disable_code=true
556+
match frame {
557+
PreStateFrame::Diff(diff_mode) => {
558+
// Check that no account in pre state has code
559+
for (_, account_state) in diff_mode.pre.iter() {
560+
assert!(
561+
account_state.code.is_none(),
562+
"Code should be None in pre state when disable_code=true"
563+
);
564+
}
565+
566+
// Check that no account in post state has code
567+
for (_, account_state) in diff_mode.post.iter() {
568+
assert!(
569+
account_state.code.is_none(),
570+
"Code should be None in post state when disable_code=true"
571+
);
572+
}
573+
}
574+
_ => panic!("Expected Diff mode PreStateFrame"),
575+
}
576+
577+
// Now test with diff_mode=true and disable_code=false (default)
578+
// To see code in the diff, we need to deploy during the traced transaction
579+
let prestate_config_with_code = PreStateConfig {
580+
diff_mode: Some(true),
581+
disable_code: Some(false),
582+
disable_storage: Some(false),
583+
};
584+
585+
let mut insp2 = TracingInspector::new(TracingInspectorConfig::from_geth_prestate_config(
586+
&prestate_config_with_code,
587+
));
588+
let evm2 = Context::mainnet().with_db(CacheDB::new(EmptyDB::default())).build_mainnet();
589+
590+
let db2 = evm2.ctx.db().clone();
591+
let res2 = {
592+
let mut evm2_with_insp = evm2.with_inspector(&mut insp2);
593+
// Deploy contract during traced transaction so code appears in diff
594+
evm2_with_insp
595+
.inspect_tx(TxEnv {
596+
caller: deployer,
597+
gas_limit: 1000000,
598+
kind: TransactTo::Create,
599+
data: code.into(),
600+
nonce: 0,
601+
..Default::default()
602+
})
603+
.unwrap()
604+
};
605+
assert!(res2.result.is_success());
606+
607+
let frame2 = insp2
608+
.with_transaction_gas_used(res2.result.gas_used())
609+
.geth_builder()
610+
.geth_prestate_traces(&res2, &prestate_config_with_code, db2)
611+
.unwrap();
612+
613+
// Verify that code IS present when disable_code=false
614+
match frame2 {
615+
PreStateFrame::Diff(diff_mode) => {
616+
let mut found_code = false;
617+
618+
// Check pre state for accounts with code
619+
for (addr, account_state) in diff_mode.pre.iter() {
620+
if let Some(code) = &account_state.code {
621+
assert!(
622+
!code.is_empty(),
623+
"Account {:?} in pre state has code field but it's empty",
624+
addr
625+
);
626+
found_code = true;
627+
}
628+
}
629+
630+
// Check post state for accounts with code
631+
for (addr, account_state) in diff_mode.post.iter() {
632+
if let Some(code) = &account_state.code {
633+
assert!(
634+
!code.is_empty(),
635+
"Account {:?} in post state has code field but it's empty",
636+
addr
637+
);
638+
found_code = true;
639+
}
640+
}
641+
642+
assert!(
643+
found_code,
644+
"When disable_code=false, at least one account should have code in the diff"
645+
);
646+
}
647+
_ => panic!("Expected Diff mode PreStateFrame"),
648+
}
649+
}

0 commit comments

Comments
 (0)