diff --git a/Cargo.lock b/Cargo.lock index 58b9c1cd..6e0461fd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1498,6 +1498,7 @@ name = "common" version = "0.1.0" dependencies = [ "anyhow", + "base64 0.22.1", "borsh", "hex", "log", @@ -5244,7 +5245,6 @@ name = "nssa" version = "0.1.0" dependencies = [ "anyhow", - "base64 0.22.1", "borsh", "env_logger", "hex", @@ -7177,23 +7177,30 @@ dependencies = [ "log", "mempool", "nssa", - "nssa_core", "sequencer_core", + "sequencer_service_protocol", "sequencer_service_rpc", "tokio", "tokio-util", ] [[package]] -name = "sequencer_service_rpc" +name = "sequencer_service_protocol" version = "0.1.0" dependencies = [ "common", - "jsonrpsee", "nssa", "nssa_core", ] +[[package]] +name = "sequencer_service_rpc" +version = "0.1.0" +dependencies = [ + "jsonrpsee", + "sequencer_service_protocol", +] + [[package]] name = "serde" version = "1.0.228" diff --git a/Cargo.toml b/Cargo.toml index abe84745..829a6539 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,7 @@ members = [ "programs/token", "sequencer/core", "sequencer/service", + "sequencer/service/protocol", "sequencer/service/rpc", "indexer/core", "indexer/service", @@ -43,6 +44,7 @@ mempool = { path = "mempool" } storage = { path = "storage" } key_protocol = { path = "key_protocol" } sequencer_core = { path = "sequencer/core" } +sequencer_service_protocol = { path = "sequencer/service/protocol" } sequencer_service_rpc = { path = "sequencer/service/rpc" } sequencer_service = { path = "sequencer/service" } indexer_core = { path = "indexer/core" } diff --git a/common/Cargo.toml b/common/Cargo.toml index 002e0cfc..0ae0b220 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -15,6 +15,7 @@ anyhow.workspace = true thiserror.workspace = true serde.workspace = true serde_with.workspace = true +base64.workspace = true sha2.workspace = true log.workspace = true hex.workspace = true diff --git a/common/src/block.rs b/common/src/block.rs index 7759333a..11446314 100644 --- a/common/src/block.rs +++ b/common/src/block.rs @@ -10,7 +10,7 @@ pub type BlockHash = HashType; pub type BlockId = u64; pub type TimeStamp = u64; -#[derive(Debug, Clone, Serialize, Deserialize, BorshSerialize, BorshDeserialize)] +#[derive(Debug, Clone, BorshSerialize, BorshDeserialize)] pub struct BlockMeta { pub id: BlockId, pub hash: BlockHash, @@ -31,7 +31,7 @@ impl OwnHasher { } } -#[derive(Debug, Clone, Serialize, Deserialize, BorshSerialize, BorshDeserialize)] +#[derive(Debug, Clone, BorshSerialize, BorshDeserialize)] pub struct BlockHeader { pub block_id: BlockId, pub prev_block_hash: BlockHash, @@ -40,19 +40,19 @@ pub struct BlockHeader { pub signature: nssa::Signature, } -#[derive(Debug, Clone, Serialize, Deserialize, BorshSerialize, BorshDeserialize)] +#[derive(Debug, Clone, BorshSerialize, BorshDeserialize)] pub struct BlockBody { pub transactions: Vec, } -#[derive(Debug, Clone, Serialize, Deserialize, BorshSerialize, BorshDeserialize)] +#[derive(Debug, Clone, BorshSerialize, BorshDeserialize)] pub enum BedrockStatus { Pending, Safe, Finalized, } -#[derive(Debug, Clone, Serialize, Deserialize, BorshSerialize, BorshDeserialize)] +#[derive(Debug, Clone, BorshSerialize, BorshDeserialize)] pub struct Block { pub header: BlockHeader, pub body: BlockBody, @@ -60,7 +60,19 @@ pub struct Block { pub bedrock_parent_id: MantleMsgId, } -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, BorshSerialize, BorshDeserialize)] +impl Serialize for Block { + fn serialize(&self, serializer: S) -> Result { + crate::borsh_base64::serialize(self, serializer) + } +} + +impl<'de> Deserialize<'de> for Block { + fn deserialize>(deserializer: D) -> Result { + crate::borsh_base64::deserialize(deserializer) + } +} + +#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)] pub struct HashableBlockData { pub block_id: BlockId, pub prev_block_hash: BlockHash, diff --git a/common/src/borsh_base64.rs b/common/src/borsh_base64.rs new file mode 100644 index 00000000..2dc7bdec --- /dev/null +++ b/common/src/borsh_base64.rs @@ -0,0 +1,25 @@ +//! This module provides utilities for serializing and deserializing data by combining Borsh and +//! Base64 encodings. + +use base64::{Engine as _, engine::general_purpose::STANDARD}; +use borsh::{BorshDeserialize, BorshSerialize}; +use serde::{Deserialize, Serialize}; + +pub fn serialize( + value: &T, + serializer: S, +) -> Result { + let borsh_encoded = borsh::to_vec(value).map_err(serde::ser::Error::custom)?; + let base64_encoded = STANDARD.encode(&borsh_encoded); + Serialize::serialize(&base64_encoded, serializer) +} + +pub fn deserialize<'de, T: BorshDeserialize, D: serde::Deserializer<'de>>( + deserializer: D, +) -> Result { + let base64_encoded = ::deserialize(deserializer)?; + let borsh_encoded = STANDARD + .decode(base64_encoded.as_bytes()) + .map_err(serde::de::Error::custom)?; + borsh::from_slice(&borsh_encoded).map_err(serde::de::Error::custom) +} diff --git a/common/src/lib.rs b/common/src/lib.rs index 57d70b64..a7744d63 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -4,6 +4,7 @@ use borsh::{BorshDeserialize, BorshSerialize}; use serde_with::{DeserializeFromStr, SerializeDisplay}; pub mod block; +mod borsh_base64; pub mod config; pub mod transaction; diff --git a/common/src/transaction.rs b/common/src/transaction.rs index e11b91c3..29ae8caf 100644 --- a/common/src/transaction.rs +++ b/common/src/transaction.rs @@ -5,13 +5,25 @@ use serde::{Deserialize, Serialize}; use crate::HashType; -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, BorshSerialize, BorshDeserialize)] +#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)] pub enum NSSATransaction { Public(nssa::PublicTransaction), PrivacyPreserving(nssa::PrivacyPreservingTransaction), ProgramDeployment(nssa::ProgramDeploymentTransaction), } +impl Serialize for NSSATransaction { + fn serialize(&self, serializer: S) -> Result { + crate::borsh_base64::serialize(self, serializer) + } +} + +impl<'de> Deserialize<'de> for NSSATransaction { + fn deserialize>(deserializer: D) -> Result { + crate::borsh_base64::deserialize(deserializer) + } +} + impl NSSATransaction { #[must_use] pub fn hash(&self) -> HashType { diff --git a/nssa/Cargo.toml b/nssa/Cargo.toml index 89dae607..ceebaa2e 100644 --- a/nssa/Cargo.toml +++ b/nssa/Cargo.toml @@ -19,7 +19,6 @@ sha2.workspace = true rand.workspace = true borsh.workspace = true hex.workspace = true -base64.workspace = true secp256k1 = "0.31.1" risc0-binfmt = "3.0.2" log.workspace = true diff --git a/nssa/src/base64.rs b/nssa/src/base64.rs deleted file mode 100644 index cc782e9c..00000000 --- a/nssa/src/base64.rs +++ /dev/null @@ -1,14 +0,0 @@ -use base64::prelude::{BASE64_STANDARD, Engine as _}; -use serde::{Deserialize as _, Deserializer, Serialize as _, Serializer}; - -pub fn serialize(v: &[u8], s: S) -> Result { - let base64 = BASE64_STANDARD.encode(v); - String::serialize(&base64, s) -} - -pub fn deserialize<'de, D: Deserializer<'de>>(d: D) -> Result, D::Error> { - let base64 = String::deserialize(d)?; - BASE64_STANDARD - .decode(base64.as_bytes()) - .map_err(serde::de::Error::custom) -} diff --git a/nssa/src/lib.rs b/nssa/src/lib.rs index 973433ee..bc7cf121 100644 --- a/nssa/src/lib.rs +++ b/nssa/src/lib.rs @@ -18,7 +18,6 @@ pub use public_transaction::PublicTransaction; pub use signature::{PrivateKey, PublicKey, Signature}; pub use state::V02State; -mod base64; pub mod encoding; pub mod error; mod merkle_tree; diff --git a/nssa/src/privacy_preserving_transaction/circuit.rs b/nssa/src/privacy_preserving_transaction/circuit.rs index 9f0bf83f..2ab141a3 100644 --- a/nssa/src/privacy_preserving_transaction/circuit.rs +++ b/nssa/src/privacy_preserving_transaction/circuit.rs @@ -8,7 +8,6 @@ use nssa_core::{ program::{ChainedCall, InstructionData, ProgramId, ProgramOutput}, }; use risc0_zkvm::{ExecutorEnv, InnerReceipt, ProverOpts, Receipt, default_prover}; -use serde::{Deserialize, Serialize}; use crate::{ error::NssaError, @@ -18,8 +17,8 @@ use crate::{ }; /// Proof of the privacy preserving execution circuit. -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, BorshSerialize, BorshDeserialize)] -pub struct Proof(#[serde(with = "crate::base64")] pub(crate) Vec); +#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)] +pub struct Proof(pub(crate) Vec); impl Proof { #[must_use] diff --git a/nssa/src/privacy_preserving_transaction/message.rs b/nssa/src/privacy_preserving_transaction/message.rs index a2d6812e..4b93e820 100644 --- a/nssa/src/privacy_preserving_transaction/message.rs +++ b/nssa/src/privacy_preserving_transaction/message.rs @@ -4,14 +4,13 @@ use nssa_core::{ account::{Account, Nonce}, encryption::{Ciphertext, EphemeralPublicKey, ViewingPublicKey}, }; -use serde::{Deserialize, Serialize}; use sha2::{Digest as _, Sha256}; use crate::{AccountId, error::NssaError}; pub type ViewTag = u8; -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, BorshSerialize, BorshDeserialize)] +#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)] pub struct EncryptedAccountData { pub ciphertext: Ciphertext, pub epk: EphemeralPublicKey, @@ -45,7 +44,7 @@ impl EncryptedAccountData { } } -#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, BorshSerialize, BorshDeserialize)] +#[derive(Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)] pub struct Message { pub public_account_ids: Vec, pub nonces: Vec, diff --git a/nssa/src/privacy_preserving_transaction/transaction.rs b/nssa/src/privacy_preserving_transaction/transaction.rs index 012b3bd5..2b268c07 100644 --- a/nssa/src/privacy_preserving_transaction/transaction.rs +++ b/nssa/src/privacy_preserving_transaction/transaction.rs @@ -8,7 +8,6 @@ use nssa_core::{ Commitment, CommitmentSetDigest, Nullifier, PrivacyPreservingCircuitOutput, account::{Account, AccountWithMetadata}, }; -use serde::{Deserialize, Serialize}; use sha2::{Digest as _, digest::FixedOutput as _}; use super::{message::Message, witness_set::WitnessSet}; @@ -18,7 +17,7 @@ use crate::{ privacy_preserving_transaction::{circuit::Proof, message::EncryptedAccountData}, }; -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, BorshSerialize, BorshDeserialize)] +#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)] pub struct PrivacyPreservingTransaction { pub message: Message, pub witness_set: WitnessSet, diff --git a/nssa/src/privacy_preserving_transaction/witness_set.rs b/nssa/src/privacy_preserving_transaction/witness_set.rs index 4f570a22..373bbc9c 100644 --- a/nssa/src/privacy_preserving_transaction/witness_set.rs +++ b/nssa/src/privacy_preserving_transaction/witness_set.rs @@ -1,12 +1,11 @@ use borsh::{BorshDeserialize, BorshSerialize}; -use serde::{Deserialize, Serialize}; use crate::{ PrivateKey, PublicKey, Signature, privacy_preserving_transaction::{circuit::Proof, message::Message}, }; -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, BorshSerialize, BorshDeserialize)] +#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)] pub struct WitnessSet { pub(crate) signatures_and_public_keys: Vec<(Signature, PublicKey)>, pub(crate) proof: Proof, diff --git a/nssa/src/program_deployment_transaction/message.rs b/nssa/src/program_deployment_transaction/message.rs index d4758ae2..a51e4149 100644 --- a/nssa/src/program_deployment_transaction/message.rs +++ b/nssa/src/program_deployment_transaction/message.rs @@ -1,9 +1,7 @@ use borsh::{BorshDeserialize, BorshSerialize}; -use serde::{Deserialize, Serialize}; -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, BorshSerialize, BorshDeserialize)] +#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)] pub struct Message { - #[serde(with = "crate::base64")] pub(crate) bytecode: Vec, } diff --git a/nssa/src/program_deployment_transaction/transaction.rs b/nssa/src/program_deployment_transaction/transaction.rs index 939d81be..1e53388d 100644 --- a/nssa/src/program_deployment_transaction/transaction.rs +++ b/nssa/src/program_deployment_transaction/transaction.rs @@ -1,13 +1,12 @@ use borsh::{BorshDeserialize, BorshSerialize}; use nssa_core::account::AccountId; -use serde::{Deserialize, Serialize}; use sha2::{Digest as _, digest::FixedOutput as _}; use crate::{ V02State, error::NssaError, program::Program, program_deployment_transaction::message::Message, }; -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, BorshSerialize, BorshDeserialize)] +#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)] pub struct ProgramDeploymentTransaction { pub message: Message, } diff --git a/nssa/src/public_transaction/message.rs b/nssa/src/public_transaction/message.rs index e3651ba3..d4838b87 100644 --- a/nssa/src/public_transaction/message.rs +++ b/nssa/src/public_transaction/message.rs @@ -3,11 +3,11 @@ use nssa_core::{ account::Nonce, program::{InstructionData, ProgramId}, }; -use serde::{Deserialize, Serialize}; +use serde::Serialize; use crate::{AccountId, error::NssaError, program::Program}; -#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, BorshSerialize, BorshDeserialize)] +#[derive(Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)] pub struct Message { pub program_id: ProgramId, pub account_ids: Vec, diff --git a/nssa/src/public_transaction/transaction.rs b/nssa/src/public_transaction/transaction.rs index 00d29a05..8c84d83c 100644 --- a/nssa/src/public_transaction/transaction.rs +++ b/nssa/src/public_transaction/transaction.rs @@ -6,7 +6,6 @@ use nssa_core::{ account::{Account, AccountId, AccountWithMetadata}, program::{ChainedCall, DEFAULT_PROGRAM_ID, validate_execution}, }; -use serde::{Deserialize, Serialize}; use sha2::{Digest as _, digest::FixedOutput as _}; use crate::{ @@ -16,7 +15,7 @@ use crate::{ state::MAX_NUMBER_CHAINED_CALLS, }; -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, BorshSerialize, BorshDeserialize)] +#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)] pub struct PublicTransaction { pub message: Message, pub witness_set: WitnessSet, diff --git a/nssa/src/public_transaction/witness_set.rs b/nssa/src/public_transaction/witness_set.rs index e796fbfe..d6b32891 100644 --- a/nssa/src/public_transaction/witness_set.rs +++ b/nssa/src/public_transaction/witness_set.rs @@ -1,9 +1,8 @@ use borsh::{BorshDeserialize, BorshSerialize}; -use serde::{Deserialize, Serialize}; use crate::{PrivateKey, PublicKey, Signature, public_transaction::Message}; -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, BorshSerialize, BorshDeserialize)] +#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)] pub struct WitnessSet { pub(crate) signatures_and_public_keys: Vec<(Signature, PublicKey)>, } diff --git a/nssa/src/signature/mod.rs b/nssa/src/signature/mod.rs index f0e5a863..9dfd47b3 100644 --- a/nssa/src/signature/mod.rs +++ b/nssa/src/signature/mod.rs @@ -4,14 +4,11 @@ use borsh::{BorshDeserialize, BorshSerialize}; pub use private_key::PrivateKey; pub use public_key::PublicKey; use rand::{RngCore as _, rngs::OsRng}; -use serde_with::{DeserializeFromStr, SerializeDisplay}; mod private_key; mod public_key; -#[derive( - Clone, PartialEq, Eq, SerializeDisplay, DeserializeFromStr, BorshSerialize, BorshDeserialize, -)] +#[derive(Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)] pub struct Signature { pub value: [u8; 64], } diff --git a/sequencer/service/Cargo.toml b/sequencer/service/Cargo.toml index 3efb380d..6fee808c 100644 --- a/sequencer/service/Cargo.toml +++ b/sequencer/service/Cargo.toml @@ -10,10 +10,9 @@ workspace = true [dependencies] common.workspace = true nssa.workspace = true -nssa_core.workspace = true mempool.workspace = true -borsh.workspace = true sequencer_core = { workspace = true, features = ["testnet"] } +sequencer_service_protocol.workspace = true sequencer_service_rpc = { workspace = true, features = ["server"] } indexer_service_rpc = { workspace = true, features = ["client"] } @@ -26,6 +25,7 @@ tokio-util.workspace = true jsonrpsee.workspace = true futures.workspace = true bytesize.workspace = true +borsh.workspace = true [features] default = [] diff --git a/sequencer/service/protocol/Cargo.toml b/sequencer/service/protocol/Cargo.toml new file mode 100644 index 00000000..be913104 --- /dev/null +++ b/sequencer/service/protocol/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "sequencer_service_protocol" +version = "0.1.0" +edition = "2024" +license = { workspace = true } + +[lints] +workspace = true + +[dependencies] +common.workspace = true +nssa.workspace = true +nssa_core.workspace = true diff --git a/sequencer/service/protocol/src/lib.rs b/sequencer/service/protocol/src/lib.rs new file mode 100644 index 00000000..eb868c0e --- /dev/null +++ b/sequencer/service/protocol/src/lib.rs @@ -0,0 +1,9 @@ +//! Reexports of types used by sequencer rpc specification. + +pub use common::{ + HashType, + block::{Block, BlockId}, + transaction::NSSATransaction, +}; +pub use nssa::{Account, AccountId, ProgramId}; +pub use nssa_core::{Commitment, MembershipProof, account::Nonce}; diff --git a/sequencer/service/rpc/Cargo.toml b/sequencer/service/rpc/Cargo.toml index 193b948f..d8f16b86 100644 --- a/sequencer/service/rpc/Cargo.toml +++ b/sequencer/service/rpc/Cargo.toml @@ -8,9 +8,7 @@ license = { workspace = true } workspace = true [dependencies] -common.workspace = true -nssa.workspace = true -nssa_core.workspace = true +sequencer_service_protocol.workspace = true jsonrpsee = { workspace = true, features = ["macros"] } diff --git a/sequencer/service/rpc/src/lib.rs b/sequencer/service/rpc/src/lib.rs index 620d93fb..6c03cdb6 100644 --- a/sequencer/service/rpc/src/lib.rs +++ b/sequencer/service/rpc/src/lib.rs @@ -1,17 +1,14 @@ use std::collections::BTreeMap; -use common::{ - HashType, - block::{Block, BlockId}, - transaction::NSSATransaction, -}; use jsonrpsee::proc_macros::rpc; #[cfg(feature = "server")] use jsonrpsee::types::ErrorObjectOwned; #[cfg(feature = "client")] pub use jsonrpsee::{core::ClientError, http_client::HttpClientBuilder as SequencerClientBuilder}; -use nssa::{Account, AccountId, ProgramId}; -use nssa_core::{Commitment, MembershipProof, account::Nonce}; +use sequencer_service_protocol::{ + Account, AccountId, Block, BlockId, Commitment, HashType, MembershipProof, NSSATransaction, + Nonce, ProgramId, +}; #[cfg(all(not(feature = "server"), not(feature = "client")))] compile_error!("At least one of `server` or `client` features must be enabled."); @@ -22,10 +19,14 @@ compile_error!("At least one of `server` or `client` features must be enabled.") /// /// # Example /// -/// ```ignore -/// use sequencer_service_rpc::{SequencerClientBuilder, RpcClient as _}; +/// ```no_run +/// use common::transaction::NSSATransaction; +/// use sequencer_service_rpc::{RpcClient as _, SequencerClientBuilder}; /// +/// let url = "http://localhost:3040".parse()?; /// let client = SequencerClientBuilder::default().build(url)?; +/// +/// let tx: NSSATransaction = unimplemented!("Construct your transaction here"); /// let tx_hash = client.send_transaction(tx).await?; /// ``` #[cfg(feature = "client")] diff --git a/sequencer/service/src/service.rs b/sequencer/service/src/service.rs index e31cae1e..71645363 100644 --- a/sequencer/service/src/service.rs +++ b/sequencer/service/src/service.rs @@ -1,10 +1,6 @@ use std::{collections::BTreeMap, sync::Arc}; -use common::{ - HashType, - block::{Block, BlockId}, - transaction::NSSATransaction, -}; +use common::transaction::NSSATransaction; use jsonrpsee::{ core::async_trait, types::{ErrorCode, ErrorObjectOwned}, @@ -12,15 +8,13 @@ use jsonrpsee::{ use log::warn; use mempool::MemPoolHandle; use nssa::{self, program::Program}; -use nssa_core::{ - Commitment, MembershipProof, - account::{Account, AccountId, Nonce}, - program::ProgramId, -}; use sequencer_core::{ DbError, SequencerCore, block_settlement_client::BlockSettlementClientTrait, indexer_client::IndexerClientTrait, }; +use sequencer_service_protocol::{ + Account, AccountId, Block, BlockId, Commitment, HashType, MembershipProof, Nonce, ProgramId, +}; use tokio::sync::Mutex; const NOT_FOUND_ERROR_CODE: i32 = -31999; @@ -55,12 +49,9 @@ impl