oasis_core_runtime/consensus/tendermint/verifier/store/
state.rs1use std::sync::Arc;
2
3use sgx_isa::Keypolicy;
4use tendermint_light_client::{
5 store::LightStore,
6 types::{LightBlock as TMLightBlock, Status},
7};
8
9use crate::{
10 common::{
11 namespace::Namespace,
12 sgx::{seal, EnclaveIdentity},
13 version::Version,
14 },
15 consensus::verifier::{Error, TrustRoot},
16 protocol::ProtocolUntrustedLocalStorage,
17 storage::KeyValue,
18 Protocol, TeeType, BUILD_INFO,
19};
20
21const TRUSTED_STATE_STORAGE_KEY_PREFIX: &str = "tendermint.verifier.trusted_state";
26
27const TRUSTED_STATE_CONTEXT: &[u8] = b"oasis-core/verifier: trusted state";
29
30#[derive(Debug, Clone)]
32pub struct EncodedLightBlock(TMLightBlock);
33
34impl From<TMLightBlock> for EncodedLightBlock {
35 fn from(value: TMLightBlock) -> Self {
36 Self(value)
37 }
38}
39
40impl From<EncodedLightBlock> for TMLightBlock {
41 fn from(value: EncodedLightBlock) -> Self {
42 value.0
43 }
44}
45
46impl cbor::Encode for EncodedLightBlock {
47 fn into_cbor_value(self) -> cbor::Value {
48 cbor::serde::to_value(&self.0).unwrap()
49 }
50}
51
52impl cbor::Decode for EncodedLightBlock {
53 fn try_from_cbor_value(value: cbor::Value) -> Result<Self, cbor::DecodeError> {
54 cbor::serde::from_value(value)
55 .map_err(|_| cbor::DecodeError::ParsingFailed)
56 .map(Self)
57 }
58}
59
60#[derive(Debug, Clone, Default, cbor::Encode, cbor::Decode)]
62pub struct TrustedState {
63 pub trust_root: TrustRoot,
65 pub trusted_blocks: Vec<EncodedLightBlock>,
70}
71
72pub struct TrustedStateStore {
74 runtime_id: Namespace,
75 chain_context: String,
76 untrusted_local_store: ProtocolUntrustedLocalStorage,
77}
78
79impl TrustedStateStore {
80 pub fn new(runtime_id: Namespace, chain_context: String, protocol: Arc<Protocol>) -> Self {
82 let untrusted_local_store = ProtocolUntrustedLocalStorage::new(protocol);
83
84 Self {
85 runtime_id,
86 chain_context,
87 untrusted_local_store,
88 }
89 }
90
91 pub fn save(&self, runtime_version: Version, store: &Box<dyn LightStore>) {
98 if BUILD_INFO.tee_type == TeeType::Tdx {
99 return;
102 }
103
104 let lowest_block = store.lowest(Status::Trusted).unwrap();
105 let highest_block = store.highest(Status::Trusted).unwrap();
106
107 let trust_root = TrustRoot {
109 height: highest_block.height().into(),
110 hash: highest_block.signed_header.header.hash().to_string(),
111 runtime_id: self.runtime_id,
112 chain_context: self.chain_context.clone(),
113 };
114
115 let trusted_state = TrustedState {
116 trust_root,
117 trusted_blocks: vec![lowest_block.into(), highest_block.into()],
118 };
119
120 let raw = cbor::to_vec(trusted_state);
122 let sealed = seal::seal(Keypolicy::MRENCLAVE, TRUSTED_STATE_CONTEXT, &raw);
123
124 self.untrusted_local_store
126 .insert(Self::derive_storage_key(runtime_version), sealed)
127 .unwrap();
128 }
129
130 pub fn load(
134 &self,
135 runtime_version: Version,
136 trust_root: &TrustRoot,
137 ) -> Result<TrustedState, Error> {
138 if BUILD_INFO.tee_type == TeeType::Tdx {
139 return Ok(TrustedState {
142 trust_root: trust_root.clone(),
143 trusted_blocks: vec![],
144 });
145 }
146
147 let untrusted_value = self
149 .untrusted_local_store
150 .get(Self::derive_storage_key(runtime_version))
151 .map_err(|_| Error::TrustedStateLoadingFailed)?;
152 if untrusted_value.is_empty() {
153 return Ok(TrustedState {
154 trust_root: trust_root.clone(),
155 trusted_blocks: vec![],
156 });
157 }
158
159 let raw = seal::unseal(
161 Keypolicy::MRENCLAVE,
162 TRUSTED_STATE_CONTEXT,
163 &untrusted_value,
164 )
165 .map_err(|_| Error::TrustedStateLoadingFailed)?
166 .unwrap();
167
168 let trusted_state: TrustedState =
169 cbor::from_slice(&raw).expect("corrupted sealed trusted state");
170
171 Ok(trusted_state)
172 }
173
174 fn derive_storage_key(runtime_version: Version) -> Vec<u8> {
175 format!(
179 "{}.{}.{:x}",
180 TRUSTED_STATE_STORAGE_KEY_PREFIX,
181 u64::from(runtime_version),
182 EnclaveIdentity::current()
183 .map(|eid| eid.mr_enclave)
184 .unwrap_or_default()
185 )
186 .into_bytes()
187 }
188}