Skip to content

Commit

Permalink
introduce bitcoin prover (#584)
Browse files Browse the repository at this point in the history
* introduce bitcoin prover

* - check that l2 block da heder points to previous da header
- implement send_transaction in bitcoin da

* lint

* review

* fix udeps check

* post merge fix
  • Loading branch information
eyusufatik authored May 17, 2024
1 parent bf131c8 commit fc6dfe0
Show file tree
Hide file tree
Showing 17 changed files with 162 additions and 74 deletions.
2 changes: 0 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 1 addition & 4 deletions bin/citrea/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,6 @@ sov-db = { path = "../../crates/sovereign-sdk/full-node/db/sov-db" }
ethereum-rpc = { path = "../../crates/ethereum-rpc" }
sequencer-client = { path = "../../crates/sequencer-client" }
citrea-sequencer = { path = "../../crates/sequencer" }
sov-risc0-adapter = { path = "../../crates/sovereign-sdk/adapters/risc0", features = [
"native",
] }
citrea-risc0-bonsai-adapter = { path = "../../crates/sovereign-sdk/adapters/risc0-bonsai", features = [
"native",
] }
Expand Down Expand Up @@ -112,7 +109,7 @@ regex = "1.10"
default = [
] # Deviate from convention by making the "native" feature active by default. This aligns with how this package is meant to be used (as a binary first, library second).

bench = ["hex", "sov-risc0-adapter/bench", "risc0/bench"]
bench = ["hex"] #"sov-risc0-adapter/bench", "risc0/bench"]

[[bin]]
name = "citrea"
Expand Down
2 changes: 1 addition & 1 deletion bin/citrea/provers/risc0/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ publish = false
risc0-build = { workspace = true }

[package.metadata.risc0]
methods = ["guest-mock"]
methods = ["guest-mock", "guest-bitcoin"]

[features]
bench = []
2 changes: 1 addition & 1 deletion bin/citrea/provers/risc0/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ fn main() {
let methods_path = out_dir.join("methods.rs");

let elf = r#"
pub const BITCOIN_ELF: &[u8] = &[];
pub const BITCOIN_DA_ELF: &[u8] = &[];
pub const MOCK_DA_ELF: &[u8] = &[];
"#;

Expand Down
10 changes: 0 additions & 10 deletions bin/citrea/provers/risc0/guest-bitcoin/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

51 changes: 51 additions & 0 deletions bin/citrea/provers/risc0/guest-bitcoin/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
[package]
name = "citrea-bitcoin-prover"
version = "0.3.0"
edition = "2021"
resolver = "2"

[workspace]

[dependencies]
anyhow = "1.0.68"
risc0-zkvm = { version = "0.21", default-features = false, features = ["std"] }
risc0-zkvm-platform = "0.21"
bitcoin-da = { path = "../../../../../crates/bitcoin-da", default-features = false }
rollup-constants = { path = "../../../../rollup-constants" }
citrea-stf = { path = "../../../../../crates/citrea-stf" }
sov-risc0-adapter = { path = "../../../../../crates/sovereign-sdk/adapters/risc0" }
sov-modules-api = { path = "../../../../../crates/sovereign-sdk/module-system/sov-modules-api", default-features = false }
sov-state = { path = "../../../../../crates/sovereign-sdk/module-system/sov-state" }
sov-modules-stf-blueprint = { path = "../../../../../crates/sovereign-sdk/module-system/sov-modules-stf-blueprint" }
sov-rollup-interface = { path = "../../../../../crates/sovereign-sdk/rollup-interface" }
# forcing cargo for this version or else chooses 3.1.1 and there is some dependency conflicts
revm-primitives = { version = "=3.1.0", default-features = false }
# forcing cargo for this version or else chooses 0.3.1 and there is some dependency conflicts
alloy-trie = { version = "=0.3.0", default-features = false }

[patch.crates-io]
sha2 = { git = "https://github.com/risc0/RustCrypto-hashes", tag = "sha2-v0.10.8-risczero.0" }
ed25519-dalek = { git = "https://github.com/risc0/curve25519-dalek", tag = "curve25519-4.1.0-risczero.1" }
crypto-bigint = { git = "https://github.com/risc0/RustCrypto-crypto-bigint", tag = "v0.5.2-risc0" }
secp256k1_v027 = { package = "secp256k1", version = "0.27", git = "https://github.com/Sovereign-Labs/rust-secp256k1.git", branch = "risc0-compatible-0-27-0" }
secp256k1_v028 = { package = "secp256k1", version = "0.28", git = "https://github.com/Sovereign-Labs/rust-secp256k1.git", branch = "risc0-compatible-0-28-2" }

[profile.dev]
opt-level = 3

[profile.dev.build-override]
opt-level = 3

[profile.release]
debug = 1
lto = true

[profile.release.build-override]
opt-level = 3

[features]
bench = [
"sov-modules-api/bench",
"sov-state/bench",
"sov-modules-stf-blueprint/bench",
]
61 changes: 61 additions & 0 deletions bin/citrea/provers/risc0/guest-bitcoin/src/bin/bitcoin_da.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#![no_main]
use bitcoin_da::spec::RollupParams;
use bitcoin_da::verifier::BitcoinVerifier;

use citrea_stf::runtime::Runtime;
use citrea_stf::StfVerifier;
#[cfg(feature = "bench")]
use risc0_zkvm::guest::env;
use rollup_constants::{DA_TX_ID_LEADING_ZEROS, ROLLUP_NAME};
use sov_modules_api::default_context::ZkDefaultContext;
use sov_modules_stf_blueprint::StfBlueprint;
use sov_risc0_adapter::guest::Risc0Guest;
use sov_rollup_interface::da::DaVerifier;
use sov_state::ZkStorage;

#[cfg(feature = "bench")]
fn report_bench_metrics(start_cycles: usize, end_cycles: usize) {
let cycles_per_block = (end_cycles - start_cycles) as u64;
let tuple = ("Cycles per block".to_string(), cycles_per_block);
let mut serialized = Vec::new();
serialized.extend(tuple.0.as_bytes());
serialized.push(0);
let size_bytes = tuple.1.to_ne_bytes();
serialized.extend(&size_bytes);

// calculate the syscall name.
let cycle_string = String::from("cycle_metrics\0");
let metrics_syscall_name =
risc0_zkvm_platform::syscall::SyscallName::from_bytes_with_nul(cycle_string.as_ptr());

risc0_zkvm::guest::env::send_recv_slice::<u8, u8>(metrics_syscall_name, &serialized);
}

risc0_zkvm::guest::entry!(main);

pub fn main() {
let guest = Risc0Guest::new();
let storage = ZkStorage::new();
#[cfg(feature = "bench")]
let start_cycles = env::cycle_count();

let stf: StfBlueprint<ZkDefaultContext, _, _, Runtime<_, _>> = StfBlueprint::new();

let stf_verifier = StfVerifier::new(
stf,
BitcoinVerifier::new(RollupParams {
rollup_name: ROLLUP_NAME.to_string(),
reveal_tx_id_prefix: DA_TX_ID_LEADING_ZEROS.to_vec(),
}),
);

stf_verifier
.run_sequencer_commitments_in_da_slot(guest, storage)
.expect("Prover must be honest");

#[cfg(feature = "bench")]
{
let end_cycles = env::cycle_count();
report_bench_metrics(start_cycles, end_cycles);
}
}
10 changes: 0 additions & 10 deletions bin/citrea/provers/risc0/guest-mock/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 7 additions & 4 deletions bin/citrea/src/bitcoin_rollup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use async_trait::async_trait;
use bitcoin_da::service::{BitcoinService, DaServiceConfig};
use bitcoin_da::spec::{BitcoinSpec, RollupParams};
use bitcoin_da::verifier::BitcoinVerifier;
use citrea_risc0_bonsai_adapter::host::Risc0BonsaiHost;
use citrea_stf::genesis_config::StorageConfig;
use citrea_stf::runtime::Runtime;
use rollup_constants::{DA_TX_ID_LEADING_ZEROS, ROLLUP_NAME};
Expand All @@ -11,7 +12,6 @@ use sov_modules_api::{Address, Spec};
use sov_modules_rollup_blueprint::RollupBlueprint;
use sov_modules_stf_blueprint::StfBlueprint;
use sov_prover_storage_manager::ProverStorageManager;
use sov_risc0_adapter::host::Risc0Host;
use sov_rollup_interface::da::DaVerifier;
use sov_rollup_interface::zk::ZkvmHost;
use sov_state::{DefaultStorageSpec, Storage, ZkStorage};
Expand All @@ -25,7 +25,7 @@ impl RollupBlueprint for BitcoinRollup {
type DaService = BitcoinService;
type DaSpec = BitcoinSpec;
type DaConfig = DaServiceConfig;
type Vm = Risc0Host<'static>;
type Vm = Risc0BonsaiHost<'static>;

type ZkContext = ZkDefaultContext;
type NativeContext = DefaultContext;
Expand Down Expand Up @@ -104,8 +104,11 @@ impl RollupBlueprint for BitcoinRollup {
_rollup_config: &RollupConfig<Self::DaConfig>,
_da_service: &Self::DaService,
) -> Self::ProverService {
// TODO: will be BITCOIN_ELF
let vm = Risc0Host::new(risc0::MOCK_DA_ELF);
let vm = Risc0BonsaiHost::new(
risc0::BITCOIN_DA_ELF,
std::env::var("BONSAI_API_URL").unwrap_or("".to_string()),
std::env::var("BONSAI_API_KEY").unwrap_or("".to_string()),
);
let zk_stf = StfBlueprint::new();
let zk_storage = ZkStorage::new();

Expand Down
12 changes: 6 additions & 6 deletions crates/bitcoin-da/src/helpers/builders.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,10 +191,10 @@ fn build_commit_transaction(
let mut last_size = size;

let tx = loop {
if iteration % 100 == 0 {
if iteration % 10 == 0 {
trace!(iteration, "Trying to find commitment size");
if iteration > 5000 {
warn!("Too many iterations");
if iteration > 100 {
warn!("Too many iterations choosing UTXOs");
}
}
let fee = ((last_size as f64) * fee_rate).ceil() as u64;
Expand Down Expand Up @@ -379,10 +379,10 @@ pub fn create_inscription_transactions(
// Start loop to find a 'nonce' i.e. random number that makes the reveal tx hash starting with zeros given length
let mut nonce: i64 = 0;
loop {
if nonce % 100 == 0 {
if nonce % 10000 == 0 {
trace!(nonce, "Trying to find commit & reveal nonce");
if nonce > 1000 {
warn!("Too many iterations");
if nonce > 65536 {
warn!("Too many iterations finding nonce");
}
}
let utxos = utxos.clone();
Expand Down
11 changes: 9 additions & 2 deletions crates/bitcoin-da/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use serde::{Deserialize, Serialize};
use sov_rollup_interface::da::DaSpec;
use sov_rollup_interface::services::da::{BlobWithNotifier, DaService};
use tokio::sync::mpsc::{unbounded_channel, UnboundedSender};
use tokio::sync::oneshot::channel as oneshot_channel;
use tracing::{error, info, instrument, trace};

use crate::helpers::builders::{
Expand Down Expand Up @@ -499,9 +500,15 @@ impl DaService for BitcoinService {
#[instrument(level = "trace", skip_all)]
async fn send_transaction(
&self,
_blob: &[u8],
blob: &[u8],
) -> Result<<Self as DaService>::TransactionId, Self::Error> {
unimplemented!("Use send_tx_no_wait instead")
let queue = self.get_send_transaction_queue();
let (tx, rx) = oneshot_channel();
queue.send(BlobWithNotifier {
blob: blob.to_vec(),
notify: tx,
})?;
rx.await?
}

fn get_send_transaction_queue(&self) -> UnboundedSender<BlobWithNotifier<Self::TransactionId>> {
Expand Down
1 change: 1 addition & 0 deletions crates/bitcoin-da/src/spec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ pub mod blob;
pub mod block;
mod block_hash;
pub mod header;
#[cfg(feature = "native")]
pub mod header_stream;
pub mod proof;
pub mod transaction;
Expand Down
12 changes: 8 additions & 4 deletions crates/sovereign-sdk/adapters/risc0-bonsai/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,20 +22,24 @@ serde = { workspace = true }
bytemuck = "1.13.1"
once_cell = { version = "1.19.0", optional = true }
parking_lot = { version = "0.12.1", optional = true }
sov-zk-cycle-utils = { path = "../../utils/zk-cycle-utils", version = "0.3" }
sov-rollup-interface = { path = "../../rollup-interface", version = "0.3" }
tracing = { workspace = true }
bonsai-sdk = "0.7.0"
hex = { workspace = true }

# we are going to use its guest
sov-risc0-adapter = { path = "../risc0" }
sov-risc0-adapter = { path = "../risc0", optional = true }


[features]
default = []
native = ["risc0-zkvm/prove", "dep:risc0-zkp", "dep:risc0-circuit-rv32im"]
bench = ["once_cell", "parking_lot", "native", "sov-zk-cycle-utils/native"]
native = [
"risc0-zkvm/prove",
"dep:risc0-zkp",
"dep:risc0-circuit-rv32im",
"sov-risc0-adapter/native",
]
bench = ["once_cell", "parking_lot", "native"]

[[test]]
name = "native"
Expand Down
30 changes: 5 additions & 25 deletions crates/sovereign-sdk/adapters/risc0-bonsai/src/host.rs
Original file line number Diff line number Diff line change
Expand Up @@ -212,27 +212,6 @@ pub struct Risc0BonsaiHost<'a> {
last_input_id: Option<String>,
}

#[cfg(not(feature = "bench"))]
#[inline(always)]
fn add_benchmarking_callbacks(env: ExecutorEnvBuilder<'_>) -> ExecutorEnvBuilder<'_> {
env
}

#[cfg(feature = "bench")]
fn add_benchmarking_callbacks(mut env: ExecutorEnvBuilder<'_>) -> ExecutorEnvBuilder<'_> {
use sov_zk_cycle_utils::{cycle_count_callback, get_syscall_name, get_syscall_name_cycles};

use crate::metrics::metrics_callback;

let metrics_syscall_name = get_syscall_name();
env.io_callback(metrics_syscall_name, metrics_callback);

let cycles_syscall_name = get_syscall_name_cycles();
env.io_callback(cycles_syscall_name, cycle_count_callback);

env
}

impl<'a> Risc0BonsaiHost<'a> {
/// Create a new Risc0Host to prove the given binary.
pub fn new(elf: &'a [u8], api_url: String, api_key: String) -> Self {
Expand Down Expand Up @@ -313,10 +292,11 @@ impl<'a> ZkvmHost for Risc0BonsaiHost<'a> {
/// Proofs are created on the Bonsai API.
fn run(&mut self, with_proof: bool) -> Result<Proof, anyhow::Error> {
if !with_proof {
let env = add_benchmarking_callbacks(ExecutorEnvBuilder::default())
.write_slice(&self.env)
.build()
.unwrap();
let env =
sov_risc0_adapter::host::add_benchmarking_callbacks(ExecutorEnvBuilder::default())
.write_slice(&self.env)
.build()
.unwrap();
let mut executor = ExecutorImpl::from_elf(env, self.elf)?;

let session = executor.run()?;
Expand Down
Loading

0 comments on commit fc6dfe0

Please sign in to comment.