-
Notifications
You must be signed in to change notification settings - Fork 188
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
228 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
$(call add-hdrs,fd_txn_generate.h) | ||
$(call add-objs,fd_txn_generate,fd_txn_generate) | ||
.PHONY: fd_txn_generate | ||
|
||
fd_txn_generate: $(OBJDIR)/bin/fd_txn_generate |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
#include "fd_txn_generate.h" | ||
|
||
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 | ||
) { | ||
|
||
uchar compact_sig_cnt[3]; | ||
uchar compact_sig_cnt_sz = (uchar) fd_cu16_enc( (ushort)num_signatures, compact_sig_cnt ); | ||
// Fill out txn metadata | ||
fd_txn_t * txn_meta = (fd_txn_t *) out_txn_meta; | ||
txn_meta->acct_addr_cnt = (ushort)accounts->acct_cnt; | ||
txn_meta->readonly_signed_cnt = (uchar)accounts->readonly_signed_cnt; | ||
txn_meta->readonly_unsigned_cnt = (uchar)accounts->readonly_unsigned_cnt; | ||
txn_meta->message_off = (ushort)(num_signatures * SIGNATURE_SZ + compact_sig_cnt_sz); | ||
txn_meta->signature_off = 0; | ||
txn_meta->instr_cnt = 0; | ||
|
||
uchar compact_acct_cnt[3]; | ||
uchar compact_acct_cnt_sz = (uchar) fd_cu16_enc( (ushort)txn_meta->acct_addr_cnt, compact_acct_cnt ); | ||
txn_meta->acct_addr_off = (ushort)(txn_meta->message_off + (sizeof(fd_txn_message_hdr_t)) + compact_acct_cnt_sz); | ||
txn_meta->recent_blockhash_off = (ushort)(txn_meta->acct_addr_off + (txn_meta->acct_addr_cnt * ACCOUNT_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 = (uchar)accounts->signature_cnt, | ||
.num_readonly_signatures = (uchar)accounts->readonly_signed_cnt, | ||
.num_readonly_unsigned = (uchar)accounts->readonly_unsigned_cnt }; | ||
fd_memcpy( write_ptr, &msg_header, sizeof(fd_txn_message_hdr_t)); | ||
write_ptr = out_txn_payload + txn_meta->acct_addr_off - compact_acct_cnt_sz; | ||
|
||
// Write number of accounts (compact-u16) | ||
fd_memcpy( write_ptr, compact_acct_cnt, compact_acct_cnt_sz ); | ||
write_ptr += compact_acct_cnt_sz; | ||
|
||
// Write accounts list to txn payload | ||
ulong signers_write_sz = ACCOUNT_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, ACCOUNT_SZ * accounts->readonly_signed_cnt ); | ||
write_ptr += ACCOUNT_SZ * accounts->readonly_signed_cnt; | ||
|
||
ulong non_signers_write_sz = ACCOUNT_SZ * (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, ACCOUNT_SZ * accounts->readonly_unsigned_cnt ); | ||
write_ptr += ACCOUNT_SZ * accounts->readonly_unsigned_cnt; | ||
FD_TEST( (ushort)((ulong)write_ptr - (ulong)out_txn_payload) == txn_meta->recent_blockhash_off ); | ||
|
||
// Write recent blockhash | ||
if ( opt_recent_blockhash ) { | ||
fd_memcpy( write_ptr, opt_recent_blockhash, 32 ); | ||
write_ptr += 32; | ||
} | ||
|
||
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 * accounts, | ||
ulong accounts_len, | ||
fd_build_instr_fun instr_fun, | ||
uchar * opt_build_args, | ||
ulong opt_args_len ) { | ||
|
||
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 + BLOCKHASH_SZ; | ||
txn_meta->instr_cnt++; | ||
uchar compact_instr_cnt[3]; | ||
uchar compact_instr_cnt_sz = (uchar) fd_cu16_enc( (ushort)txn_meta->instr_cnt, compact_instr_cnt ); | ||
FD_TEST( compact_instr_cnt_sz == 1 ); | ||
uchar * write_ptr = instr_start; | ||
fd_memcpy( write_ptr, compact_instr_cnt, compact_instr_cnt_sz ); | ||
write_ptr += compact_instr_cnt_sz; | ||
|
||
if ( txn_meta->instr_cnt > 1 ) { | ||
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; | ||
|
||
fd_memcpy( write_ptr, &program_id, sizeof(uchar) ); | ||
write_ptr += sizeof(uchar); | ||
|
||
uchar compact_accts_len[3]; | ||
uchar compact_accts_len_sz = (uchar) fd_cu16_enc( (ushort)accounts_len, compact_accts_len ); | ||
fd_memcpy( write_ptr, compact_accts_len, compact_accts_len_sz ); | ||
write_ptr += compact_accts_len_sz; | ||
|
||
fd_memcpy( write_ptr, accounts, accounts_len ); | ||
write_ptr += accounts_len; | ||
|
||
// Build instruction data | ||
uchar instr_buf[FD_TXN_MTU]; | ||
ushort data_sz = (*instr_fun)( instr_buf, opt_build_args, opt_args_len ); | ||
uchar compact_data_len[3]; | ||
uint compact_data_len_sz = fd_cu16_enc( data_sz, compact_data_len ); | ||
|
||
// Copy data array over | ||
fd_memcpy( write_ptr, compact_data_len, compact_data_len_sz ); | ||
write_ptr += compact_data_len_sz; | ||
ushort data_off = (ushort) (write_ptr - out_txn_payload); | ||
fd_memcpy( write_ptr, instr_buf, data_sz ); | ||
write_ptr += data_sz; | ||
ushort acct_off = (ushort) (instr_start + sizeof(uchar) + compact_accts_len_sz - out_txn_payload); | ||
|
||
(void) fd_txn_instr_meta_generate( (uchar*)&txn_meta->instr[txn_meta->instr_cnt-1], | ||
program_id, | ||
(ushort)accounts_len, | ||
data_sz, acct_off, data_off ); | ||
return (ulong)(write_ptr - out_txn_payload); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
/** | ||
* 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" | ||
|
||
#define SIGNATURE_SZ 64 | ||
#define ACCOUNT_SZ 32 | ||
#define BLOCKHASH_SZ 32 | ||
|
||
/** | ||
* 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 { | ||
ulong signature_cnt; | ||
ulong readonly_signed_cnt; | ||
ulong readonly_unsigned_cnt; | ||
ulong 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; | ||
|
||
// 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; | ||
|
||
/** | ||
* Instruction builder function signature. Accepts an output buffer and optional argument. | ||
* Returns the size of the instruction. | ||
* An example of such a function used for testing: | ||
* | ||
ushort build_vote_state_update_instr( uchar * out_buf, uchar * FD_PARAM_UNUSED opt_args, ulong FD_PARAM_UNUSED opt_args_len ) { | ||
fd_vote_instruction_t vote_instr; | ||
vote_instr.discriminant = fd_vote_instruction_enum_update_vote_state; | ||
fd_vote_state_update_t update; | ||
memset(&update, 0, sizeof(fd_vote_state_update_t)); | ||
getrandom( update.hash.key, 32UL, 0 ); | ||
ulong ts = (ulong)fd_log_wallclock(); | ||
update.timestamp = &ts; | ||
vote_instr.inner.update_vote_state = update; | ||
fd_bincode_encode_ctx_t encode = {.data = out_buf, .dataend = (out_buf + FD_TXN_MTU)}; | ||
fd_vote_instruction_encode( &vote_instr, &encode ); | ||
(void) opt_args; | ||
(void) opt_args_len; | ||
return (ushort)fd_vote_instruction_size( &vote_instr ); | ||
} | ||
**/ | ||
typedef ushort (*fd_build_instr_fun)( uchar * buf_out, uchar * opt_arg, ulong arg_sz ); | ||
|
||
FD_PROTOTYPES_BEGIN | ||
|
||
/** | ||
* Method used to create a template for a txn (useful for pre-staging and re-use) | ||
*/ | ||
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. | ||
*/ | ||
ulong fd_txn_add_instr( uchar * txn_meta_ptr, | ||
uchar out_txn_payload[ static FD_TXN_MTU ], | ||
uchar program_id, | ||
uchar * accounts, | ||
ulong accounts_len, | ||
fd_build_instr_fun instr_fun, | ||
uchar * opt_build_args, | ||
ulong opt_args_len ); | ||
FD_PROTOTYPES_END |