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}