Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions config/extra/with-arm.mk
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ include config/extra/with-zstd.mk
include config/extra/with-lz4.mk
include config/extra/with-openssl.mk
include config/extra/with-rocksdb.mk
include config/extra/with-flatcc.mk

endif

Expand Down
5 changes: 5 additions & 0 deletions config/extra/with-flatcc.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
ifneq (,$(wildcard $(OPT)/lib/libflatcc.a))
FLATCC_LIBS:=$(OPT)/lib/libflatcc.a $(OPT)/lib/libflatccrt.a
else
$(info "flatcc not installed, skipping")
endif
1 change: 1 addition & 0 deletions config/extra/with-x86-64.mk
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,6 @@ include config/extra/with-zstd.mk
include config/extra/with-lz4.mk
include config/extra/with-openssl.mk
include config/extra/with-rocksdb.mk
include config/extra/with-flatcc.mk

FD_ARCH_SUPPORTS_SANDBOX:=1
14 changes: 14 additions & 0 deletions deps.sh
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ fetch () {
checkout_repo s2n https://github.com/awslabs/s2n-bignum "" "4d2e22a"
checkout_repo openssl https://github.com/openssl/openssl "openssl-3.6.0"
checkout_repo secp256k1 https://github.com/bitcoin-core/secp256k1 "v0.7.0"
checkout_repo flatcc https://github.com/dvidelabs/flatcc.git "v0.6.1"
if [[ $DEVMODE == 1 ]]; then
checkout_repo bzip2 https://gitlab.com/bzip2/bzip2 "bzip2-1.0.8"
checkout_repo rocksdb https://github.com/facebook/rocksdb "v10.5.1"
Expand Down Expand Up @@ -610,6 +611,18 @@ install_snappy () {
echo "[+] Successfully installed snappy"
}

install_flatcc () {
echo "[+] Installing flatcc"
cd "$PREFIX/git/flatcc"
cmake -B build \
-DCMAKE_INSTALL_PREFIX=$PREFIX \
-DFLATCC_INSTALL=ON \
-DCMAKE_POSITION_INDEPENDENT_CODE=ON
cmake --build build -j
cmake --install build
echo "[+] Successfully installed flatcc"
}

install () {
CC="$(command -v $_CC)"
cc="$CC"
Expand Down Expand Up @@ -638,6 +651,7 @@ install () {
( install_bzip2 )
( install_snappy )
( install_rocksdb )
( install_flatcc )
fi

# Merge lib64 with lib
Expand Down
1 change: 1 addition & 0 deletions src/.clangd
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ CompileFlags:
- -DFD_HAS_ZSTD=1
- -DFD_HAS_SSE=1
- -DFD_USING_CLANG=1
- -I/data/mjain/repos/firedancer/opt/include
---
If:
PathMatch: .*\.h
Expand Down
9 changes: 6 additions & 3 deletions src/flamenco/runtime/tests/Local.mk
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,15 @@ $(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)

# $(call add-hdrs,generated/block_builder.h,generated/block_reader.h,generated/block_verifier.h,generated/context_builder.h,generated/context_reader.h,generated/context_verifier.h,generated/elf_builder.h,generated/elf_reader.h,generated/elf_verifier.h,generated/flatbuffers_common_builder.h,generated/flatbuffers_common_reader.h,generated/instr_builder.h,generated/instr_reader.h,generated/instr_verifier.h,generated/metadata_builder.h,generated/metadata_reader.h,generated/metadata_verifier.h,generated/txn_builder.h,generated/txn_reader.h,generated/txn_verifier.h,generated/vm_builder.h,generated/vm_reader.h,generated/vm_verifier.h)
$(call add-hdrs,flatbuffers/generated/elf_builder.h,flatbuffers/generated/elf_reader.h)

SOL_COMPAT_FLAGS:=-Wl,--undefined=fd_types_vt_by_name -Wl,--version-script=src/flamenco/runtime/tests/libfd_exec_sol_compat.map
$(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))
$(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) $(FLATCC_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) $(FLATCC_LIBS) $(SOL_COMPAT_FLAGS))
$(call make-unit-test,test_sol_compat_so,test_sol_compat_so,fd_util)

$(call make-unit-test,test_dump_block,test_dump_block,fd_flamenco_test fd_flamenco fd_funk fd_ballet fd_util fd_disco,$(SECP256K1_LIBS))
$(call make-unit-test,test_dump_block,test_dump_block,fd_flamenco_test fd_flamenco fd_funk fd_ballet fd_util fd_disco,$(SECP256K1_LIBS) $(FLATCC_LIBS))

run-runtime-backtest: $(OBJDIR)/bin/fd_ledger $(OBJDIR)/bin/firedancer-dev
OBJDIR=$(OBJDIR) src/flamenco/runtime/tests/run_backtest_ci.sh $(BACKTEST_ARGS)
Expand Down
108 changes: 108 additions & 0 deletions src/flamenco/runtime/tests/fd_elf_harness.c
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
#include "fd_solfuzz.h"
#include "fd_solfuzz_private.h"
#include "flatbuffers/generated/flatbuffers_common_builder.h"
#include "flatbuffers/generated/flatbuffers_common_reader.h"
#include "generated/elf.pb.h"
#include "../../../ballet/sbpf/fd_sbpf_loader.h"
#include "../program/fd_bpf_loader_program.h"
#include "../../vm/fd_vm_base.h"
#include "../../progcache/fd_prog_load.h"

#include "flatbuffers/generated/elf_reader.h"
#include "flatbuffers/generated/elf_builder.h"

#define SORT_NAME sort_ulong
#define SORT_KEY_T ulong
#define SORT_BEFORE(a,b) (a)<(b)
Expand Down Expand Up @@ -134,3 +139,106 @@ fd_solfuzz_pb_elf_loader_run( fd_solfuzz_runner_t * runner,
*output = elf_effects;
return actual_end - (ulong) output_buf;
}

void
fd_solfuzz_fb_elf_loader_build_err_effects( fd_solfuzz_runner_t * runner, int err ) {
FD_TEST( !SOL_COMPAT_NS(ELFLoaderEffects_start_as_root)( runner->fb_builder ) );
FD_TEST( !SOL_COMPAT_NS(ELFLoaderEffects_err_code_add)( runner->fb_builder, (uchar)(-err) ) );
FD_TEST( SOL_COMPAT_NS(ELFLoaderEffects_end_as_root)( runner->fb_builder ) );
}

int
fd_solfuzz_fb_elf_loader_run( fd_solfuzz_runner_t * runner,
void const * input_ ) {
SOL_COMPAT_NS(ELFLoaderCtx_table_t) input = fd_type_pun_const( input_ );

fd_spad_t * spad = runner->spad;
flatbuffers_uint8_vec_t elf_bin_ = SOL_COMPAT_NS(ELFLoaderCtx_elf_data( input ));
uchar const * elf_bin = (uchar const*)elf_bin_;
ulong elf_sz = flatbuffers_uint8_vec_len( elf_bin_ );

/* Restore feature set */
fd_features_t feature_set = {0};
fd_solfuzz_fb_restore_features( &feature_set, SOL_COMPAT_NS(ELFLoaderCtx_features( input )));

fd_sbpf_loader_config_t config = {
.elf_deploy_checks = SOL_COMPAT_NS(ELFLoaderCtx_deploy_checks( input )),
};

fd_prog_versions_t versions = fd_prog_versions( &feature_set, UINT_MAX );
config.sbpf_min_version = versions.min_sbpf_version;
config.sbpf_max_version = versions.max_sbpf_version;

/* Peek */
fd_sbpf_elf_info_t info;
int err = fd_sbpf_elf_peek( &info, elf_bin, elf_sz, &config );
if( err ) {
fd_solfuzz_fb_elf_loader_build_err_effects( runner, err );
return SOL_COMPAT_V2_SUCCESS;
}

/* Set up loading context */
void * rodata = fd_spad_alloc_check( spad, FD_SBPF_PROG_RODATA_ALIGN, info.bin_sz );
fd_sbpf_program_t * prog = fd_sbpf_program_new( fd_spad_alloc_check( spad, fd_sbpf_program_align(), fd_sbpf_program_footprint( &info ) ), &info, rodata );
fd_sbpf_syscalls_t * syscalls = fd_sbpf_syscalls_new( fd_spad_alloc_check( spad, fd_sbpf_syscalls_align(), fd_sbpf_syscalls_footprint() ));
void * rodata_scratch = fd_spad_alloc_check( spad, 1UL, elf_sz );

/* Register syscalls given the active feature set. We can pass in an
arbitrary slot as its just used to check if features should be
active or not. */
FD_TEST( !fd_vm_syscall_register_slot( syscalls, UINT_MAX, &feature_set, !!config.elf_deploy_checks ) );

/* Load */
err = fd_sbpf_program_load( prog, elf_bin, elf_sz, syscalls, &config, rodata_scratch, elf_sz );
if( err ) {
fd_solfuzz_fb_elf_loader_build_err_effects( runner, err );
return SOL_COMPAT_V2_SUCCESS;
}

/**** Capture effects ****/

/* Error code */
uchar out_err_code = FD_SBPF_ELF_SUCCESS;

/* Rodata */
flatbuffers_uint8_vec_ref_t out_rodata = flatbuffers_uint8_vec_create( runner->fb_builder, prog->rodata, prog->rodata_sz );

/* Text count */
ulong out_text_cnt = prog->info.text_cnt;

/* Text off */
ulong out_text_off = prog->info.text_off;

/* Entry PC */
ulong out_entry_pc = prog->entry_pc;

/* Calldests */
ulong max_out_calldests_cnt = 1UL + ( prog->calldests ? fd_sbpf_calldests_cnt( prog->calldests ) : 0UL );
ulong * tmp_out_calldests = fd_spad_alloc_check( spad, alignof(ulong), sizeof(ulong)*max_out_calldests_cnt );
ulong out_calldests_cnt = 0UL;

/* Add the entrypoint to the calldests */
tmp_out_calldests[out_calldests_cnt++] = prog->entry_pc;

/* Add the rest of the calldests */
if( FD_LIKELY( prog->calldests ) ) {
for( ulong target_pc=fd_sbpf_calldests_const_iter_init(prog->calldests);
!fd_sbpf_calldests_const_iter_done(target_pc);
target_pc=fd_sbpf_calldests_const_iter_next(prog->calldests, target_pc) ) {
if( FD_LIKELY( target_pc!=prog->entry_pc ) ) {
tmp_out_calldests[out_calldests_cnt++] = target_pc;
}
}
}

/* Sort the calldests in ascending order */
sort_ulong_inplace( tmp_out_calldests, out_calldests_cnt );

/* Create output calldests vector */
flatbuffers_uint64_vec_ref_t out_calldests = flatbuffers_uint64_vec_create( runner->fb_builder, tmp_out_calldests, out_calldests_cnt );

/* Build effects */
SOL_COMPAT_NS(ELFLoaderEffects_create)( runner->fb_builder, out_err_code, out_rodata, out_text_cnt, out_text_off, out_entry_pc, out_calldests );

return SOL_COMPAT_V2_SUCCESS;
}
19 changes: 19 additions & 0 deletions src/flamenco/runtime/tests/fd_harness_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,22 @@ fd_solfuzz_pb_restore_features( fd_features_t * features,
}
return 1;
}

void
fd_solfuzz_fb_restore_features( fd_features_t * features,
SOL_COMPAT_NS(FeatureSet_table_t) feature_set ) {
if( FD_UNLIKELY( !feature_set ) ) return;

fd_features_disable_all( features );
flatbuffers_uint64_vec_t input_features = SOL_COMPAT_NS(FeatureSet_features( feature_set ));
ulong input_features_cnt = flatbuffers_uint64_vec_len( input_features );
for( ulong i=0UL; i<input_features_cnt; i++ ) {
ulong prefix = flatbuffers_uint64_vec_at( input_features, i );
fd_feature_id_t const * id = fd_feature_id_query( prefix );
if( FD_UNLIKELY( !id ) ) {
FD_LOG_ERR(( "unsupported feature ID 0x%016lx", prefix ));
}
/* Enabled since genesis */
fd_features_set( features, id, 0UL );
}
}
44 changes: 44 additions & 0 deletions src/flamenco/runtime/tests/fd_sol_compat.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@
#include "generated/txn.pb.h"
#include "generated/type.pb.h"

#include "flatbuffers/generated/elf_reader.h"
#include "flatbuffers/generated/block_reader.h"
#include "flatbuffers/generated/instr_reader.h"
#include "flatbuffers/generated/vm_reader.h"
#include "flatbuffers/generated/txn_reader.h"
#include "flatbuffers/generated/flatbuffers_common_reader.h"

#include <assert.h>
#include <errno.h>
#include <stdio.h>
Expand Down Expand Up @@ -287,3 +294,40 @@ sol_compat_shred_parse_v1( uchar * out,
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 );
}

/*
* execute_v2
Unlike sol_compat_execute_v1 APIs, v2 APIs use flatbuffers for
zero-copy decoding. Returns SOL_COMPAT_V2_SUCCESS on success and
SOL_COMPAT_V2_FAILURE on failure.

out: output buffer
out_sz: output buffer size
in: input buffer
in_sz: input buffer size (unused)

Since flatbuffers utilizes zero-copy decoding, the v2 API does not
require an input buffer size. Therefore, it is the caller's
responsibility to ensure the input buffer is well-formed (preferably
using a call to _verify_as_root) to avoid any OOB reads.

TODO: Make sol_compat_v2 APIs infallible???
*/

int
sol_compat_elf_loader_v2( uchar * out,
ulong * out_sz,
uchar const * in,
ulong FD_FN_UNUSED in_sz ) {
SOL_COMPAT_NS(ELFLoaderCtx_table_t) input = SOL_COMPAT_NS(ELFLoaderCtx_as_root( in ));
if( FD_UNLIKELY( !input ) ) return 0;

int err = fd_solfuzz_fb_execute_wrapper( runner, input, fd_solfuzz_fb_elf_loader_run );
if( FD_UNLIKELY( err==SOL_COMPAT_V2_FAILURE ) ) return err;

ulong buffer_sz = flatcc_builder_get_buffer_size( runner->fb_builder );
flatcc_builder_copy_buffer( runner->fb_builder, out, buffer_sz );
*out_sz = buffer_sz;

return SOL_COMPAT_V2_SUCCESS;
}
7 changes: 7 additions & 0 deletions src/flamenco/runtime/tests/fd_solfuzz.c
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,11 @@ fd_solfuzz_runner_new( fd_wksp_t * wksp,
runner->runtime_stack = fd_wksp_alloc_laddr( wksp, alignof(fd_runtime_stack_t), sizeof(fd_runtime_stack_t), wksp_tag );
if( FD_UNLIKELY( !runner->runtime_stack ) ) goto bail2;

/* TODO: Consider implementing custom allocators and emitters.
The default builder / emitter uses libc allocators */
int builder_err = flatcc_builder_init( runner->fb_builder );
if( FD_UNLIKELY( builder_err ) ) 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 ) );
Expand Down Expand Up @@ -159,6 +164,8 @@ fd_solfuzz_runner_delete( fd_solfuzz_runner_t * runner ) {
fd_progcache_admin_leave( runner->progcache_admin, &shpcache );
if( shpcache ) fd_wksp_free_laddr( fd_funk_delete( shpcache ) );

flatcc_builder_clear( runner->fb_builder );

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 );
Expand Down
7 changes: 7 additions & 0 deletions src/flamenco/runtime/tests/fd_solfuzz.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "../../accdb/fd_accdb_user.h"
#include "../../progcache/fd_progcache_admin.h"
#include "../../progcache/fd_progcache_user.h"
#include "flatcc/flatcc_builder.h"

/* A fd_solfuzz_runner_t object processes solfuzz inputs. Can be reused
for different inputs, even of different types. Single-thread per
Expand All @@ -41,6 +42,8 @@ struct fd_solfuzz_runner {
fd_exec_stack_t * exec_stack;
fd_runtime_stack_t * runtime_stack;

flatcc_builder_t fb_builder[1]; /* Persistent flatbuffers builder */

int enable_vm_tracing;
};

Expand Down Expand Up @@ -172,6 +175,10 @@ fd_solfuzz_pb_elf_loader_run( fd_solfuzz_runner_t * runner,
void * output_buf,
ulong output_bufsz );

int
fd_solfuzz_fb_elf_loader_run( fd_solfuzz_runner_t * runner,
void const * input_ );

int
fd_solfuzz_pb_elf_loader_fixture( fd_solfuzz_runner_t * runner,
uchar const * in,
Expand Down
Loading
Loading