Code References

Encrypted Mempool

request_encrypt_tx
// RPC request for encrypting the transaction
pub async fn request_encrypt_tx(
    rpc_endpoint: Endpoint,
    parameter: EncryptTx,
) -> Option<EncryptTxResponse> 
encrypt_tx_with_zkp
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>)
EncryptTxResponse
pub struct EncryptTxResponse {
    pub encrypted_tx: EncryptedTx,
    pub decryption_key: DecryptionKey,
    pub pvde_zkp: Option<PvdeZkp>,
}
EncryptedTx
pub struct EncryptedTx {
   raw_tx_hash: RawTxHash,
   encrypted_data: EncryptedData,
   time_lock_puzzle: TimeLockPuzzle,
}
SendEncryptedTx
pub struct SendEncryptedTx {
    pub rollup_id: RollupId,
    pub encrypted_tx: EncryptedTx,
    pub pvde_zkp: Option<PvdeZkp>,
}
SendEncryptedTxResponse
pub struct SendEncryptedTxResponse {
    pub block_height: BlockHeight,
    pub tx_order: TxOrder,
    pub signature: Signature,
}
provide_decryption_key
pub async fn provide_decryption_key(rpc_endpoint: Endpoint, parameter: ProvideDecryptionKey) {
    match RpcClient::request::<ProvideDecryptionKeyResponse>(rpc_endpoint, parameter, 1.into())
        .await
    {
        Ok(response) => tracing::info!("{:?}", response),
        Err(error) => tracing::error!("{:?}", error),
    }
}
ProvideDecryptionKey
pub struct ProvideDecryptionKey {
    pub decryption_key: DecryptionKey,

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

Sequencing Layer ↔ User

send_encrypted_tx
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.
    runtime::spawn(decryption_offloader(
        self.rollup_id.clone(),
        block_height.clone(),
        tx_order.clone(),
        self.encrypted_tx.clone(),
        3000,
    ));
    
    // the sequencer's private key is loaded from environment
    let sequencer_private_key: PrivateKey =
        runtime::context().load(SEQUENCER_PRIVATE_KEY).await?;
    
    // 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(
        &block_height,
        &tx_order,
        raw_tx_hash,
        sequencer_private_key,
        &rollup.rollup_type,
    )?;
    
    // the order of the transaction, the block height and the signature 
    // is sent to the user as the pre-confirmation
    Ok(SendEncryptedTxResponse {
        block_height,
        tx_order,
        signature,
    })
}
add_encrypted_tx
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();
            locked_block_metadata.commit()?;

            tx_order
        } // ...error handling
    };

    // add encrypted tx to the database
    set_encrypted_tx(
        &database,
        &self.rollup_id,
        &block_height,
        &tx_order,
        Some(self.encrypted_tx.clone()),
    )?;

    Ok((block_height, tx_order))
}

Sequencing Layer ↔ Rolup

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

impl Default for RollupType {
    fn default() -> Self {
        Self::Madara
    }
}
Operator
pub struct Operator {
    address: Address,
    public_key: PublicKey,
}
add_rollup
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
    }
}
GetRawTxList
pub struct GetRawTxList {
    pub rollup_id: RollupId,
    pub block_height: Option<BlockHeight>,
    pub operator_signature: Option<Signature>,
}
GetRawTxListResponse
pub struct GetRawTxListResponse {
    pub is_building_block: bool,
    pub raw_tx_list: RawTxList,
}
get_raw_tx_list
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 
BlockMetadata
pub struct BlockMetadata {
    is_decrypted_tx_info_list: Vec<bool>,
    is_closed: bool,
}
Block
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 
                build_block(
                    &database,
                    block_metadata,
                    &self.rollup_id,
                    &block_height,
                    &sequencer_address,
                    &block_signature,
                    &rollup_signature,
                    current_time,
                );
    //    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,
            };
            Ok(get_raw_tx_list_response)
        }
        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,
                raw_tx_list,
            })
        }
    },  
}
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(),
    })    
}

Leader-based

forwarding to the leader
/*

The following code can be found in all of the methods, such as:

add_raw_tx, add_rollup, get_block_metadata, get_block, get_current_block_height,
get_encrypted_tx_list, get_encrypted_tx, get_raw_tx_list, get_raw_tx,
get_rollup_list, get_rollup, provide_decryption_key, send_encrypted_tx, send_raw_tx

*/

fn method_name() -> &'static str {
    // method's name
}

async fn handler(self) -> Result<Self::Output, Error> {
    match is_leader().await? {
        true => {
            // perform leader's actions and send syncing proposal message to the 
            // if needed follower's
        }
        false => forward_to_leader(self).await,
    }
}
request from followers to sync
RaftNode::send_proposal_message(...).await?;
RaftNode::sync_encrypted_txs(
    &raft_endpoint_list,
    rollup_id,
    &merged_rollup_snapshot.rollup.current_block_height,
    &merged_rollup_snapshot.block_metadata,
)
.await?;

RaftNode::sync_raw_txs(
    &raft_endpoint_list,
    rollup_id,
    &merged_rollup_snapshot.rollup.current_block_height,
    &merged_rollup_snapshot.block_metadata,
)
.await?;

RaftNode::sync_block(
    &raft_endpoint_list,
    rollup_id,
    &BlockHeight::from(block_height),
)
.await?;

RaftNode::sync_block_metadata(
    &raft_endpoint_list,
    &rollup_id,
    &block_height,
)
.await

Last updated