1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
use anyhow::Result;
use diem_scratchpad::SparseMerkleTree;
use diem_state_view::StateViewId;
use diem_types::{
account_address::AccountAddress,
account_config::{AccountResource, AccountSequenceInfo},
account_state::AccountState,
on_chain_config::{DiemVersion, OnChainConfigPayload, VMConfig, VMPublishingOption},
transaction::{SignedTransaction, VMValidatorResult},
};
use diem_vm::DiemVM;
use fail::fail_point;
use std::{convert::TryFrom, sync::Arc};
use storage_interface::{state_view::VerifiedStateView, DbReader};
#[cfg(test)]
#[path = "unit_tests/vm_validator_test.rs"]
mod vm_validator_test;
pub trait TransactionValidation: Send + Sync + Clone {
type ValidationInstance: diem_vm::VMValidator;
fn validate_transaction(&self, _txn: SignedTransaction) -> Result<VMValidatorResult>;
fn restart(&mut self, config: OnChainConfigPayload) -> Result<()>;
}
#[derive(Clone)]
pub struct VMValidator {
db_reader: Arc<dyn DbReader>,
vm: DiemVM,
}
impl VMValidator {
pub fn new(db_reader: Arc<dyn DbReader>) -> Self {
let (version, state_root) = db_reader.get_latest_state_root().expect("Should not fail.");
let smt = SparseMerkleTree::new(state_root);
let state_view = VerifiedStateView::new(
StateViewId::Miscellaneous,
Arc::clone(&db_reader),
Some(version),
state_root,
&smt,
);
let vm = DiemVM::new_for_validation(&state_view);
VMValidator { db_reader, vm }
}
}
impl TransactionValidation for VMValidator {
type ValidationInstance = DiemVM;
fn validate_transaction(&self, txn: SignedTransaction) -> Result<VMValidatorResult> {
fail_point!("vm_validator::validate_transaction", |_| {
Err(anyhow::anyhow!(
"Injected error in vm_validator::validate_transaction"
))
});
use diem_vm::VMValidator;
let (version, state_root) = self.db_reader.get_latest_state_root()?;
let db_reader = Arc::clone(&self.db_reader);
let vm = self.vm.clone();
let smt = SparseMerkleTree::new(state_root);
let state_view = VerifiedStateView::new(
StateViewId::TransactionValidation {
base_version: version,
},
db_reader,
Some(version),
state_root,
&smt,
);
Ok(vm.validate_transaction(txn, &state_view))
}
fn restart(&mut self, config: OnChainConfigPayload) -> Result<()> {
let vm_config = config.get::<VMConfig>()?;
let version = config.get::<DiemVersion>()?;
let publishing_option = config.get::<VMPublishingOption>()?;
self.vm = DiemVM::init_with_config(version, vm_config, publishing_option);
Ok(())
}
}
pub fn get_account_sequence_number(
storage: &dyn DbReader,
address: AccountAddress,
) -> Result<AccountSequenceInfo> {
fail_point!("vm_validator::get_account_sequence_number", |_| {
Err(anyhow::anyhow!(
"Injected error in get_account_sequence_number"
))
});
match storage.get_latest_account_state(address)? {
Some(blob) => {
if let Ok(Some(crsn)) = AccountState::try_from(&blob)?.get_crsn_resource() {
return Ok(AccountSequenceInfo::CRSN {
min_nonce: crsn.min_nonce(),
size: crsn.size(),
});
}
Ok(AccountSequenceInfo::Sequential(
AccountResource::try_from(&blob)?.sequence_number(),
))
}
None => Ok(AccountSequenceInfo::Sequential(0)),
}
}