Line data Source code
1 : #include "fd_txn_generate.h" 2 : 3 : /* Message header type */ 4 : struct __attribute__((packed)) fd_txn_message_hdr { 5 : uchar num_signatures; 6 : uchar num_readonly_signatures; 7 : uchar num_readonly_unsigned; 8 : }; 9 : 10 : typedef struct fd_txn_message_hdr fd_txn_message_hdr_t; 11 : 12 : static fd_txn_instr_t * 13 : fd_txn_instr_meta_generate( uchar * out_buf, 14 : uchar program_id, 15 : ushort acct_cnt, 16 : ushort data_sz, 17 : ushort acct_off, 18 0 : ushort data_off ) { 19 0 : fd_txn_instr_t * out_instr = (fd_txn_instr_t *) out_buf; 20 0 : out_instr->program_id = program_id; 21 0 : out_instr->acct_cnt = acct_cnt; 22 0 : out_instr->data_sz = data_sz; 23 0 : out_instr->acct_off = acct_off; 24 0 : out_instr->data_off = data_off; 25 0 : return out_instr; 26 0 : } 27 : 28 : ulong 29 : fd_txn_base_generate( uchar out_txn_meta[ static FD_TXN_MAX_SZ ], 30 : uchar out_txn_payload[ static FD_TXN_MTU ], 31 : ulong num_signatures, 32 : fd_txn_accounts_t * accounts, 33 0 : uchar const * opt_recent_blockhash ) { 34 : 35 : /* Number of signatures cannot exceed 127. */ 36 0 : FD_TEST(num_signatures <= FD_TXN_SIG_MAX); 37 0 : *out_txn_payload = (uchar)num_signatures; 38 : 39 : /* Fill out txn metadata */ 40 0 : fd_txn_t * txn_meta = (fd_txn_t *) out_txn_meta; 41 0 : txn_meta->acct_addr_cnt = accounts->acct_cnt; 42 0 : txn_meta->readonly_signed_cnt = accounts->readonly_signed_cnt; 43 0 : txn_meta->readonly_unsigned_cnt = accounts->readonly_unsigned_cnt; 44 : /* Number of signatures is encoded as a compact u16 but 45 : can always be encoded using 1 byte here. */ 46 0 : txn_meta->message_off = (ushort)(num_signatures * FD_TXN_SIGNATURE_SZ + 1); 47 0 : txn_meta->signature_off = (ushort)1UL; 48 0 : txn_meta->instr_cnt = 0; 49 : 50 0 : FD_TEST(txn_meta->acct_addr_cnt < FD_TXN_ACCT_ADDR_MAX); 51 0 : txn_meta->acct_addr_off = (ushort)(txn_meta->message_off + (sizeof(fd_txn_message_hdr_t)) + 1); 52 0 : txn_meta->recent_blockhash_off = (ushort)(txn_meta->acct_addr_off + (txn_meta->acct_addr_cnt * FD_TXN_ACCT_ADDR_SZ)); 53 : 54 : /* Fill message header in txn payload */ 55 0 : uchar * write_ptr = out_txn_payload + txn_meta->message_off; 56 0 : fd_txn_message_hdr_t msg_header = { .num_signatures = accounts->signature_cnt, 57 0 : .num_readonly_signatures = accounts->readonly_signed_cnt, 58 0 : .num_readonly_unsigned = accounts->readonly_unsigned_cnt }; 59 0 : memcpy( write_ptr, &msg_header, sizeof(fd_txn_message_hdr_t) ) ; 60 0 : write_ptr += sizeof(fd_txn_message_hdr_t); 61 : 62 : /* Write number of accounts */ 63 0 : *write_ptr = (uchar)txn_meta->acct_addr_cnt; 64 0 : write_ptr += 1; 65 : 66 : /* Write accounts list to txn payload */ 67 0 : ulong signers_write_sz = FD_TXN_ACCT_ADDR_SZ * (ulong)(accounts->signature_cnt - accounts->readonly_signed_cnt); 68 0 : fd_memcpy( write_ptr, accounts->signers_w, signers_write_sz ); 69 0 : write_ptr += signers_write_sz; 70 : 71 0 : fd_memcpy( write_ptr, accounts->signers_r, FD_TXN_ACCT_ADDR_SZ * accounts->readonly_signed_cnt ); 72 0 : write_ptr += FD_TXN_ACCT_ADDR_SZ * accounts->readonly_signed_cnt; 73 : 74 0 : ulong non_signers_write_sz = FD_TXN_ACCT_ADDR_SZ * (ulong)(accounts->acct_cnt - accounts->readonly_unsigned_cnt - accounts->signature_cnt); 75 0 : fd_memcpy( write_ptr, accounts->non_signers_w, non_signers_write_sz); 76 0 : write_ptr += non_signers_write_sz; 77 : 78 0 : fd_memcpy( write_ptr, accounts->non_signers_r, FD_TXN_ACCT_ADDR_SZ * accounts->readonly_unsigned_cnt ); 79 0 : write_ptr += FD_TXN_ACCT_ADDR_SZ * accounts->readonly_unsigned_cnt; 80 0 : FD_TEST( (ushort)((ulong)write_ptr - (ulong)out_txn_payload) == txn_meta->recent_blockhash_off ); 81 : 82 : /* Write recent blockhash */ 83 0 : if( FD_LIKELY( opt_recent_blockhash ) ) { 84 0 : memcpy( write_ptr, opt_recent_blockhash, FD_TXN_BLOCKHASH_SZ ); 85 0 : } else { 86 0 : memset( write_ptr, 0UL, FD_TXN_BLOCKHASH_SZ ); 87 0 : } 88 0 : write_ptr += FD_TXN_BLOCKHASH_SZ; 89 : 90 0 : return (ulong)(write_ptr - out_txn_payload); 91 0 : } 92 : 93 : ulong 94 : fd_txn_add_instr( uchar * txn_meta_ptr, 95 : uchar out_txn_payload[ static FD_TXN_MTU ], 96 : uchar program_id, 97 : uchar const * accounts, 98 : ulong accounts_sz, 99 : uchar const * instr_buf, 100 0 : ulong instr_buf_sz ) { 101 : 102 0 : fd_txn_t * txn_meta = (fd_txn_t *) txn_meta_ptr; 103 0 : FD_TEST( txn_meta->instr_cnt < FD_TXN_INSTR_MAX ); 104 0 : FD_TEST( txn_meta->recent_blockhash_off != 0 ); 105 : 106 0 : uchar * instr_start = out_txn_payload + txn_meta->recent_blockhash_off + FD_TXN_BLOCKHASH_SZ; 107 0 : txn_meta->instr_cnt++; 108 0 : uchar * write_ptr = instr_start; 109 : 110 0 : uint compact_instr_cnt_sz = fd_cu16_enc( (ushort)txn_meta->instr_cnt, write_ptr ); 111 0 : FD_TEST( compact_instr_cnt_sz == 1 ); 112 : 113 0 : write_ptr += compact_instr_cnt_sz; 114 : 115 : /* Calculate offset of next instruction. */ 116 0 : if ( FD_UNLIKELY( txn_meta->instr_cnt > 1 ) ) { 117 0 : write_ptr = out_txn_payload + txn_meta->instr[txn_meta->instr_cnt-2].data_off + txn_meta->instr[txn_meta->instr_cnt-2].data_sz; 118 0 : } 119 : 120 0 : instr_start = write_ptr; 121 : 122 0 : *write_ptr = program_id; 123 0 : write_ptr += sizeof(uchar); 124 : 125 0 : uint compact_accts_len_sz = fd_cu16_enc( (ushort)accounts_sz, write_ptr ); 126 0 : write_ptr += compact_accts_len_sz; 127 : 128 0 : ushort acct_off = (ushort) (write_ptr - out_txn_payload); 129 0 : fd_memcpy( write_ptr, accounts, accounts_sz ); 130 0 : write_ptr += accounts_sz; 131 : 132 0 : ushort data_sz = (ushort)instr_buf_sz; 133 0 : uint compact_data_len_sz = fd_cu16_enc( data_sz, write_ptr ); 134 0 : write_ptr += compact_data_len_sz; 135 : 136 : /* Copy data buffer over */ 137 0 : ushort data_off = (ushort) (write_ptr - out_txn_payload); 138 0 : fd_memcpy( write_ptr, instr_buf, data_sz ); 139 0 : write_ptr += data_sz; 140 : 141 0 : (void) fd_txn_instr_meta_generate( (uchar*)&txn_meta->instr[txn_meta->instr_cnt-1], 142 0 : program_id, 143 0 : (ushort)accounts_sz, 144 0 : data_sz, acct_off, data_off ); 145 0 : return (ulong)(write_ptr - out_txn_payload); 146 0 : } 147 : 148 : void 149 : fd_txn_reset_instrs( uchar * txn_meta_ptr, 150 0 : uchar out_txn_payload[ static FD_TXN_MTU ] ) { 151 0 : fd_txn_t * txn_meta = (fd_txn_t *)txn_meta_ptr; 152 0 : if( FD_UNLIKELY( txn_meta->instr_cnt == 0 ) ) { 153 0 : return; 154 0 : } 155 : 156 0 : ulong instr_start = txn_meta->recent_blockhash_off + FD_TXN_BLOCKHASH_SZ; 157 : 158 0 : *(out_txn_payload + instr_start) = 0; 159 0 : txn_meta->instr_cnt = 0; 160 0 : }