oasis_core_runtime/consensus/roothash/
message.rs1use anyhow::Result;
2
3use crate::{
4 common::{crypto::hash::Hash, quantity::Quantity, versioned::Versioned},
5 consensus::{address::Address, governance, registry, staking},
6};
7
8#[derive(Clone, Debug, PartialEq, Eq, cbor::Encode, cbor::Decode)]
10pub enum Message {
11 #[cbor(rename = "staking")]
12 Staking(Versioned<StakingMessage>),
13
14 #[cbor(rename = "registry")]
15 Registry(Versioned<RegistryMessage>),
16
17 #[cbor(rename = "governance")]
18 Governance(Versioned<GovernanceMessage>),
19}
20
21impl Message {
22 pub fn messages_hash(msgs: &[Message]) -> Hash {
24 if msgs.is_empty() {
25 return Hash::empty_hash();
27 }
28 Hash::digest_bytes(&cbor::to_vec(msgs.to_vec()))
29 }
30
31 pub fn in_messages_hash(msgs: &[IncomingMessage]) -> Hash {
33 if msgs.is_empty() {
34 return Hash::empty_hash();
36 }
37 Hash::digest_bytes(&cbor::to_vec(msgs.to_vec()))
38 }
39
40 pub fn validate_basic(&self) -> Result<()> {
42 match self {
43 Message::Staking(msg) => msg.inner.validate_basic(),
44 Message::Registry(msg) => msg.inner.validate_basic(),
45 Message::Governance(msg) => msg.inner.validate_basic(),
46 }
47 }
48}
49
50#[derive(Clone, Debug, PartialEq, Eq, Hash, cbor::Encode, cbor::Decode)]
51pub enum StakingMessage {
52 #[cbor(rename = "transfer")]
53 Transfer(staking::Transfer),
54
55 #[cbor(rename = "withdraw")]
56 Withdraw(staking::Withdraw),
57
58 #[cbor(rename = "add_escrow")]
59 AddEscrow(staking::Escrow),
60
61 #[cbor(rename = "reclaim_escrow")]
62 ReclaimEscrow(staking::ReclaimEscrow),
63}
64
65impl StakingMessage {
66 pub fn validate_basic(&self) -> Result<()> {
68 match self {
69 StakingMessage::Transfer(_) => {
70 Ok(())
72 }
73 StakingMessage::Withdraw(_) => {
74 Ok(())
76 }
77 StakingMessage::AddEscrow(_) => {
78 Ok(())
80 }
81 StakingMessage::ReclaimEscrow(_) => {
82 Ok(())
84 }
85 }
86 }
87}
88
89#[derive(Clone, Debug, PartialEq, Eq, Hash, cbor::Encode, cbor::Decode)]
90pub enum RegistryMessage {
91 #[cbor(rename = "update_runtime")]
92 UpdateRuntime(registry::Runtime),
93}
94
95impl RegistryMessage {
96 pub fn validate_basic(&self) -> Result<()> {
98 match self {
99 RegistryMessage::UpdateRuntime(_) => {
100 Ok(())
104 }
105 }
106 }
107}
108
109#[derive(Clone, Debug, PartialEq, Eq, cbor::Encode, cbor::Decode)]
110pub enum GovernanceMessage {
111 #[cbor(rename = "cast_vote")]
112 CastVote(governance::ProposalVote),
113 #[cbor(rename = "submit_proposal")]
114 SubmitProposal(governance::ProposalContent),
115}
116
117impl GovernanceMessage {
118 pub fn validate_basic(&self) -> Result<()> {
120 match self {
121 GovernanceMessage::CastVote(_) => {
122 Ok(())
124 }
125 GovernanceMessage::SubmitProposal(_) => {
126 Ok(())
128 }
129 }
130 }
131}
132
133#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, cbor::Encode, cbor::Decode)]
135pub struct IncomingMessage {
136 pub id: u64,
138 pub caller: Address,
140 #[cbor(optional)]
143 pub tag: u64,
144 #[cbor(optional)]
147 pub fee: Quantity,
148 #[cbor(optional)]
151 pub tokens: Quantity,
152 #[cbor(optional)]
154 pub data: Vec<u8>,
155}
156
157impl IncomingMessage {
158 pub fn in_messages_hash(msgs: &[IncomingMessage]) -> Hash {
160 if msgs.is_empty() {
161 return Hash::empty_hash();
163 }
164 Hash::digest_bytes(&cbor::to_vec(msgs.to_vec()))
165 }
166}
167
168#[cfg(test)]
169mod tests {
170 use std::collections::BTreeMap;
171
172 use crate::{
173 common::{crypto::signature::PublicKey, namespace::Namespace, quantity},
174 consensus::scheduler,
175 };
176
177 use super::*;
178
179 #[test]
180 fn test_consistent_messages_hash() {
181 let test_ent_id =
183 PublicKey::from("4ea5328f943ef6f66daaed74cb0e99c3b1c45f76307b425003dbc7cb3638ed35");
184
185 let q = quantity::Quantity::from(1000u32);
186
187 let mut st = BTreeMap::new();
188 st.insert(staking::ThresholdKind::KindNodeCompute, q.clone());
189
190 let mut wlc = BTreeMap::new();
191 wlc.insert(registry::RolesMask::ROLE_COMPUTE_WORKER, 2);
192
193 let mut wl = BTreeMap::new();
194 wl.insert(
195 test_ent_id,
196 registry::EntityWhitelistConfig { max_nodes: wlc },
197 );
198
199 let rt = registry::Runtime {
200 v: registry::LATEST_RUNTIME_DESCRIPTOR_VERSION,
201 id: Namespace::default(),
202 entity_id: test_ent_id,
203 genesis: registry::RuntimeGenesis {
204 state_root: Hash::empty_hash(),
205 round: 0,
206 },
207 kind: registry::RuntimeKind::KindCompute,
208 tee_hardware: registry::TEEHardware::TEEHardwareInvalid,
209 deployments: vec![registry::VersionInfo::default()],
210 key_manager: None,
211 executor: registry::ExecutorParameters {
212 group_size: 3,
213 group_backup_size: 5,
214 allowed_stragglers: 1,
215 round_timeout: 10,
216 max_messages: 32,
217 ..Default::default()
218 },
219 txn_scheduler: registry::TxnSchedulerParameters {
220 batch_flush_timeout: 1_000_000_000, max_batch_size: 1,
222 max_batch_size_bytes: 1024,
223 max_in_messages: 0,
224 propose_batch_timeout: 2_000_000_000, },
226 storage: registry::StorageParameters {
227 checkpoint_interval: 0,
228 checkpoint_num_kept: 0,
229 checkpoint_chunk_size: 0,
230 },
231 admission_policy: registry::RuntimeAdmissionPolicy {
232 entity_whitelist: Some(registry::EntityWhitelistRuntimeAdmissionPolicy {
233 entities: wl,
234 }),
235 ..Default::default()
236 },
237 constraints: {
238 let mut cs = BTreeMap::new();
239 cs.insert(scheduler::CommitteeKind::ComputeExecutor, {
240 let mut ce = BTreeMap::new();
241 ce.insert(
242 scheduler::Role::Worker,
243 registry::SchedulingConstraints {
244 min_pool_size: Some(registry::MinPoolSizeConstraint { limit: 1 }),
245 validator_set: Some(registry::ValidatorSetConstraint {}),
246 ..Default::default()
247 },
248 );
249 ce.insert(
250 scheduler::Role::BackupWorker,
251 registry::SchedulingConstraints {
252 min_pool_size: Some(registry::MinPoolSizeConstraint { limit: 2 }),
253 ..Default::default()
254 },
255 );
256 ce
257 });
258
259 cs
260 },
261 staking: registry::RuntimeStakingParameters {
262 thresholds: st,
263 ..Default::default()
264 },
265 governance_model: registry::RuntimeGovernanceModel::GovernanceEntity,
266 };
267
268 let tcs = vec![
270 (
271 vec![],
272 "c672b8d1ef56ed28ab87c3622c5114069bdd3ad7b8f9737498d0c01ecef0967a",
273 ),
274 (
275 vec![Message::Staking(Versioned::new(
276 0,
277 StakingMessage::Transfer(staking::Transfer::default()),
278 ))],
279 "a6b91f974b34a9192efd12025659a768520d2f04e1dae9839677456412cdb2be",
280 ),
281 (
282 vec![Message::Staking(Versioned::new(
283 0,
284 StakingMessage::Withdraw(staking::Withdraw::default()),
285 ))],
286 "069b0fda76d804e3fd65d4bbd875c646f15798fb573ac613100df67f5ba4c3fd",
287 ),
288 (
289 vec![Message::Staking(Versioned::new(
290 0,
291 StakingMessage::AddEscrow(staking::Escrow::default()),
292 ))],
293 "65049870b9dae657390e44065df0c78176816876e67b96dac7791ee6a1aa42e2",
294 ),
295 (
296 vec![Message::Staking(Versioned::new(
297 0,
298 StakingMessage::ReclaimEscrow(staking::ReclaimEscrow::default()),
299 ))],
300 "c78547eae2f104268e49827cbe624cf2b350ee59e8d693dec0673a70a4664a2e",
301 ),
302 (
303 vec![Message::Registry(Versioned::new(
304 0,
305 RegistryMessage::UpdateRuntime(registry::Runtime {
306 admission_policy: registry::RuntimeAdmissionPolicy {
307 any_node: Some(registry::AnyNodeRuntimeAdmissionPolicy {}),
308 ..Default::default()
309 },
310 ..Default::default()
311 }),
312 ))],
313 "baf9eeaa4860e363a9c27d99555839afc535f0cd32d23dc640f0f020677460e0",
315 ),
316 (
317 vec![Message::Registry(Versioned::new(
318 0,
319 RegistryMessage::UpdateRuntime(rt),
320 ))],
321 "03e77fbeda1a2291c87c06c59335a49fe18852266d58608c1ddec8ef64209458",
322 ),
323 (
324 vec![Message::Governance(Versioned::new(
325 0,
326 GovernanceMessage::CastVote(governance::ProposalVote {
327 id: 32,
328 vote: governance::Vote::Yes,
329 }),
330 ))],
331 "f45e26eb8ace807ad5bd02966cde1f012d1d978d4cbddd59e9bfd742dcf39b90",
332 ),
333 (
334 vec![Message::Governance(Versioned::new(
335 0,
336 GovernanceMessage::SubmitProposal(governance::ProposalContent {
337 cancel_upgrade: Some(governance::CancelUpgradeProposal { proposal_id: 32 }),
338 ..Default::default()
339 }),
340 ))],
341 "03312ddb5c41a30fbd29fb91cf6bf26d58073996f89657ca4f3b3a43a98bfd0b",
342 ),
343 ];
344 for (msgs, expected_hash) in tcs {
345 println!("{:?}", cbor::to_vec(msgs.clone()));
346 assert_eq!(Message::messages_hash(&msgs), Hash::from(expected_hash));
347 }
348 }
349}