Line data Source code
1 : #ifndef HEADER_fd_src_discoh_bank_fd_bank_abi_h 2 : #define HEADER_fd_src_discoh_bank_fd_bank_abi_h 3 : 4 : #include "../../disco/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 (392UL) 9 : 10 : /* A SanitizedTransaction is not just a 392 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 V1 transactions do not support address lookup tables, so 33 : they don't have (3) or (4). 34 : 35 : Note that the first field (the Vec<uchar>) does not need to be 36 : aligned, it has an alignment of 1, but we specify it as 8 here so 37 : that we can order the fields inside the sidecar data arbitrarily 38 : without overflowing the buffer. */ 39 : 40 : #define FD_BANK_ABI_TXN_FOOTPRINT_SIDECAR(acct_addr_cnt, addr_table_adtl_cnt, instr_cnt, addr_table_lookup_cnt) \ 41 0 : FD_LAYOUT_FINI( FD_LAYOUT_APPEND( FD_LAYOUT_APPEND( FD_LAYOUT_APPEND( FD_LAYOUT_APPEND( FD_LAYOUT_INIT, \ 42 0 : 8UL, (ulong)acct_addr_cnt+(ulong)addr_table_adtl_cnt ), \ 43 0 : 8UL, 56UL*(ulong)instr_cnt ), \ 44 0 : 8UL, 80UL*(ulong)addr_table_lookup_cnt ), \ 45 0 : 8UL, 32UL*(ulong)addr_table_adtl_cnt ), \ 46 0 : 8UL ) 47 : 48 : #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)) 49 : 50 : /* FD_BANK_ABI_TXN_INIT_{SUCCESS,ERR_{...}} are error codes. These 51 : values are persisted to logs. Entries should not be renumbered and 52 : numeric values should never be reused. */ 53 : 54 0 : #define FD_BANK_ABI_TXN_INIT_SUCCESS ( 0) 55 0 : #define FD_BANK_ABI_TXN_INIT_ERR_ACCOUNT_NOT_FOUND (-1) 56 0 : #define FD_BANK_ABI_TXN_INIT_ERR_INVALID_ACCOUNT_OWNER (-2) 57 0 : #define FD_BANK_ABI_TXN_INIT_ERR_INVALID_ACCOUNT_DATA (-3) 58 0 : #define FD_BANK_ABI_TXN_INIT_ERR_ACCOUNT_UNINITIALIZED (-4) 59 0 : #define FD_BANK_ABI_TXN_INIT_ERR_INVALID_LOOKUP_INDEX (-5) 60 : 61 : /* fd_bank_abi_txn_t is a struct that is ABI compatible with 62 : `RuntimeTransaction<SanitizedTransaction>` 63 : It is an extremely gross hack, the type has a relatively complicated 64 : Rust repr, so that layout is unspecified and unstable. Anza has 65 : plans to simplify this portion of their code, which would remove the 66 : need for this, but for now though, we need to do this for 67 : performance, as it saves us from various copies. 68 : 69 : The Rust `RuntimeTransaction<SanitizedTransaction>` returned here is 70 : very special, and is extremely unsafe to Rust code. In particular 71 : the internal Vec<> fields are not owned by the type, and are not 72 : pointing to memory allocated from the Rust heap, so dropping or 73 : attempting to modify them could crash or corrupt memory. The type 74 : overall should never be modified in Rust code, and just about the 75 : only thing it can be used for is it will survive being passed around 76 : as a reference. 77 : 78 : The only valid way to create such a struct is to use the 79 : fd_bank_abi_txn_init function below. Then it should be passed as a 80 : pointer to Rust, and treated only as an 81 : &RuntimeTransaction<SanitizedTransaction>. 82 : 83 : Because the fake RuntimeTransaction<SanitizedTransaction> does not 84 : own the underlying Vec objects, and they aren't actually vecs, these 85 : fields instead point to a sidecar buffer that is allocated by the 86 : caller. The lifetime of both the transaction and the sidecar must be 87 : the same. */ 88 : 89 : struct fd_bank_abi_txn_private; 90 : typedef struct fd_bank_abi_txn_private fd_bank_abi_txn_t; 91 : 92 : FD_PROTOTYPES_BEGIN 93 : 94 : /* This function resolves the address lookup tables for the provided 95 : transaction by writing them out to the out_lut_accts. The accounts 96 : are written, writable first, then readable, in the order they are 97 : referenced by the transaction. 98 : 99 : The function returns FD_BANK_ABI_TXN_INIT_SUCCESS on success and one 100 : of the FD_BANK_ABI_TXN_INIT_ERR_* error codes on failure. 101 : 102 : The address lookup table is retrieved as-of a particular slot that's 103 : provided. The slot is important in determining if the ALUT has been 104 : deactivated yet, or if it has been extended and the extension is in 105 : effect (extensions do not become active on the slot they occur in). */ 106 : 107 : int 108 : fd_bank_abi_resolve_address_lookup_tables( void const * bank, 109 : int fixed_root, 110 : ulong slot, 111 : fd_txn_t const * txn, 112 : uchar const * payload, 113 : fd_acct_addr_t * out_lut_accts ); 114 : 115 : /* This function takes a pointer to a buffer of at least size 116 : FD_BANK_ABI_TXN_FOOTPRINT where the resulting fd_bank_abi_txn_t will 117 : be constructed and returns FD_BANK_ABI_TXN_INIT_SUCCESS on success 118 : and FD_BANK_ABI_TXN_INIT_FAILURE on failure. 119 : 120 : Constructing a "legacy" or V1 transaction happens entirely in C and 121 : is extremely fast, mostly just laying out a struct. 122 : 123 : Constructing a V0 transaction is slower. In that case we need to 124 : load the addresses used by the transaction, which requires retrieving 125 : the related address lookup program accounts in the accounts database. */ 126 : 127 : int 128 : 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. */ 129 : uchar * out_sidecar, /* Memory to place sidecar data in, must be at least FD_BANK_ABI_TXN_FOOTPRINT_SIDECAR( out_txn ) bytes. */ 130 : void const * bank, /* Pointer to an Agave `Bank` object the transaction is being loaded for. */ 131 : ulong slot, /* Slot the transaction is being loaded for. */ 132 : fd_blake3_t * blake3, /* Blake3 implementation used to create `message_hash` of the transaction. */ 133 : uchar * payload, /* Transaction raw wire payload. */ 134 : ulong payload_sz, /* Transaction raw wire size. */ 135 : fd_txn_t * txn, /* The Firedancer parsed transaction representation. */ 136 : int is_simple_vote /* If the transaction is a "simple vote" or not. */ ); 137 : 138 : FD_PROTOTYPES_END 139 : 140 : #endif /* HEADER_fd_src_discoh_bank_fd_bank_abi_h */