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

Parse BatchProof/LightClient data from DA #1037

Merged
merged 16 commits into from
Sep 3, 2024
37 changes: 0 additions & 37 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.

12 changes: 9 additions & 3 deletions bin/citrea/tests/e2e/syncing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use citrea_stf::genesis_config::GenesisPaths;
use ethereum_rpc::CitreaStatus;
use reth_primitives::{Address, BlockNumberOrTag};
use sov_mock_da::{MockAddress, MockDaService, MockDaSpec, MockHash};
use sov_rollup_interface::da::{DaData, DaSpec};
use sov_rollup_interface::da::{DaDataLightClient, DaSpec};
use sov_rollup_interface::services::da::DaService;
use sov_stf_runner::ProverConfig;
use tokio::time::sleep;
Expand Down Expand Up @@ -396,9 +396,15 @@ async fn test_prover_sync_with_commitments() -> Result<(), anyhow::Error> {

let da_data = blob.data.accumulator();

let proof: DaData = borsh::BorshDeserialize::try_from_slice(da_data).unwrap();
let data: DaDataLightClient = borsh::BorshDeserialize::try_from_slice(da_data).unwrap();

assert!(matches!(proof, DaData::ZKProof(_)));
#[allow(unreachable_patterns)]
match data {
DaDataLightClient::ZKProof(_) => {
// All good
}
_ => panic!("Wrong da data"),
}
kpp marked this conversation as resolved.
Show resolved Hide resolved

// TODO: Also test with multiple commitments in single Mock DA Block
seq_task.abort();
Expand Down
3 changes: 2 additions & 1 deletion crates/bitcoin-da/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ thiserror = { workspace = true }
tracing = { workspace = true, optional = true }

bitcoin = { workspace = true }
brotli = { workspace = true }
brotli = { workspace = true, optional = true }
futures.workspace = true
sha2 = { workspace = true }

Expand All @@ -36,6 +36,7 @@ bitcoincore-rpc = { workspace = true, optional = true }
[features]
default = []
native = [
"dep:brotli",
"dep:tokio",
"dep:pin-project",
"dep:tracing",
Expand Down
1 change: 0 additions & 1 deletion crates/bitcoin-da/src/helpers/compression.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use std::io::Write;

#[cfg(feature = "native")]
pub fn compress_blob(blob: &[u8]) -> Vec<u8> {
use brotli::CompressorWriter;
let mut writer = CompressorWriter::new(Vec::new(), 4096, 11, 22);
Expand Down
1 change: 1 addition & 0 deletions crates/bitcoin-da/src/helpers/merkle_tree.rs
kpp marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ impl BitcoinMerkleTree {
self.nodes[self.nodes.len() - 1][0]
}

#[cfg(feature = "native")]
pub fn get_idx_path(&self, index: u32) -> Vec<[u8; 32]> {
assert!(index < self.nodes[0].len() as u32, "Index out of bounds");
let mut path = vec![];
Expand Down
4 changes: 4 additions & 0 deletions crates/bitcoin-da/src/helpers/mod.rs
kpp marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ use sha2::{Digest, Sha256};

#[cfg(feature = "native")]
pub mod builders;
#[cfg(feature = "native")]
pub mod compression;
pub mod merkle_tree;
pub mod parsers;
#[cfg(test)]
pub mod test_utils;

#[cfg(feature = "native")]
/// Type represents a typed enum for LightClient kind
#[repr(u16)]
enum TransactionKindLightClient {
Expand All @@ -22,6 +24,7 @@ enum TransactionKindLightClient {
Unknown(NonZeroU16),
}

#[cfg(feature = "native")]
kpp marked this conversation as resolved.
Show resolved Hide resolved
impl TransactionKindLightClient {
fn to_bytes(&self) -> Vec<u8> {
match self {
Expand Down Expand Up @@ -59,6 +62,7 @@ enum TransactionKindBatchProof {
}

impl TransactionKindBatchProof {
#[cfg(feature = "native")]
fn to_bytes(&self) -> Vec<u8> {
match self {
TransactionKindBatchProof::SequencerCommitment => 0u16.to_le_bytes().to_vec(),
Expand Down
42 changes: 29 additions & 13 deletions crates/bitcoin-da/src/helpers/parsers.rs
kpp marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
use core::num::NonZeroU16;

use bitcoin::blockdata::script::Instruction;
use bitcoin::hashes::Hash;
use bitcoin::opcodes::all::OP_CHECKSIGVERIFY;
use bitcoin::script::Instruction::{Op, PushBytes};
use bitcoin::script::{Error as ScriptError, PushBytes as StructPushBytes};
use bitcoin::secp256k1::{ecdsa, Message, Secp256k1};
use bitcoin::{secp256k1, Opcode, Script, Transaction, Txid};
#[cfg(feature = "native")]
use bitcoin::Txid;
use bitcoin::{secp256k1, Opcode, Script, Transaction};
use thiserror::Error;

use super::{calculate_sha256, TransactionKindBatchProof, TransactionKindLightClient};
use super::calculate_sha256;

#[cfg(feature = "native")]
#[derive(Debug, Clone)]
pub enum ParsedLightClientTransaction {
/// Kind 0
Expand All @@ -29,20 +31,31 @@ pub enum ParsedBatchProofTransaction {
// ForcedTransaction(ForcedTransaction),
}

#[cfg(feature = "native")]
#[derive(Debug, Clone)]
pub struct ParsedComplete {
pub body: Vec<u8>,
pub signature: Vec<u8>,
pub public_key: Vec<u8>,
}

#[cfg(feature = "native")]
#[derive(Debug, Clone)]
pub struct ParsedAggregate {
pub body: Vec<u8>,
pub signature: Vec<u8>,
pub public_key: Vec<u8>,
}

#[cfg(feature = "native")]
impl ParsedAggregate {
pub fn txids(&self) -> Result<Vec<Txid>, bitcoin::hashes::FromSliceError> {
use bitcoin::hashes::Hash;
self.body.chunks_exact(32).map(Txid::from_slice).collect()
}
}

#[cfg(feature = "native")]
#[derive(Debug, Clone)]
pub struct ParsedChunk {
pub body: Vec<u8>,
Expand Down Expand Up @@ -83,6 +96,7 @@ pub(crate) trait VerifyParsed {
}
}

#[cfg(feature = "native")]
impl VerifyParsed for ParsedComplete {
fn public_key(&self) -> &[u8] {
&self.public_key
Expand All @@ -95,6 +109,7 @@ impl VerifyParsed for ParsedComplete {
}
}

#[cfg(feature = "native")]
impl VerifyParsed for ParsedAggregate {
fn public_key(&self) -> &[u8] {
&self.public_key
Expand All @@ -119,16 +134,8 @@ impl VerifyParsed for ParsedSequencerCommitment {
}
}

impl ParsedAggregate {
pub fn txids(&self) -> Result<Vec<Txid>, bitcoin::hashes::FromSliceError> {
self.body.chunks_exact(32).map(Txid::from_slice).collect()
}
}

#[derive(Error, Debug, Clone, PartialEq)]
pub enum ParserError {
#[error("Invalid rollup name")]
InvalidRollupName,
#[error("Invalid header length")]
InvalidHeaderLength,
#[error("Invalid header type {0}")]
Expand All @@ -149,6 +156,7 @@ impl From<ScriptError> for ParserError {
}
}

#[cfg(feature = "native")]
pub fn parse_light_client_transaction(
tx: &Transaction,
) -> Result<ParsedLightClientTransaction, ParserError> {
Expand Down Expand Up @@ -179,9 +187,12 @@ fn get_script(tx: &Transaction) -> Result<&Script, ParserError> {
.ok_or(ParserError::NonTapscriptWitness)
}

#[cfg(feature = "native")]
fn parse_relevant_lightclient(
instructions: &mut dyn Iterator<Item = Result<Instruction<'_>, ParserError>>,
) -> Result<ParsedLightClientTransaction, ParserError> {
use super::TransactionKindLightClient;

// PushBytes(XOnlyPublicKey)
let _public_key = read_push_bytes(instructions)?;
if OP_CHECKSIGVERIFY != read_opcode(instructions)? {
Expand Down Expand Up @@ -210,6 +221,8 @@ fn parse_relevant_lightclient(
fn parse_relevant_batchproof(
instructions: &mut dyn Iterator<Item = Result<Instruction<'_>, ParserError>>,
) -> Result<ParsedBatchProofTransaction, ParserError> {
use super::TransactionKindBatchProof;

// PushBytes(XOnlyPublicKey)
let _public_key = read_push_bytes(instructions)?;
if OP_CHECKSIGVERIFY != read_opcode(instructions)? {
Expand Down Expand Up @@ -261,6 +274,7 @@ fn read_opcode(
Ok(op)
}

#[cfg(feature = "native")]
mod light_client {
use bitcoin::opcodes::all::{OP_ENDIF, OP_IF, OP_NIP};
use bitcoin::script::Instruction;
Expand Down Expand Up @@ -479,7 +493,7 @@ mod batch_proof {
}
}

#[cfg(feature = "native")]
#[cfg(all(test, feature = "native"))]
pub fn parse_hex_transaction(
tx_hex: &str,
) -> Result<Transaction, bitcoin::consensus::encode::Error> {
Expand All @@ -493,6 +507,7 @@ pub fn parse_hex_transaction(
))
}
}

#[cfg(test)]
mod tests {
use bitcoin::key::XOnlyPublicKey;
Expand All @@ -503,8 +518,9 @@ mod tests {

use super::{
parse_light_client_transaction, parse_relevant_lightclient, ParsedLightClientTransaction,
ParserError, TransactionKindLightClient,
ParserError,
};
use crate::helpers::TransactionKindLightClient;

#[test]
fn correct() {
Expand Down
2 changes: 0 additions & 2 deletions crates/bitcoin-da/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
#![allow(dead_code)] // FIXME

mod helpers;
pub mod spec;

Expand Down
Loading
Loading