Skip to content
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

Add support for old forks. #191

Merged
merged 25 commits into from
Aug 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
db01eb5
Add all forks to revm
rakita Aug 16, 2022
38bfb6d
Add all hardforks
rakita Aug 17, 2022
f2ff107
Merge remote-tracking branch 'origin/main' into main
rakita Aug 17, 2022
84739f1
EXTCODESIZE and EXTCODEHASH old hardfork gas fix
rakita Aug 17, 2022
fc1a81e
EXTCODECOPY fix gas hardfork
rakita Aug 17, 2022
daadfa2
fmt
rakita Aug 17, 2022
25f06a0
cleanups
rakita Aug 17, 2022
d10dfdf
EIP-161 is in SPURIOUS_DRAGON hardfork
rakita Aug 18, 2022
6e97f92
EIP-161 create nonce increment for SPURIOUS_DRAGON
rakita Aug 18, 2022
175aee5
Enable SPURIOUS_DRAGON tests
rakita Aug 18, 2022
c25fc75
Change database traits to return Result<Option<>>
rakita Aug 18, 2022
b1de572
80perc done transition
rakita Aug 20, 2022
0d68e72
db result compiled and new forks passing
rakita Aug 21, 2022
588d99d
not_existing, precompile perf is_cold
rakita Aug 22, 2022
4222270
fix for not_existing
rakita Aug 22, 2022
1d532dc
passing most of legact tests
rakita Aug 22, 2022
94bc2be
Remove spurious precompile hotfix for old forks
rakita Aug 22, 2022
61eebc8
EIP-2 OOG if crate bytecode can't be paid
rakita Aug 23, 2022
4859b12
Merge remote-tracking branch 'origin/main' into forks
rakita Aug 26, 2022
c8171a7
Add legacy tests to github ci, fmt,clippy
rakita Aug 26, 2022
2d1edcf
Merge remote-tracking branch 'origin/main' into forks
rakita Aug 26, 2022
b5c65f9
fmt
rakita Aug 26, 2022
4317474
Propagate FatalExternalError
rakita Aug 26, 2022
431fe68
Add Error associated type to Database.
rakita Aug 27, 2022
44f6ec1
Small cleanup
rakita Aug 29, 2022
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
3 changes: 2 additions & 1 deletion .github/workflows/ethereum-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ jobs:
with:
repository: ethereum/tests
path: ethtests
submodules: recursive,

- name: Install toolchain
uses: actions-rs/toolchain@v1
Expand All @@ -34,4 +35,4 @@ jobs:
cache-on-failure: true

- name: Run Ethereum tests
run: cargo run --profile ethtests -p revme -- statetest ethtests/GeneralStateTests
run: cargo run --profile ethtests -p revme -- statetest ethtests/GeneralStateTests ethtests/LegacyTests/Constantinople/GeneralStateTests/
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,6 @@ run tests with command: `cargo run --release -- statetest tests/GeneralStateTest

There is public telegram group: https://t.me/+Ig4WDWOzikA3MzA0

Or you can contact me directly on email: [email protected]
Or if you want to hire me or contact me directly, here is my email: [email protected] and telegram: https://t.me/draganrakita


11 changes: 7 additions & 4 deletions bins/revme/src/statetest/cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,16 @@ use structopt::StructOpt;
#[derive(StructOpt, Debug)]
pub struct Cmd {
#[structopt(required = true)]
path: PathBuf,
path: Vec<PathBuf>,
}

impl Cmd {
pub fn run(&self) -> Result<(), TestError> {
let test_files = find_all_json_tests(&self.path);
println!("Start running tests on: {:?}", self.path);
run(test_files)
for path in &self.path {
println!("Start running tests on: {:?}", path);
let test_files = find_all_json_tests(path);
run(test_files)?
}
Ok(())
}
}
11 changes: 11 additions & 0 deletions bins/revme/src/statetest/models/deserializer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,14 @@ where
.map_err(D::Error::custom)?
.into())
}

pub fn deserialize_opt_str_as_bytes<'de, D>(deserializer: D) -> Result<Option<Bytes>, D::Error>
where
D: de::Deserializer<'de>,
{
#[derive(Debug, Deserialize)]
struct WrappedValue(#[serde(deserialize_with = "deserialize_str_as_bytes")] Bytes);

Option::<WrappedValue>::deserialize(deserializer)
.map(|opt_wrapped: Option<WrappedValue>| opt_wrapped.map(|wrapped: WrappedValue| wrapped.0))
}
5 changes: 3 additions & 2 deletions bins/revme/src/statetest/models/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,9 @@ pub struct Test {
pub indexes: TxPartIndices,
// logs
pub logs: H256,
#[serde(deserialize_with = "deserialize_str_as_bytes")]
pub txbytes: Bytes,
#[serde(default)]
#[serde(deserialize_with = "deserialize_opt_str_as_bytes")]
pub txbytes: Option<Bytes>,
}

#[derive(Debug, PartialEq, Eq, Deserialize)]
Expand Down
44 changes: 27 additions & 17 deletions bins/revme/src/statetest/models/spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,34 +3,44 @@ use serde_derive::*;

#[derive(Debug, PartialEq, Eq, PartialOrd, Hash, Ord, Deserialize)]
pub enum SpecName {
EIP150,
EIP158,
Frontier,
Homestead,
Byzantium,
Constantinople,
ConstantinopleFix,
Istanbul,
EIP158ToByzantiumAt5,
FrontierToHomesteadAt5,
Homestead,
HomesteadToDaoAt5,
HomesteadToEIP150At5,
ByzantiumToConstantinopleAt5,
EIP150,
EIP158, // EIP-161: State trie clearing
EIP158ToByzantiumAt5,
Byzantium, // done
ByzantiumToConstantinopleAt5, // SKIPPED
ByzantiumToConstantinopleFixAt5,
Berlin,
London,
BerlinToLondonAt5,
Merge,
Constantinople, // SKIPPED
ConstantinopleFix,
Istanbul,
Berlin, //done
BerlinToLondonAt5, // done
London, // done
Merge, //done
}

impl SpecName {
pub fn to_spec_id(&self) -> SpecId {
match self {
Self::Merge => SpecId::MERGE,
Self::London => SpecId::LONDON,
Self::Berlin => SpecId::BERLIN,
Self::Frontier => SpecId::FRONTIER,
Self::Homestead | Self::FrontierToHomesteadAt5 => SpecId::HOMESTEAD,
Self::EIP150 | Self::HomesteadToDaoAt5 | Self::HomesteadToEIP150At5 => {
SpecId::TANGERINE
}
Self::EIP158 => SpecId::SPURIOUS_DRAGON,
Self::Byzantium | Self::EIP158ToByzantiumAt5 => SpecId::BYZANTIUM,
Self::ConstantinopleFix | Self::ByzantiumToConstantinopleFixAt5 => SpecId::PETERSBURG,
Self::Istanbul => SpecId::ISTANBUL,
_ => panic!("Conversion failed"),
Self::Berlin => SpecId::BERLIN,
Self::London | Self::BerlinToLondonAt5 => SpecId::LONDON,
Self::Merge => SpecId::MERGE,
Self::ByzantiumToConstantinopleAt5 | Self::Constantinople => {
panic!("Overriden with PETERSBURG")
} //_ => panic!("Conversion failed"),
}
}
}
32 changes: 23 additions & 9 deletions bins/revme/src/statetest/runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ pub enum TestError {
SerdeDeserialize(#[from] serde_json::Error),
#[error("Internal system error")]
SystemError,
#[error("Unknown private key: {private_key:?}")]
UnknownPrivateKey { private_key: H256 },
}

pub fn find_all_json_tests(path: &Path) -> Vec<PathBuf> {
Expand Down Expand Up @@ -112,6 +114,11 @@ pub fn execute_test_suit(path: &Path, elapsed: &Arc<Mutex<Duration>>) -> Result<
.unwrap(),
H160::from_str("0x3fb1cd2cd96c6d5c0b5eb3322d807b34482481d4").unwrap(),
),
(
H256::from_str("0xfe13266ff57000135fb9aa854bbfe455d8da85b21f626307bf3263a0c2a8e7fe")
.unwrap(),
H160::from_str("0xdcc5ba93a1ed7e045690d722f2bf460a51c61415").unwrap(),
),
]
.into_iter()
.collect();
Expand All @@ -129,7 +136,7 @@ pub fn execute_test_suit(path: &Path, elapsed: &Arc<Mutex<Duration>>) -> Result<
database.insert_account_info(*address, acc_info);
// insert storage:
for (&slot, &value) in info.storage.iter() {
database.insert_account_storage(*address, slot, value)
let _ = database.insert_account_storage(*address, slot, value);
}
}
let mut env = Env::default();
Expand All @@ -145,9 +152,13 @@ pub fn execute_test_suit(path: &Path, elapsed: &Arc<Mutex<Duration>>) -> Result<
env.block.difficulty = unit.env.current_difficulty;

//tx env
env.tx.caller = *map_caller_keys
.get(&unit.transaction.secret_key.unwrap())
.unwrap();
env.tx.caller =
if let Some(caller) = map_caller_keys.get(&unit.transaction.secret_key.unwrap()) {
*caller
} else {
let private_key = unit.transaction.secret_key.unwrap();
return Err(TestError::UnknownPrivateKey { private_key });
};
env.tx.gas_price = unit
.transaction
.gas_price
Expand All @@ -156,9 +167,9 @@ pub fn execute_test_suit(path: &Path, elapsed: &Arc<Mutex<Duration>>) -> Result<

// post and execution
for (spec_name, tests) in unit.post {
if !matches!(
if matches!(
spec_name,
SpecName::Merge | SpecName::London | SpecName::Berlin | SpecName::Istanbul
SpecName::ByzantiumToConstantinopleAt5 | SpecName::Constantinople
) {
continue;
}
Expand Down Expand Up @@ -226,13 +237,16 @@ pub fn execute_test_suit(path: &Path, elapsed: &Arc<Mutex<Duration>>) -> Result<

*elapsed.lock().unwrap() += timer;

let is_legacy = !SpecId::enabled(evm.env.cfg.spec_id, SpecId::SPURIOUS_DRAGON);
let db = evm.db().unwrap();
let state_root = state_merkle_trie_root(
db.accounts
.iter()
.filter(|(_address, acc)| {
!(acc.info.is_empty())
|| matches!(acc.account_state, AccountState::None)
(is_legacy && !matches!(acc.account_state, AccountState::NotExisting))
|| (!is_legacy
&& (!(acc.info.is_empty())
|| matches!(acc.account_state, AccountState::None)))
})
.map(|(k, v)| (*k, v.clone())),
);
Expand Down Expand Up @@ -269,7 +283,7 @@ pub fn execute_test_suit(path: &Path, elapsed: &Arc<Mutex<Duration>>) -> Result<
pub fn run(test_files: Vec<PathBuf>) -> Result<(), TestError> {
let endjob = Arc::new(AtomicBool::new(false));
let console_bar = Arc::new(ProgressBar::new(test_files.len() as u64));
let mut joins = Vec::new();
let mut joins: Vec<std::thread::JoinHandle<Result<(), TestError>>> = Vec::new();
let queue = Arc::new(Mutex::new((0, test_files)));
let elapsed = Arc::new(Mutex::new(std::time::Duration::ZERO));
for _ in 0..10 {
Expand Down
8 changes: 4 additions & 4 deletions bins/revme/src/statetest/trace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ impl<DB: Database> Inspector<DB> for CustomPrintTracer {
let gas_remaining = interp.gas.remaining() + self.full_gas_block - self.reduced_gas_block;

println!(
"depth:{}, PC:{}, gas:{:#x}({}), OPCODE: {:?}({:?}) refund:{:#x}({}) Stack:{:?}, Data:",
"depth:{}, PC:{}, gas:{:#x}({}), OPCODE: {:?}({:?}) refund:{:#x}({}) Stack:{:?}, Data size:{}",
data.journaled_state.depth(),
interp.program_counter(),
gas_remaining,
Expand All @@ -68,7 +68,7 @@ impl<DB: Database> Inspector<DB> for CustomPrintTracer {
interp.gas.refunded(),
interp.gas.refunded(),
interp.stack.data(),
//hex::encode(interp.memory.data()),
interp.memory.data().len(),
);

let pc = interp.program_counter();
Expand Down Expand Up @@ -141,12 +141,12 @@ impl<DB: Database> Inspector<DB> for CustomPrintTracer {
is_static: bool,
) -> (Return, Gas, Bytes) {
println!(
"SM CALL: {:?},context:{:?}, is_static:{:?}, transfer:{:?}, input:{:?}",
"SM CALL: {:?},context:{:?}, is_static:{:?}, transfer:{:?}, input_size:{:?}",
inputs.contract,
inputs.context,
is_static,
inputs.transfer,
hex::encode(&inputs.input),
inputs.input.len(),
);
(Return::Continue, Gas::new(0), Bytes::new())
}
Expand Down
41 changes: 20 additions & 21 deletions crates/revm/src/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,16 @@ use auto_impl::auto_impl;

#[auto_impl(& mut, Box)]
pub trait Database {
type Error;
/// Get basic account information.
fn basic(&mut self, address: H160) -> AccountInfo;
fn basic(&mut self, address: H160) -> Result<Option<AccountInfo>, Self::Error>;
/// Get account code by its hash
fn code_by_hash(&mut self, code_hash: H256) -> Bytecode;
fn code_by_hash(&mut self, code_hash: H256) -> Result<Bytecode, Self::Error>;
/// Get storage value of address at index.
fn storage(&mut self, address: H160, index: U256) -> U256;
fn storage(&mut self, address: H160, index: U256) -> Result<U256, Self::Error>;

// History related
fn block_hash(&mut self, number: U256) -> H256;
fn block_hash(&mut self, number: U256) -> Result<H256, Self::Error>;
}

#[auto_impl(& mut, Box)]
Expand All @@ -34,49 +35,47 @@ pub trait DatabaseCommit {

#[auto_impl(&, Box)]
pub trait DatabaseRef {
type Error;
/// Whether account at address exists.
//fn exists(&self, address: H160) -> Option<AccountInfo>;
/// Get basic account information.
fn basic(&self, address: H160) -> AccountInfo;
fn basic(&self, address: H160) -> Result<Option<AccountInfo>, Self::Error>;
/// Get account code by its hash
fn code_by_hash(&self, code_hash: H256) -> Bytecode;
fn code_by_hash(&self, code_hash: H256) -> Result<Bytecode, Self::Error>;
/// Get storage value of address at index.
fn storage(&self, address: H160, index: U256) -> U256;
fn storage(&self, address: H160, index: U256) -> Result<U256, Self::Error>;

// History related
fn block_hash(&self, number: U256) -> H256;
fn block_hash(&self, number: U256) -> Result<H256, Self::Error>;
}

pub struct RefDBWrapper<'a> {
pub db: &'a dyn DatabaseRef,
pub struct RefDBWrapper<'a, Error> {
pub db: &'a dyn DatabaseRef<Error = Error>,
}

impl<'a> RefDBWrapper<'a> {
pub fn new(db: &'a dyn DatabaseRef) -> Self {
impl<'a, Error> RefDBWrapper<'a, Error> {
pub fn new(db: &'a dyn DatabaseRef<Error = Error>) -> Self {
Self { db }
}
}

impl<'a> Database for RefDBWrapper<'a> {
/// Whether account at address exists.
// fn exists(&mut self, address: H160) -> Option<AccountInfo> {
// self.db.exists(address)
// }
impl<'a, Error> Database for RefDBWrapper<'a, Error> {
type Error = Error;
/// Get basic account information.
fn basic(&mut self, address: H160) -> AccountInfo {
fn basic(&mut self, address: H160) -> Result<Option<AccountInfo>, Self::Error> {
self.db.basic(address)
}
/// Get account code by its hash
fn code_by_hash(&mut self, code_hash: H256) -> Bytecode {
fn code_by_hash(&mut self, code_hash: H256) -> Result<Bytecode, Self::Error> {
self.db.code_by_hash(code_hash)
}
/// Get storage value of address at index.
fn storage(&mut self, address: H160, index: U256) -> U256 {
fn storage(&mut self, address: H160, index: U256) -> Result<U256, Self::Error> {
self.db.storage(address, index)
}

// History related
fn block_hash(&mut self, number: U256) -> H256 {
fn block_hash(&mut self, number: U256) -> Result<H256, Self::Error> {
self.db.block_hash(number)
}
}
Loading