Skip to content

Commit

Permalink
Refactor process_transaction
Browse files Browse the repository at this point in the history
  • Loading branch information
fbeutin-ledger committed Aug 4, 2023
1 parent b913367 commit fc3c435
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 71 deletions.
184 changes: 115 additions & 69 deletions src/process_transaction.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,49 +66,118 @@ static void normalize_currencies(void) {
}
}

int process_transaction(const command_t *cmd) {
PRINTF("cmd->data.size = %d\n", cmd->data.size);
for (int i = 0; i < cmd->data.size; ++i) {
PRINTF("%02x", cmd->data.bytes[i]);
static int parse_transaction(const buf_t in, subcommand_e subcommand, uint16_t *payload_length, const uint8_t **payload, uint8_t *fees_length, const uint8_t **fees) {
// On legacy flows the length field is 1 byte
uint8_t payload_length_field_size = 2;
if (subcommand == SWAP || subcommand == SELL || subcommand == FUND) {
payload_length_field_size = 1;
}
PRINTF("\n");
if (cmd->data.size < 2) {
PRINTF("Error: Can't parse process_transaction message, length should be more than 2\n");

return reply_error(DESERIALIZATION_FAILED);
// PRINTF("in.size = %d\n", in.size);
// for (int i = 0; i < in.size; ++i) {
// PRINTF("%02x", in.bytes[i]);
// }
// PRINTF("\n");
// Check that we can read payload length
if (in.size < payload_length_field_size) {
PRINTF("Received %d bytes transaction, tx length %d does not fit\n",
in.size,
payload_length_field_size);
return -1;
}

// uint8_t *data;
// uint8_t undecoded_transaction[sizeof(G_swap_ctx.raw_transaction)];
// if (in.bytes == G_swap_ctx.raw_transaction) {
// PRINTF("Copying locally, the APDU has been received split\n");
// // For memory optimization, the undecded protobuf apdu may have been stored in an union with the decoded apdus
// // Copy locally to avoid problems during protobuf decode
// memcpy(undecoded_transaction, G_swap_ctx.raw_transaction, in.size);
// PRINTF("in.size = %d\n", in.size);
// for (int i = 0; i < in.size; ++i) {
// PRINTF("%02x", undecoded_transaction[i]);
// }
// PRINTF("\n");
// data = undecoded_transaction;
// } else {
// data = in.bytes;
// }

// Read the payload length
if (payload_length_field_size == 2) {
*payload_length = U2BE(in.bytes, 0);
} else {
*payload_length = in.bytes[0];
}

// Check that we can read fees length
if (in.size < payload_length_field_size + *payload_length + 1) {
PRINTF("Received %d bytes transaction, advertizing payload (%d)%d\n",
in.size,
payload_length_field_size,
*payload_length);
return -1;
}
*fees_length = in.bytes[payload_length_field_size + *payload_length];

// Check that there is no data left to read
if (in.size != payload_length_field_size + *payload_length + 1 + *fees_length) {
PRINTF("Received %d bytes, advertizing payload (%d)%d + fees (%d)%d\n",
in.size,
payload_length_field_size,
*payload_length,
1,
*fees_length);
return -1;
}
if (*fees_length > sizeof(G_swap_ctx.transaction_fee)) {
PRINTF("Error: Transaction fee %d is too long, %d max\n",
*fees_length,
sizeof(G_swap_ctx.transaction_fee));
return -1;
}

uint8_t *data;
*payload = in.bytes + payload_length_field_size;
*fees = in.bytes + payload_length_field_size + *payload_length + 1;
return 0;
}

int process_transaction(const command_t *cmd) {
// PRINTF("in.size = %d\n", cmd->data.size);
// for (int i = 0; i < cmd->data.size; ++i) {
// PRINTF("%02x", cmd->data.bytes[i]);
// }
// PRINTF("\n");
// if (cmd->data.size < 2) {
// PRINTF("Error: Can't parse process_transaction message, length should be more than 2\n");

// return reply_error(DESERIALIZATION_FAILED);
// }

uint8_t undecoded_transaction[sizeof(G_swap_ctx.raw_transaction)];
buf_t data;
data.size = cmd->data.size;
if (cmd->data.bytes == G_swap_ctx.raw_transaction) {
PRINTF("Copying locally, the APDU has been received split\n");
// For memory optimization, the undecded protobuf apdu may have been stored in an union with the decoded apdus
// Copy locally to avoid problems during protobuf decode
memcpy(undecoded_transaction, G_swap_ctx.raw_transaction, cmd->data.size);
PRINTF("cmd->data.size = %d\n", cmd->data.size);
for (int i = 0; i < cmd->data.size; ++i) {
PRINTF("%02x", undecoded_transaction[i]);
}
PRINTF("\n");
data = undecoded_transaction;
// PRINTF("cmd->data.size = %d\n", cmd->data.size);
// for (int i = 0; i < cmd->data.size; ++i) {
// PRINTF("%02x", undecoded_transaction[i]);
// }
// PRINTF("\n");
data.bytes = undecoded_transaction;
} else {
data = cmd->data.bytes;
data.bytes = cmd->data.bytes;
}

uint16_t payload_length;
uint8_t data_offset;
if (cmd->subcommand == SWAP_NG) {
data_offset = 2;
payload_length = U2BE(data, 0);
} else {
data_offset = 1;
payload_length = data[0];
}
if (cmd->data.size < data_offset + payload_length) {
PRINTF("Error: Can't parse process_transaction message, invalid payload length\n");
const uint8_t *payload;
const uint8_t *fees;
if (parse_transaction(data, cmd->subcommand, &payload_length, &payload, &G_swap_ctx.transaction_fee_length, &fees) != 0) {
return reply_error(DESERIALIZATION_FAILED);
}
data += data_offset;

pb_istream_t stream;
cx_sha256_t sha256;
Expand All @@ -117,19 +186,19 @@ int process_transaction(const command_t *cmd) {

PRINTF("len(payload) = %d\n", payload_length);
for (int i = 0; i < payload_length; ++i) {
PRINTF("%02x", data[i]);
PRINTF("%02x", payload[i]);
}
PRINTF("\n");

if (cmd->subcommand == SWAP) {
PRINTF("payload_length = %d\n", payload_length);
for (int i = 0; i < payload_length; ++i) {
PRINTF("%02x", data[i]);
PRINTF("%02x", payload[i]);
}
PRINTF("\n");
if (cx_hash_no_throw(&sha256.header,
CX_LAST,
data,
payload,
payload_length,
G_swap_ctx.sha256_digest,
sizeof(G_swap_ctx.sha256_digest)) != CX_OK) {
Expand All @@ -139,14 +208,14 @@ int process_transaction(const command_t *cmd) {

PRINTF("sha256_digest: %.*H\n", 32, G_swap_ctx.sha256_digest);

stream = pb_istream_from_buffer(data, payload_length);
stream = pb_istream_from_buffer(payload, payload_length);

if (!pb_decode(&stream,
ledger_swap_NewTransactionResponse_fields,
&G_swap_ctx.received_transaction)) {
PRINTF("Error: Can't parse SWAP transaction protobuf\n%.*H\n",
payload_length,
data);
payload);

return reply_error(DESERIALIZATION_FAILED);
}
Expand All @@ -168,9 +237,10 @@ int process_transaction(const command_t *cmd) {
normalize_currencies();
}


if (cmd->subcommand == SELL || cmd->subcommand == FUND || cmd->subcommand == SWAP_NG || cmd->subcommand == SELL_NG || cmd->subcommand == FUND_NG) {
// arbitrary maximum payload size
unsigned char payload[256];
unsigned char decoded[256];


unsigned char dot = '.';
Expand All @@ -181,7 +251,7 @@ int process_transaction(const command_t *cmd) {
}
if (cx_hash_no_throw(&sha256.header,
CX_LAST,
data,
payload,
payload_length,
G_swap_ctx.sha256_digest,
sizeof(G_swap_ctx.sha256_digest)) != CX_OK) {
Expand All @@ -193,13 +263,13 @@ int process_transaction(const command_t *cmd) {

PRINTF("payload_length = %d\n", payload_length);
for (int i = 0; i < payload_length; ++i) {
PRINTF("%02x", data[i]);
PRINTF("%02x", payload[i]);
}
PRINTF("\n");

int n = base64_decode(payload,
sizeof(payload),
(const unsigned char *) data,
int n = base64_decode(decoded,
sizeof(decoded),
(const unsigned char *) payload,
payload_length);
if (n < 0) {
PRINTF("Error: Can't decode SELL/FUND/NG transaction base64\n");
Expand All @@ -208,23 +278,23 @@ int process_transaction(const command_t *cmd) {
}
PRINTF("payload_length = %d\n", payload_length);
for (int i = 0; i < payload_length; ++i) {
PRINTF("%02x", data[i]);
PRINTF("%02x", payload[i]);
}
PRINTF("\n");
PRINTF("payload length = %d\n", n);
PRINTF("decoded length = %d\n", n);
for (int i = 0; i < n; ++i) {
PRINTF("%02x", payload[i]);
PRINTF("%02x", decoded[i]);
}
PRINTF("\n");

PRINTF("len(base64_decode(payload)) = %d\n", n);
PRINTF("len(base64_decode(decoded)) = %d\n", n);
for (int i = 0; i < n; ++i)
{
PRINTF("%02x", payload[i]);
PRINTF("%02x", decoded[i]);
}
PRINTF("\n");

stream = pb_istream_from_buffer(payload, n);
stream = pb_istream_from_buffer(decoded, n);

if (cmd->subcommand == SELL || cmd->subcommand == SELL_NG) {
if (!pb_decode(&stream, ledger_swap_NewSellResponse_fields, &G_swap_ctx.sell_transaction)) {
Expand Down Expand Up @@ -294,32 +364,8 @@ int process_transaction(const command_t *cmd) {
}
}

if (cmd->data.size < 1 + payload_length + 1) {
PRINTF("Error: Can't parse process_transaction message, should include fee\n");

return reply_error(DESERIALIZATION_FAILED);
}

G_swap_ctx.transaction_fee_length = data[payload_length];
PRINTF("G_swap_ctx.transaction_fee_length = %d\n", G_swap_ctx.transaction_fee_length);
PRINTF("G_swap_ctx.transaction_fee_length = %d\n", G_swap_ctx.transaction_fee_length);

if (G_swap_ctx.transaction_fee_length > sizeof(G_swap_ctx.transaction_fee)) {
PRINTF("Error: Transaction fee is to long\n");

return reply_error(DESERIALIZATION_FAILED);
}

if (cmd->data.size < 1 + payload_length + 1 + G_swap_ctx.transaction_fee_length) {
PRINTF("Error: Input buffer is too small");

return reply_error(DESERIALIZATION_FAILED);
}

memset(G_swap_ctx.transaction_fee, 0, sizeof(G_swap_ctx.transaction_fee));
memcpy(G_swap_ctx.transaction_fee,
data + payload_length + 1,
G_swap_ctx.transaction_fee_length);
memcpy(G_swap_ctx.transaction_fee, fees, G_swap_ctx.transaction_fee_length);
PRINTF("Transaction fees BE = %.*H\n",
G_swap_ctx.transaction_fee_length,
G_swap_ctx.transaction_fee);
Expand Down
2 changes: 1 addition & 1 deletion test/python/apps/exchange.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ def check_partner_key(self, signed_credentials: bytes) -> RAPDU:

def process_transaction(self, transaction: bytes, fees: int) -> RAPDU:
fees_bytes = int_to_minimally_sized_bytes(fees)
prefix_length = 2 if self.subcommand == SubCommand.SWAP_NG else 1
prefix_length = 2 if (self.subcommand == SubCommand.SWAP_NG or self.subcommand == SubCommand.FUND_NG or self.subcommand == SubCommand.SELL_NG) else 1
payload = prefix_with_len_custom(transaction, prefix_length) + prefix_with_len(fees_bytes)

if self.subcommand == SubCommand.SWAP or self.subcommand == SubCommand.FUND or self.subcommand == SubCommand.SELL:
Expand Down
2 changes: 1 addition & 1 deletion test/python/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@

configuration.OPTIONAL.SIDELOADED_APPS_DIR = "test/python/lib_binaries/"

configuration.OPTIONAL.BACKEND_SCOPE = "function"
configuration.OPTIONAL.BACKEND_SCOPE = "class"

#########################
### CONFIGURATION END ###
Expand Down

0 comments on commit fc3c435

Please sign in to comment.