-
Notifications
You must be signed in to change notification settings - Fork 188
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
flamenco: adds txn generation methods #1692
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
ifdef FD_HAS_INT128 | ||
$(call add-hdrs,fd_txn_generate.h) | ||
$(call add-objs,fd_txn_generate,fd_flamenco) | ||
endif |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,160 @@ | ||
#include "fd_txn_generate.h" | ||
|
||
/* Message header type */ | ||
struct __attribute__((packed)) fd_txn_message_hdr { | ||
uchar num_signatures; | ||
uchar num_readonly_signatures; | ||
uchar num_readonly_unsigned; | ||
}; | ||
|
||
typedef struct fd_txn_message_hdr fd_txn_message_hdr_t; | ||
|
||
static fd_txn_instr_t * | ||
fd_txn_instr_meta_generate( uchar * out_buf, | ||
uchar program_id, | ||
ushort acct_cnt, | ||
ushort data_sz, | ||
ushort acct_off, | ||
ushort data_off ) { | ||
fd_txn_instr_t * out_instr = (fd_txn_instr_t *) out_buf; | ||
out_instr->program_id = program_id; | ||
out_instr->acct_cnt = acct_cnt; | ||
out_instr->data_sz = data_sz; | ||
out_instr->acct_off = acct_off; | ||
out_instr->data_off = data_off; | ||
return out_instr; | ||
} | ||
|
||
ulong | ||
fd_txn_base_generate( uchar out_txn_meta[ static FD_TXN_MAX_SZ ], | ||
uchar out_txn_payload[ static FD_TXN_MTU ], | ||
ulong num_signatures, | ||
fd_txn_accounts_t * accounts, | ||
uchar * opt_recent_blockhash ) { | ||
|
||
/* Number of signatures cannot exceed 127. */ | ||
FD_TEST(num_signatures <= FD_TXN_SIG_MAX); | ||
*out_txn_payload = (uchar)num_signatures; | ||
|
||
/* Fill out txn metadata */ | ||
fd_txn_t * txn_meta = (fd_txn_t *) out_txn_meta; | ||
txn_meta->acct_addr_cnt = accounts->acct_cnt; | ||
txn_meta->readonly_signed_cnt = accounts->readonly_signed_cnt; | ||
txn_meta->readonly_unsigned_cnt = accounts->readonly_unsigned_cnt; | ||
/* Number of signatures is encoded as a compact u16 but | ||
can always be encoded using 1 byte here. */ | ||
txn_meta->message_off = (ushort)(num_signatures * FD_TXN_SIGNATURE_SZ + 1); | ||
txn_meta->signature_off = (ushort)1UL; | ||
txn_meta->instr_cnt = 0; | ||
|
||
FD_TEST(txn_meta->acct_addr_cnt < FD_TXN_ACCT_ADDR_MAX); | ||
txn_meta->acct_addr_off = (ushort)(txn_meta->message_off + (sizeof(fd_txn_message_hdr_t)) + 1); | ||
txn_meta->recent_blockhash_off = (ushort)(txn_meta->acct_addr_off + (txn_meta->acct_addr_cnt * FD_TXN_ACCT_ADDR_SZ)); | ||
|
||
/* Fill message header in txn payload */ | ||
uchar * write_ptr = out_txn_payload + txn_meta->message_off; | ||
fd_txn_message_hdr_t msg_header = { .num_signatures = accounts->signature_cnt, | ||
.num_readonly_signatures = accounts->readonly_signed_cnt, | ||
.num_readonly_unsigned = accounts->readonly_unsigned_cnt }; | ||
memcpy( write_ptr, &msg_header, sizeof(fd_txn_message_hdr_t) ) ; | ||
write_ptr += sizeof(fd_txn_message_hdr_t); | ||
|
||
/* Write number of accounts */ | ||
*write_ptr = (uchar)txn_meta->acct_addr_cnt; | ||
write_ptr += 1; | ||
|
||
/* Write accounts list to txn payload */ | ||
ulong signers_write_sz = FD_TXN_ACCT_ADDR_SZ * (accounts->signature_cnt - accounts->readonly_signed_cnt); | ||
fd_memcpy( write_ptr, accounts->signers_w, signers_write_sz ); | ||
write_ptr += signers_write_sz; | ||
|
||
fd_memcpy( write_ptr, accounts->signers_r, FD_TXN_ACCT_ADDR_SZ * accounts->readonly_signed_cnt ); | ||
write_ptr += FD_TXN_ACCT_ADDR_SZ * accounts->readonly_signed_cnt; | ||
|
||
ulong non_signers_write_sz = FD_TXN_ACCT_ADDR_SZ * (ulong)(accounts->acct_cnt - accounts->readonly_unsigned_cnt - accounts->signature_cnt); | ||
fd_memcpy( write_ptr, accounts->non_signers_w, non_signers_write_sz); | ||
write_ptr += non_signers_write_sz; | ||
|
||
fd_memcpy( write_ptr, accounts->non_signers_r, FD_TXN_ACCT_ADDR_SZ * accounts->readonly_unsigned_cnt ); | ||
write_ptr += FD_TXN_ACCT_ADDR_SZ * accounts->readonly_unsigned_cnt; | ||
FD_TEST( (ushort)((ulong)write_ptr - (ulong)out_txn_payload) == txn_meta->recent_blockhash_off ); | ||
|
||
/* Write recent blockhash */ | ||
if( FD_LIKELY( opt_recent_blockhash ) ) { | ||
memcpy( write_ptr, opt_recent_blockhash, FD_TXN_BLOCKHASH_SZ ); | ||
} else { | ||
memset( write_ptr, 0UL, FD_TXN_BLOCKHASH_SZ ); | ||
} | ||
write_ptr += FD_TXN_BLOCKHASH_SZ; | ||
|
||
return (ulong)(write_ptr - out_txn_payload); | ||
} | ||
|
||
ulong | ||
fd_txn_add_instr( uchar * txn_meta_ptr, | ||
uchar out_txn_payload[ static FD_TXN_MTU ], | ||
uchar program_id, | ||
uchar const * accounts, | ||
ulong accounts_sz, | ||
uchar const * instr_buf, | ||
ulong instr_buf_sz ) { | ||
|
||
fd_txn_t * txn_meta = (fd_txn_t *) txn_meta_ptr; | ||
FD_TEST( txn_meta->instr_cnt < FD_TXN_INSTR_MAX ); | ||
FD_TEST( txn_meta->recent_blockhash_off != 0 ); | ||
|
||
uchar * instr_start = out_txn_payload + txn_meta->recent_blockhash_off + FD_TXN_BLOCKHASH_SZ; | ||
txn_meta->instr_cnt++; | ||
uchar * write_ptr = instr_start; | ||
|
||
uint compact_instr_cnt_sz = fd_cu16_enc( (ushort)txn_meta->instr_cnt, write_ptr ); | ||
FD_TEST( compact_instr_cnt_sz == 1 ); | ||
|
||
write_ptr += compact_instr_cnt_sz; | ||
|
||
/* Calculate offset of next instruction. */ | ||
if ( FD_UNLIKELY( txn_meta->instr_cnt > 1 ) ) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am not sure why this is There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the write_ptr is already at the right offset for that case |
||
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; | ||
} | ||
|
||
instr_start = write_ptr; | ||
|
||
*write_ptr = program_id; | ||
write_ptr += sizeof(uchar); | ||
|
||
uint compact_accts_len_sz = fd_cu16_enc( (ushort)accounts_sz, write_ptr ); | ||
write_ptr += compact_accts_len_sz; | ||
|
||
ushort acct_off = (ushort) (write_ptr - out_txn_payload); | ||
fd_memcpy( write_ptr, accounts, accounts_sz ); | ||
write_ptr += accounts_sz; | ||
|
||
ushort data_sz = (ushort)instr_buf_sz; | ||
uint compact_data_len_sz = fd_cu16_enc( data_sz, write_ptr ); | ||
write_ptr += compact_data_len_sz; | ||
|
||
/* Copy data buffer over */ | ||
ushort data_off = (ushort) (write_ptr - out_txn_payload); | ||
fd_memcpy( write_ptr, instr_buf, data_sz ); | ||
write_ptr += data_sz; | ||
|
||
(void) fd_txn_instr_meta_generate( (uchar*)&txn_meta->instr[txn_meta->instr_cnt-1], | ||
program_id, | ||
(ushort)accounts_sz, | ||
data_sz, acct_off, data_off ); | ||
return (ulong)(instr_start - out_txn_payload); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It seems that you are returning the old txn size instead of the new txn size. Is this deliberate? It seems more natural to return the new txn size. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this returns the size of the just added instr |
||
} | ||
|
||
void | ||
fd_txn_reset_instrs( uchar * txn_meta_ptr, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe call it There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. remove is used for removing a single element across firedancer so i steered clear of that for this |
||
uchar out_txn_payload[ static FD_TXN_MTU ] ) { | ||
fd_txn_t * txn_meta = (fd_txn_t *)txn_meta_ptr; | ||
if( FD_UNLIKELY( txn_meta->instr_cnt == 0 ) ) { | ||
return; | ||
} | ||
|
||
ulong instr_start = txn_meta->recent_blockhash_off + FD_TXN_BLOCKHASH_SZ; | ||
|
||
*(out_txn_payload + instr_start) = 0; | ||
txn_meta->instr_cnt = 0; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
/* Provides utility methods to create txn templates for | ||
pre-staging, as well as a mechanism to build out an | ||
entire transaction with instructions. */ | ||
|
||
#include "../../ballet/txn/fd_txn.h" | ||
#include "../../ballet/txn/fd_compact_u16.h" | ||
#include "../../flamenco/types/fd_types_custom.h" | ||
#include "../../flamenco/types/fd_types.h" | ||
|
||
/* Struct used to define a list of accounts supplied in a txn. | ||
Also provides information on number of signers/writeable accounts. */ | ||
struct fd_txn_accounts { | ||
/* signature cnt <= 128 */ | ||
uchar signature_cnt; | ||
/* readonly signed/unsigned <= 128 */ | ||
uchar readonly_signed_cnt; | ||
uchar readonly_unsigned_cnt; | ||
ushort acct_cnt; | ||
fd_pubkey_t * signers_w; | ||
fd_pubkey_t * signers_r; | ||
fd_pubkey_t * non_signers_w; | ||
fd_pubkey_t * non_signers_r; | ||
}; | ||
|
||
typedef struct fd_txn_accounts fd_txn_accounts_t; | ||
|
||
FD_PROTOTYPES_BEGIN | ||
|
||
/* Method used to create a template for a txn (useful for pre-staging and re-use) | ||
Num signatures is restricted to < 128. Returns the offset to the start of the | ||
insructions. */ | ||
ulong | ||
fd_txn_base_generate( uchar out_txn_meta[ static FD_TXN_MAX_SZ ], | ||
uchar out_txn_payload[ static FD_TXN_MTU ], | ||
ulong num_signatures, | ||
fd_txn_accounts_t * accounts, | ||
uchar * opt_recent_blockhash ); | ||
|
||
/* Method used for adding an instruction to a txn being generated. | ||
The accounts param is a list of indices to the accounts in the txn. | ||
The instruction buffer contains the data for the instruction to | ||
be added. Returns the offset to the start of the instruction added | ||
in the transaction buffer. */ | ||
ulong | ||
arjain4 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
fd_txn_add_instr( uchar * txn_meta_ptr, | ||
uchar out_txn_payload[ static FD_TXN_MTU ], | ||
uchar program_id, | ||
uchar const * accounts, | ||
ulong accounts_sz, | ||
uchar const * instr_buf, | ||
ulong instr_buf_sz ); | ||
|
||
/* Helper method to reset the list of instrs in the metadata and | ||
remove all instrs from the txn payload. */ | ||
void | ||
fd_txn_reset_instrs( uchar * txn_meta_ptr, | ||
uchar out_txn_payload[ static FD_TXN_MTU ] ); | ||
FD_PROTOTYPES_END |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If num_signatures is higher than 20, then this offset is already going beyond
FD_TXN_MTU
(20*64=1280>1232). It seems useful to guarantee that this function would never write beyondFD_TXN_MTU
bytes fromout_txn_payload
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have it setup such that the caller can specify a larger buffer. That can be changed in a follow up PR if you'd like to take a look at that