defuse_core/engine/
mod.rs1mod inspector;
2mod state;
3
4pub use self::{inspector::*, state::*};
5
6use crate::{
7 DefuseError, ExpirableNonce, Nonce, Result, SaltedNonce, Timestamp, VersionedNonce,
8 intents::{DefuseIntents, ExecutableIntent},
9 payload::{DefusePayload, ExtractDefusePayload, Payload, SignedPayload, multi::MultiPayload},
10};
11
12use self::deltas::{Deltas, Transfers};
13
14pub struct Engine<S, I> {
15 pub state: Deltas<S>,
16 pub inspector: I,
17}
18
19impl<S, I> Engine<S, I>
20where
21 S: State,
22 I: Inspector,
23{
24 #[inline]
25 pub fn new(state: S, inspector: I) -> Self {
26 Self {
27 state: Deltas::new(state),
28 inspector,
29 }
30 }
31
32 pub fn execute_signed_intents(
33 mut self,
34 signed: impl IntoIterator<Item = MultiPayload>,
35 ) -> Result<Transfers> {
36 for signed in signed {
37 self.execute_signed_intent(signed)?;
38 }
39 self.finalize()
40 }
41
42 fn execute_signed_intent(&mut self, signed: MultiPayload) -> Result<()> {
43 let public_key = signed.verify().ok_or(DefuseError::InvalidSignature)?;
45
46 let hash = signed.hash();
48
49 let DefusePayload::<DefuseIntents> {
51 signer_id,
52 verifying_contract,
53 deadline,
54 nonce,
55 message: intents,
56 } = signed.extract_defuse_payload()?;
57
58 if verifying_contract != *self.state.verifying_contract() {
60 return Err(DefuseError::WrongVerifyingContract);
61 }
62
63 self.inspector.on_deadline(deadline);
64
65 if deadline < Timestamp::now() {
67 return Err(DefuseError::DeadlineExpired);
68 }
69
70 if !self.state.has_public_key(&signer_id, &public_key) {
72 return Err(DefuseError::PublicKeyNotExist(signer_id, public_key));
73 }
74
75 self.verify_intent_nonce(nonce, deadline)?;
77 self.state.commit_nonce(signer_id.clone(), nonce)?;
78
79 intents.execute_intent(&signer_id, self, hash)?;
80 self.inspector.on_intent_executed(&signer_id, hash, nonce);
81
82 Ok(())
83 }
84
85 #[inline]
86 fn verify_intent_nonce(&self, nonce: Nonce, intent_deadline: Timestamp) -> Result<()> {
87 let Some(nonce) = VersionedNonce::maybe_from(nonce) else {
88 return Ok(());
89 };
90
91 match nonce {
92 VersionedNonce::V1(SaltedNonce {
93 salt,
94 nonce: ExpirableNonce { deadline, .. },
95 }) => {
96 if !self.state.is_valid_salt(salt) {
97 return Err(DefuseError::InvalidSalt);
98 }
99
100 if intent_deadline > deadline {
101 return Err(DefuseError::DeadlineGreaterThanNonce);
102 }
103
104 if deadline < Timestamp::now() {
105 return Err(DefuseError::NonceExpired);
106 }
107 }
108 }
109
110 Ok(())
111 }
112
113 #[inline]
114 fn finalize(self) -> Result<Transfers> {
115 self.state
116 .finalize()
117 .map_err(DefuseError::InvariantViolated)
118 }
119}