Line data Source code
1 : #ifndef HEADER_fd_src_ballet_txn_fd_txn_build_h 2 : #define HEADER_fd_src_ballet_txn_fd_txn_build_h 3 : 4 : /* fd_txn_build.h is an API to procedurally build Solana transactions 5 : from instructions (program invocations). */ 6 : 7 : #include "fd_txn.h" 8 : #include "../../disco/fd_txn_p.h" 9 : #include "../../flamenco/accdb/fd_accdb.h" 10 : 11 : /* The fd_txn_builder_t class provides methods for assembling a txn. 12 : fd_txn_builder_t is a static size struct, so a local declaration is a 13 : valid way to reserve memory for a txn_builder object: 14 : 15 : fd_txn_builder_t builder[1]; 16 : fd_txn_builder_new( builder ); 17 : ... */ 18 : 19 : struct fd_txn_b_acct { 20 : fd_acct_addr_t key; 21 : 22 : uchar cat; 23 : uchar map_next; 24 : 25 : uchar alut_i; /* idx of ALUT account */ 26 : uint alut_j; /* idx within ALUT account */ 27 : }; 28 : typedef struct fd_txn_b_acct fd_txn_b_acct_t; 29 : 30 : struct fd_txn_b_instr { 31 : uchar program_id; 32 : uchar instr_acct0; 33 : uchar instr_acct_cnt; 34 : ushort data_off; 35 : ushort data_sz; 36 : }; 37 : typedef struct fd_txn_b_instr fd_txn_b_instr_t; 38 : 39 : /* Declare a separately-chained hashmap of instruction accounts */ 40 : 41 : #define MAP_NAME fd_txn_b_addr_map 42 : #define MAP_ELE_T fd_txn_b_acct_t 43 0 : #define MAP_IDX_T uchar 44 : #define MAP_KEY_T fd_acct_addr_t 45 0 : #define MAP_KEY_EQ(a,b) 0==memcmp( a, b, sizeof(fd_acct_addr_t) ) 46 0 : #define MAP_KEY_HASH(k,s) fd_accdb_hash( (k)->b, (s) ) 47 0 : #define MAP_NEXT map_next 48 : #include "../../util/tmpl/fd_map_chain.c" 49 : #define FD_TXN_B_ADDR_CHAIN_CNT (2*FD_TXN_ACCT_ADDR_MAX) 50 : #define FD_TXN_B_ADDR_MAP_SZ (sizeof(fd_txn_b_addr_map_t) + FD_TXN_B_ADDR_CHAIN_CNT) 51 : 52 : struct fd_txn_builder { 53 : 54 : /* Misc fields */ 55 : fd_acct_addr_t recent_blockhash; 56 : uchar fee_payer_acct; 57 : 58 : /* Flags */ 59 : uchar fee_payer_set : 1; 60 : uchar alut_set : 1; 61 : 62 : /* ALUT */ 63 : uchar alut_i; /* current ALUT account, UCHAR_MAX if none open */ 64 : 65 : /* Instructions */ 66 : fd_txn_b_instr_t instr[ FD_TXN_INSTR_MAX ]; 67 : uchar instr_cnt; 68 : 69 : /* Transaction Accounts */ 70 : fd_txn_b_acct_t acct [ FD_TXN_ACCT_ADDR_MAX ]; 71 : uchar acct_map[ FD_TXN_ACCT_ADDR_MAX ]; 72 : uchar acct_rev[ FD_TXN_ACCT_ADDR_MAX ]; 73 : uchar acct_cnt; 74 : 75 : /* Instruction Account Pool */ 76 : uchar instr_acct[ FD_TXN_ACCT_ADDR_MAX ]; 77 : uchar instr_acct_cnt; 78 : 79 : /* Address Hash Map */ 80 : union { 81 : fd_txn_b_addr_map_t map; 82 : uchar map_mem[ FD_TXN_B_ADDR_MAP_SZ ]; 83 : }; 84 : 85 : /* Bump allocator for instruction datas */ 86 : #define FD_TXN_B_DATA_BUMP_MAX FD_TXN_MTU 87 : uchar data_bump[ FD_TXN_B_DATA_BUMP_MAX ]; 88 : ushort data_bump_sz; 89 : 90 : }; 91 : typedef struct fd_txn_builder fd_txn_builder_t; 92 : 93 : FD_PROTOTYPES_BEGIN 94 : 95 : /* Constructors *******************************************************/ 96 : 97 : fd_txn_builder_t * 98 : fd_txn_builder_new( fd_txn_builder_t * mem, 99 : ulong seed ); 100 : 101 : void * 102 : fd_txn_builder_delete( fd_txn_builder_t * builder ); 103 : 104 : FD_FN_UNUSED static fd_txn_builder_t * 105 0 : fd_txn_builder_reset( fd_txn_builder_t * builder ) { 106 0 : ulong const seed = builder->map.seed; 107 0 : fd_txn_builder_delete( builder ); 108 0 : return fd_txn_builder_new( builder, seed ); 109 0 : } 110 : 111 : /* Miscellaneous fields ***********************************************/ 112 : 113 : /* fd_txn_builder_fee_payer_set sets the transaction's fee payer. */ 114 : 115 : fd_txn_builder_t * 116 : fd_txn_builder_fee_payer_set( fd_txn_builder_t * builder, 117 : void const * fee_payer ); 118 : 119 : /* fd_txn_builder_blockhash_set sets the transaction's "recent block 120 : hash" field. */ 121 : 122 : static inline void 123 : fd_txn_builder_blockhash_set( fd_txn_builder_t * builder, 124 0 : void const * blockhash ) { 125 0 : memcpy( &builder->recent_blockhash, blockhash, sizeof(fd_acct_addr_t) ); 126 0 : } 127 : 128 : /* fd_txn_builder_nonce_set sets the transaction's nonce account (by 129 : making the first instruction a "system program advance nonce" 130 : instruction). This is only useful in combination with 131 : fd_txn_builder_blockhash_set( builder, nonce_hash ). Must be called 132 : before fd_txn_builder_instr_open. May not be called multiple times. */ 133 : 134 : fd_txn_builder_t * 135 : fd_txn_builder_nonce_set( fd_txn_builder_t * builder, 136 : void const * nonce_account, 137 : void const * nonce_authority ); 138 : 139 : /* Transaction Instructions *******************************************/ 140 : 141 : /* fd_txn_builder_instr_open starts building an instruction. Returns 142 : builder on success, NULL on failure. */ 143 : 144 : fd_txn_builder_t * 145 : fd_txn_builder_instr_open( fd_txn_builder_t * builder, 146 : void const * program_id, 147 : void const * data, 148 : ulong data_sz ); 149 : 150 : /* fd_txn_builder_instr_account_push appends an instruction account to 151 : the instruction being built. acct_cat is a bitwise-OR of any of 152 : FD_TXN_ACCT_CAT_{WRITABLE,SIGNER}. acct_cat==0 is fine and implies 153 : a readonly account access. */ 154 : 155 : fd_txn_builder_t * 156 : fd_txn_builder_instr_account_push( 157 : fd_txn_builder_t * builder, 158 : void const * acct_addr, 159 : uint acct_cat 160 : ); 161 : 162 : /* fd_txn_builder_instr_close finishes building an instruction. */ 163 : 164 : void 165 : fd_txn_builder_instr_close( fd_txn_builder_t * builder ); 166 : 167 : /* FIXME add compute budget / priority fee instructions */ 168 : 169 : /* Address Lookup Tables **********************************************/ 170 : 171 : /* fd_txn_builder_alut_open adds an address lookup table (ALUT) to the 172 : txn builder, which acts like a dictionary for account addresses. 173 : This helps reduce serialized transaction size. alut_addr is the 174 : account address of the ALUT. 175 : 176 : ALUTs should only be registered with the builder once the caller is 177 : done adding instructions. */ 178 : 179 : fd_txn_builder_t * 180 : fd_txn_builder_alut_open( fd_txn_builder_t * builder, 181 : void const * alut_addr ); 182 : 183 : /* fd_txn_builder_alut_address_push registers an ALUT address entry with 184 : the transaction builder. acct_addr is the address referenced by the 185 : ALUT, acct_idx is the index of that address within the ALUT. If the 186 : acct_addr is used by any instruction, it is replaced with an ALUT 187 : reference, if possible. acct_addr that are not used or cannot be 188 : referenced using ALUT (e.g. because it is also in use as a program 189 : ID) are silently ignored. Safe to call multiple times for the same 190 : acct_addr/acct_idx (ignores subsequent calls), and accepts acct_idx 191 : in arbitrary order. */ 192 : 193 : void 194 : fd_txn_builder_alut_address_push( 195 : fd_txn_builder_t * builder, 196 : void const * acct_addr, 197 : uint acct_idx 198 : ); 199 : 200 : /* fd_txn_builder_alut_close finishes adding an ALUT. */ 201 : 202 : void 203 : fd_txn_builder_alut_close( fd_txn_builder_t * builder ); 204 : 205 : /* Build Finish *******************************************************/ 206 : 207 : /* fd_txn_build_raw produces a serialized transaction object. 208 : Serializes the transaction to out and returns the byte size on 209 : success. On failure returns 0 silently. */ 210 : 211 : uint 212 : fd_txn_build_raw( fd_txn_builder_t * builder, 213 : uchar out[ FD_TXN_MTU ] ); 214 : 215 : /* fd_txn_build builds a transaction separately into a raw buffer and a 216 : fd_txn_t. Serializes the transaction to out, populates out_txn, 217 : and returns the serialized byte size on success. If opt_out_txn_t_sz 218 : !=NULL, sets *opt_out_txn_t_sz to the size of the out_txn object. 219 : The footprint of out_txn must be at least FD_TXN_MAX_SZ. On failure 220 : returns 0 silently. */ 221 : 222 : uint 223 : fd_txn_build( fd_txn_builder_t * builder, 224 : uchar out[ FD_TXN_MTU ], 225 : fd_txn_t * restrict out_txn, 226 : ushort * opt_out_txn_t_sz ); 227 : 228 : /* fd_txn_build_p builds a transaction into a txn_p_t. */ 229 : 230 : FD_FN_UNUSED static uint 231 : fd_txn_build_p( fd_txn_builder_t * builder, 232 0 : fd_txn_p_t * out ) { 233 0 : uint payload_sz = fd_txn_build( builder, out->payload, TXN( out ), NULL ); 234 0 : out->payload_sz = (ushort)payload_sz; 235 0 : return payload_sz; 236 0 : } 237 : 238 : FD_PROTOTYPES_END 239 : 240 : /* FD_TXN_ACCT_CAT_PIN prevents an ALUT demote. For internal use only. 241 : Must not overlap with the flags in fd_txn.h */ 242 0 : #define FD_TXN_ACCT_CAT_PIN 0x40 243 0 : #define FD_TXN_ACCT_CAT_FEE_PAYER 0x80 244 : #define FD_TXN_ACCT_CAT_IS_PIN (FD_TXN_ACCT_CAT_PIN|FD_TXN_ACCT_CAT_SIGNER|FD_TXN_ACCT_CAT_FEE_PAYER) 245 : 246 : #endif /* HEADER_fd_src_ballet_txn_fd_txn_build_h */