mina_tree/scan_state/transaction_logic/
transaction_applied.rs

1use super::{
2    signed_command, zkapp_command, Coinbase, FeeTransfer, Transaction, TransactionStatus,
3    UserCommand, WithStatus,
4};
5use crate::{
6    scan_state::currency::{Amount, Magnitude, Signed},
7    Account, AccountId,
8};
9use mina_core::constants::ConstraintConstants;
10use mina_curves::pasta::Fp;
11
12pub mod signed_command_applied {
13    use mina_signer::CompressedPubKey;
14
15    use crate::AccountId;
16
17    use super::{signed_command, WithStatus};
18
19    #[derive(Debug, Clone, PartialEq)]
20    pub struct Common {
21        pub user_command: WithStatus<signed_command::SignedCommand>,
22    }
23
24    #[derive(Debug, Clone, PartialEq)]
25    pub enum Body {
26        Payments {
27            new_accounts: Vec<AccountId>,
28        },
29        StakeDelegation {
30            previous_delegate: Option<CompressedPubKey>,
31        },
32        Failed,
33    }
34
35    #[derive(Debug, Clone, PartialEq)]
36    pub struct SignedCommandApplied {
37        pub common: Common,
38        pub body: Body,
39    }
40}
41
42pub use signed_command_applied::SignedCommandApplied;
43
44impl SignedCommandApplied {
45    pub fn new_accounts(&self) -> &[AccountId] {
46        use signed_command_applied::Body::*;
47
48        match &self.body {
49            Payments { new_accounts } => new_accounts.as_slice(),
50            StakeDelegation { .. } | Failed => &[],
51        }
52    }
53}
54
55/// <https://github.com/MinaProtocol/mina/blob/2ee6e004ba8c6a0541056076aab22ea162f7eb3a/src/lib/transaction_logic/mina_transaction_logic.ml#L65>
56#[derive(Debug, Clone, PartialEq)]
57pub struct ZkappCommandApplied {
58    pub accounts: Vec<(AccountId, Option<Box<Account>>)>,
59    pub command: WithStatus<zkapp_command::ZkAppCommand>,
60    pub new_accounts: Vec<AccountId>,
61}
62
63/// <https://github.com/MinaProtocol/mina/blob/2ee6e004ba8c6a0541056076aab22ea162f7eb3a/src/lib/transaction_logic/mina_transaction_logic.ml#L82>
64#[derive(Debug, Clone, PartialEq)]
65pub enum CommandApplied {
66    SignedCommand(Box<SignedCommandApplied>),
67    ZkappCommand(Box<ZkappCommandApplied>),
68}
69
70/// <https://github.com/MinaProtocol/mina/blob/2ee6e004ba8c6a0541056076aab22ea162f7eb3a/src/lib/transaction_logic/mina_transaction_logic.ml#L96>
71#[derive(Debug, Clone, PartialEq)]
72pub struct FeeTransferApplied {
73    pub fee_transfer: WithStatus<FeeTransfer>,
74    pub new_accounts: Vec<AccountId>,
75    pub burned_tokens: Amount,
76}
77
78/// <https://github.com/MinaProtocol/mina/blob/2ee6e004ba8c6a0541056076aab22ea162f7eb3a/src/lib/transaction_logic/mina_transaction_logic.ml#L112>
79#[derive(Debug, Clone, PartialEq)]
80pub struct CoinbaseApplied {
81    pub coinbase: WithStatus<Coinbase>,
82    pub new_accounts: Vec<AccountId>,
83    pub burned_tokens: Amount,
84}
85
86/// <https://github.com/MinaProtocol/mina/blob/2ee6e004ba8c6a0541056076aab22ea162f7eb3a/src/lib/transaction_logic/mina_transaction_logic.ml#L142>
87#[derive(Debug, Clone, PartialEq)]
88pub enum Varying {
89    Command(CommandApplied),
90    FeeTransfer(FeeTransferApplied),
91    Coinbase(CoinbaseApplied),
92}
93
94/// <https://github.com/MinaProtocol/mina/blob/2ee6e004ba8c6a0541056076aab22ea162f7eb3a/src/lib/transaction_logic/mina_transaction_logic.ml#L142>
95#[derive(Debug, Clone, PartialEq)]
96pub struct TransactionApplied {
97    pub previous_hash: Fp,
98    pub varying: Varying,
99}
100
101impl TransactionApplied {
102    /// <https://github.com/MinaProtocol/mina/blob/2ee6e004ba8c6a0541056076aab22ea162f7eb3a/src/lib/transaction_logic/mina_transaction_logic.ml#L639>
103    pub fn transaction(&self) -> WithStatus<Transaction> {
104        use CommandApplied::*;
105        use Varying::*;
106
107        match &self.varying {
108            Command(SignedCommand(cmd)) => cmd
109                .common
110                .user_command
111                .map(|c| Transaction::Command(UserCommand::SignedCommand(Box::new(c.clone())))),
112            Command(ZkappCommand(cmd)) => cmd
113                .command
114                .map(|c| Transaction::Command(UserCommand::ZkAppCommand(Box::new(c.clone())))),
115            FeeTransfer(f) => f.fee_transfer.map(|f| Transaction::FeeTransfer(f.clone())),
116            Coinbase(c) => c.coinbase.map(|c| Transaction::Coinbase(c.clone())),
117        }
118    }
119
120    /// <https://github.com/MinaProtocol/mina/blob/2ee6e004ba8c6a0541056076aab22ea162f7eb3a/src/lib/transaction_logic/mina_transaction_logic.ml#L662>
121    pub fn transaction_status(&self) -> &TransactionStatus {
122        use CommandApplied::*;
123        use Varying::*;
124
125        match &self.varying {
126            Command(SignedCommand(cmd)) => &cmd.common.user_command.status,
127            Command(ZkappCommand(cmd)) => &cmd.command.status,
128            FeeTransfer(f) => &f.fee_transfer.status,
129            Coinbase(c) => &c.coinbase.status,
130        }
131    }
132
133    pub fn burned_tokens(&self) -> Amount {
134        match &self.varying {
135            Varying::Command(_) => Amount::zero(),
136            Varying::FeeTransfer(f) => f.burned_tokens,
137            Varying::Coinbase(c) => c.burned_tokens,
138        }
139    }
140
141    pub fn new_accounts(&self) -> &[AccountId] {
142        use CommandApplied::*;
143        use Varying::*;
144
145        match &self.varying {
146            Command(SignedCommand(cmd)) => cmd.new_accounts(),
147            Command(ZkappCommand(cmd)) => cmd.new_accounts.as_slice(),
148            FeeTransfer(f) => f.new_accounts.as_slice(),
149            Coinbase(cb) => cb.new_accounts.as_slice(),
150        }
151    }
152
153    /// <https://github.com/MinaProtocol/mina/blob/e5183ca1dde1c085b4c5d37d1d9987e24c294c32/src/lib/transaction_logic/mina_transaction_logic.ml#L176>
154    pub fn supply_increase(
155        &self,
156        constraint_constants: &ConstraintConstants,
157    ) -> Result<Signed<Amount>, String> {
158        let burned_tokens = Signed::<Amount>::of_unsigned(self.burned_tokens());
159
160        let account_creation_fees = {
161            let account_creation_fee_int = constraint_constants.account_creation_fee;
162            let num_accounts_created = self.new_accounts().len() as u64;
163
164            // int type is OK, no danger of overflow
165            let amount = account_creation_fee_int
166                .checked_mul(num_accounts_created)
167                .unwrap();
168            Signed::<Amount>::of_unsigned(Amount::from_u64(amount))
169        };
170
171        let expected_supply_increase = match &self.varying {
172            Varying::Coinbase(cb) => cb.coinbase.data.expected_supply_increase()?,
173            _ => Amount::zero(),
174        };
175        let expected_supply_increase = Signed::<Amount>::of_unsigned(expected_supply_increase);
176
177        // TODO: Make sure it's correct
178        let total = [burned_tokens, account_creation_fees]
179            .into_iter()
180            .try_fold(expected_supply_increase, |total, amt| {
181                total.add(&amt.negate())
182            });
183
184        total.ok_or_else(|| "overflow".to_string())
185    }
186}