rename State::snapshot to checkpoint to avoid confusion (#2796)
This commit is contained in:
parent
3ff1ca81f4
commit
8e5c9ff162
@ -250,7 +250,7 @@ impl<'a> Executive<'a> {
|
|||||||
vm_tracer: &mut V
|
vm_tracer: &mut V
|
||||||
) -> evm::Result<U256> where T: Tracer, V: VMTracer {
|
) -> evm::Result<U256> where T: Tracer, V: VMTracer {
|
||||||
// backup used in case of running out of gas
|
// backup used in case of running out of gas
|
||||||
self.state.snapshot();
|
self.state.checkpoint();
|
||||||
|
|
||||||
// at first, transfer value to destination
|
// at first, transfer value to destination
|
||||||
if let ActionValue::Transfer(val) = params.value {
|
if let ActionValue::Transfer(val) = params.value {
|
||||||
@ -269,7 +269,7 @@ impl<'a> Executive<'a> {
|
|||||||
let cost = self.engine.cost_of_builtin(¶ms.code_address, data);
|
let cost = self.engine.cost_of_builtin(¶ms.code_address, data);
|
||||||
if cost <= params.gas {
|
if cost <= params.gas {
|
||||||
self.engine.execute_builtin(¶ms.code_address, data, &mut output);
|
self.engine.execute_builtin(¶ms.code_address, data, &mut output);
|
||||||
self.state.discard_snapshot();
|
self.state.discard_checkpoint();
|
||||||
|
|
||||||
// trace only top level calls to builtins to avoid DDoS attacks
|
// trace only top level calls to builtins to avoid DDoS attacks
|
||||||
if self.depth == 0 {
|
if self.depth == 0 {
|
||||||
@ -289,7 +289,7 @@ impl<'a> Executive<'a> {
|
|||||||
Ok(params.gas - cost)
|
Ok(params.gas - cost)
|
||||||
} else {
|
} else {
|
||||||
// just drain the whole gas
|
// just drain the whole gas
|
||||||
self.state.revert_to_snapshot();
|
self.state.revert_to_checkpoint();
|
||||||
|
|
||||||
tracer.trace_failed_call(trace_info, vec![], evm::Error::OutOfGas.into());
|
tracer.trace_failed_call(trace_info, vec![], evm::Error::OutOfGas.into());
|
||||||
|
|
||||||
@ -335,7 +335,7 @@ impl<'a> Executive<'a> {
|
|||||||
res
|
res
|
||||||
} else {
|
} else {
|
||||||
// otherwise it's just a basic transaction, only do tracing, if necessary.
|
// otherwise it's just a basic transaction, only do tracing, if necessary.
|
||||||
self.state.discard_snapshot();
|
self.state.discard_checkpoint();
|
||||||
|
|
||||||
tracer.trace_call(trace_info, U256::zero(), trace_output, vec![]);
|
tracer.trace_call(trace_info, U256::zero(), trace_output, vec![]);
|
||||||
Ok(params.gas)
|
Ok(params.gas)
|
||||||
@ -354,7 +354,7 @@ impl<'a> Executive<'a> {
|
|||||||
vm_tracer: &mut V
|
vm_tracer: &mut V
|
||||||
) -> evm::Result<U256> where T: Tracer, V: VMTracer {
|
) -> evm::Result<U256> where T: Tracer, V: VMTracer {
|
||||||
// backup used in case of running out of gas
|
// backup used in case of running out of gas
|
||||||
self.state.snapshot();
|
self.state.checkpoint();
|
||||||
|
|
||||||
// part of substate that may be reverted
|
// part of substate that may be reverted
|
||||||
let mut unconfirmed_substate = Substate::new();
|
let mut unconfirmed_substate = Substate::new();
|
||||||
@ -485,10 +485,10 @@ impl<'a> Executive<'a> {
|
|||||||
| Err(evm::Error::BadInstruction {.. })
|
| Err(evm::Error::BadInstruction {.. })
|
||||||
| Err(evm::Error::StackUnderflow {..})
|
| Err(evm::Error::StackUnderflow {..})
|
||||||
| Err(evm::Error::OutOfStack {..}) => {
|
| Err(evm::Error::OutOfStack {..}) => {
|
||||||
self.state.revert_to_snapshot();
|
self.state.revert_to_checkpoint();
|
||||||
},
|
},
|
||||||
Ok(_) | Err(evm::Error::Internal) => {
|
Ok(_) | Err(evm::Error::Internal) => {
|
||||||
self.state.discard_snapshot();
|
self.state.discard_checkpoint();
|
||||||
substate.accrue(un_substate);
|
substate.accrue(un_substate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -167,24 +167,24 @@ impl AccountEntry {
|
|||||||
/// Upon destruction all the local cache data propagated into the global cache.
|
/// Upon destruction all the local cache data propagated into the global cache.
|
||||||
/// Propagated items might be rejected if current state is non-canonical.
|
/// Propagated items might be rejected if current state is non-canonical.
|
||||||
///
|
///
|
||||||
/// State snapshotting.
|
/// State checkpointing.
|
||||||
///
|
///
|
||||||
/// A new snapshot can be created with `snapshot()`. Snapshots can be
|
/// A new checkpoint can be created with `checkpoint()`. checkpoints can be
|
||||||
/// created in a hierarchy.
|
/// created in a hierarchy.
|
||||||
/// When a snapshot is active all changes are applied directly into
|
/// When a checkpoint is active all changes are applied directly into
|
||||||
/// `cache` and the original value is copied into an active snapshot.
|
/// `cache` and the original value is copied into an active checkpoint.
|
||||||
/// Reverting a snapshot with `revert_to_snapshot` involves copying
|
/// Reverting a checkpoint with `revert_to_checkpoint` involves copying
|
||||||
/// original values from the latest snapshot back into `cache`. The code
|
/// original values from the latest checkpoint back into `cache`. The code
|
||||||
/// takes care not to overwrite cached storage while doing that.
|
/// takes care not to overwrite cached storage while doing that.
|
||||||
/// Snapshot can be discateded with `discard_snapshot`. All of the orignal
|
/// checkpoint can be discateded with `discard_checkpoint`. All of the orignal
|
||||||
/// backed-up values are moved into a parent snapshot (if any).
|
/// backed-up values are moved into a parent checkpoint (if any).
|
||||||
///
|
///
|
||||||
pub struct State {
|
pub struct State {
|
||||||
db: StateDB,
|
db: StateDB,
|
||||||
root: H256,
|
root: H256,
|
||||||
cache: RefCell<HashMap<Address, AccountEntry>>,
|
cache: RefCell<HashMap<Address, AccountEntry>>,
|
||||||
// The original account is preserved in
|
// The original account is preserved in
|
||||||
snapshots: RefCell<Vec<HashMap<Address, Option<AccountEntry>>>>,
|
checkpoints: RefCell<Vec<HashMap<Address, Option<AccountEntry>>>>,
|
||||||
account_start_nonce: U256,
|
account_start_nonce: U256,
|
||||||
factories: Factories,
|
factories: Factories,
|
||||||
}
|
}
|
||||||
@ -213,7 +213,7 @@ impl State {
|
|||||||
db: db,
|
db: db,
|
||||||
root: root,
|
root: root,
|
||||||
cache: RefCell::new(HashMap::new()),
|
cache: RefCell::new(HashMap::new()),
|
||||||
snapshots: RefCell::new(Vec::new()),
|
checkpoints: RefCell::new(Vec::new()),
|
||||||
account_start_nonce: account_start_nonce,
|
account_start_nonce: account_start_nonce,
|
||||||
factories: factories,
|
factories: factories,
|
||||||
}
|
}
|
||||||
@ -229,7 +229,7 @@ impl State {
|
|||||||
db: db,
|
db: db,
|
||||||
root: root,
|
root: root,
|
||||||
cache: RefCell::new(HashMap::new()),
|
cache: RefCell::new(HashMap::new()),
|
||||||
snapshots: RefCell::new(Vec::new()),
|
checkpoints: RefCell::new(Vec::new()),
|
||||||
account_start_nonce: account_start_nonce,
|
account_start_nonce: account_start_nonce,
|
||||||
factories: factories
|
factories: factories
|
||||||
};
|
};
|
||||||
@ -237,21 +237,21 @@ impl State {
|
|||||||
Ok(state)
|
Ok(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a recoverable snaphot of this state.
|
/// Create a recoverable checkpoint of this state.
|
||||||
pub fn snapshot(&mut self) {
|
pub fn checkpoint(&mut self) {
|
||||||
self.snapshots.get_mut().push(HashMap::new());
|
self.checkpoints.get_mut().push(HashMap::new());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Merge last snapshot with previous.
|
/// Merge last checkpoint with previous.
|
||||||
pub fn discard_snapshot(&mut self) {
|
pub fn discard_checkpoint(&mut self) {
|
||||||
// merge with previous snapshot
|
// merge with previous checkpoint
|
||||||
let last = self.snapshots.get_mut().pop();
|
let last = self.checkpoints.get_mut().pop();
|
||||||
if let Some(mut snapshot) = last {
|
if let Some(mut checkpoint) = last {
|
||||||
if let Some(ref mut prev) = self.snapshots.get_mut().last_mut() {
|
if let Some(ref mut prev) = self.checkpoints.get_mut().last_mut() {
|
||||||
if prev.is_empty() {
|
if prev.is_empty() {
|
||||||
**prev = snapshot;
|
**prev = checkpoint;
|
||||||
} else {
|
} else {
|
||||||
for (k, v) in snapshot.drain() {
|
for (k, v) in checkpoint.drain() {
|
||||||
prev.entry(k).or_insert(v);
|
prev.entry(k).or_insert(v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -259,15 +259,15 @@ impl State {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Revert to the last snapshot and discard it.
|
/// Revert to the last checkpoint and discard it.
|
||||||
pub fn revert_to_snapshot(&mut self) {
|
pub fn revert_to_checkpoint(&mut self) {
|
||||||
if let Some(mut snapshot) = self.snapshots.get_mut().pop() {
|
if let Some(mut checkpoint) = self.checkpoints.get_mut().pop() {
|
||||||
for (k, v) in snapshot.drain() {
|
for (k, v) in checkpoint.drain() {
|
||||||
match v {
|
match v {
|
||||||
Some(v) => {
|
Some(v) => {
|
||||||
match self.cache.get_mut().entry(k) {
|
match self.cache.get_mut().entry(k) {
|
||||||
Entry::Occupied(mut e) => {
|
Entry::Occupied(mut e) => {
|
||||||
// Merge snapshotted changes back into the main account
|
// Merge checkpointed changes back into the main account
|
||||||
// storage preserving the cache.
|
// storage preserving the cache.
|
||||||
e.get_mut().overwrite_with(v);
|
e.get_mut().overwrite_with(v);
|
||||||
},
|
},
|
||||||
@ -293,14 +293,14 @@ impl State {
|
|||||||
|
|
||||||
fn insert_cache(&self, address: &Address, account: AccountEntry) {
|
fn insert_cache(&self, address: &Address, account: AccountEntry) {
|
||||||
// Dirty account which is not in the cache means this is a new account.
|
// Dirty account which is not in the cache means this is a new account.
|
||||||
// It goes directly into the snapshot as there's nothing to rever to.
|
// It goes directly into the checkpoint as there's nothing to rever to.
|
||||||
//
|
//
|
||||||
// In all other cases account is read as clean first, and after that made
|
// In all other cases account is read as clean first, and after that made
|
||||||
// dirty in and added to the snapshot with `note_cache`.
|
// dirty in and added to the checkpoint with `note_cache`.
|
||||||
if account.is_dirty() {
|
if account.is_dirty() {
|
||||||
if let Some(ref mut snapshot) = self.snapshots.borrow_mut().last_mut() {
|
if let Some(ref mut checkpoint) = self.checkpoints.borrow_mut().last_mut() {
|
||||||
if !snapshot.contains_key(address) {
|
if !checkpoint.contains_key(address) {
|
||||||
snapshot.insert(address.clone(), self.cache.borrow_mut().insert(address.clone(), account));
|
checkpoint.insert(address.clone(), self.cache.borrow_mut().insert(address.clone(), account));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -309,9 +309,9 @@ impl State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn note_cache(&self, address: &Address) {
|
fn note_cache(&self, address: &Address) {
|
||||||
if let Some(ref mut snapshot) = self.snapshots.borrow_mut().last_mut() {
|
if let Some(ref mut checkpoint) = self.checkpoints.borrow_mut().last_mut() {
|
||||||
if !snapshot.contains_key(address) {
|
if !checkpoint.contains_key(address) {
|
||||||
snapshot.insert(address.clone(), self.cache.borrow().get(address).map(AccountEntry::clone_dirty));
|
checkpoint.insert(address.clone(), self.cache.borrow().get(address).map(AccountEntry::clone_dirty));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -548,7 +548,7 @@ impl State {
|
|||||||
|
|
||||||
/// Commits our cached account changes into the trie.
|
/// Commits our cached account changes into the trie.
|
||||||
pub fn commit(&mut self) -> Result<(), Error> {
|
pub fn commit(&mut self) -> Result<(), Error> {
|
||||||
assert!(self.snapshots.borrow().is_empty());
|
assert!(self.checkpoints.borrow().is_empty());
|
||||||
Self::commit_into(&self.factories, &mut self.db, &mut self.root, &mut *self.cache.borrow_mut())
|
Self::commit_into(&self.factories, &mut self.db, &mut self.root, &mut *self.cache.borrow_mut())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -561,7 +561,7 @@ impl State {
|
|||||||
#[cfg(feature = "json-tests")]
|
#[cfg(feature = "json-tests")]
|
||||||
/// Populate the state from `accounts`.
|
/// Populate the state from `accounts`.
|
||||||
pub fn populate_from(&mut self, accounts: PodState) {
|
pub fn populate_from(&mut self, accounts: PodState) {
|
||||||
assert!(self.snapshots.borrow().is_empty());
|
assert!(self.checkpoints.borrow().is_empty());
|
||||||
for (add, acc) in accounts.drain().into_iter() {
|
for (add, acc) in accounts.drain().into_iter() {
|
||||||
self.cache.borrow_mut().insert(add, AccountEntry::new_dirty(Some(Account::from_pod(acc))));
|
self.cache.borrow_mut().insert(add, AccountEntry::new_dirty(Some(Account::from_pod(acc))));
|
||||||
}
|
}
|
||||||
@ -569,7 +569,7 @@ impl State {
|
|||||||
|
|
||||||
/// Populate a PodAccount map from this state.
|
/// Populate a PodAccount map from this state.
|
||||||
pub fn to_pod(&self) -> PodState {
|
pub fn to_pod(&self) -> PodState {
|
||||||
assert!(self.snapshots.borrow().is_empty());
|
assert!(self.checkpoints.borrow().is_empty());
|
||||||
// TODO: handle database rather than just the cache.
|
// TODO: handle database rather than just the cache.
|
||||||
// will need fat db.
|
// will need fat db.
|
||||||
PodState::from(self.cache.borrow().iter().fold(BTreeMap::new(), |mut m, (add, opt)| {
|
PodState::from(self.cache.borrow().iter().fold(BTreeMap::new(), |mut m, (add, opt)| {
|
||||||
@ -739,7 +739,7 @@ impl Clone for State {
|
|||||||
db: self.db.boxed_clone(),
|
db: self.db.boxed_clone(),
|
||||||
root: self.root.clone(),
|
root: self.root.clone(),
|
||||||
cache: RefCell::new(cache),
|
cache: RefCell::new(cache),
|
||||||
snapshots: RefCell::new(Vec::new()),
|
checkpoints: RefCell::new(Vec::new()),
|
||||||
account_start_nonce: self.account_start_nonce.clone(),
|
account_start_nonce: self.account_start_nonce.clone(),
|
||||||
factories: self.factories.clone(),
|
factories: self.factories.clone(),
|
||||||
}
|
}
|
||||||
@ -1777,34 +1777,34 @@ fn ensure_cached() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn snapshot_basic() {
|
fn checkpoint_basic() {
|
||||||
let mut state_result = get_temp_state();
|
let mut state_result = get_temp_state();
|
||||||
let mut state = state_result.reference_mut();
|
let mut state = state_result.reference_mut();
|
||||||
let a = Address::zero();
|
let a = Address::zero();
|
||||||
state.snapshot();
|
state.checkpoint();
|
||||||
state.add_balance(&a, &U256::from(69u64));
|
state.add_balance(&a, &U256::from(69u64));
|
||||||
assert_eq!(state.balance(&a), U256::from(69u64));
|
assert_eq!(state.balance(&a), U256::from(69u64));
|
||||||
state.discard_snapshot();
|
state.discard_checkpoint();
|
||||||
assert_eq!(state.balance(&a), U256::from(69u64));
|
assert_eq!(state.balance(&a), U256::from(69u64));
|
||||||
state.snapshot();
|
state.checkpoint();
|
||||||
state.add_balance(&a, &U256::from(1u64));
|
state.add_balance(&a, &U256::from(1u64));
|
||||||
assert_eq!(state.balance(&a), U256::from(70u64));
|
assert_eq!(state.balance(&a), U256::from(70u64));
|
||||||
state.revert_to_snapshot();
|
state.revert_to_checkpoint();
|
||||||
assert_eq!(state.balance(&a), U256::from(69u64));
|
assert_eq!(state.balance(&a), U256::from(69u64));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn snapshot_nested() {
|
fn checkpoint_nested() {
|
||||||
let mut state_result = get_temp_state();
|
let mut state_result = get_temp_state();
|
||||||
let mut state = state_result.reference_mut();
|
let mut state = state_result.reference_mut();
|
||||||
let a = Address::zero();
|
let a = Address::zero();
|
||||||
state.snapshot();
|
state.checkpoint();
|
||||||
state.snapshot();
|
state.checkpoint();
|
||||||
state.add_balance(&a, &U256::from(69u64));
|
state.add_balance(&a, &U256::from(69u64));
|
||||||
assert_eq!(state.balance(&a), U256::from(69u64));
|
assert_eq!(state.balance(&a), U256::from(69u64));
|
||||||
state.discard_snapshot();
|
state.discard_checkpoint();
|
||||||
assert_eq!(state.balance(&a), U256::from(69u64));
|
assert_eq!(state.balance(&a), U256::from(69u64));
|
||||||
state.revert_to_snapshot();
|
state.revert_to_checkpoint();
|
||||||
assert_eq!(state.balance(&a), U256::from(0));
|
assert_eq!(state.balance(&a), U256::from(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user