1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-11-26 09:28:13 +00:00

implement TXEXTRADATA transaction RequestType

This commit is contained in:
Pavol Rusnak 2016-10-19 09:37:46 +02:00
parent 68a1bcc908
commit c288a0e328
No known key found for this signature in database
GPG Key ID: 91F3B339B9A02A3D
7 changed files with 115 additions and 18 deletions

View File

@ -21,6 +21,7 @@ TxOutputBinType.script_pubkey max_size:520
TransactionType.inputs max_count:1 TransactionType.inputs max_count:1
TransactionType.bin_outputs max_count:1 TransactionType.bin_outputs max_count:1
TransactionType.outputs max_count:1 TransactionType.outputs max_count:1
TransactionType.extra_data max_size:1024
TxRequestDetailsType.tx_hash max_size:32 TxRequestDetailsType.tx_hash max_size:32

View File

@ -75,7 +75,7 @@ const pb_field_t TxOutputBinType_fields[3] = {
PB_LAST_FIELD PB_LAST_FIELD
}; };
const pb_field_t TransactionType_fields[8] = { const pb_field_t TransactionType_fields[10] = {
PB_FIELD2( 1, UINT32 , OPTIONAL, STATIC , FIRST, TransactionType, version, version, 0), PB_FIELD2( 1, UINT32 , OPTIONAL, STATIC , FIRST, TransactionType, version, version, 0),
PB_FIELD2( 2, MESSAGE , REPEATED, STATIC , OTHER, TransactionType, inputs, version, &TxInputType_fields), PB_FIELD2( 2, MESSAGE , REPEATED, STATIC , OTHER, TransactionType, inputs, version, &TxInputType_fields),
PB_FIELD2( 3, MESSAGE , REPEATED, STATIC , OTHER, TransactionType, bin_outputs, inputs, &TxOutputBinType_fields), PB_FIELD2( 3, MESSAGE , REPEATED, STATIC , OTHER, TransactionType, bin_outputs, inputs, &TxOutputBinType_fields),
@ -83,12 +83,16 @@ const pb_field_t TransactionType_fields[8] = {
PB_FIELD2( 5, MESSAGE , REPEATED, STATIC , OTHER, TransactionType, outputs, lock_time, &TxOutputType_fields), PB_FIELD2( 5, MESSAGE , REPEATED, STATIC , OTHER, TransactionType, outputs, lock_time, &TxOutputType_fields),
PB_FIELD2( 6, UINT32 , OPTIONAL, STATIC , OTHER, TransactionType, inputs_cnt, outputs, 0), PB_FIELD2( 6, UINT32 , OPTIONAL, STATIC , OTHER, TransactionType, inputs_cnt, outputs, 0),
PB_FIELD2( 7, UINT32 , OPTIONAL, STATIC , OTHER, TransactionType, outputs_cnt, inputs_cnt, 0), PB_FIELD2( 7, UINT32 , OPTIONAL, STATIC , OTHER, TransactionType, outputs_cnt, inputs_cnt, 0),
PB_FIELD2( 8, BYTES , OPTIONAL, STATIC , OTHER, TransactionType, extra_data, outputs_cnt, 0),
PB_FIELD2( 9, UINT32 , OPTIONAL, STATIC , OTHER, TransactionType, extra_data_len, extra_data, 0),
PB_LAST_FIELD PB_LAST_FIELD
}; };
const pb_field_t TxRequestDetailsType_fields[3] = { const pb_field_t TxRequestDetailsType_fields[5] = {
PB_FIELD2( 1, UINT32 , OPTIONAL, STATIC , FIRST, TxRequestDetailsType, request_index, request_index, 0), PB_FIELD2( 1, UINT32 , OPTIONAL, STATIC , FIRST, TxRequestDetailsType, request_index, request_index, 0),
PB_FIELD2( 2, BYTES , OPTIONAL, STATIC , OTHER, TxRequestDetailsType, tx_hash, request_index, 0), PB_FIELD2( 2, BYTES , OPTIONAL, STATIC , OTHER, TxRequestDetailsType, tx_hash, request_index, 0),
PB_FIELD2( 3, UINT32 , OPTIONAL, STATIC , OTHER, TxRequestDetailsType, extra_data_len, tx_hash, 0),
PB_FIELD2( 4, UINT32 , OPTIONAL, STATIC , OTHER, TxRequestDetailsType, extra_data_offset, extra_data_len, 0),
PB_LAST_FIELD PB_LAST_FIELD
}; };

View File

@ -45,7 +45,8 @@ typedef enum _RequestType {
RequestType_TXINPUT = 0, RequestType_TXINPUT = 0,
RequestType_TXOUTPUT = 1, RequestType_TXOUTPUT = 1,
RequestType_TXMETA = 2, RequestType_TXMETA = 2,
RequestType_TXFINISHED = 3 RequestType_TXFINISHED = 3,
RequestType_TXEXTRADATA = 4
} RequestType; } RequestType;
typedef enum _ButtonRequestType { typedef enum _ButtonRequestType {
@ -149,6 +150,10 @@ typedef struct _TxRequestDetailsType {
uint32_t request_index; uint32_t request_index;
bool has_tx_hash; bool has_tx_hash;
TxRequestDetailsType_tx_hash_t tx_hash; TxRequestDetailsType_tx_hash_t tx_hash;
bool has_extra_data_len;
uint32_t extra_data_len;
bool has_extra_data_offset;
uint32_t extra_data_offset;
} TxRequestDetailsType; } TxRequestDetailsType;
typedef struct { typedef struct {
@ -235,6 +240,11 @@ typedef struct _TxOutputType {
TxOutputType_op_return_data_t op_return_data; TxOutputType_op_return_data_t op_return_data;
} TxOutputType; } TxOutputType;
typedef struct {
size_t size;
uint8_t bytes[1024];
} TransactionType_extra_data_t;
typedef struct _TransactionType { typedef struct _TransactionType {
bool has_version; bool has_version;
uint32_t version; uint32_t version;
@ -250,6 +260,10 @@ typedef struct _TransactionType {
uint32_t inputs_cnt; uint32_t inputs_cnt;
bool has_outputs_cnt; bool has_outputs_cnt;
uint32_t outputs_cnt; uint32_t outputs_cnt;
bool has_extra_data;
TransactionType_extra_data_t extra_data;
bool has_extra_data_len;
uint32_t extra_data_len;
} TransactionType; } TransactionType;
/* Extensions */ /* Extensions */
@ -275,8 +289,8 @@ extern const uint32_t IdentityType_index_default;
#define TxInputType_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, {0, {0}}, 0, false, {0, {0}}, false, 4294967295u, false, InputScriptType_SPENDADDRESS, false, MultisigRedeemScriptType_init_default, false, 0} #define TxInputType_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}, {0, {0}}, 0, false, {0, {0}}, false, 4294967295u, false, InputScriptType_SPENDADDRESS, false, MultisigRedeemScriptType_init_default, false, 0}
#define TxOutputType_init_default {false, "", 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, (OutputScriptType)0, false, MultisigRedeemScriptType_init_default, false, {0, {0}}} #define TxOutputType_init_default {false, "", 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, (OutputScriptType)0, false, MultisigRedeemScriptType_init_default, false, {0, {0}}}
#define TxOutputBinType_init_default {0, {0, {0}}} #define TxOutputBinType_init_default {0, {0, {0}}}
#define TransactionType_init_default {false, 0, 0, {TxInputType_init_default}, 0, {TxOutputBinType_init_default}, false, 0, 0, {TxOutputType_init_default}, false, 0, false, 0} #define TransactionType_init_default {false, 0, 0, {TxInputType_init_default}, 0, {TxOutputBinType_init_default}, false, 0, 0, {TxOutputType_init_default}, false, 0, false, 0, false, {0, {0}}, false, 0}
#define TxRequestDetailsType_init_default {false, 0, false, {0, {0}}} #define TxRequestDetailsType_init_default {false, 0, false, {0, {0}}, false, 0, false, 0}
#define TxRequestSerializedType_init_default {false, 0, false, {0, {0}}, false, {0, {0}}} #define TxRequestSerializedType_init_default {false, 0, false, {0, {0}}, false, {0, {0}}}
#define IdentityType_init_default {false, "", false, "", false, "", false, "", false, "", false, 0u} #define IdentityType_init_default {false, "", false, "", false, "", false, "", false, "", false, 0u}
#define HDNodeType_init_zero {0, 0, 0, {0, {0}}, false, {0, {0}}, false, {0, {0}}} #define HDNodeType_init_zero {0, 0, 0, {0, {0}}, false, {0, {0}}, false, {0, {0}}}
@ -286,8 +300,8 @@ extern const uint32_t IdentityType_index_default;
#define TxInputType_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, {0, {0}}, 0, false, {0, {0}}, false, 0, false, (InputScriptType)0, false, MultisigRedeemScriptType_init_zero, false, 0} #define TxInputType_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}, {0, {0}}, 0, false, {0, {0}}, false, 0, false, (InputScriptType)0, false, MultisigRedeemScriptType_init_zero, false, 0}
#define TxOutputType_init_zero {false, "", 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, (OutputScriptType)0, false, MultisigRedeemScriptType_init_zero, false, {0, {0}}} #define TxOutputType_init_zero {false, "", 0, {0, 0, 0, 0, 0, 0, 0, 0}, 0, (OutputScriptType)0, false, MultisigRedeemScriptType_init_zero, false, {0, {0}}}
#define TxOutputBinType_init_zero {0, {0, {0}}} #define TxOutputBinType_init_zero {0, {0, {0}}}
#define TransactionType_init_zero {false, 0, 0, {TxInputType_init_zero}, 0, {TxOutputBinType_init_zero}, false, 0, 0, {TxOutputType_init_zero}, false, 0, false, 0} #define TransactionType_init_zero {false, 0, 0, {TxInputType_init_zero}, 0, {TxOutputBinType_init_zero}, false, 0, 0, {TxOutputType_init_zero}, false, 0, false, 0, false, {0, {0}}, false, 0}
#define TxRequestDetailsType_init_zero {false, 0, false, {0, {0}}} #define TxRequestDetailsType_init_zero {false, 0, false, {0, {0}}, false, 0, false, 0}
#define TxRequestSerializedType_init_zero {false, 0, false, {0, {0}}, false, {0, {0}}} #define TxRequestSerializedType_init_zero {false, 0, false, {0, {0}}, false, {0, {0}}}
#define IdentityType_init_zero {false, "", false, "", false, "", false, "", false, "", false, 0} #define IdentityType_init_zero {false, "", false, "", false, "", false, "", false, "", false, 0}
@ -316,6 +330,8 @@ extern const uint32_t IdentityType_index_default;
#define TxOutputBinType_script_pubkey_tag 2 #define TxOutputBinType_script_pubkey_tag 2
#define TxRequestDetailsType_request_index_tag 1 #define TxRequestDetailsType_request_index_tag 1
#define TxRequestDetailsType_tx_hash_tag 2 #define TxRequestDetailsType_tx_hash_tag 2
#define TxRequestDetailsType_extra_data_len_tag 3
#define TxRequestDetailsType_extra_data_offset_tag 4
#define TxRequestSerializedType_signature_index_tag 1 #define TxRequestSerializedType_signature_index_tag 1
#define TxRequestSerializedType_signature_tag 2 #define TxRequestSerializedType_signature_tag 2
#define TxRequestSerializedType_serialized_tx_tag 3 #define TxRequestSerializedType_serialized_tx_tag 3
@ -345,6 +361,8 @@ extern const uint32_t IdentityType_index_default;
#define TransactionType_lock_time_tag 4 #define TransactionType_lock_time_tag 4
#define TransactionType_inputs_cnt_tag 6 #define TransactionType_inputs_cnt_tag 6
#define TransactionType_outputs_cnt_tag 7 #define TransactionType_outputs_cnt_tag 7
#define TransactionType_extra_data_tag 8
#define TransactionType_extra_data_len_tag 9
#define wire_in_tag 50002 #define wire_in_tag 50002
#define wire_out_tag 50003 #define wire_out_tag 50003
#define wire_debug_in_tag 50004 #define wire_debug_in_tag 50004
@ -358,8 +376,8 @@ extern const pb_field_t MultisigRedeemScriptType_fields[4];
extern const pb_field_t TxInputType_fields[9]; extern const pb_field_t TxInputType_fields[9];
extern const pb_field_t TxOutputType_fields[7]; extern const pb_field_t TxOutputType_fields[7];
extern const pb_field_t TxOutputBinType_fields[3]; extern const pb_field_t TxOutputBinType_fields[3];
extern const pb_field_t TransactionType_fields[8]; extern const pb_field_t TransactionType_fields[10];
extern const pb_field_t TxRequestDetailsType_fields[3]; extern const pb_field_t TxRequestDetailsType_fields[5];
extern const pb_field_t TxRequestSerializedType_fields[4]; extern const pb_field_t TxRequestSerializedType_fields[4];
extern const pb_field_t IdentityType_fields[7]; extern const pb_field_t IdentityType_fields[7];
@ -371,8 +389,8 @@ extern const pb_field_t IdentityType_fields[7];
#define TxInputType_size 5508 #define TxInputType_size 5508
#define TxOutputType_size 3934 #define TxOutputType_size 3934
#define TxOutputBinType_size 534 #define TxOutputBinType_size 534
#define TransactionType_size 10009 #define TransactionType_size 11042
#define TxRequestDetailsType_size 40 #define TxRequestDetailsType_size 52
#define TxRequestSerializedType_size 2132 #define TxRequestSerializedType_size 2132
#define IdentityType_size 416 #define IdentityType_size 416

View File

@ -38,6 +38,7 @@ enum {
STAGE_REQUEST_2_PREV_META, STAGE_REQUEST_2_PREV_META,
STAGE_REQUEST_2_PREV_INPUT, STAGE_REQUEST_2_PREV_INPUT,
STAGE_REQUEST_2_PREV_OUTPUT, STAGE_REQUEST_2_PREV_OUTPUT,
STAGE_REQUEST_2_PREV_EXTRADATA,
STAGE_REQUEST_3_OUTPUT, STAGE_REQUEST_3_OUTPUT,
STAGE_REQUEST_4_INPUT, STAGE_REQUEST_4_INPUT,
STAGE_REQUEST_4_OUTPUT, STAGE_REQUEST_4_OUTPUT,
@ -85,6 +86,7 @@ foreach I (idx1):
foreach prevhash O (idx2): foreach prevhash O (idx2):
Request prevhash O STAGE_REQUEST_2_PREV_OUTPUT Request prevhash O STAGE_REQUEST_2_PREV_OUTPUT
Add amount of prevhash O (which is amount of I) Add amount of prevhash O (which is amount of I)
Request prevhash extra data (if applicable) STAGE_REQUEST_2_PREV_EXTRADATA
Calculate hash of streamed tx, compare to prevhash I Calculate hash of streamed tx, compare to prevhash I
foreach O (idx1): foreach O (idx1):
Request O STAGE_REQUEST_3_OUTPUT Request O STAGE_REQUEST_3_OUTPUT
@ -173,6 +175,22 @@ void send_req_2_prev_output(void)
msg_write(MessageType_MessageType_TxRequest, &resp); msg_write(MessageType_MessageType_TxRequest, &resp);
} }
void send_req_2_prev_extradata(uint32_t chunk_offset, uint32_t chunk_len)
{
signing_stage = STAGE_REQUEST_2_PREV_EXTRADATA;
resp.has_request_type = true;
resp.request_type = RequestType_TXEXTRADATA;
resp.has_details = true;
resp.details.has_extra_data_offset = true;
resp.details.extra_data_offset = chunk_offset;
resp.details.has_extra_data_len = true;
resp.details.extra_data_len = chunk_len;
resp.details.has_tx_hash = true;
resp.details.tx_hash.size = input.prev_hash.size;
memcpy(resp.details.tx_hash.bytes, input.prev_hash.bytes, resp.details.tx_hash.size);
msg_write(MessageType_MessageType_TxRequest, &resp);
}
void send_req_3_output(void) void send_req_3_output(void)
{ {
signing_stage = STAGE_REQUEST_3_OUTPUT; signing_stage = STAGE_REQUEST_3_OUTPUT;
@ -249,7 +267,7 @@ void signing_init(uint32_t _inputs_count, uint32_t _outputs_count, const CoinTyp
multisig_fp_set = false; multisig_fp_set = false;
multisig_fp_mismatch = false; multisig_fp_mismatch = false;
tx_init(&to, inputs_count, outputs_count, version, lock_time, false); tx_init(&to, inputs_count, outputs_count, version, lock_time, 0, false);
sha256_Init(&tc); sha256_Init(&tc);
sha256_Update(&tc, (const uint8_t *)&inputs_count, sizeof(inputs_count)); sha256_Update(&tc, (const uint8_t *)&inputs_count, sizeof(inputs_count));
sha256_Update(&tc, (const uint8_t *)&outputs_count, sizeof(outputs_count)); sha256_Update(&tc, (const uint8_t *)&outputs_count, sizeof(outputs_count));
@ -261,6 +279,8 @@ void signing_init(uint32_t _inputs_count, uint32_t _outputs_count, const CoinTyp
send_req_1_input(); send_req_1_input();
} }
#define MIN(a,b) (((a)<(b))?(a):(b))
void signing_txack(TransactionType *tx) void signing_txack(TransactionType *tx)
{ {
if (!signing) { if (!signing) {
@ -311,7 +331,7 @@ void signing_txack(TransactionType *tx)
send_req_2_prev_meta(); send_req_2_prev_meta();
return; return;
case STAGE_REQUEST_2_PREV_META: case STAGE_REQUEST_2_PREV_META:
tx_init(&tp, tx->inputs_cnt, tx->outputs_cnt, tx->version, tx->lock_time, false); tx_init(&tp, tx->inputs_cnt, tx->outputs_cnt, tx->version, tx->lock_time, tx->extra_data_len, false);
progress_meta_step = progress_step / (tp.inputs_len + tp.outputs_len); progress_meta_step = progress_step / (tp.inputs_len + tp.outputs_len);
idx2 = 0; idx2 = 0;
send_req_2_prev_input(); send_req_2_prev_input();
@ -345,8 +365,35 @@ void signing_txack(TransactionType *tx)
/* Check prevtx of next input */ /* Check prevtx of next input */
idx2++; idx2++;
send_req_2_prev_output(); send_req_2_prev_output();
} else { // last output
if (tp.extra_data_len > 0) { // has extra data
send_req_2_prev_extradata(0, MIN(1024, tp.extra_data_len));
return;
}
tx_hash_final(&tp, hash, true);
if (memcmp(hash, input.prev_hash.bytes, 32) != 0) {
fsm_sendFailure(FailureType_Failure_Other, "Encountered invalid prevhash");
signing_abort();
return;
}
if (idx1 < inputs_count - 1) {
idx1++;
send_req_1_input();
} else {
idx1 = 0;
send_req_3_output();
}
}
return;
case STAGE_REQUEST_2_PREV_EXTRADATA:
if (!tx_serialize_extra_data_hash(&tp, tx->extra_data.bytes, tx->extra_data.size)) {
fsm_sendFailure(FailureType_Failure_Other, "Failed to serialize extra data");
signing_abort();
return;
}
if (tp.extra_data_received < tp.extra_data_len) { // still some data remanining
send_req_2_prev_extradata(tp.extra_data_received, MIN(1024, tp.extra_data_len - tp.extra_data_received));
} else { } else {
/* Check next output */
tx_hash_final(&tp, hash, true); tx_hash_final(&tp, hash, true);
if (memcmp(hash, input.prev_hash.bytes, 32) != 0) { if (memcmp(hash, input.prev_hash.bytes, 32) != 0) {
fsm_sendFailure(FailureType_Failure_Other, "Encountered invalid prevhash"); fsm_sendFailure(FailureType_Failure_Other, "Encountered invalid prevhash");
@ -453,7 +500,7 @@ void signing_txack(TransactionType *tx)
case STAGE_REQUEST_4_INPUT: case STAGE_REQUEST_4_INPUT:
progress = 500 + ((idx1 * progress_step + idx2 * progress_meta_step) >> PROGRESS_PRECISION); progress = 500 + ((idx1 * progress_step + idx2 * progress_meta_step) >> PROGRESS_PRECISION);
if (idx2 == 0) { if (idx2 == 0) {
tx_init(&ti, inputs_count, outputs_count, version, lock_time, true); tx_init(&ti, inputs_count, outputs_count, version, lock_time, 0, true);
sha256_Init(&tc); sha256_Init(&tc);
sha256_Update(&tc, (const uint8_t *)&inputs_count, sizeof(inputs_count)); sha256_Update(&tc, (const uint8_t *)&inputs_count, sizeof(inputs_count));
sha256_Update(&tc, (const uint8_t *)&outputs_count, sizeof(outputs_count)); sha256_Update(&tc, (const uint8_t *)&outputs_count, sizeof(outputs_count));

View File

@ -407,7 +407,27 @@ uint32_t tx_serialize_output_hash(TxStruct *tx, const TxOutputBinType *output)
return r; return r;
} }
void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t version, uint32_t lock_time, bool add_hash_type) uint32_t tx_serialize_extra_data_hash(TxStruct *tx, const uint8_t *data, uint32_t datalen)
{
if (tx->have_inputs < tx->inputs_len) {
// not all inputs provided
return 0;
}
if (tx->have_outputs < tx->outputs_len) {
// not all inputs provided
return 0;
}
if (tx->extra_data_received + datalen > tx->extra_data_len) {
// we are receiving too much data
return 0;
}
sha256_Update(&(tx->ctx), data, datalen);
tx->extra_data_received += datalen;
tx->size += datalen;
return datalen;
}
void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t version, uint32_t lock_time, uint32_t extra_data_len, bool add_hash_type)
{ {
tx->inputs_len = inputs_len; tx->inputs_len = inputs_len;
tx->outputs_len = outputs_len; tx->outputs_len = outputs_len;
@ -416,6 +436,8 @@ void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t v
tx->add_hash_type = add_hash_type; tx->add_hash_type = add_hash_type;
tx->have_inputs = 0; tx->have_inputs = 0;
tx->have_outputs = 0; tx->have_outputs = 0;
tx->extra_data_len = extra_data_len;
tx->extra_data_received = 0;
tx->size = 0; tx->size = 0;
sha256_Init(&(tx->ctx)); sha256_Init(&(tx->ctx));
} }

View File

@ -36,6 +36,10 @@ typedef struct {
uint32_t have_inputs; uint32_t have_inputs;
uint32_t have_outputs; uint32_t have_outputs;
uint32_t extra_data_len;
uint32_t extra_data_received;
uint32_t size; uint32_t size;
SHA256_CTX ctx; SHA256_CTX ctx;
@ -50,9 +54,10 @@ int compile_output(const CoinType *coin, const HDNode *root, TxOutputType *in, T
uint32_t tx_serialize_input(TxStruct *tx, const TxInputType *input, uint8_t *out); uint32_t tx_serialize_input(TxStruct *tx, const TxInputType *input, uint8_t *out);
uint32_t tx_serialize_output(TxStruct *tx, const TxOutputBinType *output, uint8_t *out); uint32_t tx_serialize_output(TxStruct *tx, const TxOutputBinType *output, uint8_t *out);
void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t version, uint32_t lock_time, bool add_hash_type); void tx_init(TxStruct *tx, uint32_t inputs_len, uint32_t outputs_len, uint32_t version, uint32_t lock_time, uint32_t extra_data_len, bool add_hash_type);
uint32_t tx_serialize_input_hash(TxStruct *tx, const TxInputType *input); uint32_t tx_serialize_input_hash(TxStruct *tx, const TxInputType *input);
uint32_t tx_serialize_output_hash(TxStruct *tx, const TxOutputBinType *output); uint32_t tx_serialize_output_hash(TxStruct *tx, const TxOutputBinType *output);
uint32_t tx_serialize_extra_data_hash(TxStruct *tx, const uint8_t *data, uint32_t datalen);
void tx_hash_final(TxStruct *t, uint8_t *hash, bool reverse); void tx_hash_final(TxStruct *t, uint8_t *hash, bool reverse);
uint32_t transactionEstimateSize(uint32_t inputs, uint32_t outputs); uint32_t transactionEstimateSize(uint32_t inputs, uint32_t outputs);

@ -1 +1 @@
Subproject commit 1e749523593506f2f268c038225f2c847ad2d0ef Subproject commit 20c1d05f9de778e28726690c4969e6ce92296ce4