From a3ad5b0315f114d04fc853d792c3915c5ad4a3b4 Mon Sep 17 00:00:00 2001 From: Richard Patel Date: Thu, 7 Aug 2025 15:56:37 +0000 Subject: [PATCH 1/4] solfuzz: remove compute budget program fuzzer No longer maintained / used --- src/flamenco/runtime/tests/Local.mk | 8 +- .../tests/harness/fd_exec_sol_compat.c | 33 ----- .../runtime/tests/harness/fd_pack_harness.c | 65 --------- .../runtime/tests/harness/fd_pack_harness.h | 18 --- .../runtime/tests/harness/generated/pack.pb.c | 18 --- .../runtime/tests/harness/generated/pack.pb.h | 123 ------------------ .../tests/harness/generated/pack_runtime.pb.c | 18 --- .../tests/harness/generated/pack_runtime.pb.h | 107 --------------- 8 files changed, 4 insertions(+), 386 deletions(-) delete mode 100644 src/flamenco/runtime/tests/harness/fd_pack_harness.c delete mode 100644 src/flamenco/runtime/tests/harness/fd_pack_harness.h delete mode 100644 src/flamenco/runtime/tests/harness/generated/pack.pb.c delete mode 100644 src/flamenco/runtime/tests/harness/generated/pack.pb.h delete mode 100644 src/flamenco/runtime/tests/harness/generated/pack_runtime.pb.c delete mode 100644 src/flamenco/runtime/tests/harness/generated/pack_runtime.pb.h diff --git a/src/flamenco/runtime/tests/Local.mk b/src/flamenco/runtime/tests/Local.mk index dbf3790284f..fe3be4522cb 100644 --- a/src/flamenco/runtime/tests/Local.mk +++ b/src/flamenco/runtime/tests/Local.mk @@ -1,10 +1,10 @@ -$(call add-hdrs,harness/generated/context.pb.h,harness/generated/elf.pb.h,harness/generated/invoke.pb.h,harness/generated/txn.pb.h,harness/generated/block.pb.h,harness/generated/vm.pb.h,harness/generated/type.pb.h,harness/generated/shred.pb.h harness/generated/metadata.pb.h harness/generated/pack.pb.h) -$(call add-objs,harness/generated/context.pb harness/generated/elf.pb harness/generated/invoke.pb harness/generated/txn.pb harness/generated/block.pb harness/generated/vm.pb harness/generated/type.pb harness/generated/shred.pb harness/generated/metadata.pb harness/generated/pack.pb,fd_flamenco) +$(call add-hdrs,harness/generated/context.pb.h,harness/generated/elf.pb.h,harness/generated/invoke.pb.h,harness/generated/txn.pb.h,harness/generated/block.pb.h,harness/generated/vm.pb.h,harness/generated/type.pb.h,harness/generated/shred.pb.h harness/generated/metadata.pb.h) +$(call add-objs,harness/generated/context.pb harness/generated/elf.pb harness/generated/invoke.pb harness/generated/txn.pb harness/generated/block.pb harness/generated/vm.pb harness/generated/type.pb harness/generated/shred.pb harness/generated/metadata.pb,fd_flamenco) ifdef FD_HAS_INT128 ifdef FD_HAS_SECP256K1 -$(call add-hdrs,harness/fd_elf_harness.h harness/fd_instr_harness.h harness/fd_txn_harness.h harness/fd_block_harness.h harness/fd_harness_common.h harness/fd_vm_harness.h harness/fd_pack_harness.h harness/fd_types_harness.h) -$(call add-objs,harness/fd_elf_harness harness/fd_instr_harness harness/fd_txn_harness harness/fd_block_harness harness/fd_harness_common harness/fd_vm_harness harness/fd_pack_harness harness/fd_types_harness,fd_flamenco_test) +$(call add-hdrs,harness/fd_elf_harness.h harness/fd_instr_harness.h harness/fd_txn_harness.h harness/fd_block_harness.h harness/fd_harness_common.h harness/fd_vm_harness.h harness/fd_types_harness.h) +$(call add-objs,harness/fd_elf_harness harness/fd_instr_harness harness/fd_txn_harness harness/fd_block_harness harness/fd_harness_common harness/fd_vm_harness harness/fd_types_harness,fd_flamenco_test) $(call add-objs,harness/fd_exec_sol_compat,fd_flamenco_test) SOL_COMPAT_FLAGS:=-Wl,--undefined=fd_types_vt_by_name diff --git a/src/flamenco/runtime/tests/harness/fd_exec_sol_compat.c b/src/flamenco/runtime/tests/harness/fd_exec_sol_compat.c index f06b647e341..e39a5481bce 100644 --- a/src/flamenco/runtime/tests/harness/fd_exec_sol_compat.c +++ b/src/flamenco/runtime/tests/harness/fd_exec_sol_compat.c @@ -14,7 +14,6 @@ #include "fd_block_harness.h" #include "fd_types_harness.h" #include "fd_vm_harness.h" -#include "fd_pack_harness.h" #include "fd_elf_harness.h" #include "generated/elf.pb.h" @@ -890,38 +889,6 @@ int sol_compat_shred_parse_v1( uchar * out, return !!sol_compat_encode( out, out_sz, output, &fd_exec_test_accepts_shred_t_msg ); } -int -sol_compat_pack_compute_budget_v1( uchar * out, - ulong * out_sz, - uchar const * in, - ulong in_sz ) { - fd_runtime_fuzz_runner_t * runner = sol_compat_setup_runner( ); - - fd_exec_test_pack_compute_budget_context_t input[1] = {0}; - void * res = sol_compat_decode( &input, in, in_sz, &fd_exec_test_pack_compute_budget_context_t_msg ); - if( res==NULL ) { - sol_compat_cleanup_runner( runner ); - return 0; - } - - int ok = 0; - FD_SPAD_FRAME_BEGIN( runner->spad ) { - void * output = NULL; - sol_compat_execute_wrapper( runner, input, &output, fd_runtime_fuzz_pack_cpb_run ); - - if( output ) { - ok = !!sol_compat_encode( out, out_sz, output, &fd_exec_test_pack_compute_budget_effects_t_msg ); - } - } FD_SPAD_FRAME_END; - - pb_release( &fd_exec_test_pack_compute_budget_context_t_msg, input ); - sol_compat_cleanup_runner( runner ); - - // Check wksp usage is 0 - sol_compat_check_wksp_usage(); - return ok; -} - int sol_compat_type_execute_v1( uchar * out, ulong * out_sz, diff --git a/src/flamenco/runtime/tests/harness/fd_pack_harness.c b/src/flamenco/runtime/tests/harness/fd_pack_harness.c deleted file mode 100644 index e9dcf602a8f..00000000000 --- a/src/flamenco/runtime/tests/harness/fd_pack_harness.c +++ /dev/null @@ -1,65 +0,0 @@ -#include "fd_pack_harness.h" -#include "../../../../disco/pack/fd_compute_budget_program.h" - -ulong -fd_runtime_fuzz_pack_cpb_run( fd_runtime_fuzz_runner_t * _unused FD_PARAM_UNUSED, - void const * input_, - void ** output_, - void * output_buf, - ulong output_bufsz ){ - fd_exec_test_pack_compute_budget_context_t const * input = fd_type_pun_const( input_ ); - fd_exec_test_pack_compute_budget_effects_t ** output = fd_type_pun( output_ ); - - ulong output_end = (ulong) output_buf + output_bufsz; - FD_SCRATCH_ALLOC_INIT( l, output_buf ); - - fd_exec_test_pack_compute_budget_effects_t * effects = - FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_exec_test_pack_compute_budget_effects_t), - sizeof (fd_exec_test_pack_compute_budget_effects_t) ); - if( FD_UNLIKELY( _l > output_end ) ) { - return 0UL; - } - *effects = (fd_exec_test_pack_compute_budget_effects_t) FD_EXEC_TEST_PACK_COMPUTE_BUDGET_EFFECTS_INIT_ZERO; - - fd_compute_budget_program_state_t cbp_state[1]; - fd_compute_budget_program_init( cbp_state ); -do { - - int ok = 1; - for( ulong i=0UL; iinstr_datas_count; ++i ){ - pb_bytes_array_t * instr_data = input->instr_datas[i]; - // Reject if any of the instructions fail to parse - if( !fd_compute_budget_program_parse( instr_data->bytes, instr_data->size, cbp_state ) ) { - ok = 0; - break; - }; - } - - if( !ok ) { - effects->is_empty = 1; - break; - } - ulong rewards; - uint compute_unit_limit; - ulong loaded_accounts_data_cost = 0UL; - fd_compute_budget_program_finalize( cbp_state, - input->instr_datas_count, - &rewards, - &compute_unit_limit, - &loaded_accounts_data_cost ); - effects->rewards = rewards; - effects->compute_unit_limit = compute_unit_limit; - - /* If not set, use defaults. See: - https://github.com/firedancer-io/firedancer/blob/688cb04408cf20b0600d900900cdbebebd181e5b/src/ballet/pack/fd_compute_budget_program.h#L64-L70 - https://github.com/firedancer-io/agave/blob/838c1952595809a31520ff1603a13f2c9123aa51/runtime-transaction/src/compute_budget_instruction_details.rs#L49-L101 - */ - effects->heap_sz = !!( cbp_state->flags & FD_COMPUTE_BUDGET_PROGRAM_FLAG_SET_HEAP ) ? cbp_state->heap_size : FD_VM_HEAP_DEFAULT; - effects->loaded_acct_data_sz = !!( cbp_state->flags & FD_COMPUTE_BUDGET_PROGRAM_FLAG_SET_LOADED_DATA_SZ ) ? cbp_state->loaded_acct_data_sz : FD_COMPUTE_BUDGET_MAX_LOADED_DATA_SZ; -} while(0); - - ulong actual_end = FD_SCRATCH_ALLOC_FINI( l, 1UL ); - - *output = effects; - return actual_end - (ulong) output_buf; -} diff --git a/src/flamenco/runtime/tests/harness/fd_pack_harness.h b/src/flamenco/runtime/tests/harness/fd_pack_harness.h deleted file mode 100644 index 4dc61e50976..00000000000 --- a/src/flamenco/runtime/tests/harness/fd_pack_harness.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef HEADER_fd_src_flamenco_runtime_tests_fd_pack_harness_h -#define HEADER_fd_src_flamenco_runtime_tests_fd_pack_harness_h - -#include "fd_instr_harness.h" -#include "generated/pack.pb.h" - -FD_PROTOTYPES_BEGIN - -ulong -fd_runtime_fuzz_pack_cpb_run( fd_runtime_fuzz_runner_t * _unused , /* fd_runtime_fuzz_runner_t */ - void const * input_, - void ** output_, - void * output_buf, - ulong output_bufsz ); - -FD_PROTOTYPES_END - -#endif /* HEADER_fd_src_flamenco_runtime_tests_fd_pack_harness_h */ diff --git a/src/flamenco/runtime/tests/harness/generated/pack.pb.c b/src/flamenco/runtime/tests/harness/generated/pack.pb.c deleted file mode 100644 index 18071411b00..00000000000 --- a/src/flamenco/runtime/tests/harness/generated/pack.pb.c +++ /dev/null @@ -1,18 +0,0 @@ -/* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.4.9.1 */ - -#include "pack.pb.h" -#if PB_PROTO_HEADER_VERSION != 40 -#error Regenerate this file with the current version of nanopb generator. -#endif - -PB_BIND(FD_EXEC_TEST_PACK_COMPUTE_BUDGET_CONTEXT, fd_exec_test_pack_compute_budget_context_t, AUTO) - - -PB_BIND(FD_EXEC_TEST_PACK_COMPUTE_BUDGET_EFFECTS, fd_exec_test_pack_compute_budget_effects_t, AUTO) - - -PB_BIND(FD_EXEC_TEST_PACK_COMPUTE_BUDGET_FIXTURE, fd_exec_test_pack_compute_budget_fixture_t, AUTO) - - - diff --git a/src/flamenco/runtime/tests/harness/generated/pack.pb.h b/src/flamenco/runtime/tests/harness/generated/pack.pb.h deleted file mode 100644 index 85cb1a1e819..00000000000 --- a/src/flamenco/runtime/tests/harness/generated/pack.pb.h +++ /dev/null @@ -1,123 +0,0 @@ -/* Automatically generated nanopb header */ -/* Generated by nanopb-0.4.9.1 */ - -#ifndef PB_ORG_SOLANA_SEALEVEL_V1_PACK_PB_H_INCLUDED -#define PB_ORG_SOLANA_SEALEVEL_V1_PACK_PB_H_INCLUDED - -#include "../../../../../ballet/nanopb/pb_firedancer.h" -#include "metadata.pb.h" -#include "context.pb.h" - -#if PB_PROTO_HEADER_VERSION != 40 -#error Regenerate this file with the current version of nanopb generator. -#endif - -/* Struct definitions */ -typedef struct fd_exec_test_pack_compute_budget_context { - pb_size_t instr_datas_count; - pb_bytes_array_t **instr_datas; - bool has_features; - fd_exec_test_feature_set_t features; -} fd_exec_test_pack_compute_budget_context_t; - -typedef struct fd_exec_test_pack_compute_budget_effects { - uint64_t compute_unit_limit; - uint64_t rewards; - uint32_t heap_sz; - uint32_t loaded_acct_data_sz; - /* To prevent empty effects when encoding a "skipped" effects */ - uint32_t is_empty; -} fd_exec_test_pack_compute_budget_effects_t; - -typedef struct fd_exec_test_pack_compute_budget_fixture { - bool has_metadata; - fd_exec_test_fixture_metadata_t metadata; - bool has_input; - fd_exec_test_pack_compute_budget_context_t input; - bool has_output; - fd_exec_test_pack_compute_budget_effects_t output; -} fd_exec_test_pack_compute_budget_fixture_t; - - -#ifdef __cplusplus -extern "C" { -#endif - -/* Initializer values for message structs */ -#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_CONTEXT_INIT_DEFAULT {0, NULL, false, FD_EXEC_TEST_FEATURE_SET_INIT_DEFAULT} -#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_EFFECTS_INIT_DEFAULT {0, 0, 0, 0, 0} -#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_FIXTURE_INIT_DEFAULT {false, FD_EXEC_TEST_FIXTURE_METADATA_INIT_DEFAULT, false, FD_EXEC_TEST_PACK_COMPUTE_BUDGET_CONTEXT_INIT_DEFAULT, false, FD_EXEC_TEST_PACK_COMPUTE_BUDGET_EFFECTS_INIT_DEFAULT} -#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_CONTEXT_INIT_ZERO {0, NULL, false, FD_EXEC_TEST_FEATURE_SET_INIT_ZERO} -#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_EFFECTS_INIT_ZERO {0, 0, 0, 0, 0} -#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_FIXTURE_INIT_ZERO {false, FD_EXEC_TEST_FIXTURE_METADATA_INIT_ZERO, false, FD_EXEC_TEST_PACK_COMPUTE_BUDGET_CONTEXT_INIT_ZERO, false, FD_EXEC_TEST_PACK_COMPUTE_BUDGET_EFFECTS_INIT_ZERO} - -/* Field tags (for use in manual encoding/decoding) */ -#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_CONTEXT_INSTR_DATAS_TAG 1 -#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_CONTEXT_FEATURES_TAG 2 -#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_EFFECTS_COMPUTE_UNIT_LIMIT_TAG 1 -#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_EFFECTS_REWARDS_TAG 2 -#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_EFFECTS_HEAP_SZ_TAG 3 -#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_EFFECTS_LOADED_ACCT_DATA_SZ_TAG 4 -#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_EFFECTS_IS_EMPTY_TAG 5 -#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_FIXTURE_METADATA_TAG 1 -#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_FIXTURE_INPUT_TAG 2 -#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_FIXTURE_OUTPUT_TAG 3 - -/* Struct field encoding specification for nanopb */ -#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_CONTEXT_FIELDLIST(X, a) \ -X(a, POINTER, REPEATED, BYTES, instr_datas, 1) \ -X(a, STATIC, OPTIONAL, MESSAGE, features, 2) -#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_CONTEXT_CALLBACK NULL -#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_CONTEXT_DEFAULT NULL -#define fd_exec_test_pack_compute_budget_context_t_features_MSGTYPE fd_exec_test_feature_set_t - -#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_EFFECTS_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, UINT64, compute_unit_limit, 1) \ -X(a, STATIC, SINGULAR, UINT64, rewards, 2) \ -X(a, STATIC, SINGULAR, UINT32, heap_sz, 3) \ -X(a, STATIC, SINGULAR, UINT32, loaded_acct_data_sz, 4) \ -X(a, STATIC, SINGULAR, UINT32, is_empty, 5) -#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_EFFECTS_CALLBACK NULL -#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_EFFECTS_DEFAULT NULL - -#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_FIXTURE_FIELDLIST(X, a) \ -X(a, STATIC, OPTIONAL, MESSAGE, metadata, 1) \ -X(a, STATIC, OPTIONAL, MESSAGE, input, 2) \ -X(a, STATIC, OPTIONAL, MESSAGE, output, 3) -#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_FIXTURE_CALLBACK NULL -#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_FIXTURE_DEFAULT NULL -#define fd_exec_test_pack_compute_budget_fixture_t_metadata_MSGTYPE fd_exec_test_fixture_metadata_t -#define fd_exec_test_pack_compute_budget_fixture_t_input_MSGTYPE fd_exec_test_pack_compute_budget_context_t -#define fd_exec_test_pack_compute_budget_fixture_t_output_MSGTYPE fd_exec_test_pack_compute_budget_effects_t - -extern const pb_msgdesc_t fd_exec_test_pack_compute_budget_context_t_msg; -extern const pb_msgdesc_t fd_exec_test_pack_compute_budget_effects_t_msg; -extern const pb_msgdesc_t fd_exec_test_pack_compute_budget_fixture_t_msg; - -/* Defines for backwards compatibility with code written before nanopb-0.4.0 */ -#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_CONTEXT_FIELDS &fd_exec_test_pack_compute_budget_context_t_msg -#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_EFFECTS_FIELDS &fd_exec_test_pack_compute_budget_effects_t_msg -#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_FIXTURE_FIELDS &fd_exec_test_pack_compute_budget_fixture_t_msg - -/* Maximum encoded size of messages (where known) */ -/* fd_exec_test_PackComputeBudgetContext_size depends on runtime parameters */ -/* fd_exec_test_PackComputeBudgetFixture_size depends on runtime parameters */ -#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_EFFECTS_SIZE 40 -#define ORG_SOLANA_SEALEVEL_V1_PACK_PB_H_MAX_SIZE FD_EXEC_TEST_PACK_COMPUTE_BUDGET_EFFECTS_SIZE - -/* Mapping from canonical names (mangle_names or overridden package name) */ -#define org_solana_sealevel_v1_PackComputeBudgetContext fd_exec_test_PackComputeBudgetContext -#define org_solana_sealevel_v1_PackComputeBudgetEffects fd_exec_test_PackComputeBudgetEffects -#define org_solana_sealevel_v1_PackComputeBudgetFixture fd_exec_test_PackComputeBudgetFixture -#define ORG_SOLANA_SEALEVEL_V1_PACK_COMPUTE_BUDGET_CONTEXT_INIT_DEFAULT FD_EXEC_TEST_PACK_COMPUTE_BUDGET_CONTEXT_INIT_DEFAULT -#define ORG_SOLANA_SEALEVEL_V1_PACK_COMPUTE_BUDGET_EFFECTS_INIT_DEFAULT FD_EXEC_TEST_PACK_COMPUTE_BUDGET_EFFECTS_INIT_DEFAULT -#define ORG_SOLANA_SEALEVEL_V1_PACK_COMPUTE_BUDGET_FIXTURE_INIT_DEFAULT FD_EXEC_TEST_PACK_COMPUTE_BUDGET_FIXTURE_INIT_DEFAULT -#define ORG_SOLANA_SEALEVEL_V1_PACK_COMPUTE_BUDGET_CONTEXT_INIT_ZERO FD_EXEC_TEST_PACK_COMPUTE_BUDGET_CONTEXT_INIT_ZERO -#define ORG_SOLANA_SEALEVEL_V1_PACK_COMPUTE_BUDGET_EFFECTS_INIT_ZERO FD_EXEC_TEST_PACK_COMPUTE_BUDGET_EFFECTS_INIT_ZERO -#define ORG_SOLANA_SEALEVEL_V1_PACK_COMPUTE_BUDGET_FIXTURE_INIT_ZERO FD_EXEC_TEST_PACK_COMPUTE_BUDGET_FIXTURE_INIT_ZERO - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif diff --git a/src/flamenco/runtime/tests/harness/generated/pack_runtime.pb.c b/src/flamenco/runtime/tests/harness/generated/pack_runtime.pb.c deleted file mode 100644 index f3e72ff3d4d..00000000000 --- a/src/flamenco/runtime/tests/harness/generated/pack_runtime.pb.c +++ /dev/null @@ -1,18 +0,0 @@ -/* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.4.8-dev */ - -#include "pack_runtime.pb.h" -#if PB_PROTO_HEADER_VERSION != 40 -#error Regenerate this file with the current version of nanopb generator. -#endif - -PB_BIND(FD_EXEC_TEST_PACK_COMPUTE_BUDGET_CONTEXT, fd_exec_test_pack_compute_budget_context_t, AUTO) - - -PB_BIND(FD_EXEC_TEST_PACK_COMPUTE_BUDGET_EFFECTS, fd_exec_test_pack_compute_budget_effects_t, AUTO) - - -PB_BIND(FD_EXEC_TEST_PACK_COMPUTE_BUDGET_FIXTURE, fd_exec_test_pack_compute_budget_fixture_t, AUTO) - - - diff --git a/src/flamenco/runtime/tests/harness/generated/pack_runtime.pb.h b/src/flamenco/runtime/tests/harness/generated/pack_runtime.pb.h deleted file mode 100644 index 83875bdbecf..00000000000 --- a/src/flamenco/runtime/tests/harness/generated/pack_runtime.pb.h +++ /dev/null @@ -1,107 +0,0 @@ -/* Automatically generated nanopb header */ -/* Generated by nanopb-0.4.8-dev */ - -#ifndef PB_ORG_SOLANA_SEALEVEL_V1_PACK_RUNTIME_PB_H_INCLUDED -#define PB_ORG_SOLANA_SEALEVEL_V1_PACK_RUNTIME_PB_H_INCLUDED - -#include "../../../../ballet/pb_firedancer.h" -#include "metadata.pb.h" - -#if PB_PROTO_HEADER_VERSION != 40 -#error Regenerate this file with the current version of nanopb generator. -#endif - -/* Struct definitions */ -typedef struct fd_exec_test_pack_compute_budget_context { - pb_size_t instr_datas_count; - pb_bytes_array_t **instr_datas; -} fd_exec_test_pack_compute_budget_context_t; - -typedef struct fd_exec_test_pack_compute_budget_effects { - uint64_t compute_unit_limit; - uint64_t rewards; -} fd_exec_test_pack_compute_budget_effects_t; - -typedef struct fd_exec_test_pack_compute_budget_fixture { - bool has_metadata; - fd_exec_test_fixture_metadata_t metadata; - bool has_input; - fd_exec_test_pack_compute_budget_context_t input; - bool has_output; - fd_exec_test_pack_compute_budget_effects_t output; -} fd_exec_test_pack_compute_budget_fixture_t; - - -#ifdef __cplusplus -extern "C" { -#endif - -/* Initializer values for message structs */ -#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_CONTEXT_INIT_DEFAULT {0, NULL} -#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_EFFECTS_INIT_DEFAULT {0, 0} -#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_FIXTURE_INIT_DEFAULT {false, FD_EXEC_TEST_FIXTURE_METADATA_INIT_DEFAULT, false, FD_EXEC_TEST_PACK_COMPUTE_BUDGET_CONTEXT_INIT_DEFAULT, false, FD_EXEC_TEST_PACK_COMPUTE_BUDGET_EFFECTS_INIT_DEFAULT} -#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_CONTEXT_INIT_ZERO {0, NULL} -#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_EFFECTS_INIT_ZERO {0, 0} -#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_FIXTURE_INIT_ZERO {false, FD_EXEC_TEST_FIXTURE_METADATA_INIT_ZERO, false, FD_EXEC_TEST_PACK_COMPUTE_BUDGET_CONTEXT_INIT_ZERO, false, FD_EXEC_TEST_PACK_COMPUTE_BUDGET_EFFECTS_INIT_ZERO} - -/* Field tags (for use in manual encoding/decoding) */ -#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_CONTEXT_INSTR_DATAS_TAG 1 -#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_EFFECTS_COMPUTE_UNIT_LIMIT_TAG 1 -#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_EFFECTS_REWARDS_TAG 2 -#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_FIXTURE_METADATA_TAG 1 -#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_FIXTURE_INPUT_TAG 2 -#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_FIXTURE_OUTPUT_TAG 3 - -/* Struct field encoding specification for nanopb */ -#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_CONTEXT_FIELDLIST(X, a) \ -X(a, POINTER, REPEATED, BYTES, instr_datas, 1) -#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_CONTEXT_CALLBACK NULL -#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_CONTEXT_DEFAULT NULL - -#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_EFFECTS_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, UINT64, compute_unit_limit, 1) \ -X(a, STATIC, SINGULAR, UINT64, rewards, 2) -#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_EFFECTS_CALLBACK NULL -#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_EFFECTS_DEFAULT NULL - -#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_FIXTURE_FIELDLIST(X, a) \ -X(a, STATIC, OPTIONAL, MESSAGE, metadata, 1) \ -X(a, STATIC, OPTIONAL, MESSAGE, input, 2) \ -X(a, STATIC, OPTIONAL, MESSAGE, output, 3) -#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_FIXTURE_CALLBACK NULL -#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_FIXTURE_DEFAULT NULL -#define fd_exec_test_pack_compute_budget_fixture_t_metadata_MSGTYPE fd_exec_test_fixture_metadata_t -#define fd_exec_test_pack_compute_budget_fixture_t_input_MSGTYPE fd_exec_test_pack_compute_budget_context_t -#define fd_exec_test_pack_compute_budget_fixture_t_output_MSGTYPE fd_exec_test_pack_compute_budget_effects_t - -extern const pb_msgdesc_t fd_exec_test_pack_compute_budget_context_t_msg; -extern const pb_msgdesc_t fd_exec_test_pack_compute_budget_effects_t_msg; -extern const pb_msgdesc_t fd_exec_test_pack_compute_budget_fixture_t_msg; - -/* Defines for backwards compatibility with code written before nanopb-0.4.0 */ -#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_CONTEXT_FIELDS &fd_exec_test_pack_compute_budget_context_t_msg -#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_EFFECTS_FIELDS &fd_exec_test_pack_compute_budget_effects_t_msg -#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_FIXTURE_FIELDS &fd_exec_test_pack_compute_budget_fixture_t_msg - -/* Maximum encoded size of messages (where known) */ -/* fd_exec_test_PackComputeBudgetContext_size depends on runtime parameters */ -/* fd_exec_test_PackComputeBudgetFixture_size depends on runtime parameters */ -#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_EFFECTS_SIZE 22 -#define ORG_SOLANA_SEALEVEL_V1_PACK_RUNTIME_PB_H_MAX_SIZE FD_EXEC_TEST_PACK_COMPUTE_BUDGET_EFFECTS_SIZE - -/* Mapping from canonical names (mangle_names or overridden package name) */ -#define org_solana_sealevel_v1_PackComputeBudgetContext fd_exec_test_PackComputeBudgetContext -#define org_solana_sealevel_v1_PackComputeBudgetEffects fd_exec_test_PackComputeBudgetEffects -#define org_solana_sealevel_v1_PackComputeBudgetFixture fd_exec_test_PackComputeBudgetFixture -#define ORG_SOLANA_SEALEVEL_V1_PACK_COMPUTE_BUDGET_CONTEXT_INIT_DEFAULT FD_EXEC_TEST_PACK_COMPUTE_BUDGET_CONTEXT_INIT_DEFAULT -#define ORG_SOLANA_SEALEVEL_V1_PACK_COMPUTE_BUDGET_EFFECTS_INIT_DEFAULT FD_EXEC_TEST_PACK_COMPUTE_BUDGET_EFFECTS_INIT_DEFAULT -#define ORG_SOLANA_SEALEVEL_V1_PACK_COMPUTE_BUDGET_FIXTURE_INIT_DEFAULT FD_EXEC_TEST_PACK_COMPUTE_BUDGET_FIXTURE_INIT_DEFAULT -#define ORG_SOLANA_SEALEVEL_V1_PACK_COMPUTE_BUDGET_CONTEXT_INIT_ZERO FD_EXEC_TEST_PACK_COMPUTE_BUDGET_CONTEXT_INIT_ZERO -#define ORG_SOLANA_SEALEVEL_V1_PACK_COMPUTE_BUDGET_EFFECTS_INIT_ZERO FD_EXEC_TEST_PACK_COMPUTE_BUDGET_EFFECTS_INIT_ZERO -#define ORG_SOLANA_SEALEVEL_V1_PACK_COMPUTE_BUDGET_FIXTURE_INIT_ZERO FD_EXEC_TEST_PACK_COMPUTE_BUDGET_FIXTURE_INIT_ZERO - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif From a147928e9e1b52fa3b93dbcf391abd8abd46d5ed Mon Sep 17 00:00:00 2001 From: Richard Patel Date: Thu, 7 Aug 2025 18:04:16 +0000 Subject: [PATCH 2/4] solfuzz: belt sanding - Flatten directory structure - Add venv to gitignore - Define and document separation of layers - Centralize memory management of 'solfuzz executor' - Use demand-paged THP workspace memory for solfuzz (Greatly reduces startup time with minimal prod perf impact) - Allow reusing a preallocated workspace for run-test-vectors --- contrib/test/run_test_vectors.sh | 45 +- src/flamenco/capture/fd_solcap_writer.h | 1 - src/flamenco/fd_flamenco_base.h | 3 + src/flamenco/runtime/context/fd_capture_ctx.h | 1 + src/flamenco/runtime/fd_executor.h | 2 - src/flamenco/runtime/test_txn_rw_conflicts.c | 2 - src/flamenco/runtime/tests/.gitignore | 1 + src/flamenco/runtime/tests/Local.mk | 25 +- src/flamenco/runtime/tests/Makefile | 4 - src/flamenco/runtime/tests/README.md | 46 + .../tests/{harness => }/fd_block_harness.c | 42 +- src/flamenco/runtime/tests/fd_dump_pb.c | 10 +- src/flamenco/runtime/tests/fd_dump_pb.h | 4 +- .../tests/{harness => }/fd_elf_harness.c | 15 +- .../tests/{harness => }/fd_harness_common.c | 74 +- .../tests/{harness => }/fd_instr_harness.c | 38 +- src/flamenco/runtime/tests/fd_instr_harness.h | 33 + src/flamenco/runtime/tests/fd_sol_compat.c | 354 +++++++ src/flamenco/runtime/tests/fd_sol_compat.h | 137 +++ src/flamenco/runtime/tests/fd_solfuzz.c | 126 +++ src/flamenco/runtime/tests/fd_solfuzz.h | 192 ++++ src/flamenco/runtime/tests/fd_solfuzz_exec.c | 396 ++++++++ .../runtime/tests/fd_solfuzz_private.h | 92 ++ .../tests/{harness => }/fd_txn_harness.c | 60 +- src/flamenco/runtime/tests/fd_txn_harness.h | 30 + .../tests/{harness => }/fd_types_harness.c | 28 +- .../tests/{harness => }/fd_vm_harness.c | 30 +- .../runtime/tests/fetch_and_generate.sh | 2 +- .../tests/{harness => }/generated/block.pb.c | 0 .../tests/{harness => }/generated/block.pb.h | 2 +- .../{harness => }/generated/context.pb.c | 0 .../{harness => }/generated/context.pb.h | 2 +- .../tests/{harness => }/generated/elf.pb.c | 0 .../tests/{harness => }/generated/elf.pb.h | 2 +- .../tests/{harness => }/generated/invoke.pb.c | 0 .../tests/{harness => }/generated/invoke.pb.h | 2 +- .../{harness => }/generated/metadata.pb.c | 0 .../{harness => }/generated/metadata.pb.h | 2 +- .../runtime/tests/generated/pack.pb.c | 18 + .../runtime/tests/generated/pack.pb.h | 123 +++ .../{harness => }/generated/serialize.pb.c | 0 .../{harness => }/generated/serialize.pb.h | 0 .../tests/{harness => }/generated/shred.pb.c | 0 .../tests/{harness => }/generated/shred.pb.h | 2 +- .../tests/{harness => }/generated/txn.pb.c | 0 .../tests/{harness => }/generated/txn.pb.h | 2 +- .../tests/{harness => }/generated/type.pb.c | 0 .../tests/{harness => }/generated/type.pb.h | 13 +- .../tests/{harness => }/generated/vm.pb.c | 0 .../tests/{harness => }/generated/vm.pb.h | 2 +- .../runtime/tests/harness/fd_block_harness.h | 35 - .../runtime/tests/harness/fd_elf_harness.h | 30 - .../tests/harness/fd_exec_sol_compat.c | 924 ------------------ .../tests/harness/fd_exec_sol_compat.h | 58 -- .../runtime/tests/harness/fd_harness_common.h | 83 -- .../runtime/tests/harness/fd_instr_harness.h | 72 -- .../runtime/tests/harness/fd_txn_harness.h | 73 -- .../runtime/tests/harness/fd_types_harness.h | 17 - .../runtime/tests/harness/fd_vm_harness.h | 37 - ...st_exec_sol_compat.c => test_sol_compat.c} | 63 +- src/flamenco/vm/fd_vm_interp.c | 1 + src/flamenco/vm/fd_vm_private.h | 1 - src/flamenco/vm/fd_vm_tool.c | 2 +- src/util/shmem/fd_shmem.h | 2 +- 64 files changed, 1797 insertions(+), 1564 deletions(-) create mode 100644 src/flamenco/runtime/tests/.gitignore delete mode 100644 src/flamenco/runtime/tests/Makefile create mode 100644 src/flamenco/runtime/tests/README.md rename src/flamenco/runtime/tests/{harness => }/fd_block_harness.c (95%) rename src/flamenco/runtime/tests/{harness => }/fd_elf_harness.c (87%) rename src/flamenco/runtime/tests/{harness => }/fd_harness_common.c (54%) rename src/flamenco/runtime/tests/{harness => }/fd_instr_harness.c (95%) create mode 100644 src/flamenco/runtime/tests/fd_instr_harness.h create mode 100644 src/flamenco/runtime/tests/fd_sol_compat.c create mode 100644 src/flamenco/runtime/tests/fd_sol_compat.h create mode 100644 src/flamenco/runtime/tests/fd_solfuzz.c create mode 100644 src/flamenco/runtime/tests/fd_solfuzz.h create mode 100644 src/flamenco/runtime/tests/fd_solfuzz_exec.c create mode 100644 src/flamenco/runtime/tests/fd_solfuzz_private.h rename src/flamenco/runtime/tests/{harness => }/fd_txn_harness.c (90%) create mode 100644 src/flamenco/runtime/tests/fd_txn_harness.h rename src/flamenco/runtime/tests/{harness => }/fd_types_harness.c (92%) rename src/flamenco/runtime/tests/{harness => }/fd_vm_harness.c (96%) rename src/flamenco/runtime/tests/{harness => }/generated/block.pb.c (100%) rename src/flamenco/runtime/tests/{harness => }/generated/block.pb.h (99%) rename src/flamenco/runtime/tests/{harness => }/generated/context.pb.c (100%) rename src/flamenco/runtime/tests/{harness => }/generated/context.pb.h (99%) rename src/flamenco/runtime/tests/{harness => }/generated/elf.pb.c (100%) rename src/flamenco/runtime/tests/{harness => }/generated/elf.pb.h (99%) rename src/flamenco/runtime/tests/{harness => }/generated/invoke.pb.c (100%) rename src/flamenco/runtime/tests/{harness => }/generated/invoke.pb.h (99%) rename src/flamenco/runtime/tests/{harness => }/generated/metadata.pb.c (100%) rename src/flamenco/runtime/tests/{harness => }/generated/metadata.pb.h (97%) create mode 100644 src/flamenco/runtime/tests/generated/pack.pb.c create mode 100644 src/flamenco/runtime/tests/generated/pack.pb.h rename src/flamenco/runtime/tests/{harness => }/generated/serialize.pb.c (100%) rename src/flamenco/runtime/tests/{harness => }/generated/serialize.pb.h (100%) rename src/flamenco/runtime/tests/{harness => }/generated/shred.pb.c (100%) rename src/flamenco/runtime/tests/{harness => }/generated/shred.pb.h (99%) rename src/flamenco/runtime/tests/{harness => }/generated/txn.pb.c (100%) rename src/flamenco/runtime/tests/{harness => }/generated/txn.pb.h (99%) rename src/flamenco/runtime/tests/{harness => }/generated/type.pb.c (100%) rename src/flamenco/runtime/tests/{harness => }/generated/type.pb.h (90%) rename src/flamenco/runtime/tests/{harness => }/generated/vm.pb.c (100%) rename src/flamenco/runtime/tests/{harness => }/generated/vm.pb.h (99%) delete mode 100644 src/flamenco/runtime/tests/harness/fd_block_harness.h delete mode 100644 src/flamenco/runtime/tests/harness/fd_elf_harness.h delete mode 100644 src/flamenco/runtime/tests/harness/fd_exec_sol_compat.c delete mode 100644 src/flamenco/runtime/tests/harness/fd_exec_sol_compat.h delete mode 100644 src/flamenco/runtime/tests/harness/fd_harness_common.h delete mode 100644 src/flamenco/runtime/tests/harness/fd_instr_harness.h delete mode 100644 src/flamenco/runtime/tests/harness/fd_txn_harness.h delete mode 100644 src/flamenco/runtime/tests/harness/fd_types_harness.h delete mode 100644 src/flamenco/runtime/tests/harness/fd_vm_harness.h rename src/flamenco/runtime/tests/{test_exec_sol_compat.c => test_sol_compat.c} (51%) diff --git a/contrib/test/run_test_vectors.sh b/contrib/test/run_test_vectors.sh index 2c92fadae57..c140b2fdf47 100755 --- a/contrib/test/run_test_vectors.sh +++ b/contrib/test/run_test_vectors.sh @@ -1,5 +1,8 @@ #!/bin/bash +# FIXME This whole file should just really be a firedancer-dev +# invocation with parallelism natively implemented in C. + set -ex DIR="$( dirname -- "${BASH_SOURCE[0]}"; )"; # Get the directory name @@ -8,6 +11,8 @@ cd $DIR/../.. OBJDIR=${OBJDIR:-build/native/gcc} NUM_PROCESSES=${NUM_PROCESSES:-12} +PAGE_SZ=gigantic +PAGE_CNT=$(( 6 * $NUM_PROCESSES )) if [ "$LOG_PATH" == "" ]; then LOG_PATH="`mktemp -d`" @@ -30,27 +35,39 @@ else cd dump/test-vectors fi -git fetch -q --depth=1 origin $GIT_REF -git checkout -q $GIT_REF +if ! git checkout -q $GIT_REF; then + git fetch -q --depth=1 origin $GIT_REF + git checkout -q FETCH_HEAD +fi cd ../.. -LOG=$LOG_PATH/test_exec_block -find dump/test-vectors/block/fixtures/* -type f -name '*.fix' | xargs -P $NUM_PROCESSES -n 1000 ./$OBJDIR/unit-test/test_exec_sol_compat --log-path $LOG --wksp-page-sz 1073741824 +WKSP=run-test-vectors +# If workspace already exists, reset it (and hope that it has the correct size) +if ./$OBJDIR/bin/fd_wksp_ctl query $WKSP --log-path '' >/dev/null 2>/dev/null; then + ./$OBJDIR/bin/fd_wksp_ctl reset $WKSP --log-path '' +else + ./$OBJDIR/bin/fd_wksp_ctl new run-test-vectors $PAGE_CNT $PAGE_SZ 0 0644 --log-path '' +fi + +SOL_COMPAT=( "$OBJDIR/unit-test/test_sol_compat" "--wksp" "$WKSP" ) + +export FD_LOG_PATH=$LOG_PATH/test_exec_block +find dump/test-vectors/block/fixtures -type f -name '*.fix' | xargs -P $NUM_PROCESSES -n 1000 ${SOL_COMPAT[@]} -LOG=$LOG_PATH/test_exec_syscall -find dump/test-vectors/syscall/fixtures/* -type f -name '*.fix' | xargs -P $NUM_PROCESSES -n 1000 ./$OBJDIR/unit-test/test_exec_sol_compat --log-path $LOG --wksp-page-sz 1073741824 +export FD_LOG_PATH=$LOG_PATH/test_exec_syscall +find dump/test-vectors/syscall/fixtures -type f -name '*.fix' | xargs -P $NUM_PROCESSES -n 1000 ${SOL_COMPAT[@]} -LOG=$LOG_PATH/test_exec_interp -find dump/test-vectors/vm_interp/fixtures/* -type f -name '*.fix' | xargs -P $NUM_PROCESSES -n 1000 ./$OBJDIR/unit-test/test_exec_sol_compat --log-path $LOG --wksp-page-sz 1073741824 +export FD_LOG_PATH=$LOG_PATH/test_exec_interp +find dump/test-vectors/vm_interp/fixtures -type f -name '*.fix' | xargs -P $NUM_PROCESSES -n 1000 ${SOL_COMPAT[@]} -LOG=$LOG_PATH/test_exec_txn -find dump/test-vectors/txn/fixtures/* -type f -name '*.fix' | xargs -P $NUM_PROCESSES ./$OBJDIR/unit-test/test_exec_sol_compat --log-path $LOG --wksp-page-sz 1073741824 +export FD_LOG_PATH=$LOG_PATH/test_exec_txn +find dump/test-vectors/txn/fixtures -type f -name '*.fix' | xargs -P $NUM_PROCESSES ${SOL_COMPAT[@]} zstd -df dump/test-vectors/elf_loader/fixtures/*.zst -LOG=$LOG_PATH/test_elf_loader -find dump/test-vectors/elf_loader/fixtures/* -type f -name '*.fix' | xargs -P $NUM_PROCESSES -n 1000 ./$OBJDIR/unit-test/test_exec_sol_compat --log-path $LOG --wksp-page-sz 1073741824 +export FD_LOG_PATH=$LOG_PATH/test_elf_loader +find dump/test-vectors/elf_loader/fixtures -type f -name '*.fix' | xargs -P $NUM_PROCESSES -n 1000 ${SOL_COMPAT[@]} -LOG=$LOG_PATH/test_exec_instr -find dump/test-vectors/instr/fixtures/* -type f -name '*.fix' | xargs -P $NUM_PROCESSES -n 1000 ./$OBJDIR/unit-test/test_exec_sol_compat --log-path $LOG --wksp-page-sz 1073741824 +export FD_LOG_PATH=$LOG_PATH/test_exec_instr +find dump/test-vectors/instr/fixtures -type f -name '*.fix' | xargs -P $NUM_PROCESSES -n 1000 ${SOL_COMPAT[@]} echo Test vectors success diff --git a/src/flamenco/capture/fd_solcap_writer.h b/src/flamenco/capture/fd_solcap_writer.h index 190ac969baf..ca807e54835 100644 --- a/src/flamenco/capture/fd_solcap_writer.h +++ b/src/flamenco/capture/fd_solcap_writer.h @@ -4,7 +4,6 @@ #include "fd_solcap_proto.h" #include "fd_solcap.pb.h" #include "../types/fd_types.h" -#include "../runtime/fd_runtime_public.h" /* fd_solcap_writer_t is an opaque handle to a capture writer object. Currently, it implements writing SOLCAP_V1_BANK files. See below diff --git a/src/flamenco/fd_flamenco_base.h b/src/flamenco/fd_flamenco_base.h index 0b1f1bb50f6..ccfd1ffee8f 100644 --- a/src/flamenco/fd_flamenco_base.h +++ b/src/flamenco/fd_flamenco_base.h @@ -75,6 +75,9 @@ fd_base58_enc_64_fmt( char * out, struct fd_bank; typedef struct fd_bank fd_bank_t; +struct fd_banks; +typedef struct fd_banks fd_banks_t; + struct fd_exec_slot_ctx; typedef struct fd_exec_slot_ctx fd_exec_slot_ctx_t; diff --git a/src/flamenco/runtime/context/fd_capture_ctx.h b/src/flamenco/runtime/context/fd_capture_ctx.h index 282caf06362..d2ed7950a6f 100644 --- a/src/flamenco/runtime/context/fd_capture_ctx.h +++ b/src/flamenco/runtime/context/fd_capture_ctx.h @@ -2,6 +2,7 @@ #define HEADER_fd_src_flamenco_runtime_context_fd_capture_ctx_h #include "../../capture/fd_solcap_writer.h" +#include "../fd_runtime_public.h" /* FD_RUNTIME_PUBLIC_ACCOUNT_UPDATE_MSG_FOOTPRINT */ /* Maximum number of accounts that can be updated in a single transaction */ #define FD_CAPTURE_CTX_MAX_ACCOUNT_UPDATES (128UL) diff --git a/src/flamenco/runtime/fd_executor.h b/src/flamenco/runtime/fd_executor.h index e6b4bdba5d6..2a188a2a35b 100644 --- a/src/flamenco/runtime/fd_executor.h +++ b/src/flamenco/runtime/fd_executor.h @@ -10,8 +10,6 @@ #include "../../ballet/poh/fd_poh.h" #include "../types/fd_types_yaml.h" #include "../log_collector/fd_log_collector.h" -#include "tests/harness/generated/invoke.pb.h" -#include "tests/harness/generated/txn.pb.h" #include "../features/fd_features.h" #include "fd_runtime.h" diff --git a/src/flamenco/runtime/test_txn_rw_conflicts.c b/src/flamenco/runtime/test_txn_rw_conflicts.c index 097e991b58f..680ee2813a1 100644 --- a/src/flamenco/runtime/test_txn_rw_conflicts.c +++ b/src/flamenco/runtime/test_txn_rw_conflicts.c @@ -1,5 +1,3 @@ -#include "../../util/fd_util_base.h" -#include "../fd_flamenco_base.h" #include "fd_acc_mgr.h" #include "fd_runtime.h" #include "fd_runtime_err.h" diff --git a/src/flamenco/runtime/tests/.gitignore b/src/flamenco/runtime/tests/.gitignore new file mode 100644 index 00000000000..0de6fed1b6d --- /dev/null +++ b/src/flamenco/runtime/tests/.gitignore @@ -0,0 +1 @@ +nanopb_venv/ diff --git a/src/flamenco/runtime/tests/Local.mk b/src/flamenco/runtime/tests/Local.mk index fe3be4522cb..269a2da812f 100644 --- a/src/flamenco/runtime/tests/Local.mk +++ b/src/flamenco/runtime/tests/Local.mk @@ -1,18 +1,23 @@ -$(call add-hdrs,harness/generated/context.pb.h,harness/generated/elf.pb.h,harness/generated/invoke.pb.h,harness/generated/txn.pb.h,harness/generated/block.pb.h,harness/generated/vm.pb.h,harness/generated/type.pb.h,harness/generated/shred.pb.h harness/generated/metadata.pb.h) -$(call add-objs,harness/generated/context.pb harness/generated/elf.pb harness/generated/invoke.pb harness/generated/txn.pb harness/generated/block.pb harness/generated/vm.pb harness/generated/type.pb harness/generated/shred.pb harness/generated/metadata.pb,fd_flamenco) - ifdef FD_HAS_INT128 ifdef FD_HAS_SECP256K1 -$(call add-hdrs,harness/fd_elf_harness.h harness/fd_instr_harness.h harness/fd_txn_harness.h harness/fd_block_harness.h harness/fd_harness_common.h harness/fd_vm_harness.h harness/fd_types_harness.h) -$(call add-objs,harness/fd_elf_harness harness/fd_instr_harness harness/fd_txn_harness harness/fd_block_harness harness/fd_harness_common harness/fd_vm_harness harness/fd_types_harness,fd_flamenco_test) -$(call add-objs,harness/fd_exec_sol_compat,fd_flamenco_test) + +$(call add-hdrs,fd_solfuzz.h) +$(call add-objs,fd_solfuzz fd_solfuzz_exec,fd_flamenco_test) + +$(call add-hdrs,fd_instr_harness.h fd_txn_harness.h) +$(call add-objs,fd_elf_harness fd_instr_harness fd_txn_harness fd_block_harness fd_harness_common fd_vm_harness fd_types_harness,fd_flamenco_test) +$(call add-objs,fd_sol_compat,fd_flamenco_test) + +$(call add-hdrs,generated/context.pb.h,generated/elf.pb.h,generated/invoke.pb.h,generated/txn.pb.h,generated/block.pb.h,generated/vm.pb.h,generated/type.pb.h,generated/shred.pb.h generated/metadata.pb.h) +$(call add-objs,generated/context.pb generated/elf.pb generated/invoke.pb generated/txn.pb generated/block.pb generated/vm.pb generated/type.pb generated/shred.pb generated/metadata.pb,fd_flamenco) SOL_COMPAT_FLAGS:=-Wl,--undefined=fd_types_vt_by_name -$(call make-unit-test,test_exec_sol_compat,test_exec_sol_compat,fd_flamenco_test fd_flamenco fd_funk fd_ballet fd_util fd_disco,$(SECP256K1_LIBS)) -$(call make-shared,libfd_exec_sol_compat.so,harness/fd_exec_sol_compat,fd_flamenco_test fd_flamenco fd_funk fd_ballet fd_util fd_disco,$(SECP256K1_LIBS) $(SOL_COMPAT_FLAGS)) +$(call make-unit-test,test_sol_compat,test_sol_compat,fd_flamenco_test fd_flamenco fd_funk fd_ballet fd_util fd_disco,$(SECP256K1_LIBS)) +$(call make-shared,libfd_exec_sol_compat.so,fd_sol_compat,fd_flamenco_test fd_flamenco fd_funk fd_ballet fd_util fd_disco,$(SECP256K1_LIBS) $(SOL_COMPAT_FLAGS)) + +run-runtime-backtest: $(OBJDIR)/bin/fd_ledger + OBJDIR=$(OBJDIR) src/flamenco/runtime/tests/run_backtest_ci.sh endif endif -run-runtime-backtest: $(OBJDIR)/bin/fd_ledger - OBJDIR=$(OBJDIR) src/flamenco/runtime/tests/run_backtest_ci.sh diff --git a/src/flamenco/runtime/tests/Makefile b/src/flamenco/runtime/tests/Makefile deleted file mode 100644 index a5cf76a3008..00000000000 --- a/src/flamenco/runtime/tests/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -all: fetch_and_generate - -fetch_and_generate: - ./fetch_and_generate.sh diff --git a/src/flamenco/runtime/tests/README.md b/src/flamenco/runtime/tests/README.md new file mode 100644 index 00000000000..d4262c1b297 --- /dev/null +++ b/src/flamenco/runtime/tests/README.md @@ -0,0 +1,46 @@ +# solfuzz APIs + +solfuzz wraps the Solana runtime (SVM) in a generic Protobuf format. +This allows users to execute inputs against different SVM +implementations such as Agave, Firedancer, Mithril, or Sig. + +This directory provides the Firedancer SVM backend for solfuzz. + +## Internal design + +This integration is layered as follows top to bottom: + +- `sol_compat` (solfuzz public ABI) +- `fd_solfuzz` (internal APIs for solfuzz) +- `fd_runtime` (internal APIs for the Firedancer SVM) + +i.e., if a user executes a Solana transaction via `sol_compat`, it is +passed down to `fd_solfuzz`, which in turn executes the transaction in +`fd_runtime`. + +### sol_compat layer + +`sol_compat` is a C API defined by `solfuzz`. +It is stable-ABI (no breaking changes to symbol names, struct layouts, +and function signatures). + +The Firedancer build outputs a `libfd_exec_sol_compat.so` shared library +containing an implementation of the `sol_compat` C API. External users +like `solfuzz` or `solana-conformance` use this API. + +See [fd_sol_compat.h](./fd_sol_compat.h). + +### fd_solfuzz layer + +Like `sol_compat`, `fd_solfuzz` uses Protobuf as its input and output +formats. `fd_solfuzz` is not a stable API but supports a number of +advanced features useful for internal use. + +Mainly used by command-line tooling and tests in the Firedancer repo +(e.g. the `fd_exec_sol_compat` executable). + +See [fd_solfuzz.h](./fd_solfuzz.h). + +### fd_runtime layer + +The actual Firedancer SVM. See `src/flamenco/runtime`. diff --git a/src/flamenco/runtime/tests/harness/fd_block_harness.c b/src/flamenco/runtime/tests/fd_block_harness.c similarity index 95% rename from src/flamenco/runtime/tests/harness/fd_block_harness.c rename to src/flamenco/runtime/tests/fd_block_harness.c index d22c04cf4d7..0b28742b842 100644 --- a/src/flamenco/runtime/tests/harness/fd_block_harness.c +++ b/src/flamenco/runtime/tests/fd_block_harness.c @@ -1,5 +1,20 @@ -#include "fd_block_harness.h" -#include "../../fd_cost_tracker.h" +#include "fd_solfuzz_private.h" +#include "../fd_cost_tracker.h" +#include "fd_txn_harness.h" +#include "../fd_runtime.h" +#include "../fd_system_ids.h" +#include "../fd_txn_account.h" +#include "../context/fd_exec_slot_ctx.h" +#include "../info/fd_runtime_block_info.h" +#include "../program/fd_stake_program.h" +#include "../program/fd_vote_program.h" +#include "../sysvar/fd_sysvar_epoch_schedule.h" +#include "../sysvar/fd_sysvar_rent.h" +#include "../sysvar/fd_sysvar_recent_hashes.h" +#include "../../rewards/fd_rewards.h" +#include "../../stakes/fd_stakes.h" +#include "../../types/fd_types.h" +#include "generated/block.pb.h" /* Stripped down version of `fd_refresh_vote_accounts()` that simply refreshes the stake delegation amount for each of the vote accounts using the stake delegations cache. */ @@ -180,16 +195,14 @@ fd_runtime_fuzz_block_update_prev_epoch_votes_cache( fd_vote_accounts_pair_globa } static void -fd_runtime_fuzz_block_ctx_destroy( fd_runtime_fuzz_runner_t * runner, - fd_wksp_t * wksp ) { +fd_runtime_fuzz_block_ctx_destroy( fd_solfuzz_runner_t * runner ) { fd_funk_txn_cancel_all( runner->funk, 1 ); - fd_wksp_detach( wksp ); } /* Sets up block execution context from an input test case to execute against the runtime. Returns block_info on success and NULL on failure. */ static fd_runtime_block_info_t * -fd_runtime_fuzz_block_ctx_create( fd_runtime_fuzz_runner_t * runner, +fd_runtime_fuzz_block_ctx_create( fd_solfuzz_runner_t * runner, fd_exec_slot_ctx_t * slot_ctx, fd_exec_test_block_context_t const * test_ctx ) { fd_funk_t * funk = runner->funk; @@ -489,7 +502,7 @@ fd_runtime_fuzz_block_ctx_create( fd_runtime_fuzz_runner_t * runner, /* Takes in a block_info created from `fd_runtime_fuzz_block_ctx_create()` and executes it against the runtime. Returns the execution result. */ static int -fd_runtime_fuzz_block_ctx_exec( fd_runtime_fuzz_runner_t * runner, +fd_runtime_fuzz_block_ctx_exec( fd_solfuzz_runner_t * runner, fd_exec_slot_ctx_t * slot_ctx, fd_runtime_block_info_t * block_info ) { int res = 0; @@ -571,24 +584,23 @@ fd_runtime_fuzz_block_ctx_exec( fd_runtime_fuzz_runner_t * runner, } ulong -fd_runtime_fuzz_block_run( fd_runtime_fuzz_runner_t * runner, - void const * input_, - void ** output_, - void * output_buf, - ulong output_bufsz ) { +fd_solfuzz_block_run( fd_solfuzz_runner_t * runner, + void const * input_, + void ** output_, + void * output_buf, + ulong output_bufsz ) { fd_exec_test_block_context_t const * input = fd_type_pun_const( input_ ); fd_exec_test_block_effects_t ** output = fd_type_pun( output_ ); FD_SPAD_FRAME_BEGIN( runner->spad ) { /* Initialize memory */ - fd_wksp_t * wksp = fd_wksp_attach( "wksp" ); uchar * slot_ctx_mem = fd_spad_alloc( runner->spad, FD_EXEC_SLOT_CTX_ALIGN, FD_EXEC_SLOT_CTX_FOOTPRINT ); fd_exec_slot_ctx_t * slot_ctx = fd_exec_slot_ctx_join ( fd_exec_slot_ctx_new ( slot_ctx_mem ) ); /* Set up the block execution context */ fd_runtime_block_info_t * block_info = fd_runtime_fuzz_block_ctx_create( runner, slot_ctx, input ); if( block_info==NULL ) { - fd_runtime_fuzz_block_ctx_destroy( runner, wksp ); + fd_runtime_fuzz_block_ctx_destroy( runner ); return 0; } @@ -618,7 +630,7 @@ fd_runtime_fuzz_block_run( fd_runtime_fuzz_runner_t * runner, fd_memcpy( effects->bank_hash, bank_hash.hash, sizeof(fd_hash_t) ); ulong actual_end = FD_SCRATCH_ALLOC_FINI( l, 1UL ); - fd_runtime_fuzz_block_ctx_destroy( runner, wksp ); + fd_runtime_fuzz_block_ctx_destroy( runner ); *output = effects; return actual_end - (ulong)output_buf; diff --git a/src/flamenco/runtime/tests/fd_dump_pb.c b/src/flamenco/runtime/tests/fd_dump_pb.c index bc4a9c24053..fcb6150b28f 100644 --- a/src/flamenco/runtime/tests/fd_dump_pb.c +++ b/src/flamenco/runtime/tests/fd_dump_pb.c @@ -1,17 +1,15 @@ #include "fd_dump_pb.h" -#include "harness/generated/block.pb.h" -#include "harness/generated/invoke.pb.h" -#include "harness/generated/txn.pb.h" -#include "harness/generated/vm.pb.h" +#include "generated/block.pb.h" +#include "generated/invoke.pb.h" +#include "generated/txn.pb.h" +#include "generated/vm.pb.h" #include "../fd_system_ids.h" #include "../fd_runtime.h" #include "../program/fd_address_lookup_table_program.h" -#include "../../../ballet/lthash/fd_lthash.h" #include "../../../ballet/nanopb/pb_encode.h" #include "../program/fd_program_cache.h" -#include #include /* fopen */ #include /* mmap */ #include /* ftruncate */ diff --git a/src/flamenco/runtime/tests/fd_dump_pb.h b/src/flamenco/runtime/tests/fd_dump_pb.h index 22eb1804ce3..9c396ee9135 100644 --- a/src/flamenco/runtime/tests/fd_dump_pb.h +++ b/src/flamenco/runtime/tests/fd_dump_pb.h @@ -55,8 +55,8 @@ #include "../info/fd_instr_info.h" #include "../info/fd_runtime_block_info.h" #include "../../vm/fd_vm.h" -#include "harness/generated/block.pb.h" -#include "harness/generated/elf.pb.h" +#include "generated/block.pb.h" +#include "generated/elf.pb.h" FD_PROTOTYPES_BEGIN diff --git a/src/flamenco/runtime/tests/harness/fd_elf_harness.c b/src/flamenco/runtime/tests/fd_elf_harness.c similarity index 87% rename from src/flamenco/runtime/tests/harness/fd_elf_harness.c rename to src/flamenco/runtime/tests/fd_elf_harness.c index fcd77062829..476210ef78d 100644 --- a/src/flamenco/runtime/tests/harness/fd_elf_harness.c +++ b/src/flamenco/runtime/tests/fd_elf_harness.c @@ -1,11 +1,14 @@ -#include "fd_elf_harness.h" +#include "fd_solfuzz.h" +#include "generated/elf.pb.h" +#include "../../../ballet/sbpf/fd_sbpf_loader.h" +#include "../../vm/fd_vm_base.h" ulong -fd_runtime_fuzz_sbpf_load_run( fd_runtime_fuzz_runner_t * runner, - void const * input_, - void ** output_, - void * output_buf, - ulong output_bufsz ) { +fd_solfuzz_elf_loader_run( fd_solfuzz_runner_t * runner, + void const * input_, + void ** output_, + void * output_buf, + ulong output_bufsz ) { fd_exec_test_elf_loader_ctx_t const * input = fd_type_pun_const( input_ ); fd_exec_test_elf_loader_effects_t ** output = fd_type_pun( output_ ); diff --git a/src/flamenco/runtime/tests/harness/fd_harness_common.c b/src/flamenco/runtime/tests/fd_harness_common.c similarity index 54% rename from src/flamenco/runtime/tests/harness/fd_harness_common.c rename to src/flamenco/runtime/tests/fd_harness_common.c index 52bda38d9b5..eae9e36b212 100644 --- a/src/flamenco/runtime/tests/harness/fd_harness_common.c +++ b/src/flamenco/runtime/tests/fd_harness_common.c @@ -1,74 +1,6 @@ -#include "fd_harness_common.h" -#include "../../fd_system_ids.h" -#include "../../context/fd_exec_slot_ctx.h" -#include "../../sysvar/fd_sysvar_recent_hashes.h" -#include "../../program/fd_program_cache.h" - -ulong -fd_runtime_fuzz_runner_align( void ) { - return alignof(fd_runtime_fuzz_runner_t); -} - -ulong -fd_runtime_fuzz_runner_footprint( void ) { - ulong txn_max = 4+fd_tile_cnt(); - uint rec_max = 1024; - - ulong l = FD_LAYOUT_INIT; - l = FD_LAYOUT_APPEND( l, fd_runtime_fuzz_runner_align(), sizeof(fd_runtime_fuzz_runner_t) ); - l = FD_LAYOUT_APPEND( l, fd_funk_align(), fd_funk_footprint( txn_max, rec_max ) ); - /* Spad memory is not included in the footprint since its allocated separately at the beginning of a fuzzing run */ - return FD_LAYOUT_FINI( l, fd_runtime_fuzz_runner_align() ); -} - -fd_runtime_fuzz_runner_t * -fd_runtime_fuzz_runner_new( void * mem, - void * spad_mem, - fd_banks_t * banks, - fd_bank_t * bank, - ulong wksp_tag ) { - ulong txn_max = 4+fd_tile_cnt(); - uint rec_max = 1024; - - FD_SCRATCH_ALLOC_INIT( l, mem ); - void * runner_mem = FD_SCRATCH_ALLOC_APPEND( l, fd_runtime_fuzz_runner_align(), sizeof(fd_runtime_fuzz_runner_t) ); - void * funk_mem = FD_SCRATCH_ALLOC_APPEND( l, fd_funk_align(), fd_funk_footprint( txn_max, rec_max ) ); - FD_SCRATCH_ALLOC_FINI( l, fd_runtime_fuzz_runner_align() ); - - fd_runtime_fuzz_runner_t * runner = runner_mem; - - fd_funk_t * funk = fd_funk_join( runner->funk, fd_funk_new( funk_mem, wksp_tag, (ulong)fd_tickcount(), txn_max, rec_max ) ); - if( FD_UNLIKELY( !funk ) ) { - FD_LOG_WARNING(( "fd_funk_new() failed" )); - return NULL; - } - - /* Create spad */ - runner->spad = fd_spad_join( fd_spad_new( spad_mem, FD_RUNTIME_TRANSACTION_EXECUTION_FOOTPRINT_FUZZ ) ); - runner->wksp = fd_wksp_containing( runner->spad ); - - /* Reuse the same bank for each iteration of the fuzzer */ - runner->banks = banks; - runner->bank = bank; - - return runner; -} - -void * -fd_runtime_fuzz_runner_delete( fd_runtime_fuzz_runner_t * runner ) { - if( FD_UNLIKELY( !runner ) ) return NULL; - void * shfunk; - fd_funk_leave( runner->funk, &shfunk ); - fd_funk_delete( shfunk ); - if( FD_UNLIKELY( fd_spad_verify( runner->spad ) ) ) { - FD_LOG_ERR(( "fd_spad_verify() failed" )); - } - if( FD_UNLIKELY( fd_spad_frame_used( runner->spad )!=0 ) ) { - FD_LOG_ERR(( "stray spad frame frame_used=%lu", fd_spad_frame_used( runner->spad ) )); - } - runner->spad = NULL; - return runner; -} +#include "../program/fd_program_cache.h" +#include "generated/context.pb.h" +#include int fd_runtime_fuzz_load_account( fd_txn_account_t * acc, diff --git a/src/flamenco/runtime/tests/harness/fd_instr_harness.c b/src/flamenco/runtime/tests/fd_instr_harness.c similarity index 95% rename from src/flamenco/runtime/tests/harness/fd_instr_harness.c rename to src/flamenco/runtime/tests/fd_instr_harness.c index 9518e023782..fc49f58a4c1 100644 --- a/src/flamenco/runtime/tests/harness/fd_instr_harness.c +++ b/src/flamenco/runtime/tests/fd_instr_harness.c @@ -1,18 +1,22 @@ - #undef FD_SPAD_USE_HANDHOLDING #define FD_SPAD_USE_HANDHOLDING 1 +#include "fd_solfuzz_private.h" #include "fd_instr_harness.h" -#include "../../sysvar/fd_sysvar.h" -#include "../../sysvar/fd_sysvar_clock.h" -#include "../../sysvar/fd_sysvar_epoch_schedule.h" -#include "../../sysvar/fd_sysvar_recent_hashes.h" -#include "../../sysvar/fd_sysvar_last_restart_slot.h" -#include "../../sysvar/fd_sysvar_rent.h" -#include "../../fd_system_ids.h" +#include "../fd_executor.h" +#include "../context/fd_exec_txn_ctx.h" +#include "../program/fd_bpf_loader_program.h" +#include "../sysvar/fd_sysvar.h" +#include "../sysvar/fd_sysvar_clock.h" +#include "../sysvar/fd_sysvar_epoch_schedule.h" +#include "../sysvar/fd_sysvar_recent_hashes.h" +#include "../sysvar/fd_sysvar_last_restart_slot.h" +#include "../sysvar/fd_sysvar_rent.h" +#include "../fd_system_ids.h" +#include int -fd_runtime_fuzz_instr_ctx_create( fd_runtime_fuzz_runner_t * runner, +fd_runtime_fuzz_instr_ctx_create( fd_solfuzz_runner_t * runner, fd_exec_instr_ctx_t * ctx, fd_exec_test_instr_context_t const * test_ctx, bool is_syscall ) { @@ -39,7 +43,7 @@ fd_runtime_fuzz_instr_ctx_create( fd_runtime_fuzz_runner_t * runner, fd_exec_slot_ctx_t * slot_ctx = fd_exec_slot_ctx_join ( fd_exec_slot_ctx_new ( slot_ctx_mem ) ); fd_exec_txn_ctx_t * txn_ctx = fd_exec_txn_ctx_join ( fd_exec_txn_ctx_new ( txn_ctx_mem ), runner->spad, fd_wksp_containing( runner->spad ) ); - assert( slot_ctx ); + assert( slot_ctx ); ctx->txn_ctx = txn_ctx; @@ -379,8 +383,8 @@ fd_runtime_fuzz_instr_ctx_create( fd_runtime_fuzz_runner_t * runner, void -fd_runtime_fuzz_instr_ctx_destroy( fd_runtime_fuzz_runner_t * runner, - fd_exec_instr_ctx_t * ctx ) { +fd_runtime_fuzz_instr_ctx_destroy( fd_solfuzz_runner_t * runner, + fd_exec_instr_ctx_t * ctx ) { if( !ctx ) return; fd_funk_txn_t * funk_txn = ctx->txn_ctx->funk_txn; @@ -389,11 +393,11 @@ fd_runtime_fuzz_instr_ctx_destroy( fd_runtime_fuzz_runner_t * runner, ulong -fd_runtime_fuzz_instr_run( fd_runtime_fuzz_runner_t * runner, - void const * input_, - void ** output_, - void * output_buf, - ulong output_bufsz ) { +fd_solfuzz_instr_run( fd_solfuzz_runner_t * runner, + void const * input_, + void ** output_, + void * output_buf, + ulong output_bufsz ) { fd_exec_test_instr_context_t const * input = fd_type_pun_const( input_ ); fd_exec_test_instr_effects_t ** output = fd_type_pun( output_ ); diff --git a/src/flamenco/runtime/tests/fd_instr_harness.h b/src/flamenco/runtime/tests/fd_instr_harness.h new file mode 100644 index 00000000000..18eac5fb550 --- /dev/null +++ b/src/flamenco/runtime/tests/fd_instr_harness.h @@ -0,0 +1,33 @@ +#ifndef HEADER_fd_src_flamenco_runtime_tests_fd_instr_harness_h +#define HEADER_fd_src_flamenco_runtime_tests_fd_instr_harness_h + +/* fd_instr_harness.h provides APIs for running instruction processor + tests. */ + +#include "fd_solfuzz.h" +#include "generated/invoke.pb.h" + +FD_PROTOTYPES_BEGIN + +/* fd_runtime_fuzz_instr_ctx_create takes in a test runner and InstrCtx protobuf + and creates an fd_exec_instr_ctx_t that can be used in runtime. + + Setting is_syscall avoids some operations/checks only relevant for + program instructions. + + Should be coupled with fd_exec_test_instr_context_destroy when the instr_ctx + is no longer needed. */ +int +fd_runtime_fuzz_instr_ctx_create( fd_solfuzz_runner_t * runner, + fd_exec_instr_ctx_t * ctx, + fd_exec_test_instr_context_t const * test_ctx, + bool is_syscall ); + +/* Frees an instr_ctx created by fd_runtime_fuzz_instr_ctx_create */ +void +fd_runtime_fuzz_instr_ctx_destroy( fd_solfuzz_runner_t * runner, + fd_exec_instr_ctx_t * ctx ); + +FD_PROTOTYPES_END + +#endif /* HEADER_fd_src_flamenco_runtime_tests_fd_instr_harness_h */ diff --git a/src/flamenco/runtime/tests/fd_sol_compat.c b/src/flamenco/runtime/tests/fd_sol_compat.c new file mode 100644 index 00000000000..0787dd5ec24 --- /dev/null +++ b/src/flamenco/runtime/tests/fd_sol_compat.c @@ -0,0 +1,354 @@ +#include "fd_solfuzz_private.h" +#define _GNU_SOURCE +#include "fd_sol_compat.h" + +#include "../fd_executor_err.h" +#include "../../capture/fd_solcap_writer.h" +#include "../../../ballet/shred/fd_shred.h" + +#include "generated/block.pb.h" +#include "generated/elf.pb.h" +#include "generated/invoke.pb.h" +#include "generated/shred.pb.h" +#include "generated/vm.pb.h" +#include "generated/txn.pb.h" +#include "generated/type.pb.h" + +#include +#include +#include + +/* FIXME: Spad isn't properly sized out or cleaned up */ + +static fd_wksp_t * wksp = NULL; +static fd_solfuzz_runner_t * runner = NULL; + +#define WKSP_EXECUTE_ALLOC_TAG (2UL) +#define WKSP_INIT_ALLOC_TAG (3UL) + +void +sol_compat_init( int log_level ) { + int argc = 1; + char * argv[2] = { (char *)"fd_exec_sol_compat", NULL }; + char ** argv_ = argv; + if( !getenv( "FD_LOG_PATH" ) ) { + setenv( "FD_LOG_PATH", "", 1 ); + } + fd_log_enable_unclean_exit(); + fd_boot( &argc, &argv_ ); + fd_log_level_logfile_set( log_level ); + fd_log_level_core_set(4); /* abort on FD_LOG_ERR */ +} + +void +sol_compat_fini( void ) { + fd_wksp_delete_anonymous( wksp ); + wksp = NULL; + runner = NULL; +} + +sol_compat_features_t const * +sol_compat_get_features_v1( void ) { + static sol_compat_features_t features; + static ulong hardcoded_features[ FD_FEATURE_ID_CNT ]; + static ulong supported_features[ FD_FEATURE_ID_CNT ]; + + FD_ONCE_BEGIN { + features.hardcoded_features = hardcoded_features; + features.supported_features = supported_features; + for( fd_feature_id_t const * iter = fd_feature_iter_init(); + !fd_feature_iter_done( iter ); + iter = fd_feature_iter_next( iter ) ) { + if( iter->reverted ) continue; /* skip reverted features */ + + /* Pretend that features activated on all clusters are hardcoded */ + if( iter->activated_on_all_clusters ) { + hardcoded_features[ features.hardcoded_features_cnt++ ] = iter->id.ul[0]; + } else { + supported_features[ features.supported_feature_cnt++ ] = iter->id.ul[0]; + } + } + } + FD_ONCE_END; + + return &features; +} + +static fd_solfuzz_runner_t * +sol_compat_setup_runner( void ) { + + char const * solcap_path = getenv( "FD_SOLCAP" ); + if( solcap_path ) { + runner->solcap_file = fopen( solcap_path, "w" ); + if( FD_UNLIKELY( !runner->solcap_file ) ) { + FD_LOG_ERR(( "fopen($FD_SOLCAP=%s) failed (%i-%s)", solcap_path, errno, fd_io_strerror( errno ) )); + } + FD_LOG_NOTICE(( "Logging to solcap file %s", solcap_path )); + + void * solcap_mem = fd_wksp_alloc_laddr( runner->wksp, fd_solcap_writer_align(), fd_solcap_writer_footprint(), 1UL ); + runner->solcap = fd_solcap_writer_new( solcap_mem ); + FD_TEST( runner->solcap ); + FD_TEST( fd_solcap_writer_init( solcap_mem, runner->solcap_file ) ); + } + + return runner; +} + +static void +sol_compat_cleanup_runner( fd_solfuzz_runner_t * runner ) { + /* Cleanup test runner */ + if( runner->solcap ) { + fd_solcap_writer_flush( runner->solcap ); + fd_wksp_free_laddr( fd_solcap_writer_delete( runner->solcap ) ); + runner->solcap = NULL; + fclose( runner->solcap_file ); + runner->solcap_file = NULL; + } + fd_solfuzz_runner_delete( runner ); +} + +/* + * execute_v1 + */ + +int +sol_compat_instr_execute_v1( uchar * out, + ulong * out_sz, + uchar const * in, + ulong in_sz ) { + // Setup + fd_solfuzz_runner_t * runner = sol_compat_setup_runner(); + + // Decode context + fd_exec_test_instr_context_t input[1] = {0}; + void * res = sol_compat_decode( &input, in, in_sz, &fd_exec_test_instr_context_t_msg ); + if( !res ) { + sol_compat_cleanup_runner( runner ); + return 0; + } + + int ok = 0; + fd_spad_push( runner->spad ); + void * output = NULL; + fd_solfuzz_execute_wrapper( runner, input, &output, fd_solfuzz_instr_run ); + if( output ) { + ok = !!sol_compat_encode( out, out_sz, output, &fd_exec_test_instr_effects_t_msg ); + } + fd_spad_pop( runner->spad ); + + // Cleanup + pb_release( &fd_exec_test_instr_context_t_msg, input ); + sol_compat_cleanup_runner( runner ); + + return ok; +} + +int +sol_compat_txn_execute_v1( uchar * out, + ulong * out_sz, + uchar const * in, + ulong in_sz ) { + // Setup + fd_solfuzz_runner_t * runner = sol_compat_setup_runner(); + + // Decode context + fd_exec_test_txn_context_t input[1] = {0}; + void * res = sol_compat_decode( &input, in, in_sz, &fd_exec_test_txn_context_t_msg ); + if( FD_UNLIKELY( !res ) ) { + sol_compat_cleanup_runner( runner ); + return 0; + } + + int ok = 0; + fd_spad_push( runner->spad ); + void * output = NULL; + fd_solfuzz_execute_wrapper( runner, input, &output, fd_solfuzz_txn_run ); + if( output ) { + ok = !!sol_compat_encode( out, out_sz, output, &fd_exec_test_txn_result_t_msg ); + } + fd_spad_pop( runner->spad ); + + // Cleanup + pb_release( &fd_exec_test_txn_context_t_msg, input ); + sol_compat_cleanup_runner( runner ); + + return ok; +} + +int +sol_compat_block_execute_v1( uchar * out, + ulong * out_sz, + uchar const * in, + ulong in_sz ) { + // Setup + fd_solfuzz_runner_t * runner = sol_compat_setup_runner(); + + // Decode context + fd_exec_test_block_context_t input[1] = {0}; + void * res = sol_compat_decode( &input, in, in_sz, &fd_exec_test_block_context_t_msg ); + if( FD_UNLIKELY( !res ) ) { + sol_compat_cleanup_runner( runner ); + return 0; + } + + fd_spad_push( runner->spad ); + int ok = 0; + void * output = NULL; + fd_solfuzz_execute_wrapper( runner, input, &output, fd_solfuzz_block_run ); + if( output ) { + ok = !!sol_compat_encode( out, out_sz, output, &fd_exec_test_block_effects_t_msg ); + } + fd_spad_pop( runner->spad ); + + // Cleanup + pb_release( &fd_exec_test_block_context_t_msg, input ); + sol_compat_cleanup_runner( runner ); + + return ok; +} + +int +sol_compat_elf_loader_v1( uchar * out, + ulong * out_sz, + uchar const * in, + ulong in_sz ) { + // Setup + fd_solfuzz_runner_t * runner = sol_compat_setup_runner(); + + // Decode context + fd_exec_test_elf_loader_ctx_t input[1] = {0}; + void * res = sol_compat_decode( &input, in, in_sz, &fd_exec_test_elf_loader_ctx_t_msg ); + if( FD_UNLIKELY( !res ) ) { + sol_compat_cleanup_runner( runner ); + return 0; + } + + fd_spad_push( runner->spad ); + int ok = 0; + void * output = NULL; + fd_solfuzz_execute_wrapper( runner, input, &output, fd_solfuzz_elf_loader_run ); + if( output ) { + ok = !!sol_compat_encode( out, out_sz, output, &fd_exec_test_elf_loader_effects_t_msg ); + } + fd_spad_pop( runner->spad ); + + // Cleanup + pb_release( &fd_exec_test_elf_loader_ctx_t_msg, input ); + sol_compat_cleanup_runner( runner ); + + return ok; +} + +int +sol_compat_vm_syscall_execute_v1( uchar * out, + ulong * out_sz, + uchar const * in, + ulong in_sz ) { + // Setup + fd_solfuzz_runner_t * runner = sol_compat_setup_runner(); + + // Decode context + fd_exec_test_syscall_context_t input[1] = {0}; + void * res = sol_compat_decode( &input, in, in_sz, &fd_exec_test_syscall_context_t_msg ); + if( FD_UNLIKELY( !res ) ) { + sol_compat_cleanup_runner( runner ); + return 0; + } + + fd_spad_push( runner->spad ); + int ok = 0; + void * output = NULL; + fd_solfuzz_execute_wrapper( runner, input, &output, fd_solfuzz_syscall_run ); + if( output ) { + ok = !!sol_compat_encode( out, out_sz, output, &fd_exec_test_syscall_effects_t_msg ); + } + fd_spad_pop( runner->spad ); + + // Cleanup + pb_release( &fd_exec_test_syscall_context_t_msg, input ); + sol_compat_cleanup_runner( runner ); + + return ok; +} + +int +sol_compat_vm_interp_v1( uchar * out, + ulong * out_sz, + uchar const * in, + ulong in_sz ) { + // Setup + fd_solfuzz_runner_t * runner = sol_compat_setup_runner(); + + // Decode context + fd_exec_test_syscall_context_t input[1] = {0}; + void * res = sol_compat_decode( &input, in, in_sz, &fd_exec_test_syscall_context_t_msg ); + if( FD_UNLIKELY( !res ) ) { + sol_compat_cleanup_runner( runner ); + return 0; + } + + fd_spad_push( runner->spad ); + int ok = 0; + void * output = NULL; + fd_solfuzz_execute_wrapper( runner, input, &output, fd_solfuzz_vm_interp_run ); + if( output ) { + ok = !!sol_compat_encode( out, out_sz, output, &fd_exec_test_syscall_effects_t_msg ); + } + fd_spad_pop( runner->spad ); + + // Cleanup + pb_release( &fd_exec_test_syscall_context_t_msg, input ); + sol_compat_cleanup_runner( runner ); + + return ok; +} + +int +sol_compat_shred_parse_v1( uchar * out, + ulong * out_sz, + uchar const * in, + ulong in_sz ) { + fd_exec_test_shred_binary_t input[1] = {0}; + void * res = sol_compat_decode( &input, in, in_sz, &fd_exec_test_shred_binary_t_msg ); + if( FD_UNLIKELY( res==NULL ) ) { + return 0; + } + if( FD_UNLIKELY( input[0].data==NULL ) ) { + pb_release( &fd_exec_test_shred_binary_t_msg, input ); + return 0; + } + fd_exec_test_accepts_shred_t output[1] = {0}; + output[0].valid = !!fd_shred_parse( input[0].data->bytes, input[0].data->size ); + pb_release( &fd_exec_test_shred_binary_t_msg, input ); + return !!sol_compat_encode( out, out_sz, output, &fd_exec_test_accepts_shred_t_msg ); +} + +int +sol_compat_type_execute_v1( uchar * out, + ulong * out_sz, + uchar const * in, + ulong in_sz ) { + // Setup + fd_solfuzz_runner_t * runner = sol_compat_setup_runner(); + // Decode context + fd_exec_test_type_context_t input[1] = {0}; + void * res = sol_compat_decode( &input, in, in_sz, &fd_exec_test_type_context_t_msg ); + if( res==NULL ) { + sol_compat_cleanup_runner( runner ); + return 0; + } + + fd_spad_push( runner->spad ); + int ok = 0; + void * output = NULL; + fd_solfuzz_execute_wrapper( runner, input, &output, fd_solfuzz_type_run ); + if( output ) { + ok = !!sol_compat_encode( out, out_sz, output, &fd_exec_test_type_effects_t_msg ); + } + fd_spad_pop( runner->spad ); + + pb_release( &fd_exec_test_type_context_t_msg, input ); + sol_compat_cleanup_runner( runner ); + + return ok; +} diff --git a/src/flamenco/runtime/tests/fd_sol_compat.h b/src/flamenco/runtime/tests/fd_sol_compat.h new file mode 100644 index 00000000000..e0319c634e8 --- /dev/null +++ b/src/flamenco/runtime/tests/fd_sol_compat.h @@ -0,0 +1,137 @@ +#ifndef HEADER_fd_src_flamenco_runtime_tests_fd_sol_compat_h +#define HEADER_fd_src_flamenco_runtime_tests_fd_sol_compat_h + +/* fd_sol_compat_abi.h provides a public stable ABI exposed in a shared + library. Fuzzing / testing engines (such as solfuzz) can use these + to invoke Firedancer SVM components. + + General usage is like this: + + sol_compat_init() -- Allocates an anonymous shared memory workspace + for each input { + sol_compat_instr_execute_v1() -- Run a test vector + } + sol_compat_fini() -- Releases all resources back to the kernel + + Note that sol_compat usage relies on global variables, thus does not + support multiple sessions or multi-threading. */ + +#include "../../fd_flamenco_base.h" + +/* Admin API */ + +FD_PROTOTYPES_BEGIN + +/* sol_compat_init installs a new solfuzz execution context into the + current process. Under the hood, acquires some demand-paged memory + (with transparent huge page hint), and initializes some reusable data + structures. Must be called before any other solfuzz APIs. */ + +void +sol_compat_init( int log_level ); + +/* sol_compat_fini undoes the global setup done above. Releases all + memory allocations and file handles created back to the kernel. */ + +void +sol_compat_fini( void ); + +FD_PROTOTYPES_END + +/* Features API */ + +/* sol_compat_features_t is a compressed feature set storage format. + {harcoded,supported}_features point to a vector of features. + Each entry contains the first 8 bytes of the feature gate account + address identifying the feature, interpreted as a little-endian + 64-bit integer. */ + +struct sol_compat_features { + ulong struct_size; /* used for ABI versioning */ + ulong * hardcoded_features; + ulong hardcoded_features_cnt; + ulong * supported_features; + ulong supported_feature_cnt; +}; + +typedef struct sol_compat_features sol_compat_features_t; + +FD_PROTOTYPES_BEGIN + +/* sol_compat_get_features_v1 returns the feature set supported by this + Firedancer SVM build. */ + +sol_compat_features_t const * +sol_compat_get_features_v1( void ); + +FD_PROTOTYPES_END + +/* Execution API */ + +FD_PROTOTYPES_BEGIN + +/* The 'execute_v1' methods execute a single input against an Firedancer + SVM component. in points to a byte array of in_sz bytes containing a + Protobuf-encoded input message. out points to a byte array that the + method will write the Protobuf-encoded output message to. The caller + sets *out_sz to the capacity of the out buffer. On return, *out_sz + contains the serialized size of the output message (guaranteed to be + <= capacity). */ + +int +sol_compat_instr_execute_v1( uchar * out, + ulong * out_sz, + uchar const * in, + ulong in_sz ); + +int +sol_compat_txn_execute_v1( uchar * out, + ulong * out_sz, + uchar const * in, + ulong in_sz ); + +int +sol_compat_block_execute_v1( uchar * out, + ulong * out_sz, + uchar const * in, + ulong in_sz ); + +int +sol_compat_elf_loader_v1( uchar * out, + ulong * out_sz, + uchar const * in, + ulong in_sz ); + +int +sol_compat_vm_syscall_execute_v1( uchar * out, + ulong * out_sz, + uchar const * in, + ulong in_sz ); + +int +sol_compat_vm_interp_v1( uchar * out, + ulong * out_sz, + uchar const * in, + ulong in_sz ); + +int +sol_compat_shred_parse_v1( uchar * out, + ulong * out_sz, + uchar const * in, + ulong in_sz ); + +int +sol_compat_pack_compute_budget_v1( uchar * out, + ulong * out_sz, + uchar const * in, + ulong in_sz ); + +int +sol_compat_type_execute_v1( uchar * out, + ulong * out_sz, + uchar const * in, + ulong in_sz ); + +FD_PROTOTYPES_END + +#endif /* HEADER_fd_src_flamenco_runtime_tests_fd_sol_compat_h */ diff --git a/src/flamenco/runtime/tests/fd_solfuzz.c b/src/flamenco/runtime/tests/fd_solfuzz.c new file mode 100644 index 00000000000..142af4fa2d9 --- /dev/null +++ b/src/flamenco/runtime/tests/fd_solfuzz.c @@ -0,0 +1,126 @@ +/* fd_solfuzz.c contains support routines */ + +#define _GNU_SOURCE +#include "fd_solfuzz.h" +#include "../fd_runtime.h" +#include +#include + +fd_wksp_t * +fd_wksp_demand_paged_new( char const * name, + uint seed, + ulong part_max, + ulong data_max ) { + ulong footprint = fd_wksp_footprint( part_max, data_max ); + if( FD_UNLIKELY( !footprint ) ) { + FD_LOG_WARNING(( "invalid workspace params (part_max=%lu data_max=%lu)", part_max, data_max )); + return NULL; + } + + /* Round up footprint to nearest huge page size */ + footprint = fd_ulong_align_up( footprint, FD_SHMEM_HUGE_PAGE_SZ ); + + /* Acquire anonymous demand-paged memory */ + void * mem = mmap( NULL, footprint, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0 ); + if( FD_UNLIKELY( mem==MAP_FAILED ) ) { + FD_LOG_WARNING(( "mmap() failed (%i-%s)", errno, fd_io_strerror( errno ) )); + return NULL; + } + + /* Indicate to kernel that hugepages are a fine backing store + (Transparent Huge Pages) */ + if( FD_UNLIKELY( 0!=madvise( mem, footprint, MADV_HUGEPAGE ) ) ) { + FD_LOG_WARNING(( "madvise() failed (%i-%s)", errno, fd_io_strerror( errno ) )); + munmap( mem, footprint ); + return NULL; + } + + /* Create workspace */ + fd_wksp_t * wksp = fd_wksp_join( fd_wksp_new( mem, name, seed, part_max, data_max ) ); + if( FD_UNLIKELY( !wksp ) ) { + FD_LOG_WARNING(( "fd_wksp_new() failed (%i-%s)", errno, fd_io_strerror( errno ) )); + munmap( mem, footprint ); + return NULL; + } + + /* Register shared memory region */ + ulong fake_page_cnt = footprint>>FD_SHMEM_HUGE_LG_PAGE_SZ; + int join_err = fd_shmem_join_anonymous( + name, + FD_SHMEM_JOIN_MODE_READ_WRITE, + wksp, + mem, + FD_SHMEM_HUGE_PAGE_SZ, + fake_page_cnt + ); + if( FD_UNLIKELY( join_err ) ) { + FD_LOG_WARNING(( "fd_shmem_join_anonymous() failed (%i-%s)", join_err, fd_io_strerror( join_err ) )); + fd_wksp_delete( fd_wksp_leave( wksp ) ); + munmap( mem, footprint ); + return NULL; + } + + return wksp; +} + +void +fd_wksp_demand_paged_delete( fd_wksp_t * wksp ) { + fd_shmem_leave_anonymous( wksp, NULL ); + FD_TEST( fd_wksp_delete( fd_wksp_leave( wksp ) ) ); +} + +fd_solfuzz_runner_t * +fd_solfuzz_runner_new( fd_wksp_t * wksp, + ulong wksp_tag ) { + + /* Allocate objects */ + ulong const txn_max = 64UL; + ulong const rec_max = 1024UL; + ulong const spad_max = FD_RUNTIME_TRANSACTION_EXECUTION_FOOTPRINT_FUZZ; + ulong const bank_max = 1UL; + ulong const fork_max = 1UL; + fd_solfuzz_runner_t * runner = fd_wksp_alloc_laddr( wksp, alignof(fd_solfuzz_runner_t), sizeof(fd_solfuzz_runner_t), wksp_tag ); + void * funk_mem = fd_wksp_alloc_laddr( wksp, fd_funk_align(), fd_funk_footprint( txn_max, rec_max ), wksp_tag ); + void * spad_mem = fd_wksp_alloc_laddr( wksp, fd_spad_align(), fd_spad_footprint( spad_max ), wksp_tag ); + void * banks_mem = fd_wksp_alloc_laddr( wksp, fd_banks_align(), fd_banks_footprint( bank_max, fork_max ), wksp_tag ); + if( FD_UNLIKELY( !runner || !funk_mem || !spad_mem || !banks_mem ) ) goto bail1; + + /* Create objects */ + fd_memset( runner, 0, sizeof(fd_solfuzz_runner_t) ); + runner->wksp = wksp; + void * shfunk = fd_funk_new( funk_mem, wksp_tag, 1UL, txn_max, rec_max ); + if( FD_UNLIKELY( !shfunk ) ) goto bail1; + if( FD_UNLIKELY( !fd_funk_join( runner->funk, funk_mem ) ) ) goto bail2; + runner->spad = fd_spad_join( fd_spad_new( spad_mem, spad_max ) ); + if( FD_UNLIKELY( !runner->spad ) ) goto bail2; + runner->banks = fd_banks_join( fd_banks_new( banks_mem, bank_max, fork_max ) ); + if( FD_UNLIKELY( !runner->banks ) ) goto bail2; + runner->bank = fd_banks_init_bank( runner->banks, 0UL ); + if( FD_UNLIKELY( !runner->bank ) ) { + FD_LOG_WARNING(( "fd_banks_init_bank failed" )); + goto bail2; + } + return runner; + +bail2: + if( runner->spad ) fd_spad_delete( fd_spad_leave( runner->spad ) ); + if( shfunk ) fd_funk_delete( funk_mem ); /* free underlying fd_alloc instance */ + if( runner->banks ) fd_banks_delete( fd_banks_leave( runner->banks ) ); +bail1: + fd_wksp_free_laddr( funk_mem ); + fd_wksp_free_laddr( spad_mem ); + fd_wksp_free_laddr( banks_mem ); + fd_wksp_free_laddr( runner ); + FD_LOG_WARNING(( "fd_solfuzz_runner_new failed" )); + return NULL; +} + +void +fd_solfuzz_runner_delete( fd_solfuzz_runner_t * runner ) { + void * shfunk = NULL; + fd_funk_leave( runner->funk, &shfunk ); + if( shfunk ) fd_wksp_free_laddr( fd_funk_delete( shfunk ) ); + if( runner->spad ) fd_wksp_free_laddr( fd_spad_delete( fd_spad_leave( runner->spad ) ) ); + if( runner->banks ) fd_wksp_free_laddr( fd_banks_delete( fd_banks_leave( runner->banks ) ) ); + fd_wksp_free_laddr( runner ); +} diff --git a/src/flamenco/runtime/tests/fd_solfuzz.h b/src/flamenco/runtime/tests/fd_solfuzz.h new file mode 100644 index 00000000000..b2be89f12ad --- /dev/null +++ b/src/flamenco/runtime/tests/fd_solfuzz.h @@ -0,0 +1,192 @@ +#ifndef HEADER_fd_src_flamenco_runtime_tests_harness_fd_solfuzz_h +#define HEADER_fd_src_flamenco_runtime_tests_harness_fd_solfuzz_h + +/* fd_solfuzz.h provides internal/unstable APIs for executing solfuzz + inputs. This API is fully object-oriented and does not use globals + (other than a fd_shmem region registration). + + Supports a number of advanced features: + - Custom memory workspace setups + - Multi-threaded use + - Multi-session use */ + +#include "../../capture/fd_solcap_writer.h" +#include "../../../funk/fd_funk.h" + +/* A fd_solfuzz_runner_t object processes solfuzz inputs. Can be reused + for different inputs, even of different types. Single-thread per + object, but multiple threads can use different objects. Each object + holds a shared mutable reference to a workspace throughout its + lifetime. Multiple solfuzz runner objects can share a workspace with + each other (or any other allocations) just fine. */ + +struct fd_solfuzz_runner { + fd_funk_t funk[1]; + fd_wksp_t * wksp; + fd_spad_t * spad; + fd_banks_t * banks; + fd_bank_t * bank; + + fd_solcap_writer_t * solcap; + void * solcap_file; /* FILE * */ +}; + +typedef struct fd_solfuzz_runner fd_solfuzz_runner_t; + +FD_PROTOTYPES_BEGIN + +/* Constructor */ + +/* fd_solfuzz_runner_new allocates a new solfuzz runner object, a bank + context, and ~5 GiB of scratch memory (worst case bound for the most + expensive input type). + + Scratch memory is lazily used/initialized, therefore plays well with + demand paged memory. */ + +fd_solfuzz_runner_t * +fd_solfuzz_runner_new( fd_wksp_t * wksp, + ulong wksp_tag ); + +/* fd_solfuzz_runner_delete frees all previously done workspace + allocations. */ + +void +fd_solfuzz_runner_delete( fd_solfuzz_runner_t * runner ); + +/* fd_wksp_demand_paged_new attempts to create a workspace backed by + demand-paged transparent huge page memory. */ + +fd_wksp_t * +fd_wksp_demand_paged_new( char const * name, + uint seed, + ulong part_max, + ulong data_max ); + +/* fd_wksp_demand_paged_delete destroys a demand-paged workspace. */ + +void +fd_wksp_demand_paged_delete( fd_wksp_t * wksp ); + +/* Methods + + fd_solfuzz__run executes a Protobuf test input and returns a + Protobuf test output. + + fd_solfuzz__fixture executes a Protobuf test fixture + (containing both inputs and expected outputs). Silently returns 1 if + actual output matches expected output. Returns 0 and logs diff if + a mismatch occurred. */ + +/* SVM Instruction Execution */ + +ulong +fd_solfuzz_instr_run( fd_solfuzz_runner_t * runner, + void const * input_, + void ** output_, + void * output_buf, + ulong output_bufsz ); + +int +fd_solfuzz_instr_fixture( fd_solfuzz_runner_t * runner, + uchar const * in, + ulong in_sz ); + +/* SVM Transaction Execution */ + +ulong +fd_solfuzz_txn_run( fd_solfuzz_runner_t * runner, + void const * input_, + void ** output_, + void * output_buf, + ulong output_bufsz ); + +int +fd_solfuzz_txn_fixture( fd_solfuzz_runner_t * runner, + uchar const * in, + ulong in_sz ); + +/* SVM Block Execution + + - All sysvars must be provided + - This does not test sigverify or POH + - Epoch boundaries are tested + - Associated entrypoint tested in Agave is `confirm_slot_entries` (except sigverify and verify_ticks are removed) + - (idk about this yet) Recent blockhashes sysvar account must NOT be provided in the input account states. + Instead, the sysvar is populated through the input blockhash queue. */ + +ulong +fd_solfuzz_block_run( fd_solfuzz_runner_t * runner, + void const * input_, + void ** output_, + void * output_buf, + ulong output_bufsz ); + +int +fd_solfuzz_block_fixture( fd_solfuzz_runner_t * runner, + uchar const * in, + ulong in_sz ); + +/* SVM Program Loading + + Loads an ELF binary (in input->elf.data()). + output_buf points to a memory region of output_bufsz bytes where the + result is allocated into. During execution, the contents of + fd_sbpf_program_t are wrapped in *output (backed by output_buf). + + Returns number of bytes allocated at output_buf OR 0UL on any + harness-specific failures. Execution failures still return number of allocated bytes, + but output is incomplete/undefined. */ + +ulong +fd_solfuzz_elf_loader_run( fd_solfuzz_runner_t * runner, + void const * input_, + void ** output_, + void * output_buf, + ulong output_bufsz ); + +int +fd_solfuzz_elf_loader_fixture( fd_solfuzz_runner_t * runner, + uchar const * in, + ulong in_sz ); + +/* SVM sBPF Syscall Handling */ + +ulong +fd_solfuzz_syscall_run( fd_solfuzz_runner_t * runner, + void const * input_, + void ** output_, + void * output_buf, + ulong output_bufsz ); + +int +fd_solfuzz_syscall_fixture( fd_solfuzz_runner_t * runner, + uchar const * in, + ulong in_sz ); + +/* SVM sBPF Bytecode Execution */ + +ulong +fd_solfuzz_vm_interp_run( fd_solfuzz_runner_t * runner, + void const * input, + void ** output, + void * output_buf, + ulong output_bufsz ); + +int +fd_solfuzz_vm_interp_fixture( fd_solfuzz_runner_t * runner, + uchar const * in, + ulong in_sz ); + +/* Bincode Encoding */ + +ulong +fd_solfuzz_type_run( fd_solfuzz_runner_t * runner, + void const * input_, + void ** output_, + void * output_buf, + ulong output_bufsz ); + +FD_PROTOTYPES_END + +#endif /* HEADER_fd_src_flamenco_runtime_tests_harness_fd_solfuzz_h */ diff --git a/src/flamenco/runtime/tests/fd_solfuzz_exec.c b/src/flamenco/runtime/tests/fd_solfuzz_exec.c new file mode 100644 index 00000000000..6835f2d820d --- /dev/null +++ b/src/flamenco/runtime/tests/fd_solfuzz_exec.c @@ -0,0 +1,396 @@ +/* fd_solfuzz_exec.c contains internal executors */ + +#include "fd_solfuzz_private.h" +#include "generated/block.pb.h" +#include "generated/invoke.pb.h" +#include "generated/txn.pb.h" +#include "generated/vm.pb.h" +#include "generated/elf.pb.h" +#include "../fd_executor_err.h" +#include + +/* + * fixtures + */ + +static int +sol_compat_cmp_binary_strict( void const * effects, + void const * expected, + pb_msgdesc_t const * encode_type, + fd_spad_t * spad ) { +#define MAX_SZ 32*1024*1024 +FD_SPAD_FRAME_BEGIN( spad ) { + if( effects==NULL ) { + FD_LOG_WARNING(( "No output effects" )); + return 0; + } + + /* Note: Most likely this spad allocation won't fail. If it does, you may need to bump + the allocated spad memory amount in fd_exec_sol_compat.c. */ + ulong out_sz = MAX_SZ; + uchar * out = fd_spad_alloc( spad, 1UL, out_sz ); + if( !sol_compat_encode( out, &out_sz, effects, encode_type ) ) { + FD_LOG_WARNING(( "Error encoding effects" )); + return 0; + } + + ulong exp_sz = MAX_SZ; + uchar * exp = fd_spad_alloc( spad, 1UL, exp_sz ); + if( !sol_compat_encode( exp, &exp_sz, expected, encode_type ) ) { + FD_LOG_WARNING(( "Error encoding expected" )); + return 0; + } + + if( out_sz!=exp_sz ) { + FD_LOG_WARNING(( "Binary cmp failed: different size. out_sz=%lu exp_sz=%lu", out_sz, exp_sz )); + return 0; + } + if( !fd_memeq( out, exp, out_sz ) ) { + FD_LOG_WARNING(( "Binary cmp failed: different values." )); + return 0; + } + + return 1; +} FD_SPAD_FRAME_END; +#undef MAX_SIZE +} + +static int +_diff_txn_acct( fd_exec_test_acct_state_t * expected, + fd_exec_test_acct_state_t * actual ) { + /* AcctState -> address (This must hold true when calling this function!) */ + assert( fd_memeq( expected->address, actual->address, sizeof(fd_pubkey_t) ) ); + + /* AcctState -> lamports */ + if( expected->lamports != actual->lamports ) { + FD_LOG_WARNING(( "Lamports mismatch: expected=%lu actual=%lu", expected->lamports, actual->lamports )); + return 0; + } + + /* AcctState -> data */ + if( expected->data != NULL || actual->data != NULL ) { + if( expected->data == NULL ) { + FD_LOG_WARNING(( "Expected account data is NULL, actual is non-NULL" )); + return 0; + } + + if( actual->data == NULL ) { + FD_LOG_WARNING(( "Expected account data is NULL, actual is non-NULL" )); + return 0; + } + + if( expected->data->size != actual->data->size ) { + FD_LOG_WARNING(( "Account data size mismatch: expected=%u actual=%u", expected->data->size, actual->data->size )); + return 0; + } + + if( !fd_memeq( expected->data->bytes, actual->data->bytes, expected->data->size ) ) { + FD_LOG_WARNING(( "Account data mismatch" )); + return 0; + } + } + + /* AcctState -> executable */ + if( expected->executable != actual->executable ) { + FD_LOG_WARNING(( "Executable mismatch: expected=%d actual=%d", expected->executable, actual->executable )); + return 0; + } + + /* AcctState -> rent_epoch */ + if( expected->rent_epoch != actual->rent_epoch ) { + FD_LOG_WARNING(( "Rent epoch mismatch: expected=%lu actual=%lu", expected->rent_epoch, actual->rent_epoch )); + return 0; + } + + /* AcctState -> owner */ + if( !fd_memeq( expected->owner, actual->owner, sizeof(fd_pubkey_t) ) ) { + char a[ FD_BASE58_ENCODED_32_SZ ]; + char b[ FD_BASE58_ENCODED_32_SZ ]; + FD_LOG_WARNING(( "Owner mismatch: expected=%s, actual=%s", fd_acct_addr_cstr( a, expected->owner ), fd_acct_addr_cstr( b, actual->owner ) )); + return 0; + } + + return 1; +} + + +static int +_diff_resulting_states( fd_exec_test_resulting_state_t * expected, + fd_exec_test_resulting_state_t * actual ) { + // Verify that the number of accounts are the same + if( expected->acct_states_count != actual->acct_states_count ) { + FD_LOG_WARNING(( "Account states count mismatch: expected=%u actual=%u", expected->acct_states_count, actual->acct_states_count )); + return 0; + } + + // Verify that the account states are the same + for( ulong i = 0; i < expected->acct_states_count; ++i ) { + for( ulong j = 0; j < actual->acct_states_count; ++j ) { + if( fd_memeq( expected->acct_states[i].address, actual->acct_states[j].address, sizeof(fd_pubkey_t) ) ) { + if( !_diff_txn_acct( &expected->acct_states[i], &actual->acct_states[j] ) ) { + return 0; + } + } + } + } + + // TODO: resulting_state -> rent_debits, resulting_state->transaction_rent + return 1; +} + +static int +sol_compat_cmp_txn( fd_exec_test_txn_result_t * expected, + fd_exec_test_txn_result_t * actual ) { + /* TxnResult -> executed */ + if( expected->executed != actual->executed ) { + FD_LOG_WARNING(( "Executed mismatch: expected=%d actual=%d", expected->executed, actual->executed )); + return 0; + } + + /* TxnResult -> sanitization_error */ + if( expected->sanitization_error != actual->sanitization_error ) { + FD_LOG_WARNING(( "Sanitization error mismatch: expected=%d actual=%d", expected->sanitization_error, actual->sanitization_error )); + return 0; + } + + /* TxnResult -> resulting_state */ + if( !_diff_resulting_states( &expected->resulting_state, &actual->resulting_state ) ) { + return 0; + } + + /* TxnResult -> rent */ + if( expected->rent != actual->rent ) { + FD_LOG_WARNING(( "Rent mismatch: expected=%lu actual=%lu", expected->rent, actual->rent )); + return 0; + } + + /* TxnResult -> is_ok */ + if( expected->is_ok != actual->is_ok ) { + FD_LOG_WARNING(( "Is ok mismatch: expected=%d actual=%d", expected->is_ok, actual->is_ok )); + return 0; + } + + /* TxnResult -> status */ + if( expected->status != actual->status ) { + FD_LOG_WARNING(( "Status mismatch: expected=%u actual=%u", expected->status, actual->status )); + return 0; + } + + /* TxnResult -> instruction_error */ + if( expected->instruction_error != actual->instruction_error ) { + FD_LOG_WARNING(( "Instruction error mismatch: expected=%u actual=%u", expected->instruction_error, actual->instruction_error )); + return 0; + } + + if( expected->instruction_error ) { + /* TxnResult -> instruction_error_index */ + if( expected->instruction_error_index != actual->instruction_error_index ) { + FD_LOG_WARNING(( "Instruction error index mismatch: expected=%u actual=%u", expected->instruction_error_index, actual->instruction_error_index )); + return 0; + } + + /* TxnResult -> custom_error */ + if( expected->instruction_error == (ulong) -FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR && expected->custom_error != actual->custom_error ) { + FD_LOG_WARNING(( "Custom error mismatch: expected=%u actual=%u", expected->custom_error, actual->custom_error )); + return 0; + } + } + + /* TxnResult -> return_data */ + if( expected->return_data != NULL || actual->return_data != NULL ) { + if( expected->return_data == NULL ) { + FD_LOG_WARNING(( "Expected return data is NULL, actual is non-NULL" )); + return 0; + } + + if( actual->return_data == NULL ) { + FD_LOG_WARNING(( "Expected return data is NULL, actual is non-NULL" )); + return 0; + } + + if( expected->return_data->size != actual->return_data->size ) { + FD_LOG_WARNING(( "Return data size mismatch: expected=%u actual=%u", expected->return_data->size, actual->return_data->size )); + return 0; + } + + if( !fd_memeq( expected->return_data->bytes, actual->return_data->bytes, expected->return_data->size ) ) { + FD_LOG_WARNING(( "Return data mismatch" )); + return 0; + } + } + + /* TxnResult -> executed_units */ + if( expected->executed_units != actual->executed_units ) { + FD_LOG_WARNING(( "Executed units mismatch: expected=%lu actual=%lu", expected->executed_units, actual->executed_units )); + return 0; + } + + /* TxnResult -> fee_details */ + if( expected->has_fee_details != actual->has_fee_details ) { + FD_LOG_WARNING(( "Has fee details mismatch: expected=%d actual=%d", expected->has_fee_details, actual->has_fee_details )); + return 0; + } + + if( expected->has_fee_details ) { + if( expected->fee_details.transaction_fee != actual->fee_details.transaction_fee ) { + FD_LOG_WARNING(( "Transaction fee mismatch: expected=%lu actual=%lu", expected->fee_details.transaction_fee, actual->fee_details.transaction_fee )); + return 0; + } + + if( expected->fee_details.prioritization_fee != actual->fee_details.prioritization_fee ) { + FD_LOG_WARNING(( "Priority fee mismatch: expected=%lu actual=%lu", expected->fee_details.prioritization_fee, actual->fee_details.prioritization_fee )); + return 0; + } + } + + /* TxnResult -> loaded_accounts_data_size */ + if( expected->loaded_accounts_data_size != actual->loaded_accounts_data_size ) { + FD_LOG_WARNING(( "Loaded accounts data size mismatch: expected=%lu actual=%lu", expected->loaded_accounts_data_size, actual->loaded_accounts_data_size )); + return 0; + } + + return 1; +} + +int +fd_solfuzz_instr_fixture( fd_solfuzz_runner_t * runner, + uchar const * in, + ulong in_sz ) { + // Decode fixture + fd_exec_test_instr_fixture_t fixture[1] = {0}; + void * res = sol_compat_decode( &fixture, in, in_sz, &fd_exec_test_instr_fixture_t_msg ); + if( !res ) { + FD_LOG_WARNING(( "Invalid instr fixture." )); + return 0; + } + + int ok = 0; + // Execute + void * output = NULL; + fd_solfuzz_execute_wrapper( runner, &fixture->input, &output, fd_solfuzz_instr_run ); + + // Compare effects + ok = sol_compat_cmp_binary_strict( output, &fixture->output, &fd_exec_test_instr_effects_t_msg, runner->spad ); + + // Cleanup + pb_release( &fd_exec_test_instr_fixture_t_msg, fixture ); + return ok; +} + +int +fd_solfuzz_txn_fixture( fd_solfuzz_runner_t * runner, + uchar const * in, + ulong in_sz ) { + // Decode fixture + fd_exec_test_txn_fixture_t fixture[1] = {0}; + void * res = sol_compat_decode( &fixture, in, in_sz, &fd_exec_test_txn_fixture_t_msg ); + if( !res ) { + FD_LOG_WARNING(( "Invalid txn fixture." )); + return 0; + } + + fd_spad_push( runner->spad ); + int ok = 0; + void * output = NULL; + fd_solfuzz_execute_wrapper( runner, &fixture->input, &output, fd_solfuzz_txn_run ); + if( FD_LIKELY( output ) ) { + // Compare effects + fd_exec_test_txn_result_t * effects = output; + ok = sol_compat_cmp_txn( &fixture->output, effects ); + } + fd_spad_pop( runner->spad ); + + // Cleanup + pb_release( &fd_exec_test_txn_fixture_t_msg, fixture ); + return ok; +} + +int +fd_solfuzz_block_fixture( fd_solfuzz_runner_t * runner, + uchar const * in, + ulong in_sz ) { + // Decode fixture + fd_exec_test_block_fixture_t fixture[1] = {0}; + void * res = sol_compat_decode( &fixture, in, in_sz, &fd_exec_test_block_fixture_t_msg ); + if( !res ) { + FD_LOG_WARNING(( "Invalid block fixture" )); + return 0; + } + + fd_spad_push( runner->spad ); + void * output = NULL; + fd_solfuzz_execute_wrapper( runner, &fixture->input, &output, fd_solfuzz_block_run ); + int ok = sol_compat_cmp_binary_strict( output, &fixture->output, &fd_exec_test_block_effects_t_msg, runner->spad ); + fd_spad_pop( runner->spad ); + + // Cleanup + pb_release( &fd_exec_test_block_fixture_t_msg, fixture ); + return ok; +} + +int +fd_solfuzz_elf_loader_fixture( fd_solfuzz_runner_t * runner, + uchar const * in, + ulong in_sz ) { + // Decode fixture + fd_exec_test_elf_loader_fixture_t fixture[1] = {0}; + void * res = sol_compat_decode( &fixture, in, in_sz, &fd_exec_test_elf_loader_fixture_t_msg ); + if( !res ) { + FD_LOG_WARNING(( "Invalid elf_loader fixture." )); + return 0; + } + + fd_spad_push( runner->spad ); + void * output = NULL; + fd_solfuzz_execute_wrapper( runner, &fixture->input, &output, fd_solfuzz_elf_loader_run ); + int ok = sol_compat_cmp_binary_strict( output, &fixture->output, &fd_exec_test_elf_loader_effects_t_msg, runner->spad ); + fd_spad_pop( runner->spad ); + + // Cleanup + pb_release( &fd_exec_test_elf_loader_fixture_t_msg, fixture ); + return ok; +} + +int +fd_solfuzz_syscall_fixture( fd_solfuzz_runner_t * runner, + uchar const * in, + ulong in_sz ) { + // Decode fixture + fd_exec_test_syscall_fixture_t fixture[1] = {0}; + if( !sol_compat_decode( &fixture, in, in_sz, &fd_exec_test_syscall_fixture_t_msg ) ) { + FD_LOG_WARNING(( "Invalid syscall fixture." )); + return 0; + } + + fd_spad_push( runner->spad ); + void * output = NULL; + fd_solfuzz_execute_wrapper( runner, &fixture->input, &output, fd_solfuzz_syscall_run ); + int ok = sol_compat_cmp_binary_strict( output, &fixture->output, &fd_exec_test_syscall_effects_t_msg, runner->spad ); + fd_spad_pop( runner->spad ); + + // Cleanup + pb_release( &fd_exec_test_syscall_fixture_t_msg, fixture ); + return ok; +} + +int +fd_solfuzz_vm_interp_fixture( fd_solfuzz_runner_t * runner, + uchar const * in, + ulong in_sz ) { + // Decode fixture + fd_exec_test_syscall_fixture_t fixture[1] = {0}; + if( !sol_compat_decode( &fixture, in, in_sz, &fd_exec_test_syscall_fixture_t_msg ) ) { + FD_LOG_WARNING(( "Invalid syscall fixture." )); + return 0; + } + + fd_spad_push( runner->spad ); + void * output = NULL; + fd_solfuzz_execute_wrapper( runner, &fixture->input, &output, fd_solfuzz_vm_interp_run ); + int ok = sol_compat_cmp_binary_strict( output, &fixture->output, &fd_exec_test_syscall_effects_t_msg, runner->spad ); + fd_spad_pop( runner->spad ); + + // Cleanup + pb_release( &fd_exec_test_syscall_fixture_t_msg, fixture ); + return ok; +} diff --git a/src/flamenco/runtime/tests/fd_solfuzz_private.h b/src/flamenco/runtime/tests/fd_solfuzz_private.h new file mode 100644 index 00000000000..67861e33725 --- /dev/null +++ b/src/flamenco/runtime/tests/fd_solfuzz_private.h @@ -0,0 +1,92 @@ +#ifndef HEADER_fd_src_flamenco_runtime_tests_harness_fd_solfuzz_private_h +#define HEADER_fd_src_flamenco_runtime_tests_harness_fd_solfuzz_private_h + +/* fd_solfuzz_private.h contains internal components for the solfuzz + Protobuf shim. */ + +#include "fd_solfuzz.h" +#include "../../features/fd_features.h" +#include "../../../ballet/nanopb/pb_encode.h" +#include "../../../ballet/nanopb/pb_decode.h" +#include "generated/context.pb.h" + +FD_PROTOTYPES_BEGIN + +/* Creates / overwrites an account in funk given an input account state. + On success, loads the account into `acc`. Optionally, reject any zero-lamport + accounts from being loaded in. */ +int +fd_runtime_fuzz_load_account( fd_txn_account_t * acc, + fd_funk_t * funk, + fd_funk_txn_t * funk_txn, + fd_exec_test_acct_state_t const * state, + uchar reject_zero_lamports ); + +/* Activates features in the runtime given an input feature set. Fails if a passed-in feature + is unknown / not supported. */ +int +fd_runtime_fuzz_restore_features( fd_features_t * features, + fd_exec_test_feature_set_t const * feature_set ); + +void +fd_runtime_fuzz_refresh_program_cache( fd_exec_slot_ctx_t * slot_ctx, + fd_exec_test_acct_state_t const * acct_states, + ulong acct_states_count, + fd_spad_t * runtime_spad ); + +typedef ulong( exec_test_run_fn_t )( fd_solfuzz_runner_t *, + void const *, + void **, + void *, + ulong ); + +static inline void +fd_solfuzz_execute_wrapper( fd_solfuzz_runner_t * runner, + void * input, + void ** output, + exec_test_run_fn_t * exec_test_run_fn ) { + + ulong out_bufsz = 100000000; /* 100 MB */ + void * out0 = fd_spad_alloc( runner->spad, 1UL, out_bufsz ); + FD_TEST( out_bufsz <= fd_spad_alloc_max( runner->spad, 1UL ) ); + + ulong out_used = exec_test_run_fn( runner, input, output, out0, out_bufsz ); + if( FD_UNLIKELY( !out_used ) ) { + *output = NULL; + } + +} + +/* Utils */ + +static FD_FN_UNUSED void * +sol_compat_decode( void * decoded, + uchar const * in, + ulong in_sz, + pb_msgdesc_t const * decode_type ) { + pb_istream_t istream = pb_istream_from_buffer( in, in_sz ); + int decode_ok = pb_decode_ex( &istream, decode_type, decoded, PB_DECODE_NOINIT ); + if( !decode_ok ) { + pb_release( decode_type, decoded ); + return NULL; + } + return decoded; +} + +static FD_FN_UNUSED void const * +sol_compat_encode( uchar * out, + ulong * out_sz, + void const * to_encode, + pb_msgdesc_t const * encode_type ) { + pb_ostream_t ostream = pb_ostream_from_buffer( out, *out_sz ); + int encode_ok = pb_encode( &ostream, encode_type, to_encode ); + if( !encode_ok ) { + return NULL; + } + *out_sz = ostream.bytes_written; + return to_encode; +} + +FD_PROTOTYPES_END + +#endif /* HEADER_fd_src_flamenco_runtime_tests_harness_fd_solfuzz_private_h */ diff --git a/src/flamenco/runtime/tests/harness/fd_txn_harness.c b/src/flamenco/runtime/tests/fd_txn_harness.c similarity index 90% rename from src/flamenco/runtime/tests/harness/fd_txn_harness.c rename to src/flamenco/runtime/tests/fd_txn_harness.c index 1cdf40373b4..5d65b311e29 100644 --- a/src/flamenco/runtime/tests/harness/fd_txn_harness.c +++ b/src/flamenco/runtime/tests/fd_txn_harness.c @@ -1,9 +1,43 @@ +#include "fd_solfuzz.h" +#include "fd_solfuzz_private.h" #include "fd_txn_harness.h" -#include "fd_harness_common.h" +#include "../fd_runtime.h" +#include "../fd_executor.h" +#include "../fd_txn_account.h" +#include "../context/fd_exec_slot_ctx.h" +#include "../program/fd_builtin_programs.h" +#include "../sysvar/fd_sysvar_clock.h" +#include "../sysvar/fd_sysvar_epoch_rewards.h" +#include "../sysvar/fd_sysvar_epoch_schedule.h" +#include "../sysvar/fd_sysvar_recent_hashes.h" +#include "../sysvar/fd_sysvar_rent.h" +#include "../sysvar/fd_sysvar_slot_hashes.h" +#include "../sysvar/fd_sysvar_stake_history.h" +#include "../sysvar/fd_sysvar_last_restart_slot.h" +#include "../../../disco/pack/fd_pack.h" +#include + +/* Macros to append data to construct a serialized transaction + without exceeding bounds */ +#define FD_CHECKED_ADD_TO_TXN_DATA( _begin, _cur_data, _to_add, _sz ) __extension__({ \ + if( FD_UNLIKELY( (*_cur_data)+_sz>_begin+FD_TXN_MTU ) ) return ULONG_MAX; \ + fd_memcpy( *_cur_data, _to_add, _sz ); \ + *_cur_data += _sz; \ +}) + +#define FD_CHECKED_ADD_CU16_TO_TXN_DATA( _begin, _cur_data, _to_add ) __extension__({ \ + do { \ + uchar _buf[3]; \ + fd_bincode_encode_ctx_t _encode_ctx = { .data = _buf, .dataend = _buf+3 }; \ + fd_bincode_compact_u16_encode( &_to_add, &_encode_ctx ); \ + ulong _sz = (ulong) ((uchar *)_encode_ctx.data - _buf ); \ + FD_CHECKED_ADD_TO_TXN_DATA( _begin, _cur_data, _buf, _sz ); \ + } while(0); \ +}) static void -fd_runtime_fuzz_txn_ctx_destroy( fd_runtime_fuzz_runner_t * runner, - fd_exec_slot_ctx_t * slot_ctx ) { +fd_runtime_fuzz_txn_ctx_destroy( fd_solfuzz_runner_t * runner, + fd_exec_slot_ctx_t * slot_ctx ) { if( !slot_ctx ) return; // This shouldn't be false either fd_funk_txn_t * funk_txn = slot_ctx->funk_txn; @@ -13,7 +47,7 @@ fd_runtime_fuzz_txn_ctx_destroy( fd_runtime_fuzz_runner_t * runner, /* Creates transaction execution context for a single test case. Returns a a parsed txn descriptor on success and NULL on failure. */ static fd_txn_p_t * -fd_runtime_fuzz_txn_ctx_create( fd_runtime_fuzz_runner_t * runner, +fd_runtime_fuzz_txn_ctx_create( fd_solfuzz_runner_t * runner, fd_exec_slot_ctx_t * slot_ctx, fd_exec_test_txn_context_t const * test_ctx ) { fd_funk_t * funk = runner->funk; @@ -352,10 +386,10 @@ fd_runtime_fuzz_serialize_txn( uchar * txn_ } fd_exec_txn_ctx_t * -fd_runtime_fuzz_txn_ctx_exec( fd_runtime_fuzz_runner_t * runner, - fd_exec_slot_ctx_t * slot_ctx, - fd_txn_p_t * txn, - int * exec_res ) { +fd_runtime_fuzz_txn_ctx_exec( fd_solfuzz_runner_t * runner, + fd_exec_slot_ctx_t * slot_ctx, + fd_txn_p_t * txn, + int * exec_res ) { /* Setup the spad for account allocation */ uchar * txn_ctx_mem = fd_spad_alloc( runner->spad, FD_EXEC_TXN_CTX_ALIGN, FD_EXEC_TXN_CTX_FOOTPRINT ); @@ -376,11 +410,11 @@ fd_runtime_fuzz_txn_ctx_exec( fd_runtime_fuzz_runner_t * runner, } ulong -fd_runtime_fuzz_txn_run( fd_runtime_fuzz_runner_t * runner, - void const * input_, - void ** output_, - void * output_buf, - ulong output_bufsz ) { +fd_solfuzz_txn_run( fd_solfuzz_runner_t * runner, + void const * input_, + void ** output_, + void * output_buf, + ulong output_bufsz ) { fd_exec_test_txn_context_t const * input = fd_type_pun_const( input_ ); fd_exec_test_txn_result_t ** output = fd_type_pun( output_ ); diff --git a/src/flamenco/runtime/tests/fd_txn_harness.h b/src/flamenco/runtime/tests/fd_txn_harness.h new file mode 100644 index 00000000000..4e362b0d7f1 --- /dev/null +++ b/src/flamenco/runtime/tests/fd_txn_harness.h @@ -0,0 +1,30 @@ +#ifndef HEADER_fd_src_flamenco_runtime_tests_harness_fd_txn_harness_h +#define HEADER_fd_src_flamenco_runtime_tests_harness_fd_txn_harness_h + +#include "fd_solfuzz.h" +#include "../../../disco/pack/fd_microblock.h" +#include "generated/txn.pb.h" + +FD_PROTOTYPES_BEGIN + +/* Serializes a Protobuf SanitizedTransaction that can be parsed into a + txn descriptor and returns the number of bytes consumed. Returns + ULONG_MAX if the number of bytes read exceeds 1232 (FD_TXN_MTU). + _txn_raw_begin is assumed to be a pre-allocated buffer of at least + 1232 bytes. */ +ulong +fd_runtime_fuzz_serialize_txn( uchar * txn_raw_begin, + fd_exec_test_sanitized_transaction_t const * tx ); + +/* Takes in a parsed txn descriptor to be executed against the runtime. + Returns the spad-allocated transaction context. Writes the execution + result to the `exec_res` pointer (assumed to be pre-allocated). */ +fd_exec_txn_ctx_t * +fd_runtime_fuzz_txn_ctx_exec( fd_solfuzz_runner_t * runner, + fd_exec_slot_ctx_t * slot_ctx, + fd_txn_p_t * txn, + int * exec_res ); + +FD_PROTOTYPES_END + +#endif /* HEADER_fd_src_flamenco_runtime_tests_harness_fd_txn_harness_h */ diff --git a/src/flamenco/runtime/tests/harness/fd_types_harness.c b/src/flamenco/runtime/tests/fd_types_harness.c similarity index 92% rename from src/flamenco/runtime/tests/harness/fd_types_harness.c rename to src/flamenco/runtime/tests/fd_types_harness.c index 5aae4aea7af..412cfdcc2b2 100644 --- a/src/flamenco/runtime/tests/harness/fd_types_harness.c +++ b/src/flamenco/runtime/tests/fd_types_harness.c @@ -1,7 +1,7 @@ -#include "fd_types_harness.h" -#include "../../../types/fd_types_yaml.h" -#include "../../../types/fd_types_reflect.h" -#include +#include "fd_solfuzz.h" +#include "../../types/fd_types_yaml.h" +#include "../../types/fd_types_reflect.h" +#include #include "generated/type.pb.h" @@ -162,11 +162,11 @@ custom_serializer_walk( void * _self, } static int -fd_runtime_fuzz_decode_type_run( fd_runtime_fuzz_runner_t * runner, - uchar const * input, - ulong input_sz, - uchar * output, - ulong * output_sz ) { +fd_runtime_fuzz_decode_type_run( fd_solfuzz_runner_t * runner, + uchar const * input, + ulong input_sz, + uchar * output, + ulong * output_sz ) { FD_SPAD_FRAME_BEGIN( runner->spad ) { if( input_sz < 1 ) { @@ -290,11 +290,11 @@ fd_runtime_fuzz_decode_type_run( fd_runtime_fuzz_runner_t * runner, } ulong -fd_runtime_fuzz_type_run( fd_runtime_fuzz_runner_t * runner, - void const * input_, - void ** output_, - void * output_buf, - ulong output_bufsz ) { +fd_runtime_fuzz_type_run( fd_solfuzz_runner_t * runner, + void const * input_, + void ** output_, + void * output_buf, + ulong output_bufsz ) { fd_exec_test_type_context_t const * input = fd_type_pun_const( input_ ); fd_exec_test_type_effects_t ** output = fd_type_pun( output_ ); diff --git a/src/flamenco/runtime/tests/harness/fd_vm_harness.c b/src/flamenco/runtime/tests/fd_vm_harness.c similarity index 96% rename from src/flamenco/runtime/tests/harness/fd_vm_harness.c rename to src/flamenco/runtime/tests/fd_vm_harness.c index 8e0c31a40b9..8170d3ccea3 100644 --- a/src/flamenco/runtime/tests/harness/fd_vm_harness.c +++ b/src/flamenco/runtime/tests/fd_vm_harness.c @@ -1,4 +1,12 @@ -#include "fd_vm_harness.h" +#include "fd_instr_harness.h" +#include "../fd_executor.h" +#include "../fd_system_ids.h" +#include "../program/fd_bpf_loader_serialization.h" +#include "../context/fd_exec_txn_ctx.h" +#include "../../../ballet/sbpf/fd_sbpf_loader.h" +#include "../../vm/fd_vm.h" +#include "../../vm/test_vm_util.h" +#include "generated/vm.pb.h" static int fd_runtime_fuzz_vm_syscall_noop( void * _vm, @@ -87,11 +95,11 @@ fd_runtime_fuzz_load_from_vm_input_regions( fd_vm_input_region_t const * ulong -fd_runtime_fuzz_vm_interp_run( fd_runtime_fuzz_runner_t * runner, - void const * input_, - void ** output_, - void * output_buf, - ulong output_bufsz ) { +fd_solfuzz_vm_interp_run( fd_solfuzz_runner_t * runner, + void const * input_, + void ** output_, + void * output_buf, + ulong output_bufsz ) { fd_exec_test_syscall_context_t const * input = fd_type_pun_const( input_ ); fd_exec_test_syscall_effects_t ** output = fd_type_pun( output_ ); @@ -370,11 +378,11 @@ do{ } ulong -fd_runtime_fuzz_vm_syscall_run( fd_runtime_fuzz_runner_t * runner, - void const * input_, - void ** output_, - void * output_buf, - ulong output_bufsz ) { +fd_solfuzz_syscall_run( fd_solfuzz_runner_t * runner, + void const * input_, + void ** output_, + void * output_buf, + ulong output_bufsz ) { fd_exec_test_syscall_context_t const * input = fd_type_pun_const( input_ ); fd_exec_test_syscall_effects_t ** output = fd_type_pun( output_ ); diff --git a/src/flamenco/runtime/tests/fetch_and_generate.sh b/src/flamenco/runtime/tests/fetch_and_generate.sh index bb2c590d4c0..3c511f24b3a 100755 --- a/src/flamenco/runtime/tests/fetch_and_generate.sh +++ b/src/flamenco/runtime/tests/fetch_and_generate.sh @@ -31,4 +31,4 @@ else cd .. fi -./nanopb/generator/nanopb_generator.py -I ../.. -I ./protosol/proto -L "" -C ./protosol/proto/*.proto -D harness/generated +./nanopb/generator/nanopb_generator.py -I ./protosol/proto -L "" -C ./protosol/proto/*.proto -D generated diff --git a/src/flamenco/runtime/tests/harness/generated/block.pb.c b/src/flamenco/runtime/tests/generated/block.pb.c similarity index 100% rename from src/flamenco/runtime/tests/harness/generated/block.pb.c rename to src/flamenco/runtime/tests/generated/block.pb.c diff --git a/src/flamenco/runtime/tests/harness/generated/block.pb.h b/src/flamenco/runtime/tests/generated/block.pb.h similarity index 99% rename from src/flamenco/runtime/tests/harness/generated/block.pb.h rename to src/flamenco/runtime/tests/generated/block.pb.h index 0884ba6dffc..df5664b0ea2 100644 --- a/src/flamenco/runtime/tests/harness/generated/block.pb.h +++ b/src/flamenco/runtime/tests/generated/block.pb.h @@ -4,7 +4,7 @@ #ifndef PB_ORG_SOLANA_SEALEVEL_V1_BLOCK_PB_H_INCLUDED #define PB_ORG_SOLANA_SEALEVEL_V1_BLOCK_PB_H_INCLUDED -#include "../../../../../ballet/nanopb/pb_firedancer.h" +#include "../../../../ballet/nanopb/pb_firedancer.h" #include "context.pb.h" #include "txn.pb.h" #include "metadata.pb.h" diff --git a/src/flamenco/runtime/tests/harness/generated/context.pb.c b/src/flamenco/runtime/tests/generated/context.pb.c similarity index 100% rename from src/flamenco/runtime/tests/harness/generated/context.pb.c rename to src/flamenco/runtime/tests/generated/context.pb.c diff --git a/src/flamenco/runtime/tests/harness/generated/context.pb.h b/src/flamenco/runtime/tests/generated/context.pb.h similarity index 99% rename from src/flamenco/runtime/tests/harness/generated/context.pb.h rename to src/flamenco/runtime/tests/generated/context.pb.h index 4ea68ed9ff4..5774abe495c 100644 --- a/src/flamenco/runtime/tests/harness/generated/context.pb.h +++ b/src/flamenco/runtime/tests/generated/context.pb.h @@ -4,7 +4,7 @@ #ifndef PB_ORG_SOLANA_SEALEVEL_V1_CONTEXT_PB_H_INCLUDED #define PB_ORG_SOLANA_SEALEVEL_V1_CONTEXT_PB_H_INCLUDED -#include "../../../../../ballet/nanopb/pb_firedancer.h" +#include "../../../../ballet/nanopb/pb_firedancer.h" #if PB_PROTO_HEADER_VERSION != 40 #error Regenerate this file with the current version of nanopb generator. diff --git a/src/flamenco/runtime/tests/harness/generated/elf.pb.c b/src/flamenco/runtime/tests/generated/elf.pb.c similarity index 100% rename from src/flamenco/runtime/tests/harness/generated/elf.pb.c rename to src/flamenco/runtime/tests/generated/elf.pb.c diff --git a/src/flamenco/runtime/tests/harness/generated/elf.pb.h b/src/flamenco/runtime/tests/generated/elf.pb.h similarity index 99% rename from src/flamenco/runtime/tests/harness/generated/elf.pb.h rename to src/flamenco/runtime/tests/generated/elf.pb.h index 6d4d6a00e2b..2d7f86aab78 100644 --- a/src/flamenco/runtime/tests/harness/generated/elf.pb.h +++ b/src/flamenco/runtime/tests/generated/elf.pb.h @@ -4,7 +4,7 @@ #ifndef PB_ORG_SOLANA_SEALEVEL_V1_ELF_PB_H_INCLUDED #define PB_ORG_SOLANA_SEALEVEL_V1_ELF_PB_H_INCLUDED -#include "../../../../../ballet/nanopb/pb_firedancer.h" +#include "../../../../ballet/nanopb/pb_firedancer.h" #include "context.pb.h" #include "metadata.pb.h" diff --git a/src/flamenco/runtime/tests/harness/generated/invoke.pb.c b/src/flamenco/runtime/tests/generated/invoke.pb.c similarity index 100% rename from src/flamenco/runtime/tests/harness/generated/invoke.pb.c rename to src/flamenco/runtime/tests/generated/invoke.pb.c diff --git a/src/flamenco/runtime/tests/harness/generated/invoke.pb.h b/src/flamenco/runtime/tests/generated/invoke.pb.h similarity index 99% rename from src/flamenco/runtime/tests/harness/generated/invoke.pb.h rename to src/flamenco/runtime/tests/generated/invoke.pb.h index 6880b667005..11d1f3e740e 100644 --- a/src/flamenco/runtime/tests/harness/generated/invoke.pb.h +++ b/src/flamenco/runtime/tests/generated/invoke.pb.h @@ -4,7 +4,7 @@ #ifndef PB_ORG_SOLANA_SEALEVEL_V1_INVOKE_PB_H_INCLUDED #define PB_ORG_SOLANA_SEALEVEL_V1_INVOKE_PB_H_INCLUDED -#include "../../../../../ballet/nanopb/pb_firedancer.h" +#include "../../../../ballet/nanopb/pb_firedancer.h" #include "context.pb.h" #include "metadata.pb.h" diff --git a/src/flamenco/runtime/tests/harness/generated/metadata.pb.c b/src/flamenco/runtime/tests/generated/metadata.pb.c similarity index 100% rename from src/flamenco/runtime/tests/harness/generated/metadata.pb.c rename to src/flamenco/runtime/tests/generated/metadata.pb.c diff --git a/src/flamenco/runtime/tests/harness/generated/metadata.pb.h b/src/flamenco/runtime/tests/generated/metadata.pb.h similarity index 97% rename from src/flamenco/runtime/tests/harness/generated/metadata.pb.h rename to src/flamenco/runtime/tests/generated/metadata.pb.h index 22540d338a8..75274ae94d5 100644 --- a/src/flamenco/runtime/tests/harness/generated/metadata.pb.h +++ b/src/flamenco/runtime/tests/generated/metadata.pb.h @@ -4,7 +4,7 @@ #ifndef PB_ORG_SOLANA_SEALEVEL_V1_METADATA_PB_H_INCLUDED #define PB_ORG_SOLANA_SEALEVEL_V1_METADATA_PB_H_INCLUDED -#include "../../../../../ballet/nanopb/pb_firedancer.h" +#include "../../../../ballet/nanopb/pb_firedancer.h" #if PB_PROTO_HEADER_VERSION != 40 #error Regenerate this file with the current version of nanopb generator. diff --git a/src/flamenco/runtime/tests/generated/pack.pb.c b/src/flamenco/runtime/tests/generated/pack.pb.c new file mode 100644 index 00000000000..18071411b00 --- /dev/null +++ b/src/flamenco/runtime/tests/generated/pack.pb.c @@ -0,0 +1,18 @@ +/* Automatically generated nanopb constant definitions */ +/* Generated by nanopb-0.4.9.1 */ + +#include "pack.pb.h" +#if PB_PROTO_HEADER_VERSION != 40 +#error Regenerate this file with the current version of nanopb generator. +#endif + +PB_BIND(FD_EXEC_TEST_PACK_COMPUTE_BUDGET_CONTEXT, fd_exec_test_pack_compute_budget_context_t, AUTO) + + +PB_BIND(FD_EXEC_TEST_PACK_COMPUTE_BUDGET_EFFECTS, fd_exec_test_pack_compute_budget_effects_t, AUTO) + + +PB_BIND(FD_EXEC_TEST_PACK_COMPUTE_BUDGET_FIXTURE, fd_exec_test_pack_compute_budget_fixture_t, AUTO) + + + diff --git a/src/flamenco/runtime/tests/generated/pack.pb.h b/src/flamenco/runtime/tests/generated/pack.pb.h new file mode 100644 index 00000000000..63f5b38a8a7 --- /dev/null +++ b/src/flamenco/runtime/tests/generated/pack.pb.h @@ -0,0 +1,123 @@ +/* Automatically generated nanopb header */ +/* Generated by nanopb-0.4.9.1 */ + +#ifndef PB_ORG_SOLANA_SEALEVEL_V1_PACK_PB_H_INCLUDED +#define PB_ORG_SOLANA_SEALEVEL_V1_PACK_PB_H_INCLUDED + +#include "../../../../ballet/nanopb/pb_firedancer.h" +#include "metadata.pb.h" +#include "context.pb.h" + +#if PB_PROTO_HEADER_VERSION != 40 +#error Regenerate this file with the current version of nanopb generator. +#endif + +/* Struct definitions */ +typedef struct fd_exec_test_pack_compute_budget_context { + pb_size_t instr_datas_count; + pb_bytes_array_t **instr_datas; + bool has_features; + fd_exec_test_feature_set_t features; +} fd_exec_test_pack_compute_budget_context_t; + +typedef struct fd_exec_test_pack_compute_budget_effects { + uint64_t compute_unit_limit; + uint64_t rewards; + uint32_t heap_sz; + uint32_t loaded_acct_data_sz; + /* To prevent empty effects when encoding a "skipped" effects */ + uint32_t is_empty; +} fd_exec_test_pack_compute_budget_effects_t; + +typedef struct fd_exec_test_pack_compute_budget_fixture { + bool has_metadata; + fd_exec_test_fixture_metadata_t metadata; + bool has_input; + fd_exec_test_pack_compute_budget_context_t input; + bool has_output; + fd_exec_test_pack_compute_budget_effects_t output; +} fd_exec_test_pack_compute_budget_fixture_t; + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Initializer values for message structs */ +#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_CONTEXT_INIT_DEFAULT {0, NULL, false, FD_EXEC_TEST_FEATURE_SET_INIT_DEFAULT} +#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_EFFECTS_INIT_DEFAULT {0, 0, 0, 0, 0} +#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_FIXTURE_INIT_DEFAULT {false, FD_EXEC_TEST_FIXTURE_METADATA_INIT_DEFAULT, false, FD_EXEC_TEST_PACK_COMPUTE_BUDGET_CONTEXT_INIT_DEFAULT, false, FD_EXEC_TEST_PACK_COMPUTE_BUDGET_EFFECTS_INIT_DEFAULT} +#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_CONTEXT_INIT_ZERO {0, NULL, false, FD_EXEC_TEST_FEATURE_SET_INIT_ZERO} +#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_EFFECTS_INIT_ZERO {0, 0, 0, 0, 0} +#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_FIXTURE_INIT_ZERO {false, FD_EXEC_TEST_FIXTURE_METADATA_INIT_ZERO, false, FD_EXEC_TEST_PACK_COMPUTE_BUDGET_CONTEXT_INIT_ZERO, false, FD_EXEC_TEST_PACK_COMPUTE_BUDGET_EFFECTS_INIT_ZERO} + +/* Field tags (for use in manual encoding/decoding) */ +#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_CONTEXT_INSTR_DATAS_TAG 1 +#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_CONTEXT_FEATURES_TAG 2 +#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_EFFECTS_COMPUTE_UNIT_LIMIT_TAG 1 +#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_EFFECTS_REWARDS_TAG 2 +#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_EFFECTS_HEAP_SZ_TAG 3 +#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_EFFECTS_LOADED_ACCT_DATA_SZ_TAG 4 +#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_EFFECTS_IS_EMPTY_TAG 5 +#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_FIXTURE_METADATA_TAG 1 +#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_FIXTURE_INPUT_TAG 2 +#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_FIXTURE_OUTPUT_TAG 3 + +/* Struct field encoding specification for nanopb */ +#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_CONTEXT_FIELDLIST(X, a) \ +X(a, POINTER, REPEATED, BYTES, instr_datas, 1) \ +X(a, STATIC, OPTIONAL, MESSAGE, features, 2) +#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_CONTEXT_CALLBACK NULL +#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_CONTEXT_DEFAULT NULL +#define fd_exec_test_pack_compute_budget_context_t_features_MSGTYPE fd_exec_test_feature_set_t + +#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_EFFECTS_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, UINT64, compute_unit_limit, 1) \ +X(a, STATIC, SINGULAR, UINT64, rewards, 2) \ +X(a, STATIC, SINGULAR, UINT32, heap_sz, 3) \ +X(a, STATIC, SINGULAR, UINT32, loaded_acct_data_sz, 4) \ +X(a, STATIC, SINGULAR, UINT32, is_empty, 5) +#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_EFFECTS_CALLBACK NULL +#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_EFFECTS_DEFAULT NULL + +#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_FIXTURE_FIELDLIST(X, a) \ +X(a, STATIC, OPTIONAL, MESSAGE, metadata, 1) \ +X(a, STATIC, OPTIONAL, MESSAGE, input, 2) \ +X(a, STATIC, OPTIONAL, MESSAGE, output, 3) +#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_FIXTURE_CALLBACK NULL +#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_FIXTURE_DEFAULT NULL +#define fd_exec_test_pack_compute_budget_fixture_t_metadata_MSGTYPE fd_exec_test_fixture_metadata_t +#define fd_exec_test_pack_compute_budget_fixture_t_input_MSGTYPE fd_exec_test_pack_compute_budget_context_t +#define fd_exec_test_pack_compute_budget_fixture_t_output_MSGTYPE fd_exec_test_pack_compute_budget_effects_t + +extern const pb_msgdesc_t fd_exec_test_pack_compute_budget_context_t_msg; +extern const pb_msgdesc_t fd_exec_test_pack_compute_budget_effects_t_msg; +extern const pb_msgdesc_t fd_exec_test_pack_compute_budget_fixture_t_msg; + +/* Defines for backwards compatibility with code written before nanopb-0.4.0 */ +#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_CONTEXT_FIELDS &fd_exec_test_pack_compute_budget_context_t_msg +#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_EFFECTS_FIELDS &fd_exec_test_pack_compute_budget_effects_t_msg +#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_FIXTURE_FIELDS &fd_exec_test_pack_compute_budget_fixture_t_msg + +/* Maximum encoded size of messages (where known) */ +/* fd_exec_test_PackComputeBudgetContext_size depends on runtime parameters */ +/* fd_exec_test_PackComputeBudgetFixture_size depends on runtime parameters */ +#define FD_EXEC_TEST_PACK_COMPUTE_BUDGET_EFFECTS_SIZE 40 +#define ORG_SOLANA_SEALEVEL_V1_PACK_PB_H_MAX_SIZE FD_EXEC_TEST_PACK_COMPUTE_BUDGET_EFFECTS_SIZE + +/* Mapping from canonical names (mangle_names or overridden package name) */ +#define org_solana_sealevel_v1_PackComputeBudgetContext fd_exec_test_PackComputeBudgetContext +#define org_solana_sealevel_v1_PackComputeBudgetEffects fd_exec_test_PackComputeBudgetEffects +#define org_solana_sealevel_v1_PackComputeBudgetFixture fd_exec_test_PackComputeBudgetFixture +#define ORG_SOLANA_SEALEVEL_V1_PACK_COMPUTE_BUDGET_CONTEXT_INIT_DEFAULT FD_EXEC_TEST_PACK_COMPUTE_BUDGET_CONTEXT_INIT_DEFAULT +#define ORG_SOLANA_SEALEVEL_V1_PACK_COMPUTE_BUDGET_EFFECTS_INIT_DEFAULT FD_EXEC_TEST_PACK_COMPUTE_BUDGET_EFFECTS_INIT_DEFAULT +#define ORG_SOLANA_SEALEVEL_V1_PACK_COMPUTE_BUDGET_FIXTURE_INIT_DEFAULT FD_EXEC_TEST_PACK_COMPUTE_BUDGET_FIXTURE_INIT_DEFAULT +#define ORG_SOLANA_SEALEVEL_V1_PACK_COMPUTE_BUDGET_CONTEXT_INIT_ZERO FD_EXEC_TEST_PACK_COMPUTE_BUDGET_CONTEXT_INIT_ZERO +#define ORG_SOLANA_SEALEVEL_V1_PACK_COMPUTE_BUDGET_EFFECTS_INIT_ZERO FD_EXEC_TEST_PACK_COMPUTE_BUDGET_EFFECTS_INIT_ZERO +#define ORG_SOLANA_SEALEVEL_V1_PACK_COMPUTE_BUDGET_FIXTURE_INIT_ZERO FD_EXEC_TEST_PACK_COMPUTE_BUDGET_FIXTURE_INIT_ZERO + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/src/flamenco/runtime/tests/harness/generated/serialize.pb.c b/src/flamenco/runtime/tests/generated/serialize.pb.c similarity index 100% rename from src/flamenco/runtime/tests/harness/generated/serialize.pb.c rename to src/flamenco/runtime/tests/generated/serialize.pb.c diff --git a/src/flamenco/runtime/tests/harness/generated/serialize.pb.h b/src/flamenco/runtime/tests/generated/serialize.pb.h similarity index 100% rename from src/flamenco/runtime/tests/harness/generated/serialize.pb.h rename to src/flamenco/runtime/tests/generated/serialize.pb.h diff --git a/src/flamenco/runtime/tests/harness/generated/shred.pb.c b/src/flamenco/runtime/tests/generated/shred.pb.c similarity index 100% rename from src/flamenco/runtime/tests/harness/generated/shred.pb.c rename to src/flamenco/runtime/tests/generated/shred.pb.c diff --git a/src/flamenco/runtime/tests/harness/generated/shred.pb.h b/src/flamenco/runtime/tests/generated/shred.pb.h similarity index 99% rename from src/flamenco/runtime/tests/harness/generated/shred.pb.h rename to src/flamenco/runtime/tests/generated/shred.pb.h index d24d74fd295..6c5dcd1a5db 100644 --- a/src/flamenco/runtime/tests/harness/generated/shred.pb.h +++ b/src/flamenco/runtime/tests/generated/shred.pb.h @@ -4,7 +4,7 @@ #ifndef PB_ORG_SOLANA_SEALEVEL_V1_SHRED_PB_H_INCLUDED #define PB_ORG_SOLANA_SEALEVEL_V1_SHRED_PB_H_INCLUDED -#include "../../../../../ballet/nanopb/pb_firedancer.h" +#include "../../../../ballet/nanopb/pb_firedancer.h" #if PB_PROTO_HEADER_VERSION != 40 #error Regenerate this file with the current version of nanopb generator. diff --git a/src/flamenco/runtime/tests/harness/generated/txn.pb.c b/src/flamenco/runtime/tests/generated/txn.pb.c similarity index 100% rename from src/flamenco/runtime/tests/harness/generated/txn.pb.c rename to src/flamenco/runtime/tests/generated/txn.pb.c diff --git a/src/flamenco/runtime/tests/harness/generated/txn.pb.h b/src/flamenco/runtime/tests/generated/txn.pb.h similarity index 99% rename from src/flamenco/runtime/tests/harness/generated/txn.pb.h rename to src/flamenco/runtime/tests/generated/txn.pb.h index 5bf7e68d7fa..e303e21084c 100644 --- a/src/flamenco/runtime/tests/harness/generated/txn.pb.h +++ b/src/flamenco/runtime/tests/generated/txn.pb.h @@ -4,7 +4,7 @@ #ifndef PB_ORG_SOLANA_SEALEVEL_V1_TXN_PB_H_INCLUDED #define PB_ORG_SOLANA_SEALEVEL_V1_TXN_PB_H_INCLUDED -#include "../../../../../ballet/nanopb/pb_firedancer.h" +#include "../../../../ballet/nanopb/pb_firedancer.h" #include "context.pb.h" #include "metadata.pb.h" diff --git a/src/flamenco/runtime/tests/harness/generated/type.pb.c b/src/flamenco/runtime/tests/generated/type.pb.c similarity index 100% rename from src/flamenco/runtime/tests/harness/generated/type.pb.c rename to src/flamenco/runtime/tests/generated/type.pb.c diff --git a/src/flamenco/runtime/tests/harness/generated/type.pb.h b/src/flamenco/runtime/tests/generated/type.pb.h similarity index 90% rename from src/flamenco/runtime/tests/harness/generated/type.pb.h rename to src/flamenco/runtime/tests/generated/type.pb.h index 17e0fbec231..b3d50354aae 100644 --- a/src/flamenco/runtime/tests/harness/generated/type.pb.h +++ b/src/flamenco/runtime/tests/generated/type.pb.h @@ -4,7 +4,7 @@ #ifndef PB_ORG_SOLANA_SEALEVEL_V1_TYPE_PB_H_INCLUDED #define PB_ORG_SOLANA_SEALEVEL_V1_TYPE_PB_H_INCLUDED -#include "../../../../../ballet/nanopb/pb_firedancer.h" +#include "../../../../ballet/nanopb/pb_firedancer.h" #include "metadata.pb.h" #if PB_PROTO_HEADER_VERSION != 40 @@ -14,6 +14,7 @@ /* Struct definitions */ typedef struct fd_exec_test_type_context { pb_bytes_array_t *content; + pb_callback_t typename; } fd_exec_test_type_context_t; typedef struct fd_exec_test_type_effects { @@ -37,15 +38,16 @@ extern "C" { #endif /* Initializer values for message structs */ -#define FD_EXEC_TEST_TYPE_CONTEXT_INIT_DEFAULT {NULL} +#define FD_EXEC_TEST_TYPE_CONTEXT_INIT_DEFAULT {NULL, {{NULL}, NULL}} #define FD_EXEC_TEST_TYPE_EFFECTS_INIT_DEFAULT {0, NULL, NULL} #define FD_EXEC_TEST_TYPE_FIXTURE_INIT_DEFAULT {false, FD_EXEC_TEST_FIXTURE_METADATA_INIT_DEFAULT, false, FD_EXEC_TEST_TYPE_CONTEXT_INIT_DEFAULT, false, FD_EXEC_TEST_TYPE_EFFECTS_INIT_DEFAULT} -#define FD_EXEC_TEST_TYPE_CONTEXT_INIT_ZERO {NULL} +#define FD_EXEC_TEST_TYPE_CONTEXT_INIT_ZERO {NULL, {{NULL}, NULL}} #define FD_EXEC_TEST_TYPE_EFFECTS_INIT_ZERO {0, NULL, NULL} #define FD_EXEC_TEST_TYPE_FIXTURE_INIT_ZERO {false, FD_EXEC_TEST_FIXTURE_METADATA_INIT_ZERO, false, FD_EXEC_TEST_TYPE_CONTEXT_INIT_ZERO, false, FD_EXEC_TEST_TYPE_EFFECTS_INIT_ZERO} /* Field tags (for use in manual encoding/decoding) */ #define FD_EXEC_TEST_TYPE_CONTEXT_CONTENT_TAG 1 +#define FD_EXEC_TEST_TYPE_CONTEXT_TYPENAME_TAG 2 #define FD_EXEC_TEST_TYPE_EFFECTS_RESULT_TAG 1 #define FD_EXEC_TEST_TYPE_EFFECTS_REPRESENTATION_TAG 2 #define FD_EXEC_TEST_TYPE_EFFECTS_YAML_TAG 3 @@ -55,8 +57,9 @@ extern "C" { /* Struct field encoding specification for nanopb */ #define FD_EXEC_TEST_TYPE_CONTEXT_FIELDLIST(X, a) \ -X(a, POINTER, SINGULAR, BYTES, content, 1) -#define FD_EXEC_TEST_TYPE_CONTEXT_CALLBACK NULL +X(a, POINTER, SINGULAR, BYTES, content, 1) \ +X(a, CALLBACK, SINGULAR, STRING, typename, 2) +#define FD_EXEC_TEST_TYPE_CONTEXT_CALLBACK pb_default_field_callback #define FD_EXEC_TEST_TYPE_CONTEXT_DEFAULT NULL #define FD_EXEC_TEST_TYPE_EFFECTS_FIELDLIST(X, a) \ diff --git a/src/flamenco/runtime/tests/harness/generated/vm.pb.c b/src/flamenco/runtime/tests/generated/vm.pb.c similarity index 100% rename from src/flamenco/runtime/tests/harness/generated/vm.pb.c rename to src/flamenco/runtime/tests/generated/vm.pb.c diff --git a/src/flamenco/runtime/tests/harness/generated/vm.pb.h b/src/flamenco/runtime/tests/generated/vm.pb.h similarity index 99% rename from src/flamenco/runtime/tests/harness/generated/vm.pb.h rename to src/flamenco/runtime/tests/generated/vm.pb.h index 507b31ddf00..65a8386f4ca 100644 --- a/src/flamenco/runtime/tests/harness/generated/vm.pb.h +++ b/src/flamenco/runtime/tests/generated/vm.pb.h @@ -4,7 +4,7 @@ #ifndef PB_ORG_SOLANA_SEALEVEL_V1_VM_PB_H_INCLUDED #define PB_ORG_SOLANA_SEALEVEL_V1_VM_PB_H_INCLUDED -#include "../../../../../ballet/nanopb/pb_firedancer.h" +#include "../../../../ballet/nanopb/pb_firedancer.h" #include "invoke.pb.h" #include "context.pb.h" #include "metadata.pb.h" diff --git a/src/flamenco/runtime/tests/harness/fd_block_harness.h b/src/flamenco/runtime/tests/harness/fd_block_harness.h deleted file mode 100644 index 4f55e905ce8..00000000000 --- a/src/flamenco/runtime/tests/harness/fd_block_harness.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef HEADER_fd_src_flamenco_runtime_tests_fd_block_harness_h -#define HEADER_fd_src_flamenco_runtime_tests_fd_block_harness_h - -#include "../../fd_executor.h" -#include "../../program/fd_vote_program.h" -#include "../../program/fd_stake_program.h" -#include "../../sysvar/fd_sysvar_epoch_schedule.h" -#include "../../sysvar/fd_sysvar_recent_hashes.h" -#include "../../../rewards/fd_rewards.h" - -#include "fd_harness_common.h" -#include "fd_txn_harness.h" -#include "generated/block.pb.h" - -FD_PROTOTYPES_BEGIN - -/* - Executes a block containing zero or more transactions. - - All sysvars must be provided - - This does not test sigverify or POH - - Epoch boundaries are tested - - Associated entrypoint tested in Agave is `confirm_slot_entries` (except sigverify and verify_ticks are removed) - - (idk about this yet) Recent blockhashes sysvar account must NOT be provided in the input account states. - Instead, the sysvar is populated through the input blockhash queue. -*/ -ulong -fd_runtime_fuzz_block_run( fd_runtime_fuzz_runner_t * runner, - void const * input_, - void ** output_, - void * output_buf, - ulong output_bufsz ); - -FD_PROTOTYPES_END - -#endif /* HEADER_fd_src_flamenco_runtime_tests_fd_block_harness_h */ diff --git a/src/flamenco/runtime/tests/harness/fd_elf_harness.h b/src/flamenco/runtime/tests/harness/fd_elf_harness.h deleted file mode 100644 index a382c033080..00000000000 --- a/src/flamenco/runtime/tests/harness/fd_elf_harness.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef HEADER_fd_src_flamenco_runtime_tests_harness_fd_elf_harness_h -#define HEADER_fd_src_flamenco_runtime_tests_harness_fd_elf_harness_h - -#include "fd_harness_common.h" - -#include "../../../vm/fd_vm_base.h" - -#include "generated/elf.pb.h" - -FD_PROTOTYPES_BEGIN - -/* Loads an ELF binary (in input->elf.data()). - output_buf points to a memory region of output_bufsz bytes where the - result is allocated into. During execution, the contents of - fd_sbpf_program_t are wrapped in *output (backed by output_buf). - - Returns number of bytes allocated at output_buf OR 0UL on any - harness-specific failures. Execution failures still return number of allocated bytes, - but output is incomplete/undefined. - */ -ulong -fd_runtime_fuzz_sbpf_load_run( fd_runtime_fuzz_runner_t * runner, - void const * input_, - void ** output_, - void * output_buf, - ulong output_bufsz ); - -FD_PROTOTYPES_END - -#endif /* HEADER_fd_src_flamenco_runtime_tests_harness_fd_elf_harness_h */ diff --git a/src/flamenco/runtime/tests/harness/fd_exec_sol_compat.c b/src/flamenco/runtime/tests/harness/fd_exec_sol_compat.c deleted file mode 100644 index e39a5481bce..00000000000 --- a/src/flamenco/runtime/tests/harness/fd_exec_sol_compat.c +++ /dev/null @@ -1,924 +0,0 @@ -#define _GNU_SOURCE -#include "fd_exec_sol_compat.h" - -#include "../../../../ballet/nanopb/pb_encode.h" -#include "../../../../ballet/nanopb/pb_decode.h" - -#include "../../fd_executor_err.h" -#include "../../../capture/fd_solcap_writer.h" -#include "../../../features/fd_features.h" -#include "../../../../ballet/shred/fd_shred.h" - -#include "fd_instr_harness.h" -#include "fd_txn_harness.h" -#include "fd_block_harness.h" -#include "fd_types_harness.h" -#include "fd_vm_harness.h" -#include "fd_elf_harness.h" - -#include "generated/elf.pb.h" -#include "generated/invoke.pb.h" -#include "generated/shred.pb.h" -#include "generated/vm.pb.h" -#include "generated/type.pb.h" - -#include -#include - -/* FIXME: Spad isn't properly sized out or cleaned up */ - -/* This file defines stable APIs for compatibility testing. - - For the "compat" shared library used by the differential fuzzer, - ideally the symbols defined in this file would be the only visible - globals. Unfortunately, we currently export all symbols, which leads - to great symbol table bloat from fd_types.c. */ - -typedef struct { - ulong struct_size; - ulong * hardcoded_features; - ulong hardcoded_features_cnt; - ulong * supported_features; - ulong supported_feature_cnt; -} sol_compat_features_t; - -static sol_compat_features_t features; -static uchar * spad_mem; -static fd_wksp_t * wksp = NULL; -static fd_banks_t * banks = NULL; -static fd_bank_t * bank = NULL; - -#define WKSP_EXECUTE_ALLOC_TAG (2UL) -#define WKSP_INIT_ALLOC_TAG (3UL) - -void -sol_compat_init( int log_level ) { - int argc = 1; - char * argv[2] = { (char *)"fd_exec_sol_compat", NULL }; - char ** argv_ = argv; - if( !getenv( "FD_LOG_PATH" ) ) { - setenv( "FD_LOG_PATH", "", 1 ); - } - fd_log_enable_unclean_exit(); - fd_boot( &argc, &argv_ ); - fd_log_level_logfile_set( log_level ); - fd_log_level_core_set(4); /* abort on FD_LOG_ERR */ - - sol_compat_wksp_init( FD_SHMEM_NORMAL_PAGE_SZ ); -} - -fd_wksp_t * -sol_compat_wksp_init( ulong wksp_page_sz ) { - ulong cpu_idx = fd_tile_cpu_id( fd_tile_idx() ); - if( cpu_idx>=fd_shmem_cpu_cnt() ) cpu_idx = 0UL; - switch( wksp_page_sz ) - { - case FD_SHMEM_GIGANTIC_PAGE_SZ: - wksp = fd_wksp_new_anonymous( FD_SHMEM_GIGANTIC_PAGE_SZ, 6UL, fd_shmem_cpu_idx( fd_shmem_numa_idx( cpu_idx ) ), "wksp", 0UL ); - break; - case FD_SHMEM_NORMAL_PAGE_SZ: - wksp = fd_wksp_new_anonymous( FD_SHMEM_NORMAL_PAGE_SZ, 512UL * 512UL * 6UL, fd_shmem_cpu_idx( fd_shmem_numa_idx( cpu_idx ) ), "wksp", 0UL ); - break; - default: - FD_LOG_ERR(( "Unsupported page size %lu", wksp_page_sz )); - } - FD_TEST( wksp ); - - spad_mem = fd_wksp_alloc_laddr( wksp, FD_SPAD_ALIGN, FD_SPAD_FOOTPRINT( FD_RUNTIME_TRANSACTION_EXECUTION_FOOTPRINT_FUZZ ), WKSP_INIT_ALLOC_TAG ); /* 4738713960 B */ - FD_TEST( spad_mem ); - - ulong banks_footprint = fd_banks_footprint( 1UL, 1UL ); - uchar * banks_mem = fd_wksp_alloc_laddr( wksp, fd_banks_align(), banks_footprint, WKSP_INIT_ALLOC_TAG ); - if( FD_UNLIKELY( !banks_mem ) ) { - FD_LOG_CRIT(( "Unable to allocate memory for banks" )); - } - - banks = fd_banks_join( fd_banks_new( banks_mem, 1UL, 1UL ) ); - if( FD_UNLIKELY( !banks ) ) { - FD_LOG_CRIT(( "Unable to create and join banks" )); - } - bank = fd_banks_init_bank( banks, 0UL ); - if( FD_UNLIKELY( !bank ) ) { - FD_LOG_CRIT(( "Unable to initialize bank" )); - } - - features.struct_size = sizeof(sol_compat_features_t); - features.hardcoded_features = fd_wksp_alloc_laddr( wksp, 8UL, FD_FEATURE_ID_CNT * sizeof(ulong), WKSP_INIT_ALLOC_TAG ); - features.supported_features = fd_wksp_alloc_laddr( wksp, 8UL, FD_FEATURE_ID_CNT * sizeof(ulong), WKSP_INIT_ALLOC_TAG ); - - for( const fd_feature_id_t * current_feature = fd_feature_iter_init(); !fd_feature_iter_done( current_feature ); current_feature = fd_feature_iter_next( current_feature ) ) { - // Skip reverted features - if( current_feature->reverted ) continue; - - // Only hardcode features that are activated on all clusters - if( current_feature->activated_on_all_clusters ) { - memcpy( &features.hardcoded_features[features.hardcoded_features_cnt++], ¤t_feature->id, sizeof(ulong) ); - } else { - memcpy( &features.supported_features[features.supported_feature_cnt++], ¤t_feature->id, sizeof(ulong) ); - } - } - - return wksp; -} - -void -sol_compat_fini( void ) { - fd_wksp_free_laddr( spad_mem ); - fd_wksp_free_laddr( features.hardcoded_features ); - fd_wksp_free_laddr( features.supported_features ); - fd_wksp_delete_anonymous( wksp ); - wksp = NULL; - spad_mem = NULL; -} - -void -sol_compat_check_wksp_usage( void ) { - fd_wksp_usage_t usage[1]; - ulong tags[1] = { WKSP_EXECUTE_ALLOC_TAG }; - fd_wksp_usage( wksp, tags, 1, usage ); - if( usage->used_sz ) { - FD_LOG_ERR(( "%lu bytes leaked in %lu allocations", usage->used_sz, usage->used_cnt )); - } -} - -sol_compat_features_t const * -sol_compat_get_features_v1( void ) { - return &features; -} - -fd_runtime_fuzz_runner_t * -sol_compat_setup_runner( void ) { - - // Setup test runner - void * runner_mem = fd_wksp_alloc_laddr( wksp, fd_runtime_fuzz_runner_align(), fd_runtime_fuzz_runner_footprint(), WKSP_EXECUTE_ALLOC_TAG ); - fd_runtime_fuzz_runner_t * runner = fd_runtime_fuzz_runner_new( runner_mem, spad_mem, banks, bank, WKSP_EXECUTE_ALLOC_TAG ); - - char const * solcap_path = getenv( "FD_SOLCAP" ); - if( solcap_path ) { - runner->solcap_file = fopen( solcap_path, "w" ); - if( FD_UNLIKELY( !runner->solcap_file ) ) { - FD_LOG_ERR(( "fopen($FD_SOLCAP=%s) failed (%i-%s)", solcap_path, errno, fd_io_strerror( errno ) )); - } - FD_LOG_NOTICE(( "Logging to solcap file %s", solcap_path )); - - void * solcap_mem = fd_wksp_alloc_laddr( runner->wksp, fd_solcap_writer_align(), fd_solcap_writer_footprint(), 1UL ); - runner->solcap = fd_solcap_writer_new( solcap_mem ); - FD_TEST( runner->solcap ); - FD_TEST( fd_solcap_writer_init( solcap_mem, runner->solcap_file ) ); - } - - return runner; -} - -void -sol_compat_cleanup_runner( fd_runtime_fuzz_runner_t * runner ) { - /* Cleanup test runner */ - if( runner->solcap ) { - fd_solcap_writer_flush( runner->solcap ); - fd_wksp_free_laddr( fd_solcap_writer_delete( runner->solcap ) ); - runner->solcap = NULL; - fclose( runner->solcap_file ); - runner->solcap_file = NULL; - } - fd_wksp_free_laddr( fd_runtime_fuzz_runner_delete( runner ) ); -} - -void * -sol_compat_decode( void * decoded, - uchar const * in, - ulong in_sz, - pb_msgdesc_t const * decode_type ) { - pb_istream_t istream = pb_istream_from_buffer( in, in_sz ); - int decode_ok = pb_decode_ex( &istream, decode_type, decoded, PB_DECODE_NOINIT ); - if( !decode_ok ) { - pb_release( decode_type, decoded ); - return NULL; - } - return decoded; -} - -void const * -sol_compat_encode( uchar * out, - ulong * out_sz, - void const * to_encode, - pb_msgdesc_t const * encode_type ) { - pb_ostream_t ostream = pb_ostream_from_buffer( out, *out_sz ); - int encode_ok = pb_encode( &ostream, encode_type, to_encode ); - if( !encode_ok ) { - return NULL; - } - *out_sz = ostream.bytes_written; - return to_encode; -} - -typedef ulong( exec_test_run_fn_t )( fd_runtime_fuzz_runner_t *, - void const *, - void **, - void *, - ulong ); - -void -sol_compat_execute_wrapper( fd_runtime_fuzz_runner_t * runner, - void * input, - void ** output, - exec_test_run_fn_t * exec_test_run_fn ) { - - ulong out_bufsz = 100000000; /* 100 MB */ - void * out0 = fd_spad_alloc( runner->spad, 1UL, out_bufsz ); - FD_TEST( out_bufsz <= fd_spad_alloc_max( runner->spad, 1UL ) ); - - ulong out_used = exec_test_run_fn( runner, input, output, out0, out_bufsz ); - if( FD_UNLIKELY( !out_used ) ) { - *output = NULL; - } - -} - -/* - * fixtures - */ - -int -sol_compat_cmp_binary_strict( void const * effects, - void const * expected, - pb_msgdesc_t const * encode_type, - fd_spad_t * spad ) { -#define MAX_SZ 32*1024*1024 -FD_SPAD_FRAME_BEGIN( spad ) { - if( effects==NULL ) { - FD_LOG_WARNING(( "No output effects" )); - return 0; - } - - /* Note: Most likely this spad allocation won't fail. If it does, you may need to bump - the allocated spad memory amount in fd_exec_sol_compat.c. */ - ulong out_sz = MAX_SZ; - uchar * out = fd_spad_alloc( spad, 1UL, out_sz ); - if( !sol_compat_encode( out, &out_sz, effects, encode_type ) ) { - FD_LOG_WARNING(( "Error encoding effects" )); - return 0; - } - - ulong exp_sz = MAX_SZ; - uchar * exp = fd_spad_alloc( spad, 1UL, exp_sz ); - if( !sol_compat_encode( exp, &exp_sz, expected, encode_type ) ) { - FD_LOG_WARNING(( "Error encoding expected" )); - return 0; - } - - if( out_sz!=exp_sz ) { - FD_LOG_WARNING(( "Binary cmp failed: different size. out_sz=%lu exp_sz=%lu", out_sz, exp_sz )); - return 0; - } - if( !fd_memeq( out, exp, out_sz ) ) { - FD_LOG_WARNING(( "Binary cmp failed: different values." )); - return 0; - } - - return 1; -} FD_SPAD_FRAME_END; -#undef MAX_SIZE -} - -static int -_diff_txn_acct( fd_exec_test_acct_state_t * expected, - fd_exec_test_acct_state_t * actual ) { - /* AcctState -> address (This must hold true when calling this function!) */ - assert( fd_memeq( expected->address, actual->address, sizeof(fd_pubkey_t) ) ); - - /* AcctState -> lamports */ - if( expected->lamports != actual->lamports ) { - FD_LOG_WARNING(( "Lamports mismatch: expected=%lu actual=%lu", expected->lamports, actual->lamports )); - return 0; - } - - /* AcctState -> data */ - if( expected->data != NULL || actual->data != NULL ) { - if( expected->data == NULL ) { - FD_LOG_WARNING(( "Expected account data is NULL, actual is non-NULL" )); - return 0; - } - - if( actual->data == NULL ) { - FD_LOG_WARNING(( "Expected account data is NULL, actual is non-NULL" )); - return 0; - } - - if( expected->data->size != actual->data->size ) { - FD_LOG_WARNING(( "Account data size mismatch: expected=%u actual=%u", expected->data->size, actual->data->size )); - return 0; - } - - if( !fd_memeq( expected->data->bytes, actual->data->bytes, expected->data->size ) ) { - FD_LOG_WARNING(( "Account data mismatch" )); - return 0; - } - } - - /* AcctState -> executable */ - if( expected->executable != actual->executable ) { - FD_LOG_WARNING(( "Executable mismatch: expected=%d actual=%d", expected->executable, actual->executable )); - return 0; - } - - /* AcctState -> rent_epoch */ - if( expected->rent_epoch != actual->rent_epoch ) { - FD_LOG_WARNING(( "Rent epoch mismatch: expected=%lu actual=%lu", expected->rent_epoch, actual->rent_epoch )); - return 0; - } - - /* AcctState -> owner */ - if( !fd_memeq( expected->owner, actual->owner, sizeof(fd_pubkey_t) ) ) { - char a[ FD_BASE58_ENCODED_32_SZ ]; - char b[ FD_BASE58_ENCODED_32_SZ ]; - FD_LOG_WARNING(( "Owner mismatch: expected=%s, actual=%s", fd_acct_addr_cstr( a, expected->owner ), fd_acct_addr_cstr( b, actual->owner ) )); - return 0; - } - - return 1; -} - - -static int -_diff_resulting_states( fd_exec_test_resulting_state_t * expected, - fd_exec_test_resulting_state_t * actual ) { - // Verify that the number of accounts are the same - if( expected->acct_states_count != actual->acct_states_count ) { - FD_LOG_WARNING(( "Account states count mismatch: expected=%u actual=%u", expected->acct_states_count, actual->acct_states_count )); - return 0; - } - - // Verify that the account states are the same - for( ulong i = 0; i < expected->acct_states_count; ++i ) { - for( ulong j = 0; j < actual->acct_states_count; ++j ) { - if( fd_memeq( expected->acct_states[i].address, actual->acct_states[j].address, sizeof(fd_pubkey_t) ) ) { - if( !_diff_txn_acct( &expected->acct_states[i], &actual->acct_states[j] ) ) { - return 0; - } - } - } - } - - // TODO: resulting_state -> rent_debits, resulting_state->transaction_rent - return 1; -} - -int -sol_compat_cmp_txn( fd_exec_test_txn_result_t * expected, - fd_exec_test_txn_result_t * actual ) { - /* TxnResult -> executed */ - if( expected->executed != actual->executed ) { - FD_LOG_WARNING(( "Executed mismatch: expected=%d actual=%d", expected->executed, actual->executed )); - return 0; - } - - /* TxnResult -> sanitization_error */ - if( expected->sanitization_error != actual->sanitization_error ) { - FD_LOG_WARNING(( "Sanitization error mismatch: expected=%d actual=%d", expected->sanitization_error, actual->sanitization_error )); - return 0; - } - - /* TxnResult -> resulting_state */ - if( !_diff_resulting_states( &expected->resulting_state, &actual->resulting_state ) ) { - return 0; - } - - /* TxnResult -> rent */ - if( expected->rent != actual->rent ) { - FD_LOG_WARNING(( "Rent mismatch: expected=%lu actual=%lu", expected->rent, actual->rent )); - return 0; - } - - /* TxnResult -> is_ok */ - if( expected->is_ok != actual->is_ok ) { - FD_LOG_WARNING(( "Is ok mismatch: expected=%d actual=%d", expected->is_ok, actual->is_ok )); - return 0; - } - - /* TxnResult -> status */ - if( expected->status != actual->status ) { - FD_LOG_WARNING(( "Status mismatch: expected=%u actual=%u", expected->status, actual->status )); - return 0; - } - - /* TxnResult -> instruction_error */ - if( expected->instruction_error != actual->instruction_error ) { - FD_LOG_WARNING(( "Instruction error mismatch: expected=%u actual=%u", expected->instruction_error, actual->instruction_error )); - return 0; - } - - if( expected->instruction_error ) { - /* TxnResult -> instruction_error_index */ - if( expected->instruction_error_index != actual->instruction_error_index ) { - FD_LOG_WARNING(( "Instruction error index mismatch: expected=%u actual=%u", expected->instruction_error_index, actual->instruction_error_index )); - return 0; - } - - /* TxnResult -> custom_error */ - if( expected->instruction_error == (ulong) -FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR && expected->custom_error != actual->custom_error ) { - FD_LOG_WARNING(( "Custom error mismatch: expected=%u actual=%u", expected->custom_error, actual->custom_error )); - return 0; - } - } - - /* TxnResult -> return_data */ - if( expected->return_data != NULL || actual->return_data != NULL ) { - if( expected->return_data == NULL ) { - FD_LOG_WARNING(( "Expected return data is NULL, actual is non-NULL" )); - return 0; - } - - if( actual->return_data == NULL ) { - FD_LOG_WARNING(( "Expected return data is NULL, actual is non-NULL" )); - return 0; - } - - if( expected->return_data->size != actual->return_data->size ) { - FD_LOG_WARNING(( "Return data size mismatch: expected=%u actual=%u", expected->return_data->size, actual->return_data->size )); - return 0; - } - - if( !fd_memeq( expected->return_data->bytes, actual->return_data->bytes, expected->return_data->size ) ) { - FD_LOG_WARNING(( "Return data mismatch" )); - return 0; - } - } - - /* TxnResult -> executed_units */ - if( expected->executed_units != actual->executed_units ) { - FD_LOG_WARNING(( "Executed units mismatch: expected=%lu actual=%lu", expected->executed_units, actual->executed_units )); - return 0; - } - - /* TxnResult -> fee_details */ - if( expected->has_fee_details != actual->has_fee_details ) { - FD_LOG_WARNING(( "Has fee details mismatch: expected=%d actual=%d", expected->has_fee_details, actual->has_fee_details )); - return 0; - } - - if( expected->has_fee_details ) { - if( expected->fee_details.transaction_fee != actual->fee_details.transaction_fee ) { - FD_LOG_WARNING(( "Transaction fee mismatch: expected=%lu actual=%lu", expected->fee_details.transaction_fee, actual->fee_details.transaction_fee )); - return 0; - } - - if( expected->fee_details.prioritization_fee != actual->fee_details.prioritization_fee ) { - FD_LOG_WARNING(( "Priority fee mismatch: expected=%lu actual=%lu", expected->fee_details.prioritization_fee, actual->fee_details.prioritization_fee )); - return 0; - } - } - - /* TxnResult -> loaded_accounts_data_size */ - if( expected->loaded_accounts_data_size != actual->loaded_accounts_data_size ) { - FD_LOG_WARNING(( "Loaded accounts data size mismatch: expected=%lu actual=%lu", expected->loaded_accounts_data_size, actual->loaded_accounts_data_size )); - return 0; - } - - return 1; -} - -int -sol_compat_instr_fixture( fd_runtime_fuzz_runner_t * runner, - uchar const * in, - ulong in_sz ) { - // Decode fixture - fd_exec_test_instr_fixture_t fixture[1] = {0}; - void * res = sol_compat_decode( &fixture, in, in_sz, &fd_exec_test_instr_fixture_t_msg ); - if ( res==NULL ) { - FD_LOG_WARNING(( "Invalid instr fixture." )); - return 0; - } - - int ok = 0; - // Execute - void * output = NULL; - sol_compat_execute_wrapper( runner, &fixture->input, &output, fd_runtime_fuzz_instr_run ); - - // Compare effects - ok = sol_compat_cmp_binary_strict( output, &fixture->output, &fd_exec_test_instr_effects_t_msg, runner->spad ); - - // Cleanup - pb_release( &fd_exec_test_instr_fixture_t_msg, fixture ); - return ok; -} - -int -sol_compat_txn_fixture( fd_runtime_fuzz_runner_t * runner, - uchar const * in, - ulong in_sz ) { - // Decode fixture - fd_exec_test_txn_fixture_t fixture[1] = {0}; - void * res = sol_compat_decode( &fixture, in, in_sz, &fd_exec_test_txn_fixture_t_msg ); - if ( res==NULL ) { - FD_LOG_WARNING(( "Invalid txn fixture." )); - return 0; - } - - int ok = 0; - FD_SPAD_FRAME_BEGIN( runner->spad ) { - // Execute - void * output = NULL; - sol_compat_execute_wrapper( runner, &fixture->input, &output, fd_runtime_fuzz_txn_run ); - if( FD_LIKELY( output ) ) { - // Compare effects - fd_exec_test_txn_result_t * effects = output; - ok = sol_compat_cmp_txn( &fixture->output, effects ); - } - } FD_SPAD_FRAME_END; - - // Cleanup - pb_release( &fd_exec_test_txn_fixture_t_msg, fixture ); - return ok; -} - -int -sol_compat_block_fixture( fd_runtime_fuzz_runner_t * runner, - uchar const * in, - ulong in_sz ) { - // Decode fixture - fd_exec_test_block_fixture_t fixture[1] = {0}; - void * res = sol_compat_decode( &fixture, in, in_sz, &fd_exec_test_block_fixture_t_msg ); - if ( res==NULL ) { - FD_LOG_WARNING(( "Invalid block fixture." )); - return 0; - } - - int ok = 0; - FD_SPAD_FRAME_BEGIN( runner->spad ) { - // Execute - void * output = NULL; - sol_compat_execute_wrapper( runner, &fixture->input, &output, fd_runtime_fuzz_block_run ); - - // Compare effects - ok = sol_compat_cmp_binary_strict( output, &fixture->output, &fd_exec_test_block_effects_t_msg, runner->spad ); - } FD_SPAD_FRAME_END; - - // Cleanup - pb_release( &fd_exec_test_block_fixture_t_msg, fixture ); - return ok; -} - -int -sol_compat_elf_loader_fixture( fd_runtime_fuzz_runner_t * runner, - uchar const * in, - ulong in_sz ) { - // Decode fixture - fd_exec_test_elf_loader_fixture_t fixture[1] = {0}; - void * res = sol_compat_decode( &fixture, in, in_sz, &fd_exec_test_elf_loader_fixture_t_msg ); - if ( res==NULL ) { - FD_LOG_WARNING(( "Invalid elf_loader fixture." )); - return 0; - } - int ok = 0; - FD_SPAD_FRAME_BEGIN( runner->spad ) { - // Execute - void * output = NULL; - sol_compat_execute_wrapper( runner, &fixture->input, &output, fd_runtime_fuzz_sbpf_load_run ); - - // Compare effects - ok = sol_compat_cmp_binary_strict( output, &fixture->output, &fd_exec_test_elf_loader_effects_t_msg, runner->spad ); - } FD_SPAD_FRAME_END; - - // Cleanup - pb_release( &fd_exec_test_elf_loader_fixture_t_msg, fixture ); - return ok; -} - -int -sol_compat_syscall_fixture( fd_runtime_fuzz_runner_t * runner, - uchar const * in, - ulong in_sz ) { - // Decode fixture - fd_exec_test_syscall_fixture_t fixture[1] = {0}; - if ( !sol_compat_decode( &fixture, in, in_sz, &fd_exec_test_syscall_fixture_t_msg ) ) { - FD_LOG_WARNING(( "Invalid syscall fixture." )); - return 0; - } - - int ok = 0; - FD_SPAD_FRAME_BEGIN( runner->spad ) { - // Execute - void * output = NULL; - sol_compat_execute_wrapper( runner, &fixture->input, &output, fd_runtime_fuzz_vm_syscall_run ); - - // Compare effects - ok = sol_compat_cmp_binary_strict( output, &fixture->output, &fd_exec_test_syscall_effects_t_msg, runner->spad ); - } FD_SPAD_FRAME_END; - - // Cleanup - pb_release( &fd_exec_test_syscall_fixture_t_msg, fixture ); - return ok; -} - -int -sol_compat_vm_interp_fixture( fd_runtime_fuzz_runner_t * runner, - uchar const * in, - ulong in_sz ) { - // Decode fixture - fd_exec_test_syscall_fixture_t fixture[1] = {0}; - if ( !sol_compat_decode( &fixture, in, in_sz, &fd_exec_test_syscall_fixture_t_msg ) ) { - FD_LOG_WARNING(( "Invalid syscall fixture." )); - return 0; - } - - int ok = 0; - FD_SPAD_FRAME_BEGIN( runner->spad ) { - // Execute - void * output = NULL; - sol_compat_execute_wrapper( runner, &fixture->input, &output, (exec_test_run_fn_t *)fd_runtime_fuzz_vm_interp_run ); - - // Compare effects - ok = sol_compat_cmp_binary_strict( output, &fixture->output, &fd_exec_test_syscall_effects_t_msg, runner->spad ); - } FD_SPAD_FRAME_END; - - // Cleanup - pb_release( &fd_exec_test_syscall_fixture_t_msg, fixture ); - return ok; -} - -/* - * execute_v1 - */ - -int -sol_compat_instr_execute_v1( uchar * out, - ulong * out_sz, - uchar const * in, - ulong in_sz ) { - // Setup - fd_runtime_fuzz_runner_t * runner = sol_compat_setup_runner(); - - // Decode context - fd_exec_test_instr_context_t input[1] = {0}; - void * res = sol_compat_decode( &input, in, in_sz, &fd_exec_test_instr_context_t_msg ); - if ( res==NULL ) { - sol_compat_cleanup_runner( runner ); - return 0; - } - - int ok = 0; - FD_SPAD_FRAME_BEGIN( runner->spad ) { - // Execute - void * output = NULL; - sol_compat_execute_wrapper( runner, input, &output, fd_runtime_fuzz_instr_run ); - - // Encode effects - if( output ) { - ok = !!sol_compat_encode( out, out_sz, output, &fd_exec_test_instr_effects_t_msg ); - } - } FD_SPAD_FRAME_END; - - // Cleanup - pb_release( &fd_exec_test_instr_context_t_msg, input ); - sol_compat_cleanup_runner( runner ); - - // Check wksp usage is 0 - sol_compat_check_wksp_usage(); - - return ok; -} - -int -sol_compat_txn_execute_v1( uchar * out, - ulong * out_sz, - uchar const * in, - ulong in_sz ) { - // Setup - fd_runtime_fuzz_runner_t * runner = sol_compat_setup_runner(); - - // Decode context - fd_exec_test_txn_context_t input[1] = {0}; - void * res = sol_compat_decode( &input, in, in_sz, &fd_exec_test_txn_context_t_msg ); - if ( res==NULL ) { - sol_compat_cleanup_runner( runner ); - return 0; - } - - int ok = 0; - FD_SPAD_FRAME_BEGIN( runner->spad ) { - // Execute - void * output = NULL; - sol_compat_execute_wrapper( runner, input, &output, fd_runtime_fuzz_txn_run ); - - // Encode effects - if( output ) { - ok = !!sol_compat_encode( out, out_sz, output, &fd_exec_test_txn_result_t_msg ); - } - } FD_SPAD_FRAME_END; - - // Cleanup - pb_release( &fd_exec_test_txn_context_t_msg, input ); - sol_compat_cleanup_runner( runner ); - - // Check wksp usage is 0 - sol_compat_check_wksp_usage(); - return ok; -} - -int -sol_compat_block_execute_v1( uchar * out, - ulong * out_sz, - uchar const * in, - ulong in_sz ) { - // Setup - fd_runtime_fuzz_runner_t * runner = sol_compat_setup_runner(); - - // Decode context - fd_exec_test_block_context_t input[1] = {0}; - void * res = sol_compat_decode( &input, in, in_sz, &fd_exec_test_block_context_t_msg ); - if ( res==NULL ) { - sol_compat_cleanup_runner( runner ); - return 0; - } - - int ok = 0; - FD_SPAD_FRAME_BEGIN( runner->spad ) { - void * output = NULL; - - // Execute - sol_compat_execute_wrapper( runner, input, &output, fd_runtime_fuzz_block_run ); - - // Encode effects - if( output ) { - ok = !!sol_compat_encode( out, out_sz, output, &fd_exec_test_block_effects_t_msg ); - } - } FD_SPAD_FRAME_END; - - // Cleanup - pb_release( &fd_exec_test_block_context_t_msg, input ); - sol_compat_cleanup_runner( runner ); - - // Check wksp usage is 0 - sol_compat_check_wksp_usage(); - - return ok; -} - -int -sol_compat_elf_loader_v1( uchar * out, - ulong * out_sz, - uchar const * in, - ulong in_sz ) { - // Setup - fd_runtime_fuzz_runner_t * runner = sol_compat_setup_runner(); - - // Decode context - fd_exec_test_elf_loader_ctx_t input[1] = {0}; - void * res = sol_compat_decode( &input, in, in_sz, &fd_exec_test_elf_loader_ctx_t_msg ); - if ( res==NULL ) { - sol_compat_cleanup_runner( runner ); - return 0; - } - - int ok = 0; - FD_SPAD_FRAME_BEGIN( runner->spad ) { - void * output = NULL; - - // Execute - sol_compat_execute_wrapper( runner, input, &output, fd_runtime_fuzz_sbpf_load_run ); - - // Encode effects - if( output ) { - ok = !!sol_compat_encode( out, out_sz, output, &fd_exec_test_elf_loader_effects_t_msg ); - } - } FD_SPAD_FRAME_END; - - // Cleanup - pb_release( &fd_exec_test_elf_loader_ctx_t_msg, input ); - sol_compat_cleanup_runner( runner ); - - // Check wksp usage is 0 - sol_compat_check_wksp_usage(); - - return ok; -} - -int -sol_compat_vm_syscall_execute_v1( uchar * out, - ulong * out_sz, - uchar const * in, - ulong in_sz ) { - // Setup - fd_runtime_fuzz_runner_t * runner = sol_compat_setup_runner(); - - // Decode context - fd_exec_test_syscall_context_t input[1] = {0}; - void * res = sol_compat_decode( &input, in, in_sz, &fd_exec_test_syscall_context_t_msg ); - if ( res==NULL ) { - sol_compat_cleanup_runner( runner ); - return 0; - } - - int ok = 0; - FD_SPAD_FRAME_BEGIN( runner->spad ) { - // Execute - void * output = NULL; - sol_compat_execute_wrapper( runner, input, &output, fd_runtime_fuzz_vm_syscall_run ); - - // Encode effects - if( output ) { - ok = !!sol_compat_encode( out, out_sz, output, &fd_exec_test_syscall_effects_t_msg ); - } - } FD_SPAD_FRAME_END; - - // Cleanup - pb_release( &fd_exec_test_syscall_context_t_msg, input ); - sol_compat_cleanup_runner( runner ); - - // Check wksp usage is 0 - sol_compat_check_wksp_usage(); - - return ok; -} - -int -sol_compat_vm_interp_v1( uchar * out, - ulong * out_sz, - uchar const * in, - ulong in_sz ) { - // Setup - fd_runtime_fuzz_runner_t * runner = sol_compat_setup_runner(); - - // Decode context - fd_exec_test_syscall_context_t input[1] = {0}; - void * res = sol_compat_decode( &input, in, in_sz, &fd_exec_test_syscall_context_t_msg ); - if ( res==NULL ) { - sol_compat_cleanup_runner( runner ); - return 0; - } - - int ok = 0; - - FD_SPAD_FRAME_BEGIN( runner->spad ) { - // Execute - void * output = NULL; - sol_compat_execute_wrapper( runner, input, &output, (exec_test_run_fn_t *)fd_runtime_fuzz_vm_interp_run ); - - // Encode effects - if( output ) { - ok = !!sol_compat_encode( out, out_sz, output, &fd_exec_test_syscall_effects_t_msg ); - } - } FD_SPAD_FRAME_END; - - // Cleanup - pb_release( &fd_exec_test_syscall_context_t_msg, input ); - sol_compat_cleanup_runner( runner ); - - // Check wksp usage is 0 - sol_compat_check_wksp_usage(); - - return ok; -} - -int sol_compat_shred_parse_v1( uchar * out, - ulong * out_sz, - uchar const * in, - ulong in_sz ) { - fd_exec_test_shred_binary_t input[1] = {0}; - void * res = sol_compat_decode( &input, in, in_sz, &fd_exec_test_shred_binary_t_msg ); - if( FD_UNLIKELY( res==NULL ) ) { - return 0; - } - if( FD_UNLIKELY( input[0].data==NULL ) ) { - pb_release( &fd_exec_test_shred_binary_t_msg, input ); - return 0; - } - fd_exec_test_accepts_shred_t output[1] = {0}; - output[0].valid = !!fd_shred_parse( input[0].data->bytes, input[0].data->size ); - pb_release( &fd_exec_test_shred_binary_t_msg, input ); - return !!sol_compat_encode( out, out_sz, output, &fd_exec_test_accepts_shred_t_msg ); -} - -int -sol_compat_type_execute_v1( uchar * out, - ulong * out_sz, - uchar const * in, - ulong in_sz ) { - // Setup - fd_runtime_fuzz_runner_t * runner = sol_compat_setup_runner(); - // Decode context - fd_exec_test_type_context_t input[1] = {0}; - void * res = sol_compat_decode( &input, in, in_sz, &fd_exec_test_type_context_t_msg ); - if( res==NULL ) { - sol_compat_cleanup_runner( runner ); - return 0; - } - - int ok = 0; - FD_SPAD_FRAME_BEGIN( runner->spad ) { - - void * output = NULL; - sol_compat_execute_wrapper( runner, input, &output, fd_runtime_fuzz_type_run ); - if( output ) { - ok = !!sol_compat_encode( out, out_sz, output, &fd_exec_test_type_effects_t_msg ); - } - - } FD_SPAD_FRAME_END; - - pb_release( &fd_exec_test_type_context_t_msg, input ); - sol_compat_cleanup_runner( runner ); - - sol_compat_check_wksp_usage(); - - return ok; -} diff --git a/src/flamenco/runtime/tests/harness/fd_exec_sol_compat.h b/src/flamenco/runtime/tests/harness/fd_exec_sol_compat.h deleted file mode 100644 index 63305ae0f5c..00000000000 --- a/src/flamenco/runtime/tests/harness/fd_exec_sol_compat.h +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef HEADER_fd_src_flamenco_runtime_tests_fd_exec_sol_compat_h -#define HEADER_fd_src_flamenco_runtime_tests_fd_exec_sol_compat_h - -/* fd_exec_sol_compat.h provides APIs for running differential - tests between Agave and Firedancer. */ - -#include "fd_harness_common.h" - -FD_PROTOTYPES_BEGIN - -fd_wksp_t * -sol_compat_wksp_init( ulong wksp_page_sz ); - -void -sol_compat_fini( void ); - -void -sol_compat_check_wksp_usage( void ); - -fd_runtime_fuzz_runner_t * -sol_compat_setup_runner( void ); - -void -sol_compat_cleanup_runner( fd_runtime_fuzz_runner_t * runner ); - -int -sol_compat_instr_fixture( fd_runtime_fuzz_runner_t * runner, - uchar const * in, - ulong in_sz ); - -int -sol_compat_txn_fixture( fd_runtime_fuzz_runner_t * runner, - uchar const * in, - ulong in_sz ); - -int -sol_compat_block_fixture( fd_runtime_fuzz_runner_t * runner, - uchar const * in, - ulong in_sz ); - -int -sol_compat_elf_loader_fixture( fd_runtime_fuzz_runner_t * runner, - uchar const * in, - ulong in_sz ); - -int -sol_compat_syscall_fixture( fd_runtime_fuzz_runner_t * runner, - uchar const * in, - ulong in_sz ); - -int -sol_compat_vm_interp_fixture( fd_runtime_fuzz_runner_t * runner, - uchar const * in, - ulong in_sz ); - -FD_PROTOTYPES_END - -#endif /* HEADER_fd_src_flamenco_runtime_tests_fd_exec_sol_compat_h */ diff --git a/src/flamenco/runtime/tests/harness/fd_harness_common.h b/src/flamenco/runtime/tests/harness/fd_harness_common.h deleted file mode 100644 index c602a860b0d..00000000000 --- a/src/flamenco/runtime/tests/harness/fd_harness_common.h +++ /dev/null @@ -1,83 +0,0 @@ -#ifndef HEADER_fd_src_flamenco_runtime_tests_harness_fd_harness_common_h -#define HEADER_fd_src_flamenco_runtime_tests_harness_fd_harness_common_h - -#include - -#include "../../fd_runtime.h" -#include "generated/context.pb.h" - -/* fd_runtime_fuzz_runner_t provides a funk instance and spad, generic - for all harnesses. */ - -struct fd_runtime_fuzz_runner { - fd_funk_t funk[1]; - fd_wksp_t * wksp; - fd_spad_t * spad; - fd_banks_t * banks; - fd_bank_t * bank; - - fd_solcap_writer_t * solcap; - void * solcap_file; /* FILE * */ -}; -typedef struct fd_runtime_fuzz_runner fd_runtime_fuzz_runner_t; - -FD_PROTOTYPES_BEGIN - -/* Constructors */ - -ulong -fd_runtime_fuzz_runner_align( void ); - -ulong -fd_runtime_fuzz_runner_footprint( void ); - -/* fd_runtime_fuzz_runner_new formats two memory regions, one for use as - a fuzzing context object and another for an spad. `mem` must be part - of an fd_wksp and hold memory for both the runner and a funk - instance. Does additional wksp allocs. wksp_tag is the tag used for - wksp allocs managed by the runner. The runner also takes in a - initialized bank object. This bnak reused for each iteration of the - fuzzer. Returns newly created runner on success. On failure, returns - NULL and logs reason for error. */ - -fd_runtime_fuzz_runner_t * -fd_runtime_fuzz_runner_new( void * mem, - void * spad_mem, - fd_banks_t * banks, - fd_bank_t * bank, - ulong wksp_tag ); - -/* fd_runtime_fuzz_runner_delete frees wksp allocations managed by - runner and returns the memory region backing runner itself back to - the caller. */ - -void * -fd_runtime_fuzz_runner_delete( fd_runtime_fuzz_runner_t * runner ); - -/* Context setup helpers */ - -/* Creates / overwrites an account in funk given an input account state. - On success, loads the account into `acc`. Optionally, reject any zero-lamport - accounts from being loaded in. */ -int -fd_runtime_fuzz_load_account( fd_txn_account_t * acc, - fd_funk_t * funk, - fd_funk_txn_t * funk_txn, - fd_exec_test_acct_state_t const * state, - uchar reject_zero_lamports ); - -/* Activates features in the runtime given an input feature set. Fails if a passed-in feature - is unknown / not supported. */ -int -fd_runtime_fuzz_restore_features( fd_features_t * features, - fd_exec_test_feature_set_t const * feature_set ); - -void -fd_runtime_fuzz_refresh_program_cache( fd_exec_slot_ctx_t * slot_ctx, - fd_exec_test_acct_state_t const * acct_states, - ulong acct_states_count, - fd_spad_t * runtime_spad ); - -FD_PROTOTYPES_END - -#endif /* HEADER_fd_src_flamenco_runtime_tests_harness_fd_harness_common_h */ diff --git a/src/flamenco/runtime/tests/harness/fd_instr_harness.h b/src/flamenco/runtime/tests/harness/fd_instr_harness.h deleted file mode 100644 index bc3a3ba7c43..00000000000 --- a/src/flamenco/runtime/tests/harness/fd_instr_harness.h +++ /dev/null @@ -1,72 +0,0 @@ -#ifndef HEADER_fd_src_flamenco_runtime_tests_fd_instr_harness_h -#define HEADER_fd_src_flamenco_runtime_tests_fd_instr_harness_h - -/* fd_instr_harness.h provides APIs for running instruction processor - tests. */ - -#include "fd_harness_common.h" - -#include "../../fd_executor.h" -#include "../../program/fd_program_cache.h" -#include "../../context/fd_exec_slot_ctx.h" -#include "../../context/fd_exec_txn_ctx.h" -#include "../../program/fd_bpf_loader_program.h" -#include "../../../fd_flamenco.h" -#include "../../../fd_flamenco_base.h" -#include "../../../vm/fd_vm.h" -#include "../../../../funk/fd_funk.h" -#include "../../../../ballet/murmur3/fd_murmur3.h" -#include "../../../../ballet/sbpf/fd_sbpf_loader.h" - -#include - -#include "generated/invoke.pb.h" -#include "generated/txn.pb.h" -#include "generated/vm.pb.h" -#include "generated/block.pb.h" - -FD_PROTOTYPES_BEGIN - -/* fd_runtime_fuzz_instr_ctx_create takes in a test runner and InstrCtx protobuf - and creates an fd_exec_instr_ctx_t that can be used in runtime. - - Setting is_syscall avoids some operations/checks only relevant for - program instructions. - - Should be coupled with fd_exec_test_instr_context_destroy when the instr_ctx - is no longer needed. */ -int -fd_runtime_fuzz_instr_ctx_create( fd_runtime_fuzz_runner_t * runner, - fd_exec_instr_ctx_t * ctx, - fd_exec_test_instr_context_t const * test_ctx, - bool is_syscall ); - -/* Frees an instr_ctx created by fd_runtime_fuzz_instr_ctx_create */ -void -fd_runtime_fuzz_instr_ctx_destroy( fd_runtime_fuzz_runner_t * runner, - fd_exec_instr_ctx_t * ctx ); - - -/* User API */ - -/* fd_runtime_fuzz_instr_run executes a given instruction context (input) - and returns the effects of executing that instruction to the caller. - output_buf points to a memory region of output_bufsz bytes where the - result is allocated into. On successful execution, *output points - to a newly created instruction effects object, and returns the number - of bytes allocated at output_buf. (The caller can use this to shrink - the output buffer) Note that an instruction that errored (in the - runtime) is also considered a successful execution. On failure to - execute, returns 0UL and leaves *object undefined and logs reason - for failure. Reasons for failure include insufficient output_bufsz. */ - -ulong -fd_runtime_fuzz_instr_run( fd_runtime_fuzz_runner_t * runner, - void const * input_, - void ** output_, - void * output_buf, - ulong output_bufsz ); - -FD_PROTOTYPES_END - -#endif /* HEADER_fd_src_flamenco_runtime_tests_fd_instr_harness_h */ diff --git a/src/flamenco/runtime/tests/harness/fd_txn_harness.h b/src/flamenco/runtime/tests/harness/fd_txn_harness.h deleted file mode 100644 index 349b895f8a9..00000000000 --- a/src/flamenco/runtime/tests/harness/fd_txn_harness.h +++ /dev/null @@ -1,73 +0,0 @@ -#ifndef HEADER_fd_src_flamenco_runtime_tests_harness_fd_txn_harness_h -#define HEADER_fd_src_flamenco_runtime_tests_harness_fd_txn_harness_h - -#include - -#include "../../fd_executor.h" -#include "../../program/fd_builtin_programs.h" -#include "../../program/fd_program_cache.h" -#include "../../sysvar/fd_sysvar_last_restart_slot.h" -#include "../../sysvar/fd_sysvar_slot_hashes.h" -#include "../../sysvar/fd_sysvar_recent_hashes.h" -#include "../../sysvar/fd_sysvar_stake_history.h" -#include "../../sysvar/fd_sysvar_epoch_rewards.h" -#include "../../sysvar/fd_sysvar_clock.h" -#include "../../sysvar/fd_sysvar_epoch_schedule.h" -#include "../../sysvar/fd_sysvar_rent.h" -#include "../../../fd_flamenco.h" -#include "../../../../disco/pack/fd_pack.h" - -#include "fd_harness_common.h" -#include "generated/txn.pb.h" - -/* Macros to append data to construct a serialized transaction - without exceeding bounds */ -#define FD_CHECKED_ADD_TO_TXN_DATA( _begin, _cur_data, _to_add, _sz ) __extension__({ \ - if( FD_UNLIKELY( (*_cur_data)+_sz>_begin+FD_TXN_MTU ) ) return ULONG_MAX; \ - fd_memcpy( *_cur_data, _to_add, _sz ); \ - *_cur_data += _sz; \ -}) - -#define FD_CHECKED_ADD_CU16_TO_TXN_DATA( _begin, _cur_data, _to_add ) __extension__({ \ - do { \ - uchar _buf[3]; \ - fd_bincode_encode_ctx_t _encode_ctx = { .data = _buf, .dataend = _buf+3 }; \ - fd_bincode_compact_u16_encode( &_to_add, &_encode_ctx ); \ - ulong _sz = (ulong) ((uchar *)_encode_ctx.data - _buf ); \ - FD_CHECKED_ADD_TO_TXN_DATA( _begin, _cur_data, _buf, _sz ); \ - } while(0); \ -}) - -FD_PROTOTYPES_BEGIN - -/* Serializes a Protobuf SanitizedTransaction that can be parsed into a - txn descriptor and returns the number of bytes consumed. Returns - ULONG_MAX if the number of bytes read exceeds 1232 (FD_TXN_MTU). - _txn_raw_begin is assumed to be a pre-allocated buffer of at least - 1232 bytes. */ -ulong -fd_runtime_fuzz_serialize_txn( uchar * txn_raw_begin, - fd_exec_test_sanitized_transaction_t const * tx ); - -/* Takes in a parsed txn descriptor to be executed against the runtime. - Returns the spad-allocated transaction context. Writes the execution - result to the `exec_res` pointer (assumed to be pre-allocated). */ -fd_exec_txn_ctx_t * -fd_runtime_fuzz_txn_ctx_exec( fd_runtime_fuzz_runner_t * runner, - fd_exec_slot_ctx_t * slot_ctx, - fd_txn_p_t * txn, - int * exec_res ); - -/* - Similar to fd_runtime_fuzz_instr_run, but executes a txn given txn context (input) -*/ -ulong -fd_runtime_fuzz_txn_run( fd_runtime_fuzz_runner_t * runner, - void const * input_, - void ** output_, - void * output_buf, - ulong output_bufsz ); - -FD_PROTOTYPES_END - -#endif /* HEADER_fd_src_flamenco_runtime_tests_harness_fd_txn_harness_h */ diff --git a/src/flamenco/runtime/tests/harness/fd_types_harness.h b/src/flamenco/runtime/tests/harness/fd_types_harness.h deleted file mode 100644 index 0df6782ec45..00000000000 --- a/src/flamenco/runtime/tests/harness/fd_types_harness.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef HEADER_fd_src_flamenco_runtime_tests_fd_types_harness_h -#define HEADER_fd_src_flamenco_runtime_tests_fd_types_harness_h - -#include "fd_instr_harness.h" - -FD_PROTOTYPES_BEGIN - -ulong -fd_runtime_fuzz_type_run( fd_runtime_fuzz_runner_t * runner, - void const * input_, - void ** output_, - void * output_buf, - ulong output_bufsz ); - -FD_PROTOTYPES_END - -#endif diff --git a/src/flamenco/runtime/tests/harness/fd_vm_harness.h b/src/flamenco/runtime/tests/harness/fd_vm_harness.h deleted file mode 100644 index 969ef84c701..00000000000 --- a/src/flamenco/runtime/tests/harness/fd_vm_harness.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef HEADER_fd_src_flamenco_runtime_tests_fd_vm_harness_h -#define HEADER_fd_src_flamenco_runtime_tests_fd_vm_harness_h - -#include "fd_harness_common.h" -#include "fd_instr_harness.h" - -#include "../../fd_system_ids.h" -#include "../../program/fd_bpf_loader_serialization.h" -#include "../../fd_executor.h" -#include "../../../vm/fd_vm.h" -#include "../../../vm/test_vm_util.h" - -#include "generated/vm.pb.h" - -/* fd_exec_vm_test.h provides APIs for running VM specific tests */ -FD_PROTOTYPES_BEGIN - -/* Executes a single test case against the interpreter. */ -ulong -fd_runtime_fuzz_vm_interp_run( fd_runtime_fuzz_runner_t * runner, - void const * input, - void ** output, - void * output_buf, - ulong output_bufsz ); - -/* Executes a single test case against a target syscall within the VM. */ -ulong -fd_runtime_fuzz_vm_syscall_run( fd_runtime_fuzz_runner_t * runner, - void const * input_, - void ** output_, - void * output_buf, - ulong output_bufsz ); - - -FD_PROTOTYPES_END - -#endif /* HEADER_fd_src_flamenco_runtime_tests_fd_vm_harness_h */ diff --git a/src/flamenco/runtime/tests/test_exec_sol_compat.c b/src/flamenco/runtime/tests/test_sol_compat.c similarity index 51% rename from src/flamenco/runtime/tests/test_exec_sol_compat.c rename to src/flamenco/runtime/tests/test_sol_compat.c index fe8e56d4ca8..5fc9c8f6c0f 100644 --- a/src/flamenco/runtime/tests/test_exec_sol_compat.c +++ b/src/flamenco/runtime/tests/test_sol_compat.c @@ -1,18 +1,17 @@ -#define FD_SCRATCH_USE_HANDHOLDING 1 -#include "../../fd_flamenco.h" -#include "harness/fd_exec_sol_compat.h" +#include "fd_solfuzz.h" #include #include #include #include #include +#include "../fd_runtime.h" #include "../../../ballet/nanopb/pb_firedancer.h" /* run_test runs a test. Return 1 on success, 0 on failure. */ static int -run_test( fd_runtime_fuzz_runner_t * runner, - char const * path ) { +run_test( fd_solfuzz_runner_t * runner, + char const * path ) { /* Read file content to memory */ @@ -33,17 +32,17 @@ run_test( fd_runtime_fuzz_runner_t * runner, FD_LOG_DEBUG(( "Running test %s", path )); if( strstr( path, "/instr/" ) != NULL ) { - ok = sol_compat_instr_fixture( runner, buf, file_sz ); + ok = fd_solfuzz_instr_fixture( runner, buf, file_sz ); } else if( strstr( path, "/txn/" ) != NULL ) { - ok = sol_compat_txn_fixture( runner, buf, file_sz ); + ok = fd_solfuzz_txn_fixture( runner, buf, file_sz ); } else if( strstr( path, "/elf_loader/" ) != NULL ) { - ok = sol_compat_elf_loader_fixture( runner, buf, file_sz ); + ok = fd_solfuzz_elf_loader_fixture( runner, buf, file_sz ); } else if( strstr( path, "/syscall/" ) != NULL ) { - ok = sol_compat_syscall_fixture( runner, buf, file_sz ); + ok = fd_solfuzz_syscall_fixture( runner, buf, file_sz ); } else if( strstr( path, "/vm_interp/" ) != NULL ){ - ok = sol_compat_vm_interp_fixture( runner, buf, file_sz ); + ok = fd_solfuzz_vm_interp_fixture( runner, buf, file_sz ); } else if( strstr( path, "/block/" ) != NULL ){ - ok = sol_compat_block_fixture( runner, buf, file_sz ); + ok = fd_solfuzz_block_fixture( runner, buf, file_sz ); } else { FD_LOG_WARNING(( "Unknown test type: %s", path )); } @@ -58,42 +57,46 @@ int main( int argc, char ** argv ) { fd_boot( &argc, &argv ); - ulong wksp_page_sz = fd_env_strip_cmdline_ulong( &argc, &argv, "--wksp-page-sz", "SOL_COMPAT_WKSP_PAGE_SZ", ULONG_MAX ); - if( wksp_page_sz == ULONG_MAX ) { - wksp_page_sz = FD_SHMEM_NORMAL_PAGE_SZ; + + char const * wksp_name = fd_env_strip_cmdline_cstr ( &argc, &argv, "--wksp", NULL, NULL ); + uint wksp_seed = fd_env_strip_cmdline_uint ( &argc, &argv, "--wksp-seed", NULL, 0U ); + ulong wksp_tag = fd_env_strip_cmdline_ulong( &argc, &argv, "--wksp-tag", NULL, 1UL ); + ulong data_max = fd_env_strip_cmdline_ulong( &argc, &argv, "--data-max", NULL, 6UL<<30 ); /* 6 GiB */ + ulong part_max = fd_env_strip_cmdline_ulong( &argc, &argv, "--part-max", NULL, fd_wksp_part_max_est( data_max, 64UL<<10 ) ); + + fd_wksp_t * wksp; + if( wksp_name ) { + FD_LOG_INFO(( "Attaching to --wksp %s", wksp_name )); + wksp = fd_wksp_attach( wksp_name ); + } else { + FD_LOG_INFO(( "--wksp not specified, using anonymous demand-paged memory --part-max %lu --data-max %lu", part_max, data_max )); + wksp = fd_wksp_demand_paged_new( "solfuzz", wksp_seed, part_max, data_max ); } + if( FD_UNLIKELY( !wksp ) ) return 255; - sol_compat_wksp_init( wksp_page_sz ); + fd_solfuzz_runner_t * runner = fd_solfuzz_runner_new( wksp, wksp_tag ); + FD_TEST( runner ); ulong fail_cnt = 0UL; for( int j=1; jspad->frame_free; ulong mem_used_pre_test = runner->spad->mem_used; - FD_SPAD_FRAME_BEGIN( runner->spad ) { - + fd_spad_push( runner->spad ); fail_cnt += !run_test( runner, argv[j] ); - - } FD_SPAD_FRAME_END; + fd_spad_pop( runner->spad ); ulong frames_used_post_test = runner->spad->frame_free; ulong mem_used_post_test = runner->spad->mem_used; FD_TEST( frames_used_pre_test == frames_used_post_test ); FD_TEST( mem_used_pre_test == mem_used_post_test ); - - // Free runner - sol_compat_cleanup_runner( runner ); - - // Check usage - sol_compat_check_wksp_usage(); } - /* TODO: verify that there are no leaked libc allocs and vallocs */ - sol_compat_fini(); + fd_solfuzz_runner_delete( runner ); + if( wksp_name ) fd_wksp_detach( wksp ); + else fd_wksp_demand_paged_delete( wksp ); + fd_halt(); return fail_cnt>0UL; } diff --git a/src/flamenco/vm/fd_vm_interp.c b/src/flamenco/vm/fd_vm_interp.c index 497c083cf59..1e6303765e7 100644 --- a/src/flamenco/vm/fd_vm_interp.c +++ b/src/flamenco/vm/fd_vm_interp.c @@ -1,5 +1,6 @@ #include "fd_vm_base.h" #include "fd_vm_private.h" +#include "../runtime/tests/fd_dump_pb.h" /* FIXME: MAKE DIFFERENT VERSIONS FOR EACH COMBO OF CHECK_ALIGN/TRACE? */ /* TODO: factor out common unpacking code */ diff --git a/src/flamenco/vm/fd_vm_private.h b/src/flamenco/vm/fd_vm_private.h index f4f5bd5fb12..1efa90d753a 100644 --- a/src/flamenco/vm/fd_vm_private.h +++ b/src/flamenco/vm/fd_vm_private.h @@ -1,7 +1,6 @@ #ifndef HEADER_fd_src_flamenco_vm_fd_vm_private_h #define HEADER_fd_src_flamenco_vm_fd_vm_private_h -#include "../runtime/tests/fd_dump_pb.h" #include "fd_vm.h" #include "../../ballet/sbpf/fd_sbpf_instr.h" diff --git a/src/flamenco/vm/fd_vm_tool.c b/src/flamenco/vm/fd_vm_tool.c index 5aa1fe49d5e..3dff26c51fb 100644 --- a/src/flamenco/vm/fd_vm_tool.c +++ b/src/flamenco/vm/fd_vm_tool.c @@ -70,7 +70,7 @@ fd_vm_tool_prog_create( fd_vm_tool_prog_t * tool_prog, fd_vm_syscall_register_all( syscalls, 0 ); /* Load program */ - if( FD_UNLIKELY( 0!=fd_sbpf_program_load( prog, bin_buf, bin_sz, syscalls, false ) ) ) + if( FD_UNLIKELY( 0!=fd_sbpf_program_load( prog, bin_buf, bin_sz, syscalls, 0 ) ) ) FD_LOG_ERR(( "fd_sbpf_program_load() failed: %s", fd_sbpf_strerror() )); tool_prog->bin_buf = bin_buf; diff --git a/src/util/shmem/fd_shmem.h b/src/util/shmem/fd_shmem.h index 8b0c0d47db2..eabec13be5e 100644 --- a/src/util/shmem/fd_shmem.h +++ b/src/util/shmem/fd_shmem.h @@ -241,7 +241,7 @@ fd_shmem_join_query_by_addr( void const * addr, custom hardware that provides its own functions for getting access to its memory, etc) as a normal join. - Returns 0 on failure and a strerror friendly error code on failure + Returns 0 on success and a strerror friendly error code on failure (logs details). Reasons for failure include EINVAL: bad name (NULL / too short / too long / bad characters / already joined), bad join (NULL join / already joined), bad mem (NULL mem / unaligned mem / From 34bf84b11cc6db1ad13e690eed4ff2528e41ac52 Mon Sep 17 00:00:00 2001 From: Richard Patel Date: Tue, 12 Aug 2025 15:40:17 +0000 Subject: [PATCH 3/4] solfuzz: recursive dir descent in C --- contrib/test/run_test_vectors.sh | 14 +- src/flamenco/runtime/tests/fd_solfuzz.c | 5 +- src/flamenco/runtime/tests/test_sol_compat.c | 201 +++++++++++++++++-- 3 files changed, 192 insertions(+), 28 deletions(-) diff --git a/contrib/test/run_test_vectors.sh b/contrib/test/run_test_vectors.sh index c140b2fdf47..367c02d8546 100755 --- a/contrib/test/run_test_vectors.sh +++ b/contrib/test/run_test_vectors.sh @@ -49,25 +49,25 @@ else ./$OBJDIR/bin/fd_wksp_ctl new run-test-vectors $PAGE_CNT $PAGE_SZ 0 0644 --log-path '' fi -SOL_COMPAT=( "$OBJDIR/unit-test/test_sol_compat" "--wksp" "$WKSP" ) +SOL_COMPAT=( "$OBJDIR/unit-test/test_sol_compat" "--wksp" "$WKSP" --tile-cpus "f,0-$(( $NUM_PROCESSES - 1 ))" ) export FD_LOG_PATH=$LOG_PATH/test_exec_block -find dump/test-vectors/block/fixtures -type f -name '*.fix' | xargs -P $NUM_PROCESSES -n 1000 ${SOL_COMPAT[@]} +${SOL_COMPAT[@]} dump/test-vectors/block/fixtures export FD_LOG_PATH=$LOG_PATH/test_exec_syscall -find dump/test-vectors/syscall/fixtures -type f -name '*.fix' | xargs -P $NUM_PROCESSES -n 1000 ${SOL_COMPAT[@]} +${SOL_COMPAT[@]} dump/test-vectors/syscall/fixtures export FD_LOG_PATH=$LOG_PATH/test_exec_interp -find dump/test-vectors/vm_interp/fixtures -type f -name '*.fix' | xargs -P $NUM_PROCESSES -n 1000 ${SOL_COMPAT[@]} +${SOL_COMPAT[@]} dump/test-vectors/vm_interp/fixtures export FD_LOG_PATH=$LOG_PATH/test_exec_txn -find dump/test-vectors/txn/fixtures -type f -name '*.fix' | xargs -P $NUM_PROCESSES ${SOL_COMPAT[@]} +${SOL_COMPAT[@]} dump/test-vectors/txn/fixtures zstd -df dump/test-vectors/elf_loader/fixtures/*.zst export FD_LOG_PATH=$LOG_PATH/test_elf_loader -find dump/test-vectors/elf_loader/fixtures -type f -name '*.fix' | xargs -P $NUM_PROCESSES -n 1000 ${SOL_COMPAT[@]} +${SOL_COMPAT[@]} dump/test-vectors/elf_loader/fixtures export FD_LOG_PATH=$LOG_PATH/test_exec_instr -find dump/test-vectors/instr/fixtures -type f -name '*.fix' | xargs -P $NUM_PROCESSES -n 1000 ${SOL_COMPAT[@]} +${SOL_COMPAT[@]} dump/test-vectors/instr/fixtures echo Test vectors success diff --git a/src/flamenco/runtime/tests/fd_solfuzz.c b/src/flamenco/runtime/tests/fd_solfuzz.c index 142af4fa2d9..d7d932e7533 100644 --- a/src/flamenco/runtime/tests/fd_solfuzz.c +++ b/src/flamenco/runtime/tests/fd_solfuzz.c @@ -83,7 +83,10 @@ fd_solfuzz_runner_new( fd_wksp_t * wksp, void * funk_mem = fd_wksp_alloc_laddr( wksp, fd_funk_align(), fd_funk_footprint( txn_max, rec_max ), wksp_tag ); void * spad_mem = fd_wksp_alloc_laddr( wksp, fd_spad_align(), fd_spad_footprint( spad_max ), wksp_tag ); void * banks_mem = fd_wksp_alloc_laddr( wksp, fd_banks_align(), fd_banks_footprint( bank_max, fork_max ), wksp_tag ); - if( FD_UNLIKELY( !runner || !funk_mem || !spad_mem || !banks_mem ) ) goto bail1; + if( FD_UNLIKELY( !runner ) ) { FD_LOG_WARNING(( "fd_wksp_alloc(solfuzz_runner) failed" )); goto bail1; } + if( FD_UNLIKELY( !funk_mem ) ) { FD_LOG_WARNING(( "fd_wksp_alloc(funk) failed" )); goto bail1; } + if( FD_UNLIKELY( !spad_mem ) ) { FD_LOG_WARNING(( "fd_wksp_alloc(spad) failed (spad_max=%g)", (double)spad_max )); goto bail1; } + if( FD_UNLIKELY( !banks_mem ) ) { FD_LOG_WARNING(( "fd_wksp_alloc(banks) failed (bank_max=%lu fork_max=%lu)", bank_max, fork_max )); goto bail1; } /* Create objects */ fd_memset( runner, 0, sizeof(fd_solfuzz_runner_t) ); diff --git a/src/flamenco/runtime/tests/test_sol_compat.c b/src/flamenco/runtime/tests/test_sol_compat.c index 5fc9c8f6c0f..a30fb4f83b7 100644 --- a/src/flamenco/runtime/tests/test_sol_compat.c +++ b/src/flamenco/runtime/tests/test_sol_compat.c @@ -1,5 +1,7 @@ +#define _DEFAULT_SOURCE #include "fd_solfuzz.h" #include +#include #include #include #include @@ -7,18 +9,25 @@ #include "../fd_runtime.h" #include "../../../ballet/nanopb/pb_firedancer.h" +static int fail_fast; +static int error_occurred; + /* run_test runs a test. Return 1 on success, 0 on failure. */ static int -run_test( fd_solfuzz_runner_t * runner, - char const * path ) { +run_test1( fd_solfuzz_runner_t * runner, + char const * path ) { /* Read file content to memory */ int file = open( path, O_RDONLY ); + if( FD_UNLIKELY( file<0 ) ) { + FD_LOG_WARNING(( "open(%s) failed: (%i-%s)", path, errno, fd_io_strerror( errno ) )); + return 0; + } struct stat st; if( FD_UNLIKELY( 0!=fstat( file, &st ) ) ) { - FD_LOG_WARNING(( "fstat(%s): %s", path, fd_io_strerror( errno ) )); + FD_LOG_WARNING(( "fstat(%s) failed: (%i-%s)", path, errno, fd_io_strerror( errno ) )); return 0; } ulong file_sz = (ulong)st.st_size; @@ -53,6 +62,142 @@ run_test( fd_solfuzz_runner_t * runner, return ok; } +static int +run_test( fd_solfuzz_runner_t * runner, + char const * path ) { + ulong frames_used_pre_test = runner->spad->frame_free; + ulong mem_used_pre_test = runner->spad->mem_used; + + fd_spad_push( runner->spad ); + int ok = !!run_test1( runner, path ); + fd_spad_pop( runner->spad ); + + ulong frames_used_post_test = runner->spad->frame_free; + ulong mem_used_post_test = runner->spad->mem_used; + + FD_TEST( frames_used_pre_test == frames_used_post_test ); + FD_TEST( mem_used_pre_test == mem_used_post_test ); + return ok; +} + +/* Recursive dir walk function, follows symlinks */ + +typedef int (* visit_path)( void * ctx, char const * path ); + +static int +recursive_walk1( DIR * dir, + char path[ PATH_MAX ], + ulong path_len, + visit_path visit, + void * visit_ctx ) { + struct dirent * entry; + errno = 0; + while(( entry = readdir( dir ) )) { + path[ path_len ] = '\0'; + if( FD_LIKELY( !strcmp( entry->d_name, "." ) || !strcmp( entry->d_name, ".." ) ) ) continue; + + ulong child_len = strlen( entry->d_name ); + if( FD_UNLIKELY( path_len+1+child_len+1>PATH_MAX ) ) { + FD_LOG_WARNING(( "Ignoring overlong path name: %s/%s", path, entry->d_name )); + continue; + } + + char * p = path+path_len; + p = fd_cstr_append_char( p, '/' ); + p = fd_cstr_append_text( p, entry->d_name, child_len ); + fd_cstr_fini( p ); + ulong sub_path_len = (ulong)( p-path ); + + DIR * subdir = NULL; + char * suffix; + if( entry->d_type==DT_DIR ) { + subdir = opendir( path ); + if( FD_UNLIKELY( !subdir ) ) { + FD_LOG_WARNING(( "opendir(%s) failed: (%i-%s)", path, errno, fd_io_strerror( errno ) )); + continue; + } +as_dir: + recursive_walk1( subdir, path, sub_path_len, visit, visit_ctx ); + closedir( subdir ); + } else if( entry->d_type==DT_REG ) { +as_file: + suffix = strstr( entry->d_name, ".fix" ); + if( !suffix || suffix[4]!='\0' ) continue; + if( !visit( visit_ctx, path ) ) break; + } else if( entry->d_type==DT_LNK ) { + subdir = opendir( path ); + if( subdir ) { + goto as_dir; + } else { + if( FD_UNLIKELY( errno!=ENOTDIR ) ) { + FD_LOG_WARNING(( "opendir(%s) failed: (%i-%s)", path, errno, fd_io_strerror( errno ) )); + continue; + } + goto as_file; + } + } + } + return 1; +} + +static int +recursive_walk( char const * path, + visit_path visit, + void * visit_ctx ) { + char path1[ PATH_MAX ]; + ulong path_len = strlen( path ); + if( FD_UNLIKELY( path_len>=PATH_MAX ) ) { + FD_LOG_WARNING(( "Ignoring overlong path name: %s", path )); + return 0; + } + fd_cstr_fini( fd_cstr_append_text( fd_cstr_init( path1 ), path, path_len ) ); + DIR * root_dir = opendir( path1 ); + if( FD_UNLIKELY( !root_dir ) ) { + FD_LOG_WARNING(( "opendir(%s) failed: (%i-%s)", path, errno, fd_io_strerror( errno ) )); + return 0; + } + int ok = recursive_walk1( root_dir, path1, path_len, visit, visit_ctx ); + closedir( root_dir ); + return ok; +} + +/* Single-threaded mode: execute synchronously while walking dir */ + +static int +visit_sync( void * ctx, + char const * path ) { + fd_solfuzz_runner_t * runner = ctx; + int ok = run_test( runner, path ); + if( !ok ) { + error_occurred = 1; + if( fail_fast ) return 0; + } + return 1; +} + +static void +run_single_threaded( fd_solfuzz_runner_t * runner, + int argc, + char ** argv ) { + for( int j=1; j1UL ) worker_cnt--; - ulong fail_cnt = 0UL; - for( int j=1; jspad->frame_free; - ulong mem_used_pre_test = runner->spad->mem_used; - - fd_spad_push( runner->spad ); - fail_cnt += !run_test( runner, argv[j] ); - fd_spad_pop( runner->spad ); - - ulong frames_used_post_test = runner->spad->frame_free; - ulong mem_used_post_test = runner->spad->mem_used; + /* Allocate runners */ + int exit_code = 255; + fd_solfuzz_runner_t ** runners = fd_wksp_alloc_laddr( wksp, alignof(void *), worker_cnt*sizeof(void *), 1UL ); + if( FD_UNLIKELY( !runners ) ) { FD_LOG_WARNING(( "init failed" )); goto exit; } + fd_memset( runners, 0, worker_cnt*sizeof(void *) ); + for( ulong i=0UL; i0UL; + return exit_code; } From ab69901c05866ffa5286cef51ed8fc2d7c65acf4 Mon Sep 17 00:00:00 2001 From: Richard Patel Date: Tue, 12 Aug 2025 17:59:33 +0000 Subject: [PATCH 4/4] solfuzz: tile parallelism --- src/flamenco/runtime/tests/Local.mk | 2 +- src/flamenco/runtime/tests/test_sol_compat.c | 223 +++++++++++++++++-- 2 files changed, 207 insertions(+), 18 deletions(-) diff --git a/src/flamenco/runtime/tests/Local.mk b/src/flamenco/runtime/tests/Local.mk index 269a2da812f..28f9cd0df01 100644 --- a/src/flamenco/runtime/tests/Local.mk +++ b/src/flamenco/runtime/tests/Local.mk @@ -12,7 +12,7 @@ $(call add-hdrs,generated/context.pb.h,generated/elf.pb.h,generated/invoke.pb.h, $(call add-objs,generated/context.pb generated/elf.pb generated/invoke.pb generated/txn.pb generated/block.pb generated/vm.pb generated/type.pb generated/shred.pb generated/metadata.pb,fd_flamenco) SOL_COMPAT_FLAGS:=-Wl,--undefined=fd_types_vt_by_name -$(call make-unit-test,test_sol_compat,test_sol_compat,fd_flamenco_test fd_flamenco fd_funk fd_ballet fd_util fd_disco,$(SECP256K1_LIBS)) +$(call make-unit-test,test_sol_compat,test_sol_compat,fd_flamenco_test fd_flamenco fd_tango fd_funk fd_ballet fd_util fd_disco,$(SECP256K1_LIBS)) $(call make-shared,libfd_exec_sol_compat.so,fd_sol_compat,fd_flamenco_test fd_flamenco fd_funk fd_ballet fd_util fd_disco,$(SECP256K1_LIBS) $(SOL_COMPAT_FLAGS)) run-runtime-backtest: $(OBJDIR)/bin/fd_ledger diff --git a/src/flamenco/runtime/tests/test_sol_compat.c b/src/flamenco/runtime/tests/test_sol_compat.c index a30fb4f83b7..7c33dea71fc 100644 --- a/src/flamenco/runtime/tests/test_sol_compat.c +++ b/src/flamenco/runtime/tests/test_sol_compat.c @@ -1,17 +1,26 @@ #define _DEFAULT_SOURCE #include "fd_solfuzz.h" #include -#include +#include /* opendir */ #include +#include /* sched_yield */ #include -#include -#include +#include /* fstat */ +#include /* close */ #include "../fd_runtime.h" #include "../../../ballet/nanopb/pb_firedancer.h" +#include "../../../tango/fd_tango.h" + +#define MCACHE_DEPTH (256UL) +#define MCACHE_FOOTPRINT FD_MCACHE_FOOTPRINT( MCACHE_DEPTH, 0UL ) +#define DCACHE_DATA_SZ FD_DCACHE_REQ_DATA_SZ( PATH_MAX, MCACHE_DEPTH, 1UL, 1 ) +#define DCACHE_FOOTPRINT FD_DCACHE_FOOTPRINT( DCACHE_DATA_SZ, 0UL ) static int fail_fast; static int error_occurred; +static uint shutdown_signal __attribute__((aligned(64))); + /* run_test runs a test. Return 1 on success, 0 on failure. */ static int @@ -82,7 +91,10 @@ run_test( fd_solfuzz_runner_t * runner, /* Recursive dir walk function, follows symlinks */ -typedef int (* visit_path)( void * ctx, char const * path ); +typedef int +(* visit_path)( void * ctx, + char const * path, + ulong path_len ); static int recursive_walk1( DIR * dir, @@ -123,7 +135,7 @@ recursive_walk1( DIR * dir, as_file: suffix = strstr( entry->d_name, ".fix" ); if( !suffix || suffix[4]!='\0' ) continue; - if( !visit( visit_ctx, path ) ) break; + if( !visit( visit_ctx, path, sub_path_len ) ) break; } else if( entry->d_type==DT_LNK ) { subdir = opendir( path ); if( subdir ) { @@ -165,7 +177,9 @@ recursive_walk( char const * path, static int visit_sync( void * ctx, - char const * path ) { + char const * path, + ulong path_len ) { + (void)path_len; fd_solfuzz_runner_t * runner = ctx; int ok = run_test( runner, path ); if( !ok ) { @@ -189,13 +203,171 @@ run_single_threaded( fd_solfuzz_runner_t * runner, /* Multi-threaded mode: fan out tasks to bank of tiles */ +struct walkdir_state { + fd_frag_meta_t * mcache; + uchar * dcache; + + ulong depth; + ulong chunk0; + ulong wmark; + + ulong seq; + ulong chunk; + ulong cr_avail; + + ulong worker_cnt; + ulong ** fseqs; +}; +typedef struct walkdir_state walkdir_state_t; + +static void +walkdir_backpressure( walkdir_state_t * state ) { + ulong const worker_cnt = state->worker_cnt; + ulong const seq_pub = state->seq; + ulong cr_avail = state->cr_avail; + do { + sched_yield(); + cr_avail = ULONG_MAX; + for( ulong i=0UL; ifseqs[ i ] ) ); + /**/ lag = fd_long_max( lag, 0L ); + cr_avail = fd_ulong_min( cr_avail, MCACHE_DEPTH-(ulong)lag ); + } + } while( !cr_avail ); + state->cr_avail = cr_avail; +} + +static int +walkdir_publish( void * ctx, + char const * path, + ulong path_len ) { + walkdir_state_t * state = ctx; + if( FD_UNLIKELY( !state->cr_avail ) ) { + /* Blocked on flow-control credits ... spin until they're replenished */ + walkdir_backpressure( state ); + /* Guaranteed to have more flow-control credits */ + } + + /* Write data record */ + ulong chunk = state->chunk; + char * msg = fd_chunk_to_laddr( state->dcache, chunk ); + fd_cstr_fini( fd_cstr_append_text( fd_cstr_init( msg ), path, path_len ) ); + state->chunk = fd_dcache_compact_next( chunk, path_len+1UL, state->chunk0, state->wmark ); + + /* Write frag descriptor */ + ulong seq = state->seq; + fd_mcache_publish( state->mcache, state->depth, seq, 0UL, chunk, 0UL, 0UL, 0UL, 0UL ); + state->seq = fd_seq_inc( seq, 1UL ); + state->cr_avail--; + return 1; +} + +static void +walkdir_tile( fd_frag_meta_t * mcache, + uchar * dcache, + ulong ** fseqs, + ulong worker_cnt, + int argc, + char ** argv ) { + walkdir_state_t state = { + .mcache = mcache, + .dcache = dcache, + .depth = fd_mcache_depth( mcache ), + .chunk0 = fd_dcache_compact_chunk0( dcache, dcache ), + .wmark = fd_dcache_compact_wmark ( dcache, dcache, PATH_MAX ), + .seq = fd_mcache_seq0( mcache ), + .worker_cnt = worker_cnt, + .fseqs = fseqs + }; + state.chunk = state.chunk0; + state.cr_avail = state.depth; + + for( int j=1; jchunk ); + run_test( runner, path ); + } + + seq = fd_seq_inc( seq, 1UL ); + FD_VOLATILE( fseq[0] ) = seq; + } + FD_VOLATILE( fseq[0] ) = seq; +} + +static int +exec_task( int argc, + char ** argv ) { + ulong worker_idx = (ulong)argc; + mt_state_t const * state = fd_type_pun_const( argv ); + exec_tile( state->runners[ worker_idx ], state->mcache, state->dcache, state->fseqs[ worker_idx ], worker_idx, state->worker_cnt ); + return 0; +} + FD_FN_UNUSED static void run_multi_threaded( fd_solfuzz_runner_t ** runners, ulong worker_cnt, - int argc, - char ** argv ) { - (void)runners; (void)worker_cnt; (void)argc; (void)argv; - FD_LOG_WARNING(( "Multi-threaded mode not implemented yet" )); + int argc, + char ** argv, + fd_frag_meta_t * mcache, + uchar * dcache, + ulong ** fseqs ) { + mt_state_t state = { + .runners = runners, + .worker_cnt = worker_cnt, + .mcache = mcache, + .dcache = dcache, + .fseqs = fseqs + }; + + for( ulong i=0UL; i