Expand description
§Firewood Golang FFI
The FFI package provides a golang FFI layer for Firewood.
§Usage
§Basic Usage
import (
"context"
"time"
"github.com/ava-labs/firewood/ffi"
)
// Open a database with default configuration
db, err := ffi.New("/path/to/database_dir")
if err != nil {
log.Fatal(err)
}
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
defer db.Close(ctx)§Configuration Options
Firewood uses the functional options pattern for configuration. You can customize the database by passing option functions:
db, err := ffi.New("/path/to/database_dir",
ffi.WithTruncate(true), // Clear the database if it exists
ffi.WithNodeCacheSizeInBytes(256_000_000), // Set node cache memory limit
ffi.WithFreeListCacheEntries(50_000), // Set freelist cache size
ffi.WithRevisions(200), // Keep 200 historical revisions
ffi.WithReadCacheStrategy(ffi.CacheAllReads), // Cache all reads
ffi.WithRootStoreDir("/path/to/roots"), // Store roots on disk
)For detailed information about each configuration option, see the godoc for the With* functions
§Building Firewood Golang FFI
The Golang FFI layer uses a CGO directive to locate a C-API compatible binary built from Firewood. Firewood supports both seamless local development and a single-step compilation process for Go projects that depend or transitively depend on Firewood.
To do this, firewood.go includes CGO directives to include multiple search paths for the Firewood binary in the local target/ build directory and ffi/libs. For the latter, attach-static-libs GitHub Action pushes an FFI package for ethhash with static libraries attached for the following supported architectures:
- x86_64-unknown-linux-gnu
- aarch64-unknown-linux-gnu
- aarch64-apple-darwin
- x86_64-apple-darwin
to a separate repo firewood-go-ethhash (to avoid including binaries in the Firewood repo).
§Local Development
firewood.go includes CGO directives to include builds in the target/ directory.
Firewood prioritizes builds in the following order:
- maxperf
- release
- debug
To use and test the Firewood FFI locally, you can run:
cargo build --profile maxperf
cd ffi
go testTo use a local build of Firewood for a project that depends on Firewood, you must redirect the go.mod to use the local version of Firewood FFI, for example:
go mod edit -replace github.com/ava-labs/firewood-go-ethhash/ffi=/path/to/firewood/ffi
go mod tidy§Production Development Flow
Firewood pushes the FFI source code and attached static libraries to firewood-go-ethhash via attach-static-libs.
This enables consumers to utilize it directly without forcing them to compile Firewood locally. Go programs running on supported architectures can utilize firewood-go-ethhash/ffi just like any other dependency.
To trigger this build, attach-static-libs supports triggers for both manual GitHub Actions and tags, so you can create a mirror branch/tag on firewood-go-ethhash by either trigger a manual GitHub Action and selecting your branch or pushing a tag to Firewood.
§Hash Mode
Firewood implemented its own optimized merkle trie structure. To support Ethereum Merkle Trie hash compatibility, it also provides a feature flag ethhash.
This is an optional feature (disabled by default). To enable it for a local build, compile with:
cargo build -p firewood-ffi --features ethhashTo support development in Coreth, Firewood pushes static libraries for Ethereum-compatible hashing to firewood-go-ethhash with ethhash enabled by default. To use Firewood’s native hashing structure, you must still build the static library separately.
§Development
Iterative building is unintuitive for the ffi and some common sources of confusion are listed below.
§CGO Regeneration
As you edit any Rust code and save the file in VS Code, the firewood.h file is automatically updated with edited function and struct definitions. However, the Go linter will not recognize these changes until you manually regenerate the cgo wrappers. To do this, you can run go tool cgo firewood.go. Alternatively, in VS Code, right above the import "C" definition, you can click on the small letters saying “regenerate CGO definitions”. This will allow the linter to use the altered definitions.
Because the C header file is autogenerated from the Rust code, the naming matches exactly (due to the no_mangle macro). However, the C definitions imported in Go do not match exactly, and are prefixed with struct_. Function naming is the same as the header file. These names are generated by the go tool cgo command above.
It is possible that your editor does not properly recognize the C bindings, due to the nature of multi-module workspaces. If the Go code still compiles, this is likely the issue. To fix this, you can just ./scripts/run_just.sh setup-go-workspace from the repository root and refresh your editor. Changes to the go workspace should not be checked in.
§Testing
Although the VS Code testing feature does work, there are some quirks in ensuring proper building. The Rust code must be compiled separated, and sometimes the go test command continues to use a cached result. Whenever testing after making changes to the Rust/C builds, the cache should be cleared if results don’t seem correct. The Go testing suite can determine dynamically whether ethhash is enabled or not, so it can be run with either configuration. For each individual testing module, ensure the hashing method you compiled with matches the test.
To ensure there are no memory leaks, the easiest way is to use your preferred CLI tool (e.g. valgrind for Linux, leaks for macOS) and compile the tests into a binary. You must not compile a release binary to ensure all memory can be managed. An example flow is given below.
cd ffi
cargo build # use debug
go test -a -c -o binary_file # ignore cache
leaks --nostacks --atExit -- ./binary_fileStructs§
- Borrowed
Slice - A borrowed byte slice. Used to represent data that was passed in from C callers and will not be freed or retained by Rust code.
- Change
Proof Context - FFI context for a parsed or generated change proof. This change proof has not
been verified. Calling
verifyon it will generate aVerifiedChangeProofContextand consume theproofand replacing it with None. - Code
Iterator Handle - Committed
Change Proof Args - Create
Change Proof Args - Arguments for creating a change proof.
- Create
Iterator Result - Create
Proposal Result - Create
Range Proof Args - Arguments for creating a range proof.
- Database
Handle - A handle to the database, returned by
fwd_open_db. - Database
Handle Args - Arguments for creating or opening a database. These are passed to
fwd_open_db - GetRevision
Result - HashKey
- A database hash key, used in FFI functions that require hashes. This type requires no allocation and can be copied freely and dropped without any additional overhead.
- Iterator
Handle - An opaque wrapper around a
BoxKeyValueIterand a reference to theArcDynDbViewbacking it, preventing the view from being dropped while iteration is in progress. - LogArgs
- Arguments for initializing logging for the Firewood FFI.
- Next
KeyRange - A key range that should be fetched to continue iterating through a range
or change proof that was truncated. Represents a half-open range
[start_key, end_key). Ifend_keyisNone, the range is unbounded and continues to the end of the keyspace. - Owned
KeyValue Pair - Owned version of
KeyValuePair, returned to ffi callers. - Owned
Slice - A Rust-owned vector of bytes that can be passed to C code.
- Proposal
Handle - An opaque wrapper around a Proposal that also retains a reference to the database handle it was created from.
- Proposed
Change Proof Args - Proposed
Change Proof Context - FFI context for a proposed change proof. It is created from calling
proposeon aVerifiedChangeProofContextand stores the database, proposal handle, and other parameters need to implementfind_next_key. Callingcommiton it will consume the proof, butfind_next_keycan still be called on it. - Range
Proof Context - FFI context for for a parsed or generated range proof.
- Reconstructed
Handle - An opaque wrapper around a reconstructed view.
- Revision
Handle - Verified
Change Proof Context - FFI context for a verified change proof. It is created from calling
verifyon aChangeProofContextand stores the parameters of that call inparams. Callingproposeon it will consume the proof to create aProposedChangeProofContext. - Verify
Change Proof Args - Arguments for verifying a change proof.
- Verify
Range Proof Args - Arguments for verifying a range proof.
Enums§
- BatchOp
- A batch operation passed to the FFI.
- Change
Proof Result - A result type returned from FFI functions that create or parse change proofs.
- Code
Iterator Result - A result type returned from FFI functions that create an code hash iterator
- Handle
Result - The result type returned from the open or create database functions.
- Hash
Result - A result type returned from FFI functions return the database root hash. This may or may not be after a mutation.
- Iterator
Result - A result type returned from FFI functions that create an iterator
- KeyValue
Batch Result - A result type returned from iterator FFI functions
- KeyValue
Result - A result type returned from iterator FFI functions
- Maybe
- Maybe is a C-compatible optional type using a tagged union pattern.
- Next
KeyRange Result - Node
Hash Algorithm - The hashing mode to use for the database.
- Proposal
Result - A result type returned from FFI functions that create a proposal but do not commit it to the database.
- Proposed
Change Proof Result - Range
Proof Result - A result type returned from FFI functions that create or parse range proofs.
- Reconstructed
Result - A result type returned from FFI functions that create a reconstructed view.
- Revision
Result - A result type returned from FFI functions that get a revision
- Value
Result - A result type returned from FFI functions that retrieve a single value.
- Verified
Change Proof Result - Void
Result - The result type returned from an FFI function that returns no value but may return an error.
Traits§
- CView
- A trait that abstracts over database handles and proposal handles for creating proposals.
Functions§
- fwd_
batch - Puts the given key-value pairs into the database.
- fwd_
block_ replay_ flush - Flushes buffered block replay operations to disk.
- fwd_
change_ proof_ find_ next_ key_ proposed - Returns the next key range that should be fetched after processing the current set of operations in a change proof that was truncated.
- fwd_
change_ proof_ from_ bytes - Deserialize a
ChangeProoffrom bytes. - fwd_
change_ proof_ to_ bytes - Serialize a
ChangeProofto bytes. - fwd_
close_ db - Close and free the memory for a database handle
- fwd_
code_ hash_ iter_ free - Frees the memory associated with a
CodeIteratorHandle. - fwd_
code_ hash_ iter_ next - Advances the code hash iterator and returns the next code hash.
- fwd_
commit_ proposal - Commits a proposal to the database.
- fwd_
db_ change_ proof - Create a change proof for the given range of keys between two roots.
- fwd_
db_ commit_ change_ proof - Commit a change proof to the database.
- fwd_
db_ dump - Dumps the Trie structure of the latest revision of the database to a DOT (Graphviz) format string for debugging.
- fwd_
db_ propose_ change_ proof - Create a proposal from a change proof and return a
ProposedChangeProofResult. - fwd_
db_ range_ proof - Generate a range proof for the given range of keys for the latest revision.
- fwd_
db_ verify_ and_ commit_ range_ proof - Verify and commit a range proof to the database.
- fwd_
db_ verify_ range_ proof - Verify a range proof and prepare a proposal to later commit or drop. If the proof has already been verified, the cached validation context will be used to avoid re-verifying the proof.
- fwd_
free_ change_ proof - Frees the memory associated with a
ChangeProofContext. - fwd_
free_ iterator - Consumes the
IteratorHandle, destroys the iterator, and frees the memory. - fwd_
free_ owned_ bytes - Consumes the
OwnedBytesand frees the memory associated with it. - fwd_
free_ owned_ key_ value_ batch - Consumes the
OwnedKeyValueBatchand frees the memory associated with it. - fwd_
free_ owned_ kv_ pair - Consumes the
OwnedKeyValuePairand frees the memory associated with it. - fwd_
free_ proposal - Consumes the
ProposalHandle, cancels the proposal, and frees the memory. - fwd_
free_ proposed_ change_ proof - Frees the memory associated with a
ProposedChangeProofContext. - fwd_
free_ range_ proof - Frees the memory associated with a
RangeProofContext. - fwd_
free_ reconstructed - Consumes the
ReconstructedHandleand frees the memory associated with it. - fwd_
free_ revision - Consumes the
RevisionHandleand frees the memory associated with it. - fwd_
free_ verified_ change_ proof - Frees the memory associated with a
VerifiedChangeProofContext. - fwd_
gather - Gather latest metrics for this process.
- fwd_
get_ from_ proposal - Gets the value associated with the given key from the proposal provided.
- fwd_
get_ from_ reconstructed - Gets the value associated with the given key from the reconstructed view provided.
- fwd_
get_ from_ revision - Gets the value associated with the given key from the provided revision handle.
- fwd_
get_ latest - Gets the value associated with the given key from the database for the latest revision.
- fwd_
get_ revision - Gets a handle to the revision identified by the provided root hash.
- fwd_
iter_ next - Retrieves the next item from the iterator.
- fwd_
iter_ next_ n - Retrieves the next batch of items from the iterator.
- fwd_
iter_ on_ proposal - Returns an iterator on the provided proposal optionally starting from a key
- fwd_
iter_ on_ reconstructed - Returns an iterator on the provided reconstructed view optionally starting from a key.
- fwd_
iter_ on_ revision - Returns an iterator optionally starting from a key in the provided revision.
- fwd_
open_ db - Open a database with the given arguments.
- fwd_
proposal_ dump - Dumps the Trie structure of a proposal to a DOT (Graphviz) format string for debugging.
- fwd_
propose_ on_ db - Proposes a batch of operations to the database.
- fwd_
propose_ on_ proposal - Proposes a batch of operations to the database on top of an existing proposal.
- fwd_
range_ proof_ code_ hash_ iter - Returns an iterator over the code hashes contained in the range proof. The iterator must be freed after use.
- fwd_
range_ proof_ find_ next_ key - Returns the next key range that should be fetched after processing the current set of key-value pairs in a range proof that was truncated.
- fwd_
range_ proof_ from_ bytes - Deserialize a
RangeProoffrom bytes. - fwd_
range_ proof_ to_ bytes - Serialize a
RangeProofto bytes. - fwd_
range_ proof_ verify - Verify a range proof against the given start and end keys and root hash. The proof will be updated with the validation context if the proof is valid to avoid re-verifying it during commit.
- fwd_
reconstruct_ on_ reconstructed - Reconstructs a batch of operations on top of an existing reconstructed view.
- fwd_
reconstruct_ on_ revision - Reconstructs a batch of operations on top of a historical revision.
- fwd_
reconstructed_ dump - Dumps the Trie structure of a reconstructed view to a DOT (Graphviz) format string for debugging.
- fwd_
reconstructed_ root_ hash - Get the root hash of the reconstructed view.
- fwd_
revision_ dump - Dumps the Trie structure of a revision to a DOT (Graphviz) format string for debugging.
- fwd_
root_ hash - Get the root hash of the latest version of the database
- fwd_
start_ logs - Start logs for this process.
- fwd_
start_ metrics - Start metrics recorder for this process.
- fwd_
start_ metrics_ with_ exporter - Start metrics recorder and exporter for this process.
- fwd_
verify_ change_ proof - Verify a change proof and return a
VerifiedChangeProofResult.
Type Aliases§
- Borrowed
Batch Ops - A type alias for a borrowed slice of
BatchOps. - Borrowed
Bytes - A type alias for a borrowed byte slice.
- KeyRange
- A key range represented by a start key and an optional end key.
- Owned
Bytes - A type alias for a rust-owned byte slice.
- Owned
KeyValue Batch - A type alias for a rust-owned byte slice.