Code References

Encrypted Mempool

// RPC request for encrypting the transaction
pub async fn request_encrypt_tx(
    rpc_endpoint: Endpoint,
    parameter: EncryptTx,
) -> Option<EncryptTxResponse> 
pub fn encrypt_tx_with_zkp(
    raw_tx: String,
    time_lock_puzzle_param: TimeLockPuzzleParam,
    key_validation_zkp_param: ParamsKZG<Bn256>,
    key_validation_proving_key: ProvingKey<G1Affine>,
    encryption_zkp_param: ParamsKZG<Bn256>,
    encryption_proving_key: ProvingKey<G1Affine>,
) -> Result<(EncryptedTx, DecryptionKey, Option<PvdeZkp>)
pub struct EncryptTxResponse {
    pub encrypted_tx: EncryptedTx,
    pub decryption_key: DecryptionKey,
    pub pvde_zkp: Option<PvdeZkp>,
pub struct EncryptedTx {
   raw_tx_hash: RawTxHash,
   encrypted_data: EncryptedData,
   time_lock_puzzle: TimeLockPuzzle,
pub struct SendEncryptedTx {
    pub rollup_id: RollupId,
    pub encrypted_tx: EncryptedTx,
    pub pvde_zkp: Option<PvdeZkp>,
pub struct SendEncryptedTxResponse {
    pub block_height: BlockHeight,
    pub tx_order: TxOrder,
    pub signature: Signature,
pub async fn provide_decryption_key(rpc_endpoint: Endpoint, parameter: ProvideDecryptionKey) {
    match RpcClient::request::<ProvideDecryptionKeyResponse>(rpc_endpoint, parameter, 1.into())
        Ok(response) => tracing::info!("{:?}", response),
        Err(error) => tracing::error!("{:?}", error),
pub struct ProvideDecryptionKey {
    pub decryption_key: DecryptionKey,

    pub rollup_id: RollupId,
    pub block_height: BlockHeight,
    pub tx_order: TxOrder,
    pub signature: Signature,

Sequencer Set ↔ User

if do_verify_tx_with_zkp {
// zkp verification
match true => {
    let database: Database = runtime::context().load(DB).await?;
    // the rollup information is retrieved from the local database.
    let rollup: Rollup = get_rollup(&database, &self.rollup_id)?;
    // ...code
    // the block height and the transactions order is determined
    let (block_height, tx_order) = self.add_encrypted_tx().await?;
    let raw_tx_hash = self.encrypted_tx.raw_tx_hash.clone();
    // the decryption_offloader is passed to offload the task of decryption, 
    // to run it asynchronously without blocking the main execution flow.
    // the sequencer's private key is loaded from environment
    let sequencer_private_key: PrivateKey =
    // block height, transaction order, raw transaction hash, 
    // sequencer's private key and rollup type are signed with sequencer's private key
    let signature = sign_for_order_commitment(
    // the order of the transaction, the block height and the signature 
    // is sent to the user as the pre-confirmation
    Ok(SendEncryptedTxResponse {
pub async fn add_encrypted_tx(&self) -> Result<(BlockHeight, TxOrder), Error> {
    // ...code
    let tx_order = match get_locked_block_metadata(&database, &self.rollup_id, &block_height) {
        Ok(mut locked_block_metadata) => {
            let tx_order = locked_block_metadata.increment_encrypted_tx_order();

        } // ...error handling

    // add encrypted tx to the database

    Ok((block_height, tx_order))

Sequencer Set ↔ Rolup

pub struct AddRollup {
    pub rollup_id: RollupId,
    pub rollup_type: RollupType,
    pub operator: Operator,
    pub da_info: Option<DataAvailability>,
pub enum RollupType {
    Madara = "madara",

impl Default for RollupType {
    fn default() -> Self {
pub struct Operator {
    address: Address,
    public_key: PublicKey,
pub async fn add_rollup(&self) -> Result<Rollup, Error> {
    // loads database
    match get_rollup(&database, &self.rollup_id) {
        // throws an error if successful, meaning the given rollup is already registered
        // or
        // registers new rollup if unsuccessful by
            // adding it to the list of rollups
            // adding it to the database
            // adding its metadata to the database
pub struct GetRawTxList {
    pub rollup_id: RollupId,
    pub block_height: Option<BlockHeight>,
    pub operator_signature: Option<Signature>,
pub struct GetRawTxListResponse {
    pub is_building_block: bool,
    pub raw_tx_list: RawTxList,
let database: Database = runtime::context().load(DB).await?;

let rollup = get_rollup(&database, &self.rollup_id)?;

// if block_height is None, get rollup's current block height
let block_height: BlockHeight =
    get_block_height(&database, &self.rollup_id, &self.block_height)?;
// ...code for checking if block_height is greater than 
// rollup's current block height, return error 
pub struct BlockMetadata {
    is_decrypted_tx_info_list: Vec<bool>,
    is_closed: bool,
pub struct Block {
    block_height: BlockHeight,
    encrypted_tx_list: EncryptedTxList,
    raw_tx_list: RawTxList,
    sequencer_address: Address,
    signature: Signature,
    rollup_signature: Signature,
    timestamp: Timestamp,
impl BlockMetadata
impl BlockMetadata {
    pub fn increment_encrypted_tx_order(&mut self) -> TxOrder {
    // implementation of FCFS ↓
        // 1. gets the length of the current list, which is going to be the order of                   the next tx
        // 2. pushes it's `false` decryption status into the decrypted_tx_info_list
        // 3. returns the tx order

    pub fn set_decypted_tx(&mut self, tx_order: &TxOrder) {
       // sets the tx of order tx_order as decrypted

    pub fn is_decryption_done(&self) -> bool {
        // checks if all the transactions in the tx info list are decrypted

    pub fn set_closed(&mut self) {
        // closes the block

    pub fn is_closed(&self) -> bool {
        // checks is the block is closed
block is not closed
// if there was not block request from the rollup operator, the block is not closed
if !block_metadata.is_closed() {
    // only the registered operator can close the block for getting raw_tx_list,
    // therefore, the sequencer checks if the operator's signature is valid
    // if all the validations and verifications are valid 
         // 1. the block is closed
         // 2. the current block height is incremented
         // 3. an empty metadata is set for the future block
    // in any other case, an appropriate error is thrown
block is empty, no decrypted transactions
// 1. check if the block is empty
if block_metadata.is_decrypted_tx_info_list.is_empty() {

    // if indeed there is none
    //     1.1. record, timestamp, generate empty encrypted and raw transaction lists,
    //     1.2. sign the block by passing the lists, timestamp, block height,
    //    sequencer's private key, and rollup type into the signer function
    //     1.3. build the block by calling 
    //    1.4. return the empty raw tx list and its status of not building
    return Ok(GetRawTxListResponse {
        is_building_block: false,
        raw_tx_list: RawTxList::default(),
block is not empty, all transactions are decrypted
// 2. if there are transactions, check if they all are decrypted
match block_metadata.is_decryption_done() {
    // 2.1. if they are, attempt to get the raw transaction list and if successful, return it
    true => match get_raw_tx_list(&database, &self.rollup_id, &block_height) {
        Ok(value) => {
            let get_raw_tx_list_response = GetRawTxListResponse {
                is_building_block: false,
                raw_tx_list: value,
        Err(error) => {
            //     2.1.1 get encrypted and raw transaction lists from the db
            //     2.2.2 ~ repeat 1.2, 1.3 and return the raw transaction list
            Ok(GetRawTxListResponse {
                is_building_block: false,
block is not empty, not all transactions are decrypted
// ...code from the Case 2
// otherwise, if any encrypted transaction isn't decrypted, the sequencing layer returns
// an empty list of raw transactions along with the status is_building_block: true, 
// signaling that the building block remains incomplete
false => {
     Ok(GetRawTxListResponse {
        is_building_block: true,
        raw_tx_list: RawTxList::default(),

Last updated