Sovereign-Labs / sovereign-sdk

A framework for building seamlessly scalable and interoperable rollups that can run on any blockchain
https://sovereign.xyz
Apache License 2.0
366 stars 104 forks source link

Optimal BTC Rollups #630

Open preston-evans98 opened 1 year ago

preston-evans98 commented 1 year ago

Background

Currently, Sovereign works only in the model where raw transaction data is posted on some DA layer. This works very well in the context of a fast-finality data-optimized chain like Celestia. But this has two significant drawbacks on less rollup-optimized chains like BTC.

  1. It's data inefficient, because the full transactions have to be posted (including witnesses 🤢)
  2. It has a long block time (because Bitcoin has a long block time)

On a system like Bitcoin, a rollup would like to...

  1. Inherit the security of the L1
  2. Post as little data onto the L1 as possible
  3. Achieve fast finality in the "happy" case
  4. Avoid undue centralization

We can achieve all four of these goals by adding one extra config switch to the L1 which causes state diffs to be serialized into the final proof output in addition to the current checks for data inclusion and completeness on L1.

With this change, we'll be able to support all of the patterns that developers might want to use:

BTC Rollup with Centralized Sequencer

TL;DR

BTC Rollup with (robust) Decentralized Sequencer

TL;DR

BTC Rollup with Based Sequencing

TL;DR

Implementation Notes

This should be (roughly) a 10 line change to the SDK:

// in zk_storage.rs > validate_and_commit
// -- BEGIN CHANGE 1--
fn validate_and_commit<VM: Zkvm>( &self,
        state_accesses: OrderedReadsAndWrites,
        witness: &Self::Witness,
        output_state_diff: bool,
    ) -> Result<[u8; 32], anyhow::Error> {
// -- END CHANGE 1--
// -- several lines of unmodified code elided here  -- 
      let batch = state_accesses
            .ordered_writes
            .into_iter()
            .map(|(key, value)| {
                let key_hash = KeyHash::with::<S::Hasher>(key.key.as_ref());
                (
                    key_hash,
                    value.map(|v| Arc::try_unwrap(v.value).unwrap_or_else(|arc| (*arc).clone())),
                )
            });

        // -- BEGIN CHANGE 2--
        if output_state_diff { 
            VM::commit(batch)
        }
        // -- END CHANGE 2 --

        let next_version = latest_version + 1;
        let jmt = JellyfishMerkleTree::<_, S::Hasher>::new(&reader);

        let (new_root, _tree_update) = jmt
            .put_value_set(batch, next_version)
            .expect("JMT update must succeed");
}
cemozerr commented 1 year ago

Posting state diffs only work in ZK-rollup mode, right?

If so, does this impact the workings of the Optimistic-rollup mode? At the very least, seems like we should panic if someone tries to run optimistic-rollup mode/module with output_state_diff set to true.