From e897fd607651d0c9582e2b2124d600646c463a2a Mon Sep 17 00:00:00 2001 From: Sergio Chouhy Date: Mon, 26 Jan 2026 14:51:39 -0300 Subject: [PATCH] fix parent when resubmitting pending blocks --- Cargo.lock | 1 + common/Cargo.toml | 1 + common/src/block.rs | 29 ++++++++++++++++++- common/src/test_utils.rs | 4 ++- sequencer_core/src/block_settlement_client.rs | 21 +++++++++----- sequencer_core/src/block_store.rs | 4 ++- sequencer_core/src/lib.rs | 21 ++++++++++---- 7 files changed, 64 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 16baf5a4..c8f0b26a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1319,6 +1319,7 @@ dependencies = [ "borsh", "hex", "log", + "logos-blockchain-core", "nssa", "nssa_core", "reqwest", diff --git a/common/Cargo.toml b/common/Cargo.toml index a6e26fad..96f267df 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -17,3 +17,4 @@ log.workspace = true hex.workspace = true borsh.workspace = true base64.workspace = true +logos-blockchain-core.workspace = true diff --git a/common/src/block.rs b/common/src/block.rs index 84b7a419..e7659fbf 100644 --- a/common/src/block.rs +++ b/common/src/block.rs @@ -1,4 +1,5 @@ use borsh::{BorshDeserialize, BorshSerialize}; +use logos_blockchain_core::mantle::ops::channel::MsgId; use sha2::{Digest, Sha256, digest::FixedOutput}; use crate::transaction::EncodedTransaction; @@ -49,6 +50,11 @@ pub struct Block { pub header: BlockHeader, pub body: BlockBody, pub bedrock_status: BedrockStatus, + #[borsh( + serialize_with = "borsh_msg_id::serialize", + deserialize_with = "borsh_msg_id::deserialize" + )] + pub bedrock_parent_id: MsgId, } #[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)] @@ -60,7 +66,11 @@ pub struct HashableBlockData { } impl HashableBlockData { - pub fn into_pending_block(self, signing_key: &nssa::PrivateKey) -> Block { + pub fn into_pending_block( + self, + signing_key: &nssa::PrivateKey, + bedrock_parent_id: MsgId, + ) -> Block { let data_bytes = borsh::to_vec(&self).unwrap(); let signature = nssa::Signature::new(signing_key, &data_bytes); let hash = OwnHasher::hash(&data_bytes); @@ -76,6 +86,7 @@ impl HashableBlockData { transactions: self.transactions, }, bedrock_status: BedrockStatus::Pending, + bedrock_parent_id, } } } @@ -91,6 +102,22 @@ impl From for HashableBlockData { } } +mod borsh_msg_id { + use std::io::{Read, Write}; + + use logos_blockchain_core::mantle::ops::channel::MsgId; + + pub fn serialize(v: &MsgId, w: &mut W) -> std::io::Result<()> { + w.write_all(v.as_ref()) + } + + pub fn deserialize(r: &mut R) -> std::io::Result { + let mut buf = [0u8; 32]; + r.read_exact(&mut buf)?; + Ok(MsgId::from(buf)) + } +} + #[cfg(test)] mod tests { use crate::{block::HashableBlockData, test_utils}; diff --git a/common/src/test_utils.rs b/common/src/test_utils.rs index 1125b86e..8ae97599 100644 --- a/common/src/test_utils.rs +++ b/common/src/test_utils.rs @@ -1,3 +1,5 @@ +use logos_blockchain_core::mantle::ops::channel::MsgId; + use crate::{ block::{Block, HashableBlockData}, transaction::{EncodedTransaction, NSSATransaction}, @@ -30,7 +32,7 @@ pub fn produce_dummy_block( transactions, }; - block_data.into_pending_block(&sequencer_sign_key_for_testing()) + block_data.into_pending_block(&sequencer_sign_key_for_testing(), MsgId::from([0; 32])) } pub fn produce_dummy_empty_transaction() -> EncodedTransaction { diff --git a/sequencer_core/src/block_settlement_client.rs b/sequencer_core/src/block_settlement_client.rs index 8a01b934..62070ee2 100644 --- a/sequencer_core/src/block_settlement_client.rs +++ b/sequencer_core/src/block_settlement_client.rs @@ -2,7 +2,7 @@ use std::{fs, path::Path}; use anyhow::{Result, anyhow}; use bedrock_client::BedrockClient; -use common::block::HashableBlockData; +use common::block::{Block, HashableBlockData}; use logos_blockchain_core::mantle::{ MantleTx, Op, OpProof, SignedMantleTx, Transaction, TxHash, ledger, ops::channel::{ChannelId, MsgId, inscribe::InscriptionOp}, @@ -39,16 +39,22 @@ impl BlockSettlementClient { self.last_message_id = msg_id; } + + pub fn last_message_id(&self) -> MsgId { + self.last_message_id + } + /// Create and sign a transaction for inscribing data - pub fn create_inscribe_tx(&self, data: Vec) -> (SignedMantleTx, MsgId) { + pub fn create_inscribe_tx(&self, block: &Block) -> Result<(SignedMantleTx, MsgId)> { + let inscription_data = borsh::to_vec(block)?; let verifying_key_bytes = self.bedrock_signing_key.public_key().to_bytes(); let verifying_key = Ed25519PublicKey::from_bytes(&verifying_key_bytes).expect("valid ed25519 public key"); let inscribe_op = InscriptionOp { channel_id: self.bedrock_channel_id, - inscription: data, - parent: self.last_message_id, + inscription: inscription_data, + parent: block.bedrock_parent_id, signer: verifying_key, }; let inscribe_op_id = inscribe_op.id(); @@ -78,13 +84,12 @@ impl BlockSettlementClient { ledger_tx_proof: empty_ledger_signature(&tx_hash), mantle_tx: inscribe_tx, }; - (signed_mantle_tx, inscribe_op_id) + Ok((signed_mantle_tx, inscribe_op_id)) } /// Post a transaction to the node - pub async fn post_transaction(&self, block_data: &HashableBlockData) -> Result { - let inscription_data = borsh::to_vec(&block_data)?; - let (tx, new_msg_id) = self.create_inscribe_tx(inscription_data); + pub async fn submit_block_to_bedrock(&self, block: &Block) -> Result { + let (tx, new_msg_id) = self.create_inscribe_tx(block)?; // Post the transaction self.bedrock_client.post_transaction(tx).await?; diff --git a/sequencer_core/src/block_store.rs b/sequencer_core/src/block_store.rs index e050f181..92543be7 100644 --- a/sequencer_core/src/block_store.rs +++ b/sequencer_core/src/block_store.rs @@ -107,6 +107,7 @@ pub(crate) fn block_to_transactions_map(block: &Block) -> HashMap #[cfg(test)] mod tests { use common::{block::HashableBlockData, test_utils::sequencer_sign_key_for_testing}; + use logos_blockchain_core::mantle::ops::channel::MsgId; use tempfile::tempdir; use super::*; @@ -125,7 +126,8 @@ mod tests { transactions: vec![], }; - let genesis_block = genesis_block_hashable_data.into_pending_block(&signing_key); + let genesis_block = + genesis_block_hashable_data.into_pending_block(&signing_key, MsgId::from([0; 32])); // Start an empty node store let mut node_store = SequencerBlockStore::open_db_with_genesis(path, Some(genesis_block), signing_key) diff --git a/sequencer_core/src/lib.rs b/sequencer_core/src/lib.rs index 115baf80..5183ac43 100644 --- a/sequencer_core/src/lib.rs +++ b/sequencer_core/src/lib.rs @@ -10,8 +10,8 @@ use common::{ }; use config::SequencerConfig; use log::warn; +use logos_blockchain_core::mantle::ops::channel::MsgId; use mempool::{MemPool, MemPoolHandle}; -use nomos_core::mantle::ops::channel::MsgId; use serde::{Deserialize, Serialize}; use crate::{block_settlement_client::BlockSettlementClient, block_store::SequencerBlockStore}; @@ -54,7 +54,8 @@ impl SequencerCore { }; let signing_key = nssa::PrivateKey::try_new(config.signing_key).unwrap(); - let genesis_block = hashable_data.into_pending_block(&signing_key); + let channel_genesis_msg = MsgId::from([0; 32]); + let genesis_block = hashable_data.into_pending_block(&signing_key, channel_genesis_msg); // Sequencer should panic if unable to open db, // as fixing this issue may require actions non-native to program scope @@ -150,7 +151,10 @@ impl SequencerCore { let block_data = self.produce_new_block_with_mempool_transactions()?; if let Some(block_settlement) = self.block_settlement_client.as_mut() { - let msg_id = block_settlement.post_transaction(&block_data).await?; + let last_message_id = block_settlement.last_message_id(); + let block = + block_data.into_pending_block(self.block_store.signing_key(), last_message_id); + let msg_id = block_settlement.submit_block_to_bedrock(&block).await?; block_settlement.set_last_message_id(msg_id); log::info!("Posted block data to Bedrock"); } @@ -196,9 +200,15 @@ impl SequencerCore { timestamp: curr_time, }; + let bedrock_parent_id = self + .block_settlement_client + .as_ref() + .map(|client| client.last_message_id()) + .unwrap_or(MsgId::from([0; 32])); + let block = hashable_data .clone() - .into_pending_block(self.block_store.signing_key()); + .into_pending_block(self.block_store.signing_key(), bedrock_parent_id); self.block_store.put_block_at_id(block)?; @@ -248,8 +258,7 @@ impl SequencerCore { match block.bedrock_status { BedrockStatus::Pending => { if let Some(block_settlement) = self.block_settlement_client.as_ref() { - let block_data: HashableBlockData = block.into(); - block_settlement.post_transaction(&block_data).await?; + block_settlement.submit_block_to_bedrock(&block).await?; log::info!("Posted block data to Bedrock"); } }