Make checkpoint_storage_at use plain loop instead of recursion (#9734)
* Make checkpoint_storage_at use plain loop instead of recursion * Add target: "state" to warn! * Use iterator::Skip
This commit is contained in:
parent
5319d33bc6
commit
7434026f5f
@ -553,62 +553,70 @@ impl<B: Backend> State<B> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get the value of storage at a specific checkpoint.
|
/// Get the value of storage at a specific checkpoint.
|
||||||
pub fn checkpoint_storage_at(&self, checkpoint_index: usize, address: &Address, key: &H256) -> TrieResult<Option<H256>> {
|
pub fn checkpoint_storage_at(&self, start_checkpoint_index: usize, address: &Address, key: &H256) -> TrieResult<Option<H256>> {
|
||||||
|
#[must_use]
|
||||||
enum ReturnKind {
|
enum ReturnKind {
|
||||||
/// Use original storage at value at this address.
|
/// Use original storage at value at this address.
|
||||||
OriginalAt,
|
OriginalAt,
|
||||||
/// Use the downward checkpoint value.
|
/// The checkpoint storage value is the same as the checkpoint storage value at the next checkpoint.
|
||||||
Downward,
|
SameAsNext,
|
||||||
}
|
}
|
||||||
|
|
||||||
let (checkpoints_len, kind) = {
|
let kind = {
|
||||||
let checkpoints = self.checkpoints.borrow();
|
let checkpoints = self.checkpoints.borrow();
|
||||||
let checkpoints_len = checkpoints.len();
|
|
||||||
let checkpoint = match checkpoints.get(checkpoint_index) {
|
if start_checkpoint_index >= checkpoints.len() {
|
||||||
Some(checkpoint) => checkpoint,
|
|
||||||
// The checkpoint was not found. Return None.
|
// The checkpoint was not found. Return None.
|
||||||
None => return Ok(None),
|
return Ok(None);
|
||||||
};
|
}
|
||||||
|
|
||||||
let kind = match checkpoint.get(address) {
|
let mut kind = None;
|
||||||
// The account exists at this checkpoint.
|
|
||||||
Some(Some(AccountEntry { account: Some(ref account), .. })) => {
|
for checkpoint in checkpoints.iter().skip(start_checkpoint_index) {
|
||||||
if let Some(value) = account.cached_storage_at(key) {
|
match checkpoint.get(address) {
|
||||||
return Ok(Some(value));
|
// The account exists at this checkpoint.
|
||||||
} else {
|
Some(Some(AccountEntry { account: Some(ref account), .. })) => {
|
||||||
// This account has checkpoint entry, but the key is not in the entry's cache. We can use
|
if let Some(value) = account.cached_storage_at(key) {
|
||||||
// original_storage_at if current account's original storage root is the same as checkpoint
|
return Ok(Some(value));
|
||||||
// account's original storage root. Otherwise, the account must be a newly created contract.
|
|
||||||
if account.base_storage_root() == self.original_storage_root(address)? {
|
|
||||||
ReturnKind::OriginalAt
|
|
||||||
} else {
|
} else {
|
||||||
// If account base storage root is different from the original storage root since last
|
// This account has checkpoint entry, but the key is not in the entry's cache. We can use
|
||||||
// commit, then it can only be created from a new contract, where the base storage root
|
// original_storage_at if current account's original storage root is the same as checkpoint
|
||||||
// would always be empty. Note that this branch is actually never called, because
|
// account's original storage root. Otherwise, the account must be a newly created contract.
|
||||||
// `cached_storage_at` handled this case.
|
if account.base_storage_root() == self.original_storage_root(address)? {
|
||||||
warn!("Trying to get an account's cached storage value, but base storage root does not equal to original storage root! Assuming the value is empty.");
|
kind = Some(ReturnKind::OriginalAt);
|
||||||
return Ok(Some(H256::new()));
|
break
|
||||||
|
} else {
|
||||||
|
// If account base storage root is different from the original storage root since last
|
||||||
|
// commit, then it can only be created from a new contract, where the base storage root
|
||||||
|
// would always be empty. Note that this branch is actually never called, because
|
||||||
|
// `cached_storage_at` handled this case.
|
||||||
|
warn!(target: "state", "Trying to get an account's cached storage value, but base storage root does not equal to original storage root! Assuming the value is empty.");
|
||||||
|
return Ok(Some(H256::new()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
},
|
// The account didn't exist at that point. Return empty value.
|
||||||
// The account didn't exist at that point. Return empty value.
|
Some(Some(AccountEntry { account: None, .. })) => return Ok(Some(H256::new())),
|
||||||
Some(Some(AccountEntry { account: None, .. })) => return Ok(Some(H256::new())),
|
// The value was not cached at that checkpoint, meaning it was not modified at all.
|
||||||
// The value was not cached at that checkpoint, meaning it was not modified at all.
|
Some(None) => {
|
||||||
Some(None) => ReturnKind::OriginalAt,
|
kind = Some(ReturnKind::OriginalAt);
|
||||||
// This key does not have a checkpoint entry.
|
break
|
||||||
None => ReturnKind::Downward,
|
},
|
||||||
};
|
// This key does not have a checkpoint entry.
|
||||||
|
None => {
|
||||||
|
kind = Some(ReturnKind::SameAsNext);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
(checkpoints_len, kind)
|
kind.expect("start_checkpoint_index is checked to be below checkpoints_len; for loop above must have been executed at least once; it will either early return, or set the kind value to Some; qed")
|
||||||
};
|
};
|
||||||
|
|
||||||
match kind {
|
match kind {
|
||||||
ReturnKind::Downward => {
|
ReturnKind::SameAsNext => {
|
||||||
if checkpoint_index >= checkpoints_len - 1 {
|
// If we reached here, all previous SameAsNext failed to early return. It means that the value we want
|
||||||
Ok(Some(self.storage_at(address, key)?))
|
// to fetch is the same as current.
|
||||||
} else {
|
Ok(Some(self.storage_at(address, key)?))
|
||||||
self.checkpoint_storage_at(checkpoint_index + 1, address, key)
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
ReturnKind::OriginalAt => Ok(Some(self.original_storage_at(address, key)?)),
|
ReturnKind::OriginalAt => Ok(Some(self.original_storage_at(address, key)?)),
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user