github bestinslot-xyz/brc20-programmable-module v0.16.5

3 hours ago

Chore

  • bump non-EVM dependencies to their latest majors
    base64 0.23, zstd-safe 8 (libzstd stays 1.5.7), rocksdb 0.25 (RocksDB 11.8),
    rlimit 0.11, tower-http 0.7, public-api 0.52, rustdoc-json 0.9.10, rand 0.10.
    The consensus fixtures and the inscription decoding corpus are unchanged.

    public-api 0.52 renders signatures without parameter names and lists the
    jsonrpsee-generated client methods under TypeJsonRpseeInternal; the API itself
    is unchanged.

    bip322 stays at 0.0.11: 0.0.12 enforces LOW_S, adds variant prefixes and an
    inconclusive outcome, so adopting it needs its own activation height.

  • update dependencies within their semver ranges
    cargo update: alloy 1.1 -> 1.8, alloy-core 1.4 -> 1.7, revm-inspectors
    0.33.0 -> 0.33.2, bitcoin 0.32.7 -> 0.32.102, blst 0.3.17, c-kzg 2.1.8,
    aurora-engine-modexp 1.3, jsonrpsee 0.26.1, serde_json 1.0.154 and
    transitive crates. alloy 1.8 requires rustc 1.91, so rust-version and the
    Docker builder image move to 1.91.

    Consensus fixtures and the inscription corpus are unchanged.

Documentation

  • split the README into docs/ pages, add Differences from Ethereum

    • docs: split the README into focused pages and document differences from Ethereum

    The README keeps the description, quick start (build, Docker), a
    configuration pointer, a documentation index and the license. The
    detailed material lives under docs/:

    • configuration.md: environment variables, CLI options, authorization,
      admin RPC server
    • indexer-integration.md: inscriptions, initialisation, indexing loop,
      checklist
    • indexer-api.md: brc20_* method reference
    • eth-api.md: eth_, debug_ and txpool_content
    • embedding.md: running the module in-process through Brc20Prog
    • precompiles.md: BIP322 and Bitcoin precompiles
    • testing.md: consensus fixtures, inscription corpus, public API
      snapshot, Bitcoin RPC tests and benches
    • differences-from-ethereum.md: the four consensus differences from
      Ethereum and the activation heights in engine/hardforks.rs

    The crate docs link to the JSON-RPC references in docs/.

New Features

  • upgrade to revm 43, revm-inspectors 0.44 and alloy 2
    revm 33 -> 43, revm-inspectors 0.33 -> 0.44, revm-bytecode 7 -> 43,
    alloy 1.8 -> 2.5. alloy 2 requires rustc 1.94.1, so rust-version and the
    Docker builder image move to 1.94.

    Every block trace hash, receipt, gas figure, log, bloom and raw header/receipt
    encoding in the consensus fixtures is unchanged. Keeping it that way needed:

    • Precompiles: revm 43 reports rejected inputs and out-of-gas as a Halt status
      instead of an error. BRC20Precompiles maps any non-success status back to an
      error, so a failing Ethereum precompile call still aborts the transaction.
    • Tracing: revm-inspectors 0.44 only records call input when record_inputs is
      set. The input is part of the trace string, so it is enabled.
    • Instructions: the static gas table is fixed when EthInstructions is built.
      It is now built for the block's spec rather than revm's default (OSAKA).
    • Logs: Revert and Halt results now carry logs. Receipts and the block log
      index take logs from successful results only, as before.

    New alloy header fields (block_access_list_hash, slot_number) stay None; a raw
    block written by alloy 1.x round-trips byte for byte (new unit test).

    debug_traceTransaction reports some frame errors in revm's display form
    ("contract address collision" for CreateCollision, "return data out of
    bounds" for OutOfOffset, "invalid opcode" for NotActivated). The error field
    is not part of the trace hash.

  • embed the module in an indexer's process with Brc20Prog
    Brc20Prog opens the database and exposes every JSON-RPC method as an async method of Brc20ProgApiServer, so an indexer written in Rust calls the module directly instead of over HTTP and JSON. Clones share one engine; start_public_rpc_server serves the same instance to other clients and rejects the indexer methods for every caller. start() opens a Brc20Prog and serves it as before.

Bug Fixes

  • return range query results in key order

  • reject empty inscription payloads instead of panicking
    decode_bytes_from_inscription_data read the compression byte without a
    length check, so a payload of "" or "=" indexed an empty buffer and
    panicked. With panic = 'abort' in release builds this killed the node.
    An empty decoded buffer returns None, like any other undecodable payload.

    The inscription corpus snapshot records the empty and raw_only_padding
    cases as rejected, and a focused unit test covers "" and "=".

Style

  • rustfmt the consensus fixture and inscription corpus test

Test

  • regenerate the public API snapshot on top of Brc20Prog
    public-api 0.52 renders signatures without parameter names and lists
    default trait methods on impls, so the Brc20Prog server methods with
    default bodies now appear. The API is unchanged.

  • run each Bitcoin RPC network in its own binary, refresh expected gas
    The Bitcoin RPC client is process-wide and only rebuilt when the RPC status
    is validated, so loading .env.signet after .env.mainnet in one process kept
    the mainnet client and the signet precompile calls failed. The mainnet and
    signet tests now live in tests/btc_rpc_{mainnet,signet}.rs with shared
    helpers in test_utils, and the bench is split into
    btc_precompiles_{mainnet,signet}. Moving them out of tests/precompiles.rs
    also stops them reloading CONFIG under the signet precompile tests there.

    Expected gas values were stale; the old and new dependency sets both
    estimate 0xc8b36, 0x18c463 and 0x24fd91 for the mainnet calls and 0xc8b36
    for both signet calls.

  • pin a newer nightly for the public API snapshot
    public-api's MINIMUM_NIGHTLY_RUST_VERSION (nightly-2025-11-22) is older than
    the rustc 1.94.1 that alloy 2 requires. nightly-2026-10-01 builds the crate
    and its rustdoc JSON still parses; the snapshot is unchanged.

  • pin inactive opcodes and post-selfdestruct state
    opcodeProbe deploys runtimes using CLZ, DUPN/SWAPN/EXCHANGE and EOF opcodes,
    which must stay invalid under CANCUN and PRAGUE, next to active controls
    (PUSH0, BLOBHASH, BLOBBASEFEE, MCOPY). probeDestroyedChild reads a contract
    created and self-destructed in an earlier transaction: the engine keeps its
    code and storage, and the fixture pins that.

  • cover logs emitted before top-level and nested failures
    Receipts of reverted, invalid and out-of-gas transactions carry no logs, and
    a reverted subcall's logs are dropped while the caller's survive. The fixture
    now pins all four.

  • cover precompiles reached by DELEGATECALL/CALLCODE and top-level calls
    The engine resolves precompiles by target address, so DELEGATECALL and
    CALLCODE to a precompile run the empty code at that address. The fixture now
    pins that, plus transactions sent straight to sha256 and to the point
    evaluation precompile with a rejected input.

  • cover precompile out-of-gas and the EIP-7823 modexp limit
    Adds ecrecover and sha256 calls with too little gas, and a modexp with a
    1025-byte modulus, as separate fixture transactions. Like a rejected input, a
    precompile running out of gas aborts the whole transaction (status 0, no gas
    used). The modexp succeeds: EIP-7823 is an Osaka rule and stays off under
    PRAGUE. The per-transaction precompile cases are now labelled precompileEdge.

  • pin raw header and receipt RLP in the consensus fixture
    The fixture now also records debug_getRawHeader and the debug_getRawReceipts
    encodings per block. Receipts are sorted because the raw block lists
    transactions in storage iteration order, which varies between runs; the raw
    block itself is left out for the same reason.

  • pin inscription data decoding over a base64/nada/zstd corpus
    Inscription payloads decide transaction calldata, so their decoding is
    consensus. test_inscription_data_corpus snapshots the outcome of
    src/api/testdata/inscription_corpus.txt: canonical and non-canonical base64,
    padding variants, zstd frames with and without content size, checksums,
    skippable and concatenated frames, the 1 MB limit, dictionary and legacy
    headers. The corpus records the current behaviour as-is, including the panic
    on empty payloads.

  • consensus fixture pinning gas, traces, receipts and trace hashes
    Adds tests/consensus_fixture_{signet,mainnet}.rs, which drive a fixed workload
    (test_utils/data/consensus_fixture/Fixture.sol plus pre-signed legacy txs) through
    the engine and snapshot every block's trace hash, receipts, logs, blooms and full
    call traces with insta. Signet covers CANCUN, the PRAGUE activation and RLP tx
    hashes; mainnet covers CANCUN with signing-hash tx hashes.

    The workload covers SSTORE/transient/memory/log opcodes, nested and failing
    frames, CREATE/CREATE2 collisions, oversized code, SELFDESTRUCT, EIP-7623
    calldata floor, every Ethereum and BRC20 precompile (including rejected inputs,
    which abort the whole transaction), BRC20 deposit/withdraw, and brc20_transact
    with nonce gaps, a high-s signature, a wrong chain id and malformed bytes.

    Inputs are pre-encoded by build.sh so the workload does not depend on the
    crates under test. Any snapshot diff is a consensus change.

Commit Statistics

  • 18 commits contributed to the release.
  • 18 commits were understood as conventional.
  • 4 unique issues were worked on: #21, #22, #23, #24

Commit Details

view details
  • #21
    • Embed the module in an indexer's process with Brc20Prog (c550274)
  • #22
    • Reject empty inscription payloads instead of panicking (8ce5e4f)
  • #23
    • Split the README into docs/ pages, add Differences from Ethereum (4c01317)
  • #24
    • Return range query results in key order (c5242a4)
  • Uncategorized
    • Regenerate the public API snapshot on top of Brc20Prog (c4ee129)
    • Run each Bitcoin RPC network in its own binary, refresh expected gas (b31ec9c)
    • Pin a newer nightly for the public API snapshot (5ac1b9f)
    • Upgrade to revm 43, revm-inspectors 0.44 and alloy 2 (c2cdfe9)
    • Rustfmt the consensus fixture and inscription corpus test (91e0519)
    • Pin inactive opcodes and post-selfdestruct state (ad6a6ca)
    • Cover logs emitted before top-level and nested failures (0bef1d7)
    • Cover precompiles reached by DELEGATECALL/CALLCODE and top-level calls (cd21cb3)
    • Cover precompile out-of-gas and the EIP-7823 modexp limit (d3f8f5c)
    • Pin raw header and receipt RLP in the consensus fixture (878dba5)
    • Bump non-EVM dependencies to their latest majors (f930fc5)
    • Update dependencies within their semver ranges (b6c8bef)
    • Pin inscription data decoding over a base64/nada/zstd corpus (ecdeb17)
    • Consensus fixture pinning gas, traces, receipts and trace hashes (4fb06c7)

Don't miss a new brc20-programmable-module release

NewReleases is sending notifications on new releases.