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}