Skip to content

Commit 52fa3d0

Browse files
committed
state coverage and fix
1 parent 0984227 commit 52fa3d0

3 files changed

Lines changed: 292 additions & 69 deletions

File tree

packages/evm/core/src/state_changes.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ pub struct StorageChangeset {
3737
pub storage: Vec<(U256, StorageSlot)>,
3838
}
3939

40-
#[derive(Default, Debug)]
40+
#[derive(Default, Debug, PartialEq, Eq)]
4141
pub struct AccountUpdate {
4242
pub address: Address,
4343
pub balance: U256,
@@ -54,7 +54,7 @@ pub struct AccountUpdate {
5454
pub merge_info: Option<AccountMergeInfo>,
5555
}
5656

57-
#[derive(Default, Debug)]
57+
#[derive(Default, Debug, PartialEq, Eq)]
5858
pub struct AccountMergeInfo {
5959
pub legacy_address: LegacyAddress,
6060
pub transaction_hash: B256,

packages/evm/core/src/state_commit.rs

Lines changed: 276 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ fn collect_dirty_accounts(
152152
Some(account)
153153
});
154154

155-
break;
155+
continue;
156156
}
157157

158158
// Attempt to decode the log as a Unvoted event
@@ -168,7 +168,7 @@ fn collect_dirty_accounts(
168168
Some(account)
169169
});
170170

171-
break;
171+
continue;
172172
}
173173
}
174174
_ if log.address == info.username_contract => {
@@ -181,7 +181,7 @@ fn collect_dirty_accounts(
181181
account.username_resigned = false; // cancel out any previous resignation if one happened in same commit
182182
Some(account)
183183
});
184-
break;
184+
continue;
185185
}
186186

187187
// Attempt to decode log as a UsernameResigned event
@@ -192,7 +192,7 @@ fn collect_dirty_accounts(
192192
account.username_resigned = true;
193193
Some(account)
194194
});
195-
break;
195+
continue;
196196
}
197197
}
198198
_ => (), // ignore
@@ -209,64 +209,276 @@ fn collect_dirty_accounts(
209209
dirty_accounts.into_values().collect()
210210
}
211211

212-
#[test]
213-
fn test_apply_rewards() {
214-
let path = tempfile::Builder::new()
215-
.prefix("evm.mdb")
216-
.tempdir()
217-
.unwrap();
218-
219-
let mut db = PersistentDB::new(crate::db::PersistentDBOptions::new(
220-
path.path().to_path_buf(),
221-
))
222-
.expect("database");
223-
let mut pending = PendingCommit::default();
224-
225-
let account1 = revm::primitives::address!("bd6f65c58a46427af4b257cbe231d0ed69ed5508");
226-
let account2 = revm::primitives::address!("ad6f65c58a46427af4b257cbe231d0ed69ed5508");
227-
228-
let mut rewards = HashMap::<Address, u128>::default();
229-
rewards.insert(account1, 1234);
230-
rewards.insert(account2, 0);
231-
232-
let result = self::apply_rewards(&mut db, &mut pending, rewards);
233-
assert!(result.is_ok());
234-
235-
let cache_account1 = pending.cache.accounts.get(&account1).expect("account1");
236-
assert!(cache_account1.account.is_some());
237-
assert_eq!(
238-
cache_account1.status,
239-
revm::database::AccountStatus::InMemoryChange
240-
);
241-
242-
let cache_account2 = pending.cache.accounts.get(&account2).expect("account2");
243-
assert!(cache_account2.account.is_none());
244-
assert_eq!(
245-
cache_account2.status,
246-
revm::database::AccountStatus::Destroyed
247-
);
248-
249-
let transition_account1 = pending
250-
.transitions
251-
.transitions
252-
.get(&account1)
253-
.expect("transition_account1");
254-
assert!(transition_account1.info.is_some());
255-
assert_eq!(
256-
transition_account1.status,
257-
revm::database::AccountStatus::InMemoryChange
258-
);
259-
assert_eq!(transition_account1.storage_was_destroyed, false);
260-
261-
let transition_account2 = pending
262-
.transitions
263-
.transitions
264-
.get(&account2)
265-
.expect("transition_account2");
266-
assert!(transition_account2.info.is_none());
267-
assert_eq!(
268-
transition_account2.status,
269-
revm::database::AccountStatus::Destroyed
270-
);
271-
assert_eq!(transition_account2.storage_was_destroyed, true);
212+
#[cfg(test)]
213+
mod tests {
214+
use std::collections::BTreeMap;
215+
216+
use crate::{
217+
db::{GenesisInfo, PendingCommit, PersistentDB},
218+
events,
219+
state_changes::{AccountMergeInfo, AccountUpdate, StateChangeset},
220+
state_commit::{StateCommit, apply_rewards, collect_dirty_accounts},
221+
};
222+
use crate::{
223+
legacy::{LegacyAccountAttributes, LegacyAddress},
224+
state_changes::StorageChangeset,
225+
};
226+
use alloy_primitives::{Address, Log, U256, address};
227+
use alloy_primitives::{B256, b256};
228+
use alloy_sol_types::SolEvent;
229+
use bytes::Bytes;
230+
use revm::{
231+
context::result::{ExecutionResult, Output, ResultGas, SuccessReason},
232+
primitives::HashMap,
233+
};
234+
use revm::{database::states::StorageSlot, state::AccountInfo};
235+
236+
#[test]
237+
fn test_collect_dirty_accounts() {
238+
let mut change_set = StateChangeset::default();
239+
change_set.accounts.push((
240+
address!("0000000000000000000000000000000000000001"),
241+
Some(AccountInfo::from_balance(U256::from(1))),
242+
));
243+
change_set.accounts.push((
244+
address!("0000000000000000000000000000000000000002"),
245+
Some(AccountInfo::from_balance(U256::from(1))),
246+
));
247+
248+
let genesis_info = GenesisInfo {
249+
account: address!("0000000000000000000000000000000000000001"),
250+
deployer_account: address!("0000000000000000000000000000000000000002"),
251+
validator_contract: address!("0000000000000000000000000000000000000003"),
252+
username_contract: address!("0000000000000000000000000000000000000004"),
253+
initial_block_number: 0,
254+
initial_supply: U256::from(1_000_000),
255+
};
256+
257+
let storage = vec![
258+
(
259+
U256::from(1),
260+
StorageSlot::new_changed(U256::ZERO, U256::from(1234)),
261+
),
262+
(
263+
U256::from(2),
264+
StorageSlot::new_changed(U256::ZERO, U256::from(5678)),
265+
),
266+
];
267+
268+
change_set.storage.push(StorageChangeset {
269+
address: address!("0000000000000000000000000000000000000002"),
270+
storage,
271+
..Default::default()
272+
});
273+
274+
change_set.legacy_attributes.insert(
275+
address!("0000000000000000000000000000000000000001"),
276+
LegacyAccountAttributes {
277+
legacy_nonce: Some(5),
278+
second_public_key: Some("".into()),
279+
..Default::default()
280+
},
281+
);
282+
283+
let legacy_address: LegacyAddress =
284+
"DJmvhhiQFSrEQCq9FUxvcLcpcBjx7K3yLt".try_into().unwrap();
285+
change_set.legacy_cold_wallets.insert(
286+
legacy_address.clone(),
287+
crate::legacy::LegacyColdWallet {
288+
address: legacy_address.clone(),
289+
balance: U256::from(255),
290+
legacy_attributes: LegacyAccountAttributes {
291+
legacy_nonce: Some(3),
292+
..Default::default()
293+
},
294+
..Default::default()
295+
},
296+
);
297+
298+
change_set.merged_legacy_cold_wallets.insert(
299+
address!("0000000000000000000000000000000000000001"),
300+
(
301+
b256!("0000000000000000000000000000000000000000000000000000000000000001"),
302+
legacy_address,
303+
),
304+
);
305+
306+
let mut results = BTreeMap::<B256, (ExecutionResult, u64)>::new();
307+
308+
results.insert(
309+
b256!("0000000000000000000000000000000000000000000000000000000000000001"),
310+
(
311+
ExecutionResult::Success {
312+
reason: SuccessReason::Stop,
313+
gas: ResultGas::new(30000, 30000, 0, 0, 0),
314+
logs: vec![
315+
Log {
316+
address: genesis_info.validator_contract,
317+
data: events::Voted {
318+
validator: address!("0000000000000000000000000000000000000002"),
319+
voter: address!("0000000000000000000000000000000000000001"),
320+
}
321+
.encode_log_data(),
322+
},
323+
Log {
324+
address: genesis_info.validator_contract,
325+
data: events::Unvoted {
326+
validator: address!("0000000000000000000000000000000000000004"),
327+
voter: address!("0000000000000000000000000000000000000002"),
328+
}
329+
.encode_log_data(),
330+
},
331+
Log {
332+
address: genesis_info.username_contract,
333+
data: events::UsernameRegistered {
334+
addr: address!("0000000000000000000000000000000000000001"),
335+
username: "test".into(),
336+
previousUsername: "".into(),
337+
}
338+
.encode_log_data(),
339+
},
340+
Log {
341+
address: genesis_info.username_contract,
342+
data: events::UsernameResigned {
343+
addr: address!("0000000000000000000000000000000000000002"),
344+
username: "resigned".into(),
345+
}
346+
.encode_log_data(),
347+
},
348+
Log {
349+
address: genesis_info.validator_contract,
350+
..Default::default()
351+
},
352+
Log {
353+
address: genesis_info.username_contract,
354+
..Default::default()
355+
},
356+
Log {
357+
address: address!("0000000000000000000000000000000000000000"),
358+
..Default::default()
359+
},
360+
],
361+
output: Output::Create(
362+
alloy_primitives::Bytes(Bytes::new()),
363+
Some(address!("0000000000000000000000000000000000000001")),
364+
),
365+
},
366+
0,
367+
),
368+
);
369+
370+
results.insert(
371+
b256!("0000000000000000000000000000000000000000000000000000000000000002"),
372+
(
373+
ExecutionResult::Revert {
374+
gas: ResultGas::new(30000, 30000, 0, 0, 0),
375+
logs: vec![],
376+
output: alloy_primitives::Bytes(Bytes::new()),
377+
},
378+
0,
379+
),
380+
);
381+
382+
let state = StateCommit {
383+
change_set,
384+
results,
385+
..Default::default()
386+
};
387+
388+
let mut account_updates = collect_dirty_accounts(state, &Some(genesis_info));
389+
account_updates.sort_by_key(|k| k.address);
390+
391+
assert_eq!(
392+
account_updates,
393+
vec![
394+
AccountUpdate {
395+
address: address!("0000000000000000000000000000000000000001"),
396+
balance: U256::ONE,
397+
nonce: 0,
398+
vote: Some(address!("0000000000000000000000000000000000000002")),
399+
unvote: None,
400+
username: Some("test".into()),
401+
username_resigned: false,
402+
merge_info: Some(AccountMergeInfo {
403+
legacy_address: "DJmvhhiQFSrEQCq9FUxvcLcpcBjx7K3yLt".try_into().unwrap(),
404+
transaction_hash: b256!(
405+
"0000000000000000000000000000000000000000000000000000000000000001"
406+
)
407+
})
408+
},
409+
AccountUpdate {
410+
address: address!("0000000000000000000000000000000000000002"),
411+
balance: U256::ONE,
412+
nonce: 0,
413+
vote: None,
414+
unvote: Some(address!("0000000000000000000000000000000000000004")),
415+
username: None,
416+
username_resigned: true,
417+
merge_info: None
418+
}
419+
]
420+
);
421+
}
422+
423+
#[test]
424+
fn test_apply_rewards() {
425+
let path = tempfile::Builder::new()
426+
.prefix("evm.mdb")
427+
.tempdir()
428+
.unwrap();
429+
430+
let mut db = PersistentDB::new(crate::db::PersistentDBOptions::new(
431+
path.path().to_path_buf(),
432+
))
433+
.expect("database");
434+
let mut pending = PendingCommit::default();
435+
436+
let account1 = revm::primitives::address!("bd6f65c58a46427af4b257cbe231d0ed69ed5508");
437+
let account2 = revm::primitives::address!("ad6f65c58a46427af4b257cbe231d0ed69ed5508");
438+
439+
let mut rewards = HashMap::<Address, u128>::default();
440+
rewards.insert(account1, 1234);
441+
rewards.insert(account2, 0);
442+
443+
let result = apply_rewards(&mut db, &mut pending, rewards);
444+
assert!(result.is_ok());
445+
446+
let cache_account1 = pending.cache.accounts.get(&account1).expect("account1");
447+
assert!(cache_account1.account.is_some());
448+
assert_eq!(
449+
cache_account1.status,
450+
revm::database::AccountStatus::InMemoryChange
451+
);
452+
453+
let cache_account2 = pending.cache.accounts.get(&account2).expect("account2");
454+
assert!(cache_account2.account.is_none());
455+
assert_eq!(
456+
cache_account2.status,
457+
revm::database::AccountStatus::Destroyed
458+
);
459+
460+
let transition_account1 = pending
461+
.transitions
462+
.transitions
463+
.get(&account1)
464+
.expect("transition_account1");
465+
assert!(transition_account1.info.is_some());
466+
assert_eq!(
467+
transition_account1.status,
468+
revm::database::AccountStatus::InMemoryChange
469+
);
470+
assert_eq!(transition_account1.storage_was_destroyed, false);
471+
472+
let transition_account2 = pending
473+
.transitions
474+
.transitions
475+
.get(&account2)
476+
.expect("transition_account2");
477+
assert!(transition_account2.info.is_none());
478+
assert_eq!(
479+
transition_account2.status,
480+
revm::database::AccountStatus::Destroyed
481+
);
482+
assert_eq!(transition_account2.storage_was_destroyed, true);
483+
}
272484
}

0 commit comments

Comments
 (0)