Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

STR-929 Core STF refactors #469

Draft
wants to merge 55 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
c273378
chaintsn: started refactoring for epoch-level bookkeeping
delbonis Nov 13, 2024
cf1191c
chaintsn, state: changed exec update handling to use withdrawals queu…
delbonis Nov 14, 2024
ad8fbe2
chaintsn: fixed test
delbonis Nov 14, 2024
1c7bd8b
chaintsn, state: split out some state types to epoch-level state
delbonis Nov 14, 2024
6994510
state: reworked `WriteBatch` related types
delbonis Nov 14, 2024
4461947
misc: reworked epoch state relationships some more
delbonis Nov 14, 2024
406cf53
state: reworked `StateCache` more to remove state ops from system
delbonis Nov 15, 2024
8e94d9d
misc: fixed a bunch of compilation issues
delbonis Nov 20, 2024
7616ff1
state: fixed overwriting epoch state, fixed broken tests
delbonis Nov 23, 2024
bbfaca1
chaintsn: renamed `process_l1_view_update`
delbonis Nov 23, 2024
08a6213
proof-impl/cl-stf: fix something
delbonis Nov 29, 2024
03ff171
chaintsn: fix broken test
delbonis Nov 29, 2024
f60b458
misc: fixed a bunch more unit tests
delbonis Nov 29, 2024
177bcca
state: removing unnecessary `StateOp`s
delbonis Nov 29, 2024
08a553a
chaintsn, consensus-logic: rework `L1Segment` rules to only be presen…
delbonis Nov 29, 2024
d116caf
state: fix accessors on block types
delbonis Dec 2, 2024
20693de
state: fix ZST issue
delbonis Dec 2, 2024
23562da
fntest: shortened epoch length, added new `wait_until_checkpoint` uti…
delbonis Dec 3, 2024
199556e
misc: cleanups to improve testing
delbonis Dec 9, 2024
5f7bd5d
misc: rework a LOT of types
delbonis Dec 9, 2024
4c534ef
misc: heavy refactoring on status types and finalization code paths
delbonis Dec 10, 2024
1ffc939
misc: integrated epoch transition into slot transition, refactored so…
delbonis Dec 11, 2024
b7f6a26
status: fixed hot spinning when waiting for new client state
delbonis Dec 12, 2024
bf79419
status: fixed it a little more
delbonis Dec 12, 2024
074f4a4
chaintsn, consensus-logic: fixed slot not advancing past end of secon…
delbonis Dec 13, 2024
c09c860
misc: changed a few things to try to address broken things
delbonis Dec 19, 2024
d66769a
prover-client: fixed rebase mistakes
delbonis Dec 26, 2024
4c3bfc6
fntest: fix broken fstring
delbonis Dec 26, 2024
7e42b41
misc: stripping out most of the L1 block bookkeeping logic in CSM
delbonis Dec 27, 2024
3f1531c
fntest/fw: fixed batch field lookup (`idx` -> `epoch`)
delbonis Dec 27, 2024
501681d
misc: reworked a few things to make it more coherent, changed CSM che…
delbonis Dec 27, 2024
569815c
misc: refactored bookkeeping on write batches and accepting L1 blocks
delbonis Dec 30, 2024
a018dbd
fntest/fw: fix bash syntax
delbonis Dec 31, 2024
cfe2ca9
misc: I think I fixed the root of the state overwrite issue now
delbonis Dec 31, 2024
ce2f3b5
misc: reworked broken tests to reflect new design
delbonis Jan 3, 2025
6efb099
strata-client: fixed RPC breakage after rebase
delbonis Jan 6, 2025
d66e9cb
fntest: fixed btcio_read sometimes flaking
delbonis Jan 6, 2025
ca17169
fntest: fixed sync_genesis, converted some logs to prints (not sure w…
delbonis Jan 6, 2025
767aee0
fntest: converted sync_genesis_with_btcblocks to use its own env too
delbonis Jan 6, 2025
3f48ca7
fntest: added LOG_LEVEL envvar default as INFO, updated sync_genesis …
delbonis Jan 6, 2025
3d85580
fntest: tweaked rpc_recent_blocks to maybe make it flake less
delbonis Jan 7, 2025
3ebd783
state: removed `ClientStateWrite`, reworked types, added wrapper for …
delbonis Jan 9, 2025
ba39397
consensus-logic, db, misc: reworked more components to reflect tip-le…
delbonis Jan 15, 2025
3ee6127
primitives: added Display impl for L1BlockCommitment, should have inc…
delbonis Jan 15, 2025
b22d437
rocksdb-store: cleaned up references to client state database
delbonis Jan 15, 2025
08c9511
misc: fixed remaining references that needed to be updated
delbonis Jan 15, 2025
5654633
consensus-logic: partly fixed CSM unit tests
delbonis Jan 15, 2025
79416f3
consensus-logic: fixed CSM test
delbonis Jan 15, 2025
f38e213
rocksdb-store: fixed constructing bootstrap client state
delbonis Jan 15, 2025
50545a7
state: started removing CSM chain tip related fns
delbonis Jan 15, 2025
096649a
consensus-logic: reworked FCM to reflect chain tip and type changes
delbonis Jan 16, 2025
1d1cfab
state: added FCM state type
delbonis Jan 17, 2025
44adbf7
misc: refactoring duties
delbonis Jan 17, 2025
b0db0e1
primitives, state: moved EpochCommitment to primitives crate
delbonis Jan 17, 2025
c556bd4
misc: added more work on duty2 subsystem
delbonis Jan 23, 2025
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
6 changes: 3 additions & 3 deletions bin/prover-client/src/rpc_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,9 +159,9 @@ impl StrataProverClientApiServer for ProverClientRpc {

async fn prove_checkpoint_raw(
&self,
_checkpoint_idx: u64,
_l1_range: (u64, u64),
_l2_range: (u64, u64),
checkpoint_idx: u64,
l1_range: (u64, u64),
l2_range: (u64, u64),
) -> RpcResult<Vec<ProofKey>> {
unimplemented!()
}
Expand Down
2 changes: 1 addition & 1 deletion bin/strata-client/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ fn do_startup_checks(

// Check that we can connect to bitcoin client and block we believe to be matured in L1 is
// actually present
let safe_l1blockid = last_chain_state.l1_view().safe_block().blkid();
let safe_l1blockid = last_chain_state.epoch_state().safe_l1_blkid();
let block_hash = BlockHash::from_slice(safe_l1blockid.as_ref())?;

match handle.block_on(bitcoin_client.get_block(&block_hash)) {
Expand Down
142 changes: 74 additions & 68 deletions bin/strata-client/src/rpc_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ impl<D: Database + Send + Sync + 'static> StrataApiServer for StrataRpcImpl<D> {
}

async fn get_l1_status(&self) -> RpcResult<RpcL1Status> {
let l1s = self.status_channel.l1_status();
let l1s = self.status_channel.get_l1_reader_status();
Ok(RpcL1Status::from_l1_status(
l1s,
self.sync_manager.params().rollup().network,
Expand All @@ -182,45 +182,50 @@ impl<D: Database + Send + Sync + 'static> StrataApiServer for StrataRpcImpl<D> {
}

async fn get_client_status(&self) -> RpcResult<RpcClientStatus> {
let sync_state = self.status_channel.sync_state();
let l1_view = self.status_channel.l1_view();
let sync_state = self.status_channel.get_sync_state();
let l1_view = self.status_channel.get_l1_view();

let last_l1 = l1_view.tip_blkid().cloned().unwrap_or_else(|| {
// TODO figure out a better way to do this
warn!("last L1 block not set in client state, returning zero");
L1BlockId::from(Buf32::zero())
});
let tip_l1_blkid = l1_view.tip_l1_blkid();

// Copy these out of the sync state, if they're there.
let (chain_tip, finalized_blkid) = sync_state
.map(|ss| (*ss.chain_tip_blkid(), *ss.finalized_blkid()))
let (chain_tip, finalized_blkid, finalized_epoch) = sync_state
.map(|ss| {
(
*ss.chain_tip_blkid(),
*ss.finalized_blkid(),
ss.finalized_epoch(),
)
})
.unwrap_or_default();

// FIXME make this load from cache, and put the data we actually want
// here in the client state
// FIXME error handling
let db = self.database.clone();
let slot: u64 = wait_blocking("load_cur_block", move || {
let l2_db = db.l2_db();
l2_db
.get_block_data(chain_tip)
.map(|b| b.map(|b| b.header().blockidx()).unwrap_or(u64::MAX))
.map_err(Error::from)
})
.await?;
let Some(block) = self
.l2_block_manager
.get_block_data_async(&chain_tip)
.map_err(Error::from)
.await?
else {
// We should never encounter this.
return Err(Error::MissingL2Block(chain_tip).into());
};

let slot: u64 = block.block().header().blockidx();
let epoch = self.status_channel.get_cur_l2_epoch().unwrap_or(0);

Ok(RpcClientStatus {
chain_tip: *chain_tip.as_ref(),
chain_tip_slot: slot,
cur_epoch: epoch,
finalized_blkid: *finalized_blkid.as_ref(),
last_l1_block: *last_l1.as_ref(),
buried_l1_height: l1_view.buried_l1_height(),
finalized_epoch,
last_l1_block: *tip_l1_blkid.as_ref(),
// FIXME make this coherent when we re-add this construct
buried_l1_height: 0,
})
}

async fn get_recent_block_headers(&self, count: u64) -> RpcResult<Vec<RpcBlockHeader>> {
// FIXME: sync state should have a block number
let sync_state = self.status_channel.sync_state();
let sync_state = self.status_channel.get_sync_state();
let tip_blkid = *sync_state.ok_or(Error::ClientNotStarted)?.chain_tip_blkid();
let db = self.database.clone();

Expand Down Expand Up @@ -251,7 +256,7 @@ impl<D: Database + Send + Sync + 'static> StrataApiServer for StrataRpcImpl<D> {
}

async fn get_headers_at_idx(&self, idx: u64) -> RpcResult<Option<Vec<RpcBlockHeader>>> {
let sync_state = self.status_channel.sync_state();
let sync_state = self.status_channel.get_sync_state();
let tip_blkid = *sync_state.ok_or(Error::ClientNotStarted)?.chain_tip_blkid();
let db = self.database.clone();

Expand Down Expand Up @@ -370,7 +375,7 @@ impl<D: Database + Send + Sync + 'static> StrataApiServer for StrataRpcImpl<D> {
async fn get_current_deposits(&self) -> RpcResult<Vec<u32>> {
let deps = self
.status_channel
.deposits_table()
.get_cur_deposits_table()
.ok_or(Error::BeforeGenesis)?;

Ok(deps.get_all_deposits_idxs_iters_iter().collect())
Expand All @@ -379,7 +384,7 @@ impl<D: Database + Send + Sync + 'static> StrataApiServer for StrataRpcImpl<D> {
async fn get_current_deposit_by_id(&self, deposit_id: u32) -> RpcResult<RpcDepositEntry> {
let deps = self
.status_channel
.deposits_table()
.get_cur_deposits_table()
.ok_or(Error::BeforeGenesis)?;
Ok(deps
.get_deposit(deposit_id)
Expand All @@ -388,12 +393,21 @@ impl<D: Database + Send + Sync + 'static> StrataApiServer for StrataRpcImpl<D> {
}

async fn sync_status(&self) -> RpcResult<RpcSyncStatus> {
let sync_state = self.status_channel.sync_state();
let sync_state = self.status_channel.get_sync_state();
let (cur_epoch, cur_slot, cur_tip_blkid) =
self.status_channel.get_cur_l2_tip().unwrap_or_else(|| {
warn!("cur tip unset, using default 0");
(0, 0, L2BlockId::from(Buf32::zero()))
});
Ok(sync_state
.map(|sync| RpcSyncStatus {
tip_height: sync.chain_tip_height(),
tip_block_id: *sync.chain_tip_blkid(),
cur_epoch,
tip_slot: cur_slot,
tip_blkid: cur_tip_blkid,
csm_tip_height: sync.tip_height(),
csm_tip_block_id: *sync.chain_tip_blkid(),
finalized_block_id: *sync.finalized_blkid(),
finalized_epoch: sync.finalized_epoch(),
})
.ok_or(Error::ClientNotStarted)?)
}
Expand Down Expand Up @@ -492,16 +506,12 @@ impl<D: Database + Send + Sync + 'static> StrataApiServer for StrataRpcImpl<D> {

let deposit_duties = deposit_duties.map(BridgeDuty::from);

// withdrawal duties should only be generated from finalized checkpoint states
let withdrawal_duties = self
.get_last_checkpoint_chainstate()
.await
.map(|chainstate| {
extract_withdrawal_infos(chainstate.deposits_table())
.map(BridgeDuty::from)
.collect::<Vec<_>>()
})
.unwrap_or_default();
let deps_table = self
.status_channel
.get_cur_deposits_table()
.ok_or(Error::BeforeGenesis)?;

let withdrawal_duties = extract_withdrawal_infos(&deps_table).map(BridgeDuty::from);

let mut duties = vec![];
duties.extend(deposit_duties);
Expand All @@ -518,7 +528,7 @@ impl<D: Database + Send + Sync + 'static> StrataApiServer for StrataRpcImpl<D> {
async fn get_active_operator_chain_pubkey_set(&self) -> RpcResult<PublickeyTable> {
let operator_table = self
.status_channel
.operator_table()
.get_cur_operator_table()
.ok_or(Error::BeforeGenesis)?;
let operator_map: BTreeMap<OperatorIdx, PublicKey> = operator_table
.operators()
Expand Down Expand Up @@ -555,7 +565,7 @@ impl<D: Database + Send + Sync + 'static> StrataApiServer for StrataRpcImpl<D> {
Ok(client_state
.l1_view()
.last_finalized_checkpoint()
.map(|checkpoint| checkpoint.batch_info.idx()))
.map(|checkpoint| checkpoint.batch_info.epoch()))
} else {
// get latest checkpoint index from db
let idx = self
Expand All @@ -569,20 +579,20 @@ impl<D: Database + Send + Sync + 'static> StrataApiServer for StrataRpcImpl<D> {
}

async fn get_l2_block_status(&self, block_height: u64) -> RpcResult<L2BlockStatus> {
let sync_state = self.status_channel.sync_state();
let l1_view = self.status_channel.l1_view();
let sync_state = self.status_channel.get_sync_state();
let l1_view = self.status_channel.get_l1_view();
if let Some(last_checkpoint) = l1_view.last_finalized_checkpoint() {
if last_checkpoint.batch_info.includes_l2_block(block_height) {
return Ok(L2BlockStatus::Finalized(last_checkpoint.height));
}
}
if let Some(l1_height) = l1_view.get_verified_l1_height(block_height) {
return Ok(L2BlockStatus::Verified(l1_height));
return Ok(L2BlockStatus::Committed(l1_height));
}

if let Some(sync_status) = sync_state {
if block_height < sync_status.chain_tip_height() {
return Ok(L2BlockStatus::Confirmed);
if block_height < sync_status.tip_height() {
return Ok(L2BlockStatus::Accepted);
}
}

Expand Down Expand Up @@ -618,17 +628,11 @@ impl<D: Database + Send + Sync + 'static> StrataApiServer for StrataRpcImpl<D> {
async fn get_client_update_output(&self, idx: u64) -> RpcResult<Option<ClientUpdateOutput>> {
let db = self.database.clone();

// TODO convert to use manager interface
let res = wait_blocking("fetch_client_update_output", move || {
let client_state_db = db.client_state_db();

let writes = client_state_db.get_client_state_writes(idx)?;
let actions = client_state_db.get_client_update_actions(idx)?;

match (writes, actions) {
(Some(w), Some(a)) => Ok(Some(ClientUpdateOutput::new(w, a))),
// normally this is just that they're both missing
_ => Ok(None),
}
let output = client_state_db.get_client_update(idx)?;
Ok(output)
})
.await?;

Expand Down Expand Up @@ -746,37 +750,38 @@ impl StrataSequencerApiServer for SequencerServerImpl {

async fn submit_checkpoint_proof(
&self,
idx: u64,
checkpoint_idx: u64,
proof_receipt: ProofReceipt,
) -> RpcResult<()> {
debug!(%idx, "received checkpoint proof request");
debug!(%checkpoint_idx, "received checkpoint proof request");
let mut entry = self
.checkpoint_handle
.get_checkpoint(idx)
.get_checkpoint(checkpoint_idx)
.await
.map_err(|e| Error::Other(e.to_string()))?
.ok_or(Error::MissingCheckpointInDb(idx))?;
debug!(%idx, "found checkpoint in db");
.ok_or(Error::MissingCheckpointInDb(checkpoint_idx))?;

// If proof is not pending error out
if entry.proving_status != CheckpointProvingStatus::PendingProof {
return Err(Error::ProofAlreadyCreated(idx))?;
warn!(%checkpoint_idx, "checkpoint proof submitted but we already had one?");
return Err(Error::ProofAlreadyCreated(checkpoint_idx))?;
}

let checkpoint = entry.clone().into_batch_checkpoint();
verify_proof(&checkpoint, &proof_receipt, self.params.rollup())
.map_err(|e| Error::InvalidProof(idx, e.to_string()))?;
.map_err(|e| Error::InvalidProof(checkpoint_idx, e.to_string()))?;

entry.proof = proof_receipt;
entry.proving_status = CheckpointProvingStatus::ProofReady;

debug!(%idx, "Proof is pending, setting proof reaedy");
debug!(%checkpoint_idx, "Proof is pending, setting proof reaedy");
let checkpoint = entry.clone().into_batch_checkpoint();

self.checkpoint_handle
.put_checkpoint_and_notify(idx, entry)
.put_checkpoint_and_notify(checkpoint_idx, entry)
.await
.map_err(|e| Error::Other(e.to_string()))?;
debug!(%idx, "Success");
trace!(%checkpoint_idx, "found checkpoint and notified");

Ok(())
}
Expand Down Expand Up @@ -818,6 +823,7 @@ impl<D: Database + Sync + Send + 'static> StrataDebugApiServer for StrataDebugRp
.map(|b| b.block().clone());
Ok(l2_block)
}

async fn get_chainstate_at_idx(&self, idx: u64) -> RpcResult<Option<RpcChainState>> {
let db = self.database.clone();
let chain_state = wait_blocking("chain_state_at_idx", move || {
Expand All @@ -830,7 +836,7 @@ impl<D: Database + Sync + Send + 'static> StrataDebugApiServer for StrataDebugRp
Some(cs) => Ok(Some(RpcChainState {
tip_blkid: cs.chain_tip_blockid(),
tip_slot: cs.chain_tip_slot(),
cur_epoch: cs.epoch(),
cur_epoch: cs.cur_epoch(),
})),
None => Ok(None),
}
Expand Down
2 changes: 1 addition & 1 deletion crates/bridge-relay/src/relayer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ impl RelayerState {
// Otherwise it's better for network health to relay them
// unconditionally.
// TODO make it configurable if we relay or not without chainstate?
if let Some(op_table) = self.status_channel.operator_table() {
if let Some(op_table) = self.status_channel.get_cur_operator_table() {
let sig_res =
strata_primitives::relay::util::verify_bridge_msg_sig(&message, &op_table);

Expand Down
2 changes: 1 addition & 1 deletion crates/btcio/src/reader/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -490,7 +490,7 @@ mod test {
let (event_tx, _event_rx) = mpsc::channel::<L1Event>(10);
let mut chstate: Chainstate = ArbitraryGenerator::new().generate();
let clstate: ClientState = ArbitraryGenerator::new().generate();
let curr_epoch = chstate.epoch();
let curr_epoch = chstate.cur_epoch();

let ctx = get_reader_ctx(event_tx, chstate.clone(), clstate);
let mut state = get_reader_state(&ctx);
Expand Down
5 changes: 4 additions & 1 deletion crates/btcio/src/status.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,11 @@ pub enum L1StatusUpdate {
IncrementInscriptionCount,
}

#[deprecated(note = "TODO: refactor this to just directly update the fields")]
pub async fn apply_status_updates(st_updates: &[L1StatusUpdate], st_chan: &StatusChannel) {
let mut l1_status = st_chan.l1_status();
// FIXME this should be maintaining the authoritative state internally, updating it, and writing
// it, *not* just reading what we previously wrote from the channel and modifying that
let mut l1_status = st_chan.get_l1_reader_status();
for event in st_updates {
match event {
L1StatusUpdate::CurHeight(height) => l1_status.cur_height = *height,
Expand Down
26 changes: 26 additions & 0 deletions crates/chaintsn/src/clock.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//! Utils for reasoning about chain slots.

use strata_primitives::params::RollupParams;

pub fn get_slot_expected_epoch(slot: u64, params: &RollupParams) -> u64 {
slot / params.target_l2_batch_size as u64
}

pub fn get_epoch_initial_slot(epoch: u64, params: &RollupParams) -> u64 {
epoch * params.target_l2_batch_size
}

pub fn get_epoch_final_slot(epoch: u64, params: &RollupParams) -> u64 {
let epoch_init_slot = get_epoch_initial_slot(epoch, params);
epoch_init_slot + (params.target_l2_batch_size - 1)
Comment on lines +14 to +15
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is simpler?

Suggested change
let epoch_init_slot = get_epoch_initial_slot(epoch, params);
epoch_init_slot + (params.target_l2_batch_size - 1)
get_epoch_initial_slot(epoch + 1, params) - 1

}

pub fn is_epoch_init_slot(slot: u64, params: &RollupParams) -> bool {
let epoch = get_slot_expected_epoch(slot, params);
slot == get_epoch_initial_slot(epoch, params)
}

pub fn is_epoch_final_slot(slot: u64, params: &RollupParams) -> bool {
let epoch = get_slot_expected_epoch(slot, params);
slot == get_epoch_final_slot(epoch, params)
}
Loading