ab_contracts_standards/
tx_handler.rs

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