fix parent when resubmitting pending blocks

This commit is contained in:
Sergio Chouhy 2026-01-26 14:51:39 -03:00
parent ab31a1fd2d
commit e897fd6076
7 changed files with 64 additions and 17 deletions

1
Cargo.lock generated
View File

@ -1319,6 +1319,7 @@ dependencies = [
"borsh",
"hex",
"log",
"logos-blockchain-core",
"nssa",
"nssa_core",
"reqwest",

View File

@ -17,3 +17,4 @@ log.workspace = true
hex.workspace = true
borsh.workspace = true
base64.workspace = true
logos-blockchain-core.workspace = true

View File

@ -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<Block> for HashableBlockData {
}
}
mod borsh_msg_id {
use std::io::{Read, Write};
use logos_blockchain_core::mantle::ops::channel::MsgId;
pub fn serialize<W: Write>(v: &MsgId, w: &mut W) -> std::io::Result<()> {
w.write_all(v.as_ref())
}
pub fn deserialize<R: Read>(r: &mut R) -> std::io::Result<MsgId> {
let mut buf = [0u8; 32];
r.read_exact(&mut buf)?;
Ok(MsgId::from(buf))
}
}
#[cfg(test)]
mod tests {
use crate::{block::HashableBlockData, test_utils};

View File

@ -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 {

View File

@ -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<u8>) -> (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<MsgId> {
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<MsgId> {
let (tx, new_msg_id) = self.create_inscribe_tx(block)?;
// Post the transaction
self.bedrock_client.post_transaction(tx).await?;

View File

@ -107,6 +107,7 @@ pub(crate) fn block_to_transactions_map(block: &Block) -> HashMap<HashType, u64>
#[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)

View File

@ -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");
}
}