Skip to content
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

Add Soroban support. #5

Merged
merged 1 commit into from
Apr 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,7 @@ tests_common_js/node_modules/
fuzz/build
fuzz/testcases/
tests_generate_binary/node_modules/
.DS_Store
.DS_Store
.idea
installer/
linkermap.html
5 changes: 4 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
{
"files.associations": {
"*.h": "c",
"random": "c"
"random": "c",
"array": "c",
"string": "c",
"string_view": "c"
},
"C_Cpp.clang_format_path": "/usr/bin/clang-format",
"editor.formatOnSave": true
Expand Down
12 changes: 1 addition & 11 deletions fuzz/fuzz_tx.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,8 @@
#include "stellar/parser.h"
#include "stellar/formatter.h"

/*
* Captions don't scroll so there is no use in having more capacity than can fit on screen at once.
*/
#define DETAIL_CAPTION_MAX_LENGTH 20

/*
* DETAIL_VALUE_MAX_LENGTH value of 89 is due to the maximum length of managed data value which can
* be 64 bytes long. Managed data values are displayed as base64 encoded strings, which are
* 4*((len+2)/3) characters long. (An additional slot is required for the end-of-string character of
* course)
*/
#define DETAIL_VALUE_MAX_LENGTH 89
#define DETAIL_VALUE_MAX_LENGTH 104

int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
envelope_t envelope;
Expand Down
1,245 changes: 766 additions & 479 deletions libstellar/formatter.c

Large diffs are not rendered by default.

20 changes: 20 additions & 0 deletions libstellar/include/stellar/parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,23 @@ bool parse_transaction_operation(const uint8_t *data,
size_t data_len,
envelope_t *envelope,
uint8_t operation_index);

bool parse_soroban_authorization_envelope(const uint8_t *data,
size_t data_len,
envelope_t *envelope);

bool parse_bool(buffer_t *buffer, bool *b);

bool parse_uint64(buffer_t *buffer, uint64_t *n);

bool parse_int64(buffer_t *buffer, int64_t *n);

bool parse_scv_symbol(buffer_t *buffer, scv_symbol_t *symbol);

bool parse_scv_string(buffer_t *buffer, scv_string_t *string);

bool buffer_read32(buffer_t *buffer, uint32_t *n);

bool parse_sc_address(buffer_t *buffer, sc_address_t *sc_address);

bool read_scval_advance(buffer_t *buffer);
24 changes: 23 additions & 1 deletion libstellar/include/stellar/printer.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,4 +79,26 @@ bool print_summary(const char *in,
uint8_t num_chars_l,
uint8_t num_chars_r);

bool print_time(uint64_t seconds, char *out, size_t out_len);
bool print_time(uint64_t seconds, char *out, size_t out_len);

bool print_int32(const uint8_t *value, char *out, size_t out_len, bool add_separator);

bool print_uint32(const uint8_t *value, char *out, size_t out_len, bool add_separator);

bool print_int64(const uint8_t *value, char *out, size_t out_len, bool add_separator);

bool print_uint64(const uint8_t *value, char *out, size_t out_len, bool add_separator);

bool print_int128(const uint8_t *value, char *out, size_t out_len, bool add_separator);

bool print_uint128(const uint8_t *value, char *out, size_t out_len, bool add_separator);

bool print_int256(const uint8_t *value, char *out, size_t out_len, bool add_separator);

bool print_uint256(const uint8_t *value, char *out, size_t out_len, bool add_separator);

bool print_scv_symbol(const scv_symbol_t *scv_symbol, char *out, size_t out_len);

bool print_scv_string(const scv_string_t *scv_string, char *out, size_t out_len);

bool add_separator_to_number(char *out, size_t out_len);
26 changes: 26 additions & 0 deletions libstellar/include/stellar/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
#define DATA_NAME_MAX_SIZE 64
#define DATA_VALUE_MAX_SIZE 64
#define HOME_DOMAIN_MAX_SIZE 32
#define SCV_SYMBOL_MAX_SIZE 32

#define NETWORK_TYPE_PUBLIC 0
#define NETWORK_TYPE_TEST 1
Expand Down Expand Up @@ -512,6 +513,16 @@ typedef enum SCValType {
SCV_LEDGER_KEY_NONCE = 21
} sc_val_type_t;

typedef struct {
uint32_t size; // the max size of the symbol is SCV_SYMBOL_MAX_SIZE
const uint8_t *symbol;
} scv_symbol_t;

typedef struct {
uint32_t size; // dont include the null terminator
const uint8_t *string;
} scv_string_t;

typedef enum { SC_ADDRESS_TYPE_ACCOUNT = 0, SC_ADDRESS_TYPE_CONTRACT = 1 } sc_address_type_t;

typedef struct {
Expand All @@ -531,6 +542,7 @@ typedef struct {
const uint8_t *name;
} function;
size_t parameters_position;
uint8_t parameters_length;
} invoke_contract_args_t;

typedef enum {
Expand Down Expand Up @@ -558,6 +570,13 @@ typedef enum {
SOROBAN_AUTHORIZED_FUNCTION_TYPE_CREATE_CONTRACT_HOST_FN = 1
} soroban_authorization_function_type_t;

typedef struct {
uint64_t nonce;
uint32_t signature_expiration_ledger;
soroban_authorization_function_type_t function_type;
invoke_contract_args_t invoke_contract_args;
} soroban_authorization_t;

// ************************* Soroban ************************* //

typedef struct {
Expand Down Expand Up @@ -649,6 +668,13 @@ typedef struct {
typedef struct {
transaction_details_t tx;
fee_bump_transaction_details_t fee_bump_tx;
} tx_details_t;

typedef struct {
union {
tx_details_t tx_details;
soroban_authorization_t soroban_authorization;
};
envelope_type_t type;
uint8_t network;
} envelope_t;
143 changes: 124 additions & 19 deletions libstellar/parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@
if (!(x)) return false; \
}

static bool read_scval_advance(buffer_t *buffer);
bool read_scval_advance(buffer_t *buffer);

static bool buffer_advance(buffer_t *buffer, size_t num_bytes) {
return buffer_seek_cur(buffer, num_bytes);
}

static bool buffer_read32(buffer_t *buffer, uint32_t *n) {
bool buffer_read32(buffer_t *buffer, uint32_t *n) {
return buffer_read_u32(buffer, n, BE);
}

Expand Down Expand Up @@ -46,6 +46,32 @@ static bool buffer_read_bytes(buffer_t *buffer, uint8_t *out, size_t size) {
return true;
}

static int64_t read_i64_be(const uint8_t *ptr, size_t offset) {
int64_t result = 0;
for (int i = 0; i < 8; i++) {
result = (result << 8) | ptr[offset + i];
}
return result;
}

bool parse_uint64(buffer_t *buffer, uint64_t *n) {
PARSER_CHECK(buffer_read64(buffer, n))
return true;
}

bool parse_bool(buffer_t *buffer, bool *b) {
return buffer_read_bool(buffer, b);
}

bool parse_int64(buffer_t *buffer, int64_t *n) {
if (!buffer_can_read(buffer, 8)) {
*n = 0;
return false;
}
*n = read_i64_be(buffer->ptr, buffer->offset);
return buffer_seek_cur(buffer, 8);
}

size_t num_bytes(size_t size) {
size_t remainder = size % 4;
if (remainder == 0) {
Expand Down Expand Up @@ -110,6 +136,24 @@ static bool parse_optional_type(buffer_t *buffer, xdr_type_reader reader, void *
}
}

bool parse_scv_symbol(buffer_t *buffer, scv_symbol_t *symbol) {
if (!buffer_read32(buffer, &symbol->size) || symbol->size > SCV_SYMBOL_MAX_SIZE) {
return false;
}
PARSER_CHECK(buffer_can_read(buffer, num_bytes(symbol->size)))
symbol->symbol = buffer->ptr + buffer->offset;
return true;
}

bool parse_scv_string(buffer_t *buffer, scv_string_t *string) {
if (!buffer_read32(buffer, &string->size)) {
return false;
}
PARSER_CHECK(buffer_can_read(buffer, num_bytes(string->size)))
string->string = buffer->ptr + buffer->offset;
return true;
}

static bool parse_signer_key(buffer_t *buffer, signer_key_t *key) {
uint32_t signer_type;

Expand Down Expand Up @@ -695,7 +739,7 @@ static bool parse_begin_sponsoring_future_reserves(buffer_t *buffer,
return true;
}

static bool parse_sc_address(buffer_t *buffer, sc_address_t *sc_address) {
bool parse_sc_address(buffer_t *buffer, sc_address_t *sc_address) {
uint32_t address_type;
PARSER_CHECK(buffer_read32(buffer, &address_type))
sc_address->type = address_type;
Expand Down Expand Up @@ -749,7 +793,7 @@ static bool read_contract_executable_advance(buffer_t *buffer) {
return true;
}

static bool read_scval_advance(buffer_t *buffer) {
bool read_scval_advance(buffer_t *buffer) {
uint32_t sc_type;
PARSER_CHECK(buffer_read32(buffer, &sc_type))

Expand Down Expand Up @@ -996,13 +1040,22 @@ static bool parse_invoke_contract_args(buffer_t *buffer, invoke_contract_args_t
args->function.name_size = name_size;

// args
uint32_t args_len;
PARSER_CHECK(buffer_read32(buffer, &args_len))

args->parameters_length = args_len;
args->parameters_position = buffer->offset;
// PRINTF("function_name.text_size=%d, function_name.text=%s\n",

// if (args_len > 10) {
// // TODO: We dont support more than 10 arguments
// return false;
// }

// PRINTF("function_name.text_size=%d, function_name.text=%s, args->parameters_length=%d\n",
// args->function.name_size,
// args->function.name);
// args->function.name,
// args->parameters_length);

uint32_t args_len;
PARSER_CHECK(buffer_read32(buffer, &args_len))
for (uint32_t i = 0; i < args_len; i++) {
PARSER_CHECK(read_scval_advance(buffer))
}
Expand Down Expand Up @@ -1175,8 +1228,7 @@ static bool parse_operation(buffer_t *buffer, operation_t *operation) {
case OPERATION_TYPE_LIQUIDITY_POOL_WITHDRAW:
return parse_liquidity_pool_withdraw(buffer, &operation->liquidity_pool_withdraw_op);
case OPERATION_INVOKE_HOST_FUNCTION: {
PARSER_CHECK(parse_invoke_host_function(buffer, &operation->invoke_host_function_op))
return true;
return parse_invoke_host_function(buffer, &operation->invoke_host_function_op);
}
case OPERATION_EXTEND_FOOTPRINT_TTL:
return parse_extend_footprint_ttl(buffer, &operation->extend_footprint_ttl_op);
Expand Down Expand Up @@ -1301,30 +1353,30 @@ bool parse_transaction_envelope(const uint8_t *data, size_t data_len, envelope_t
.offset = 0,
};

explicit_bzero(&envelope->tx, sizeof(transaction_details_t));
explicit_bzero(&envelope->fee_bump_tx, sizeof(fee_bump_transaction_details_t));
explicit_bzero(&envelope->tx_details, sizeof(tx_details_t));
uint32_t envelope_type;
PARSER_CHECK(parse_network(&buffer, &envelope->network))
PARSER_CHECK(buffer_read32(&buffer, &envelope_type))
envelope->type = envelope_type;
switch (envelope_type) {
case ENVELOPE_TYPE_TX:
PARSER_CHECK(parse_transaction_details(&buffer, &envelope->tx))
PARSER_CHECK(parse_transaction_details(&buffer, &envelope->tx_details.tx))
break;
case ENVELOPE_TYPE_TX_FEE_BUMP:
PARSER_CHECK(parse_fee_bump_transaction_details(&buffer, &envelope->fee_bump_tx))
PARSER_CHECK(
parse_fee_bump_transaction_details(&buffer, &envelope->tx_details.fee_bump_tx))
uint32_t inner_envelope_type;
PARSER_CHECK(buffer_read32(&buffer, &inner_envelope_type))
if (inner_envelope_type != ENVELOPE_TYPE_TX) {
return false;
}
PARSER_CHECK(parse_transaction_details(&buffer, &envelope->tx))
PARSER_CHECK(parse_transaction_details(&buffer, &envelope->tx_details.tx))
break;
default:
return false;
}

envelope->tx.operation_position = buffer.offset;
envelope->tx_details.tx.operation_position = buffer.offset;
return true;
}

Expand All @@ -1335,11 +1387,64 @@ bool parse_transaction_operation(const uint8_t *data,
buffer_t buffer = {
.ptr = data,
.size = data_len,
.offset = envelope->tx.operation_position,
.offset = envelope->tx_details.tx.operation_position,
};
for (uint8_t i = 0; i <= operation_index; i++) {
PARSER_CHECK(parse_operation(&buffer, &envelope->tx.op_details));
PARSER_CHECK(parse_operation(&buffer, &envelope->tx_details.tx.op_details));
}
envelope->tx_details.tx.operation_index = operation_index;
return true;
}

bool parse_soroban_authorization_envelope(const uint8_t *data,
size_t data_len,
envelope_t *envelope) {
// PRINTF("parse_transaction_envelope: offset=%d\n", buffer->offset);
buffer_t buffer = {
.ptr = data,
.size = data_len,
.offset = 0,
};

explicit_bzero(&envelope->soroban_authorization, sizeof(soroban_authorization_t));

uint32_t envelope_type;
PARSER_CHECK(buffer_read32(&buffer, &envelope_type))
if (envelope_type != ENVELOPE_TYPE_SOROBAN_AUTHORIZATION) {
return false;
}
envelope->type = envelope_type;

PARSER_CHECK(parse_network(&buffer, &envelope->network))
PARSER_CHECK(buffer_read64(&buffer, &envelope->soroban_authorization.nonce))
PARSER_CHECK(
buffer_read32(&buffer, &envelope->soroban_authorization.signature_expiration_ledger))

// function
uint32_t type;
PARSER_CHECK(buffer_read32(&buffer, &type))
envelope->soroban_authorization.function_type = type;
switch (type) {
case SOROBAN_AUTHORIZED_FUNCTION_TYPE_CONTRACT_FN: {
// contractFn
PARSER_CHECK(
parse_invoke_contract_args(&buffer,
&envelope->soroban_authorization.invoke_contract_args));
break;
}
case SOROBAN_AUTHORIZED_FUNCTION_TYPE_CREATE_CONTRACT_HOST_FN:
// createContractHostFn
PARSER_CHECK(read_create_contract_args_advance(&buffer))
break;
default:
return false;
}

// subInvocations
uint32_t len;
PARSER_CHECK(buffer_read32(&buffer, &len))
for (uint32_t i = 0; i < len; i++) {
PARSER_CHECK(read_soroban_authorized_invocation_advance(&buffer))
}
envelope->tx.operation_index = operation_index;
return true;
}
Loading
Loading