Skip to content

Commit

Permalink
Moved to a tagged Borsh encoding for IBC messages.
Browse files Browse the repository at this point in the history
  • Loading branch information
murisi committed Jul 19, 2024
1 parent dfc8730 commit 4a81307
Show file tree
Hide file tree
Showing 6 changed files with 137 additions and 58 deletions.
118 changes: 67 additions & 51 deletions app/src/parser_impl_txn.c
Original file line number Diff line number Diff line change
Expand Up @@ -763,13 +763,10 @@ static parser_error_t readBridgePoolTransfer(const bytes_t *data, tx_bridge_pool
}

__Z_INLINE parser_error_t readTimestamp(parser_context_t *ctx, timestamp_t *timestamp) {
uint8_t consumed = 0;
uint64_t tmp = 0;

CHECK_ERROR(checkTag(ctx, 0x38))
const uint64_t timestampSize = ctx->bufferLen - ctx->offset;
decodeLEB128(ctx->buffer + ctx->offset, timestampSize, &consumed, &tmp);
ctx->offset += consumed;
CHECK_ERROR(readUint64(ctx, &tmp))

const uint32_t e9 = 1000000000;
timestamp->millis = tmp / e9;
Expand All @@ -781,89 +778,108 @@ __Z_INLINE parser_error_t readTimestamp(parser_context_t *ctx, timestamp_t *time
static parser_error_t readIBCTxn(const bytes_t *data, parser_tx_t *v) {
parser_context_t ctx = {.buffer = data->ptr, .bufferLen = data->len, .offset = 0, .tx_obj = NULL};

// Read the message type: 1 for Transfer, 2 for NftTransfer
CHECK_ERROR(readByte(&ctx, &v->ibc.message_type))

uint32_t tmpValue;
uint16_t tmpFieldLen = 0;
CHECK_ERROR(readUint32(&ctx, &tmpValue));
// Read port id
CHECK_ERROR(checkTag(&ctx, 0x0A))
CHECK_ERROR(readFieldSizeU16(&ctx, &v->ibc.port_id.len))
CHECK_ERROR(readUint32(&ctx, &tmpValue))
if (tmpValue > UINT16_MAX) {
return parser_value_out_of_range;
}
v->ibc.port_id.len = tmpValue;
CHECK_ERROR(readBytes(&ctx, &v->ibc.port_id.ptr, v->ibc.port_id.len))

// Read channel id
CHECK_ERROR(checkTag(&ctx, 0x12))
CHECK_ERROR(readFieldSizeU16(&ctx, &v->ibc.channel_id.len))
CHECK_ERROR(readUint32(&ctx, &tmpValue))
if (tmpValue > UINT16_MAX) {
return parser_value_out_of_range;
}
v->ibc.channel_id.len = tmpValue;
CHECK_ERROR(readBytes(&ctx, &v->ibc.channel_id.ptr, v->ibc.channel_id.len))

////// Packed data
////// Packet data
// Read token address
CHECK_ERROR(checkTag(&ctx, 0x1A))
CHECK_ERROR(readFieldSizeU16(&ctx, &tmpFieldLen))
CHECK_ERROR(readUint32(&ctx, &v->ibc.trace_path_len))
v->ibc.trace_path.ptr = ctx.buffer + ctx.offset;
for(uint32_t i = 0; i < v->ibc.trace_path_len; i++) {
CHECK_ERROR(readUint32(&ctx, &tmpValue))
if (tmpValue > UINT16_MAX) {
return parser_value_out_of_range;
}
bytes_t port_id;
port_id.len = tmpValue;
CHECK_ERROR(readBytes(&ctx, &port_id.ptr, port_id.len))
CHECK_ERROR(readUint32(&ctx, &tmpValue))
if (tmpValue > UINT16_MAX) {
return parser_value_out_of_range;
}
bytes_t channel_id;
channel_id.len = tmpValue;
CHECK_ERROR(readBytes(&ctx, &channel_id.ptr, channel_id.len))
}
v->ibc.trace_path.len = ctx.buffer + ctx.offset - v->ibc.trace_path.ptr;

CHECK_ERROR(checkTag(&ctx, 0x0A))
CHECK_ERROR(readFieldSizeU16(&ctx, &v->ibc.token_address.len))
CHECK_ERROR(readBytes(&ctx, &v->ibc.token_address.ptr, v->ibc.token_address.len))
// Read base denomination
CHECK_ERROR(readUint32(&ctx, &tmpValue))
if (tmpValue > UINT16_MAX) {
return parser_value_out_of_range;
}
v->ibc.base_denom.len = tmpValue;
CHECK_ERROR(readBytes(&ctx, &v->ibc.base_denom.ptr, v->ibc.base_denom.len))

// Read token amount
CHECK_ERROR(checkTag(&ctx, 0x12))
CHECK_ERROR(readFieldSizeU16(&ctx, &v->ibc.token_amount.len))
v->ibc.token_amount.len = 32;
CHECK_ERROR(readBytes(&ctx, &v->ibc.token_amount.ptr, v->ibc.token_amount.len))

// Read sender
CTX_CHECK_AVAIL(&ctx, 1);
if (*(ctx.buffer + ctx.offset) == 0x22) {
CHECK_ERROR(checkTag(&ctx, 0x22))
CHECK_ERROR(readFieldSizeU16(&ctx, &v->ibc.sender_address.len))
CHECK_ERROR(readBytes(&ctx, &v->ibc.sender_address.ptr, v->ibc.sender_address.len))
CHECK_ERROR(readUint32(&ctx, &tmpValue))
if (tmpValue > UINT16_MAX) {
return parser_value_out_of_range;
}
v->ibc.sender_address.len = tmpValue;
CHECK_ERROR(readBytes(&ctx, &v->ibc.sender_address.ptr, v->ibc.sender_address.len))

// Read receiver
CTX_CHECK_AVAIL(&ctx, 1);
if (*(ctx.buffer + ctx.offset) == 0x2A) {
CHECK_ERROR(checkTag(&ctx, 0x2A))
CHECK_ERROR(readFieldSizeU16(&ctx, &v->ibc.receiver.len))
CHECK_ERROR(readBytes(&ctx, &v->ibc.receiver.ptr, v->ibc.receiver.len))
CHECK_ERROR(readUint32(&ctx, &tmpValue))
if (tmpValue > UINT16_MAX) {
return parser_value_out_of_range;
}
v->ibc.receiver.len = tmpValue;
CHECK_ERROR(readBytes(&ctx, &v->ibc.receiver.ptr, v->ibc.receiver.len))

// Read memo
CHECK_ERROR(readUint32(&ctx, &tmpValue))
if (tmpValue > UINT16_MAX) {
return parser_value_out_of_range;
}
bytes_t memo;
memo.len = tmpValue;
CHECK_ERROR(readBytes(&ctx, &memo.ptr, memo.len))
////////////////

// Read timeout height
CHECK_ERROR(checkTag(&ctx, 0x32))
CHECK_ERROR(readByte(&ctx, &v->ibc.timeout_height_type))

if (v->ibc.timeout_height_type > 0) {
uint8_t consumed = 0;
uint64_t tmp = 0;

// Read 0x08
CHECK_ERROR(checkTag(&ctx, 0x08))
const uint64_t remainingBytes = ctx.bufferLen - ctx.offset;
decodeLEB128(ctx.buffer + ctx.offset, remainingBytes, &consumed, &tmp);
v->ibc.revision_number = tmp;
ctx.offset += consumed;

CHECK_ERROR(checkTag(&ctx, 0x10))
const uint64_t remainingBytes2 = ctx.bufferLen - ctx.offset;
decodeLEB128(ctx.buffer + ctx.offset, remainingBytes2, &consumed, &tmp);
v->ibc.revision_height = tmp;
ctx.offset += consumed;
if (v->ibc.timeout_height_type == 1) {
CHECK_ERROR(readUint64(&ctx, &v->ibc.revision_number))
CHECK_ERROR(readUint64(&ctx, &v->ibc.revision_height))
} else if (v->ibc.timeout_height_type != 0) {
return parser_value_out_of_range;
}

// Read timeout timestamp
CHECK_ERROR(readTimestamp(&ctx, &v->ibc.timeout_timestamp))

if (ctx.offset < ctx.bufferLen) {
CHECK_ERROR(checkTag(&ctx, 0x42))
bytes_t tmpBytes = {0};
CHECK_ERROR(readFieldSizeU16(&ctx, &tmpBytes.len))
CHECK_ERROR(readBytes(&ctx, &tmpBytes.ptr, tmpBytes.len))
}

// Read byte indicating presence of Transfer
uint8_t has_transfer;
CHECK_ERROR(readByte(&ctx, &has_transfer))

if (ctx.offset != ctx.bufferLen) {
return parser_unexpected_characters;
}

return parser_ok;
}

Expand Down
65 changes: 63 additions & 2 deletions app/src/parser_print_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -175,14 +175,75 @@ parser_error_t printPublicKey( const bytes_t *pubkey,
return parser_ok;
}

parser_error_t joinStrings(const bytes_t first, const bytes_t second, const char *separator,
parser_error_t extractPortChannel(bytes_t second_bytes, uint32_t idx, bytes_t *port_id, bytes_t *channel_id) {
parser_context_t tmpCtx = { .buffer = second_bytes.ptr,
.bufferLen = second_bytes.len,
.offset = 0};
for (uint32_t i = 0; i <= idx; i++) {
uint32_t tmpValue;
CHECK_ERROR(readUint32(&tmpCtx, &tmpValue))
if (tmpValue > UINT16_MAX) {
return parser_value_out_of_range;
}
port_id->len = tmpValue;
CHECK_ERROR(readBytes(&tmpCtx, &port_id->ptr, port_id->len))

CHECK_ERROR(readUint32(&tmpCtx, &tmpValue))
if (tmpValue > UINT16_MAX) {
return parser_value_out_of_range;
}
channel_id->len = tmpValue;
CHECK_ERROR(readBytes(&tmpCtx, &channel_id->ptr, channel_id->len))
}
return parser_ok;
}

parser_error_t joinStrings(const bytes_t first_bytes, bytes_t second_bytes, uint32_t trace_path_len, bytes_t base_denom, const char *separator,
char *outVal, uint16_t outValLen, uint8_t pageIdx, uint8_t *pageCount) {

if (first.ptr == NULL || second.ptr == NULL || outVal == NULL || pageCount == NULL ||
if (first_bytes.ptr == NULL || second_bytes.ptr == NULL || outVal == NULL || pageCount == NULL ||
outValLen <= 1) {
return parser_unexpected_error;
}

// Convert first_bytes from big-endian to a little-endian array
uint8_t first_bytes_le_array[32];
for (uint8_t i = 0; i < 4; i++) {
// Reverse the current word
for (uint8_t j = 0; j < 8; j++) {
first_bytes_le_array[8*i + j] = first_bytes.ptr[8*i + 7 - j];
}
}
// Convert first_bytes_le_array to a little endian bytes pointer
bytes_t first_bytes_le = {.ptr = first_bytes_le_array, .len = 32};
char strAmount[79] = {0};
// Convert a little endian bytes pointer to a string
CHECK_ERROR(bigint_to_str(&first_bytes_le, false, strAmount, sizeof(strAmount), 0, pageCount))
bytes_t first = {.ptr = strAmount, .len = strlen(strAmount)};

uint8_t second_bytes_array[1024] = {0};
uint32_t second_bytes_offset = 0;
// Construct the token string
for (uint32_t i = 0; i < trace_path_len; i++) {
bytes_t port_id;
bytes_t channel_id;
// Extract the port and channel starting from the back
CHECK_ERROR(extractPortChannel(second_bytes, trace_path_len - i - 1, &port_id, &channel_id))
// Append the port ID
MEMCPY(second_bytes_array + second_bytes_offset, port_id.ptr, port_id.len);
second_bytes_offset += port_id.len;
second_bytes_array[second_bytes_offset++] = '/';
// Append the channel ID
MEMCPY(second_bytes_array + second_bytes_offset, channel_id.ptr, channel_id.len);
second_bytes_offset += channel_id.len;
second_bytes_array[second_bytes_offset++] = '/';
}
// Append the base denomination
MEMCPY(second_bytes_array + second_bytes_offset, base_denom.ptr, base_denom.len);
second_bytes_offset += base_denom.len;

bytes_t second = {.ptr = second_bytes_array, .len = second_bytes_offset};

// Calculate the total length needed including the separator and null terminator
uint32_t totalLength = first.len + strlen(separator) + second.len + 1; // +1 for null terminator

Expand Down
2 changes: 1 addition & 1 deletion app/src/parser_print_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ parser_error_t printPublicKey(const bytes_t *pubkey,
char *outVal, uint16_t outValLen,
uint8_t pageIdx, uint8_t *pageCount);

parser_error_t joinStrings(const bytes_t first, const bytes_t second, const char *separator,
parser_error_t joinStrings(const bytes_t first, const bytes_t second, uint32_t trace_path_len, bytes_t base_denom, const char *separator,
char * outVal, uint16_t outValLen, uint8_t pageIdx, uint8_t *pageCount);

parser_error_t printProposal( const tx_init_proposal_t *initProposal, uint8_t displayIdx,
Expand Down
3 changes: 1 addition & 2 deletions app/src/parser_print_txn.c
Original file line number Diff line number Diff line change
Expand Up @@ -1106,7 +1106,6 @@ static parser_error_t printIBCTxn( const parser_context_t *ctx,
char *outKey, uint16_t outKeyLen,
char *outVal, uint16_t outValLen,
uint8_t pageIdx, uint8_t *pageCount) {

const tx_ibc_t *ibc = &ctx->tx_obj->ibc;
const bool hasMemo = ctx->tx_obj->transaction.header.memoSection != NULL;
if (displayIdx >= 8 && !hasMemo) {
Expand All @@ -1131,7 +1130,7 @@ static parser_error_t printIBCTxn( const parser_context_t *ctx,
break;
case 3:
snprintf(outKey, outKeyLen, "Token");
CHECK_ERROR(joinStrings(ibc->token_amount, ibc->token_address, " ", outVal, outValLen, pageIdx, pageCount))
CHECK_ERROR(joinStrings(ibc->token_amount, ibc->trace_path, ibc->trace_path_len, ibc->base_denom, " ", outVal, outValLen, pageIdx, pageCount))
break;

case 4:
Expand Down
5 changes: 4 additions & 1 deletion app/src/parser_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -333,16 +333,19 @@ typedef struct {
} tx_transfer_t;

typedef struct {
uint8_t message_type;
bytes_t port_id;
bytes_t channel_id;
bytes_t token_address;
bytes_t token_amount;
bytes_t sender_address;
bytes_t receiver;
uint8_t timeout_height_type;
uint64_t revision_number;
uint64_t revision_height;
timestamp_t timeout_timestamp;
uint32_t trace_path_len;
bytes_t trace_path;
bytes_t base_denom;
} tx_ibc_t;

typedef struct {
Expand Down
2 changes: 1 addition & 1 deletion tests/testvectors.json

Large diffs are not rendered by default.

0 comments on commit 4a81307

Please sign in to comment.