feat(sequencer): local fork mode via --fork CLI flag#445
Open
paschal533 wants to merge 14 commits intologos-blockchain:mainfrom
Open
feat(sequencer): local fork mode via --fork CLI flag#445paschal533 wants to merge 14 commits intologos-blockchain:mainfrom
paschal533 wants to merge 14 commits intologos-blockchain:mainfrom
Conversation
…ationError Replace panicking .expect() calls in send_transaction with proper error propagation using TransactionMalformationError variants. Unify the size error to use TransactionMalformationError::TransactionTooLarge instead of a raw format string. Add unit tests for too-large and valid transaction paths.
Registers the new rejected-transaction column family in RocksDB, and exposes rejected_tx_column, put_rejected_tx, and get_rejected_tx on RocksDBIO for storing and retrieving RejectedTxRecord by hash.
…tx to SequencerStore
…roduction failure
…ulate block timestamp Restructure get_transaction_receipt to scope the sequencer lock to a block expression, collect a terminal receipt (Rejected/Included) under the lock, release the lock, then lazily remove the hash from pending_txs before returning. This fixes two related issues: - pending_txs grew without bound because insert() in send_transaction had no corresponding remove() when TXs were confirmed or rejected - a TX that had been included could still appear as Pending if the caller never queried its receipt Also populate timestamp_ms for Included receipts by fetching the block from the store (an additional DB read already cached by RocksDB's block cache), replacing the previous None placeholder. Lock ordering is preserved: sequencer lock is always released before pending_txs is acquired, matching the order in send_transaction.
…ard state pattern
Implements the local fork mode described in issue logos-blockchain#379. When --features standalone is active, passing `--fork <rpc-url>` fetches the remote sequencer's execution state snapshot via the new `getStateSnapshot` RPC method and boots the local sequencer from that state. Changes: - common: add StateSnapshot type (opaque Borsh bytes + block_id) - sequencer/core: add override_initial_state field to SequencerConfig; start_from_config consults it before genesis/DB state - sequencer/service/rpc: add getStateSnapshot to RPC trait - sequencer/service: implement get_state_snapshot, add run_forked(), add --fork CLI arg, expose fork module; add service test for snapshot
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes part of #379 (local fork mode).
When the sequencer is built with
--features standalone, passing--fork <rpc-url>at startup:getStateSnapshotRPC on the remote sequencer to fetch the current execution state as opaque Borsh bytes plus the chain head block ID.V03Stateinsequencer/service/src/fork.rs.override_initial_state: Option<Box<V03State>>field inSequencerConfig(skipped during JSON serde, so config files are unaffected).SequencerCore::start_from_configchecks the override field first, if present, it skips genesis initialisation and uses the remote chain's state directly.genesis_idis set to the fork block ID, so new blocks are produced starting atfork_block_id + 1.Changes
common/src/snapshot.rsStateSnapshot { state_bytes, block_id }type with Borsh + serdesequencer/core/src/config.rsoverride_initial_state: Option<Box<V03State>>with#[serde(skip)]sequencer/core/src/lib.rsoverride_initial_statebefore genesis/DB at startupsequencer/service/rpc/src/lib.rsgetStateSnapshotto RPC traitsequencer/service/src/service.rsget_state_snapshot; add roundtrip testsequencer/service/src/fork.rsfetch_fork_state(url), fetches + deserialises snapshotsequencer/service/src/lib.rsrun_forked()public entry-point; exposeforkmodulesequencer/service/src/main.rs--fork <url>CLI argument (standalone only)Test plan
RISC0_DEV_MODE=1 cargo test --release -p sequencer_service,newget_state_snapshot_returns_deserializable_statetest passesRISC0_DEV_MODE=1 cargo test --release -p common,StateSnapshotborsh/serde roundtrip tests passcargo check --features standalone -p sequencer_service, compiles without warningscargo check -p sequencer_service, non-standalone build unchanged;--forkflag absent--fork http://localhost:<port>, second sequencer logs "Forked state fetched at block N" and continues producing blocks from N+1Notes
StateSnapshot.state_bytesis intentionally opaque:commondoes not depend onnssa, keeping the crate boundary clean. Only callers that need to deserialise the state need a directnssadependency.override_initial_stateis#[serde(skip)]so it never appears in or is read from config JSON files, it is only ever injected programmatically.