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->transaction_version = FD_TXN_VLEGACY; 42 0 : txn_meta->signature_cnt = (uchar)num_signatures; 43 0 : txn_meta->acct_addr_cnt = accounts->acct_cnt; 44 0 : txn_meta->readonly_signed_cnt = accounts->readonly_signed_cnt; 45 0 : txn_meta->readonly_unsigned_cnt = accounts->readonly_unsigned_cnt; 46 : /* Number of signatures is encoded as a compact u16 but 47 : can always be encoded using 1 byte here. */ 48 0 : txn_meta->message_off = (ushort)(num_signatures * FD_TXN_SIGNATURE_SZ + 1); 49 0 : txn_meta->signature_off = (ushort)1UL; 50 0 : txn_meta->instr_cnt = 0; 51 : 52 0 : FD_TEST(txn_meta->acct_addr_cnt < FD_TXN_ACCT_ADDR_MAX); 53 0 : txn_meta->acct_addr_off = (ushort)(txn_meta->message_off + (sizeof(fd_txn_message_hdr_t)) + 1); 54 0 : txn_meta->recent_blockhash_off = (ushort)(txn_meta->acct_addr_off + (txn_meta->acct_addr_cnt * FD_TXN_ACCT_ADDR_SZ)); 55 : 56 : /* Fill message header in txn payload */ 57 0 : uchar * write_ptr = out_txn_payload + txn_meta->message_off; 58 0 : fd_txn_message_hdr_t msg_header = { .num_signatures = accounts->signature_cnt, 59 0 : .num_readonly_signatures = accounts->readonly_signed_cnt, 60 0 : .num_readonly_unsigned = accounts->readonly_unsigned_cnt }; 61 0 : memcpy( write_ptr, &msg_header, sizeof(fd_txn_message_hdr_t) ) ; 62 0 : write_ptr += sizeof(fd_txn_message_hdr_t); 63 : 64 : /* Write number of accounts */ 65 0 : *write_ptr = (uchar)txn_meta->acct_addr_cnt; 66 0 : write_ptr += 1; 67 : 68 : /* Write accounts list to txn payload */ 69 0 : ulong signers_write_sz = FD_TXN_ACCT_ADDR_SZ * (ulong)(accounts->signature_cnt - accounts->readonly_signed_cnt); 70 0 : ulong signers_read_sz = FD_TXN_ACCT_ADDR_SZ * (ulong)accounts->readonly_signed_cnt; 71 0 : ulong non_signers_write_sz = FD_TXN_ACCT_ADDR_SZ * (ulong)(accounts->acct_cnt - accounts->readonly_unsigned_cnt - accounts->signature_cnt); 72 0 : ulong non_signers_read_sz = FD_TXN_ACCT_ADDR_SZ * (ulong)accounts->readonly_unsigned_cnt; 73 : 74 0 : if( signers_write_sz ) memcpy( write_ptr, accounts->signers_w, signers_write_sz ); 75 0 : write_ptr += signers_write_sz; 76 : 77 0 : if( signers_read_sz ) memcpy( write_ptr, accounts->signers_r, signers_read_sz ); 78 0 : write_ptr += signers_read_sz; 79 : 80 0 : if( non_signers_write_sz ) memcpy( write_ptr, accounts->non_signers_w, non_signers_write_sz ); 81 0 : write_ptr += non_signers_write_sz; 82 : 83 0 : if( non_signers_read_sz ) memcpy( write_ptr, accounts->non_signers_r, non_signers_read_sz ); 84 0 : write_ptr += non_signers_read_sz; 85 0 : FD_TEST( (ushort)((ulong)write_ptr - (ulong)out_txn_payload) == txn_meta->recent_blockhash_off ); 86 : 87 : /* Write recent blockhash */ 88 0 : if( FD_LIKELY( opt_recent_blockhash ) ) { 89 0 : memcpy( write_ptr, opt_recent_blockhash, FD_TXN_BLOCKHASH_SZ ); 90 0 : } else { 91 0 : memset( write_ptr, 0UL, FD_TXN_BLOCKHASH_SZ ); 92 0 : } 93 0 : write_ptr += FD_TXN_BLOCKHASH_SZ; 94 : 95 0 : return (ulong)(write_ptr - out_txn_payload); 96 0 : } 97 : 98 : ulong 99 : fd_txn_add_instr( uchar * txn_meta_ptr, 100 : uchar out_txn_payload[ static FD_TXN_MTU ], 101 : uchar program_id, 102 : uchar const * accounts, 103 : ulong accounts_sz, 104 : uchar const * instr_buf, 105 0 : ulong instr_buf_sz ) { 106 : 107 0 : fd_txn_t * txn_meta = (fd_txn_t *) txn_meta_ptr; 108 0 : FD_TEST( txn_meta->instr_cnt < FD_TXN_INSTR_MAX ); 109 0 : FD_TEST( txn_meta->recent_blockhash_off != 0 ); 110 : 111 0 : uchar * instr_start = out_txn_payload + txn_meta->recent_blockhash_off + FD_TXN_BLOCKHASH_SZ; 112 0 : txn_meta->instr_cnt++; 113 0 : uchar * write_ptr = instr_start; 114 : 115 0 : uint compact_instr_cnt_sz = fd_cu16_enc( (ushort)txn_meta->instr_cnt, write_ptr ); 116 0 : FD_TEST( compact_instr_cnt_sz == 1 ); 117 : 118 0 : write_ptr += compact_instr_cnt_sz; 119 : 120 : /* Calculate offset of next instruction. */ 121 0 : if ( FD_UNLIKELY( txn_meta->instr_cnt > 1 ) ) { 122 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; 123 0 : } 124 : 125 0 : instr_start = write_ptr; 126 : 127 0 : *write_ptr = program_id; 128 0 : write_ptr += sizeof(uchar); 129 : 130 0 : uint compact_accts_len_sz = fd_cu16_enc( (ushort)accounts_sz, write_ptr ); 131 0 : write_ptr += compact_accts_len_sz; 132 : 133 0 : ushort acct_off = (ushort) (write_ptr - out_txn_payload); 134 0 : fd_memcpy( write_ptr, accounts, accounts_sz ); 135 0 : write_ptr += accounts_sz; 136 : 137 0 : ushort data_sz = (ushort)instr_buf_sz; 138 0 : uint compact_data_len_sz = fd_cu16_enc( data_sz, write_ptr ); 139 0 : write_ptr += compact_data_len_sz; 140 : 141 : /* Copy data buffer over */ 142 0 : ushort data_off = (ushort) (write_ptr - out_txn_payload); 143 0 : fd_memcpy( write_ptr, instr_buf, data_sz ); 144 0 : write_ptr += data_sz; 145 : 146 0 : (void) fd_txn_instr_meta_generate( (uchar*)&txn_meta->instr[txn_meta->instr_cnt-1], 147 0 : program_id, 148 0 : (ushort)accounts_sz, 149 0 : data_sz, acct_off, data_off ); 150 0 : return (ulong)(write_ptr - out_txn_payload); 151 0 : }