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