ab_contracts_standards/
tx_handler.rs

1use ab_contracts_common::ContractError;
2use ab_contracts_common::env::Env;
3use ab_contracts_io_type::variable_bytes::VariableBytes;
4use ab_contracts_io_type::variable_elements::VariableElements;
5use ab_contracts_macros::contract;
6use ab_transaction::{TransactionHeader, TransactionSlot};
7
8pub type TxHandlerPayload = VariableElements<u128>;
9pub type TxHandlerSlots = VariableElements<TransactionSlot>;
10pub type TxHandlerSeal = VariableBytes;
11
12/// A transaction handler interface prototype
13#[contract]
14pub trait TxHandler {
15    /// Verify a transaction.
16    ///
17    /// Each transaction consists of a header, payload, read/write slots and a seal.
18    ///
19    /// Payload contains 16-byte aligned bytes, which typically represent method calls to be
20    /// executed, but the serialization format for it is contract-specific.
21    ///
22    /// Seal typically contains nonce and a signature over transaction header and payload, used for
23    /// checking whether to allow execution of methods in the payload argument.
24    ///
25    /// In the end, it is up to the contract implementing this trait to interpret both payload and
26    /// seal in any way desired.
27    ///
28    /// This method is called by execution environment is used for transaction authorization. It is
29    /// expected to do a limited amount of work before deciding whether execution is allowed or not.
30    /// Once authorization is granted (by returning a non-error result), execution environment will
31    /// deduct gas from the contract's balance and call [`TxHandler::execute()`] for actual
32    /// transaction execution.
33    ///
34    /// It is up to the host environment to decide how much work is allowed here when verifying
35    /// transaction in the transaction pool as for DoS protection. As a result, requiring too much
36    /// work may prevent transaction from being included in the block at all (unless user authors
37    /// the block and include the transaction themselves). Once a transaction is in the block, there
38    /// are no limits to the amount of work here except the ability to pay for gas.
39    #[view]
40    fn authorize(
41        #[env] env: &Env<'_>,
42        #[input] header: &TransactionHeader,
43        #[input] read_slots: &TxHandlerSlots,
44        #[input] write_slots: &TxHandlerSlots,
45        #[input] payload: &TxHandlerPayload,
46        #[input] seal: &TxHandlerSeal,
47    ) -> Result<(), ContractError>;
48
49    /// Execute previously verified transaction.
50    ///
51    /// *Execution environment will call this method with `env.caller()` set to `Address::NULL`,
52    /// which is very important to check!* Since there is no code deployed at `Address::NULL`, only
53    /// (trusted) execution environment is able to make such a call.
54    ///
55    /// Getting to this stage means that verification succeeded and except charging for gas, no
56    /// other state changes were made since then. If necessary, it is still possible to do
57    /// additional checks that would be too expensive or not possible to do in
58    /// [`TxHandler::authorize()`]. It is also important to implement a transaction replay
59    /// protection mechanism such as nonce increase or similar.
60    #[update]
61    fn execute(
62        #[env] env: &mut Env<'_>,
63        #[input] header: &TransactionHeader,
64        #[input] read_slots: &TxHandlerSlots,
65        #[input] write_slots: &TxHandlerSlots,
66        #[input] payload: &TxHandlerPayload,
67        #[input] seal: &TxHandlerSeal,
68    ) -> Result<(), ContractError>;
69}