Line data Source code
1 : #ifndef HEADER_fd_src_disco_bank_abi_h 2 : #define HEADER_fd_src_disco_bank_abi_h 3 : 4 : #include "../../ballet/pack/fd_pack.h" 5 : #include "../../ballet/blake3/fd_blake3.h" 6 : 7 : #define FD_BANK_ABI_TXN_ALIGN (8UL) 8 0 : #define FD_BANK_ABI_TXN_FOOTPRINT (248UL) 9 : 10 : /* A SanitizedTransaction is not just a 248 byte struct but also a bunch 11 : of sidecar data that's pointed to by the struct. All of this sidecar 12 : data is in the form of Vec<T>'s. Note that we only store the actual 13 : vector contents in the sidecar, the metadata like capacity and length 14 : of the vector belong to the SanitizedTransaction. The various 15 : vectors are... 16 : 17 : (1) A `Vec<uchar>` of length txn->acct_addr_cnt+txn->addr_table_adtl_cnt, 18 : which is the precomputed `is_writable_account_cache` storing for 19 : each account whether it is writable (1) or readable (0). 20 : (2) A `Vec<CompiledInstruction>` of length txn->instr_cnt. 21 : Each `CompiledInstruction` is 56 bytes. 22 : (3) A `Vec<MessageAddressTableLookup` of length txn->addr_table_lookup_cnt. 23 : Each `MessageAddressTableLookup` is 80 bytes. 24 : (4) A `Vec<Pubkey>` of length txn->addr_table_adtl_cnt. These are 25 : the loaded accounts from address lookup tables, and each pubkey 26 : is 32 bytes. 27 : 28 : Note that a SanitizedTransaction also have other Vec<T>'s internally, 29 : but we do not need a sidecar to store them because the underlying 30 : memory already exists in the payload somewhere, so we can reuse it. 31 : 32 : Note that the first field (the Vec<uchar>) does not need to be 33 : aligned, it has an alignment of 1, but we specify it as 8 here so 34 : that we can order the fields inside the sidecar data arbitrarily 35 : without overflowing the buffer. */ 36 : 37 : #define FD_BANK_ABI_TXN_FOOTPRINT_SIDECAR(acct_addr_cnt, addr_table_adtl_cnt, instr_cnt, addr_table_lookup_cnt) \ 38 0 : FD_LAYOUT_FINI( FD_LAYOUT_APPEND( FD_LAYOUT_APPEND( FD_LAYOUT_APPEND( FD_LAYOUT_APPEND( FD_LAYOUT_INIT, \ 39 0 : 8UL, (ulong)acct_addr_cnt+(ulong)addr_table_adtl_cnt ), \ 40 0 : 8UL, 56UL*(ulong)instr_cnt ), \ 41 0 : 8UL, 80UL*(ulong)addr_table_lookup_cnt ), \ 42 0 : 8UL, 32UL*(ulong)addr_table_adtl_cnt ), \ 43 0 : 8UL ) 44 : 45 : #define FD_BANK_ABI_TXN_FOOTPRINT_SIDECAR_MAX (FD_BANK_ABI_TXN_FOOTPRINT_SIDECAR(FD_TXN_ACCT_ADDR_MAX, FD_TXN_ACCT_ADDR_MAX, FD_TXN_INSTR_MAX, FD_TXN_ADDR_TABLE_LOOKUP_MAX)) 46 : 47 : /* FD_BANK_ABI_TXN_INIT_{SUCCESS,ERR_{...}} are error codes. These 48 : values are persisted to logs. Entries should not be renumbered and 49 : numeric values should never be reused. */ 50 : 51 0 : #define FD_BANK_ABI_TXN_INIT_SUCCESS ( 0) 52 0 : #define FD_BANK_ABI_TXN_INIT_ERR_ACCOUNT_NOT_FOUND (-1) 53 0 : #define FD_BANK_ABI_TXN_INIT_ERR_INVALID_ACCOUNT_OWNER (-2) 54 0 : #define FD_BANK_ABI_TXN_INIT_ERR_INVALID_ACCOUNT_DATA (-3) 55 0 : #define FD_BANK_ABI_TXN_INIT_ERR_ACCOUNT_UNINITIALIZED (-4) 56 0 : #define FD_BANK_ABI_TXN_INIT_ERR_INVALID_LOOKUP_INDEX (-5) 57 : 58 : /* fd_bank_abi_txn_t is a struct that is ABI compatible with 59 : `solana_sdk::transaction::sanitized::SanitizedTransaction`. It is an 60 : extremely gross hack, the type has Rust repr, so that layout is 61 : unspecified and unstable. For now though, we need to do this for 62 : performance, as it saves us from various copies. 63 : 64 : The Rust `SanitizedTransaction` returned here is very special, and is 65 : extremely unsafe to Rust code. In particular the internal Vec<> 66 : fields are not owned by the type, and are not pointing to memory 67 : allocated from the Rust heap, so dropping or attempting to modify 68 : them could crash or corrupt memory. The type overall should never be 69 : modified in Rust code, and just about the only thing it can be used 70 : for is it will survive being passed around as a 71 : &SanitizedTransaction. 72 : 73 : The only valid way to create such a struct is to use the 74 : fd_bank_abi_txn_init function below. Then it should be passed as a 75 : pointer to Rust, and treated only as an &SanitizedTransaction. 76 : 77 : Because the fake SanitizedTransaction does not own the underlying 78 : Vec objects, and they aren't actually vecs, these fields instead 79 : point to a sidecar buffer that is allocated by the caller. The 80 : lifetime of both the transaction and the sidecar must be the same. */ 81 : 82 : struct fd_bank_abi_txn_private; 83 : typedef struct fd_bank_abi_txn_private fd_bank_abi_txn_t; 84 : 85 : FD_PROTOTYPES_BEGIN 86 : 87 : /* This function resolves the address lookup tables for the provided 88 : transaction by writing them out to the out_lut_accts. The accounts 89 : are written, writable first, then readable, in the order they are 90 : referenced by the transaction. 91 : 92 : The function returns FD_BANK_ABI_TXN_INIT_SUCCESS on success and one 93 : of the FD_BANK_ABI_TXN_INIT_ERR_* error codes on failure. 94 : 95 : The address lookup table is retrieved as-of a particular slot that's 96 : provided. The slot is important in determining if the ALUT has been 97 : deactivated yet, or if it has been extended and the extension is in 98 : effect (extensions do not become active on the slot they occur in). */ 99 : 100 : int 101 : fd_bank_abi_resolve_address_lookup_tables( void const * bank, 102 : int fixed_root, 103 : ulong slot, 104 : fd_txn_t const * txn, 105 : uchar const * payload, 106 : fd_acct_addr_t * out_lut_accts ); 107 : 108 : /* This function takes a pointer to a buffer of at least size 109 : FD_BANK_ABI_TXN_FOOTPRINT where the resulting fd_bank_abi_txn_t will 110 : be constructed and returns FD_BANK_ABI_TXN_INIT_SUCCESS on success 111 : and FD_BANK_ABI_TXN_INIT_FAILURE on failure. 112 : 113 : Constructing a "legacy" transaction happens entirely in C and is 114 : extremely fast, mostly just laying out a struct. 115 : 116 : Constructing a "v1" transaction is slower. In this case we need to 117 : load the addresses used by the transaction, which requires retrieving 118 : the related address lookup program accounts in the accounts database. */ 119 : 120 : int 121 : fd_bank_abi_txn_init( fd_bank_abi_txn_t * out_txn, /* Memory to place the result in, must be at least FD_BANK_ABI_TXN_FOOTPRINT bytes. */ 122 : uchar * out_sidecar, /* Memory to place sidecar data in, must be at least FD_BANK_ABI_TXN_FOOTPRINT_SIDECAR( out_txn ) bytes. */ 123 : void const * bank, /* Pointer to an Agave `Bank` object the transaction is being loaded for. */ 124 : ulong slot, /* Slot the transaction is being loaded for. */ 125 : fd_blake3_t * blake3, /* Blake3 implementation used to create `message_hash` of the transaction. */ 126 : uchar * payload, /* Transaction raw wire payload. */ 127 : ulong payload_sz, /* Transaction raw wire size. */ 128 : fd_txn_t * txn, /* The Firedancer parsed transaction representation. */ 129 : int is_simple_vote /* If the transaction is a "simple vote" or not. */ ); 130 : 131 : FD_PROTOTYPES_END 132 : 133 : #endif /* HEADER_fd_src_disco_bank_abi_h */