Block building core (#401)
* Move core block to folder base module * Added blob select trait * Added tx select trait * Implement blob and tx selection filling size * Added blobs to block constructor Added block builder module * Implement block builder * Remove unnnecesary phantoms * Add default impl for selections * Added example * Fix typos Co-authored-by: Youngjoon Lee <taxihighway@gmail.com> * tx to item on generic function Co-authored-by: Youngjoon Lee <taxihighway@gmail.com> --------- Co-authored-by: Youngjoon Lee <taxihighway@gmail.com>
This commit is contained in:
parent
70dc4f3ae6
commit
e1e2b84921
|
@ -0,0 +1,111 @@
|
|||
// std
|
||||
use std::hash::Hash;
|
||||
// crates
|
||||
use serde::de::DeserializeOwned;
|
||||
use serde::Serialize;
|
||||
// internal
|
||||
use crate::block::Block;
|
||||
use crate::da::blob::{Blob, BlobSelect};
|
||||
use crate::tx::{Transaction, TxSelect};
|
||||
use consensus_engine::overlay::RandomBeaconState;
|
||||
use consensus_engine::{NodeId, Qc, View};
|
||||
|
||||
/// Wrapper over a block building `new` method than holds intermediary state and can be
|
||||
/// passed around. It also compounds the transaction selection and blob selection heuristics to be
|
||||
/// used for transaction and blob selection.
|
||||
///
|
||||
/// Example:
|
||||
/// ``` ignore
|
||||
/// use nomos_core::block::builder::BlockBuilder;
|
||||
/// let builder: BlockBuilder<(), (), FirstTx, FirstBlob> = {
|
||||
/// BlockBuilder::new( FirstTx::default(), FirstBlob::default())
|
||||
/// .with_view(View::from(0))
|
||||
/// .with_parent_qc(qc)
|
||||
/// .with_proposer(proposer)
|
||||
/// .with_beacon_state(beacon)
|
||||
/// .with_transactions([tx1].into_iter())
|
||||
/// .with_blobs([blob1].into_iter())
|
||||
/// };
|
||||
/// builder.build().expect("All block attributes should have been set")
|
||||
/// ```
|
||||
pub struct BlockBuilder<Tx, Blob, TxSelector, BlobSelector> {
|
||||
tx_selector: TxSelector,
|
||||
blob_selector: BlobSelector,
|
||||
view: Option<View>,
|
||||
parent_qc: Option<Qc>,
|
||||
proposer: Option<NodeId>,
|
||||
beacon: Option<RandomBeaconState>,
|
||||
txs: Option<Box<dyn Iterator<Item = Tx>>>,
|
||||
blobs: Option<Box<dyn Iterator<Item = Blob>>>,
|
||||
}
|
||||
|
||||
impl<Tx, B, TxSelector, BlobSelector> BlockBuilder<Tx, B, TxSelector, BlobSelector>
|
||||
where
|
||||
Tx: Transaction + Clone + Eq + Hash + Serialize + DeserializeOwned,
|
||||
B: Blob + Clone + Eq + Hash + Serialize + DeserializeOwned,
|
||||
TxSelector: TxSelect<Tx = Tx>,
|
||||
BlobSelector: BlobSelect<Blob = B>,
|
||||
{
|
||||
pub fn new(tx_selector: TxSelector, blob_selector: BlobSelector) -> Self {
|
||||
Self {
|
||||
tx_selector,
|
||||
blob_selector,
|
||||
view: None,
|
||||
parent_qc: None,
|
||||
proposer: None,
|
||||
beacon: None,
|
||||
txs: None,
|
||||
blobs: None,
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn with_view(mut self, view: View) -> Self {
|
||||
self.view = Some(view);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn with_parent_qc(mut self, qc: Qc) -> Self {
|
||||
self.parent_qc = Some(qc);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn with_proposer(mut self, proposer: NodeId) -> Self {
|
||||
self.proposer = Some(proposer);
|
||||
self
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn with_beacon_state(mut self, beacon: RandomBeaconState) -> Self {
|
||||
self.beacon = Some(beacon);
|
||||
self
|
||||
}
|
||||
|
||||
#[allow(clippy::result_large_err)]
|
||||
pub fn build(self) -> Result<Block<Tx, B>, Self> {
|
||||
if let Self {
|
||||
tx_selector,
|
||||
blob_selector,
|
||||
view: Some(view),
|
||||
parent_qc: Some(parent_qc),
|
||||
proposer: Some(proposer),
|
||||
beacon: Some(beacon),
|
||||
txs: Some(txs),
|
||||
blobs: Some(blobs),
|
||||
} = self
|
||||
{
|
||||
Ok(Block::new(
|
||||
view,
|
||||
parent_qc,
|
||||
tx_selector.select_tx_from(txs),
|
||||
blob_selector.select_blob_from(blobs),
|
||||
proposer,
|
||||
beacon,
|
||||
))
|
||||
} else {
|
||||
Err(self)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
pub mod builder;
|
||||
|
||||
use consensus_engine::overlay::RandomBeaconState;
|
||||
use indexmap::IndexSet;
|
||||
// std
|
||||
|
@ -31,11 +33,12 @@ impl<
|
|||
view: View,
|
||||
parent_qc: Qc,
|
||||
txs: impl Iterator<Item = Tx>,
|
||||
blobs: impl Iterator<Item = Blob>,
|
||||
proposer: NodeId,
|
||||
beacon: RandomBeaconState,
|
||||
) -> Self {
|
||||
let transactions = txs.collect();
|
||||
let blobs = IndexSet::new();
|
||||
let blobs = blobs.collect();
|
||||
let header = consensus_engine::Block {
|
||||
id: BlockId::zeros(),
|
||||
view,
|
|
@ -1,3 +1,5 @@
|
|||
pub mod select;
|
||||
|
||||
use bytes::Bytes;
|
||||
use std::hash::Hash;
|
||||
|
||||
|
@ -11,3 +13,11 @@ pub trait Blob {
|
|||
}
|
||||
fn as_bytes(&self) -> Bytes;
|
||||
}
|
||||
|
||||
pub trait BlobSelect {
|
||||
type Blob: Blob;
|
||||
fn select_blob_from<'i, I: Iterator<Item = Self::Blob> + 'i>(
|
||||
&self,
|
||||
blobs: I,
|
||||
) -> Box<dyn Iterator<Item = Self::Blob> + 'i>;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
// std
|
||||
use std::marker::PhantomData;
|
||||
// crates
|
||||
|
||||
// internal
|
||||
use crate::da::blob::{Blob, BlobSelect};
|
||||
use crate::utils;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct FillSize<const SIZE: usize, B> {
|
||||
_blob: PhantomData<B>,
|
||||
}
|
||||
|
||||
impl<const SIZE: usize, B> FillSize<SIZE, B> {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
_blob: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<const SIZE: usize, B: Blob> BlobSelect for FillSize<SIZE, B> {
|
||||
type Blob = B;
|
||||
|
||||
fn select_blob_from<'i, I: Iterator<Item = Self::Blob> + 'i>(
|
||||
&self,
|
||||
blobs: I,
|
||||
) -> Box<dyn Iterator<Item = Self::Blob> + 'i> {
|
||||
utils::select::select_from_till_fill_size::<SIZE, Self::Blob>(
|
||||
|blob| blob.as_bytes().len(),
|
||||
blobs,
|
||||
)
|
||||
}
|
||||
}
|
|
@ -5,5 +5,6 @@ pub mod da;
|
|||
pub mod fountain;
|
||||
pub mod staking;
|
||||
pub mod tx;
|
||||
pub mod utils;
|
||||
pub mod vote;
|
||||
pub mod wire;
|
||||
|
|
|
@ -7,6 +7,7 @@ use bytes::Bytes;
|
|||
pub mod carnot;
|
||||
#[cfg(feature = "mock")]
|
||||
pub mod mock;
|
||||
pub mod select;
|
||||
|
||||
pub type TransactionHasher<T> = fn(&T) -> <T as Transaction>::Hash;
|
||||
|
||||
|
@ -18,3 +19,11 @@ pub trait Transaction {
|
|||
}
|
||||
fn as_bytes(&self) -> Bytes;
|
||||
}
|
||||
|
||||
pub trait TxSelect {
|
||||
type Tx: Transaction;
|
||||
fn select_tx_from<'i, I: Iterator<Item = Self::Tx> + 'i>(
|
||||
&self,
|
||||
txs: I,
|
||||
) -> Box<dyn Iterator<Item = Self::Tx> + 'i>;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
// std
|
||||
use std::marker::PhantomData;
|
||||
// crates
|
||||
|
||||
// internal
|
||||
use crate::tx::{Transaction, TxSelect};
|
||||
use crate::utils;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct FillSize<const SIZE: usize, Tx> {
|
||||
_tx: PhantomData<Tx>,
|
||||
}
|
||||
|
||||
impl<const SIZE: usize, Tx> FillSize<SIZE, Tx> {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
_tx: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<const SIZE: usize, Tx: Transaction> TxSelect for FillSize<SIZE, Tx> {
|
||||
type Tx = Tx;
|
||||
|
||||
fn select_tx_from<'i, I: Iterator<Item = Self::Tx> + 'i>(
|
||||
&self,
|
||||
txs: I,
|
||||
) -> Box<dyn Iterator<Item = Self::Tx> + 'i> {
|
||||
utils::select::select_from_till_fill_size::<SIZE, Self::Tx>(|tx| tx.as_bytes().len(), txs)
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
pub mod select;
|
|
@ -0,0 +1,10 @@
|
|||
pub fn select_from_till_fill_size<'i, const SIZE: usize, T>(
|
||||
mut measure: impl FnMut(&T) -> usize + 'i,
|
||||
items: impl Iterator<Item = T> + 'i,
|
||||
) -> Box<dyn Iterator<Item = T> + 'i> {
|
||||
let mut current_size = 0usize;
|
||||
Box::new(items.take_while(move |item: &T| {
|
||||
current_size += measure(item);
|
||||
current_size <= SIZE
|
||||
}))
|
||||
}
|
|
@ -594,7 +594,7 @@ where
|
|||
match rx.await {
|
||||
Ok(txs) => {
|
||||
let beacon = RandomBeaconState::generate_happy(qc.view(), &private_key);
|
||||
let proposal = Block::new(qc.view().next(), qc, txs, id, beacon);
|
||||
let proposal = Block::new(qc.view().next(), qc, txs, [].into_iter(), id, beacon);
|
||||
output = Some(Output::BroadcastProposal { proposal });
|
||||
}
|
||||
Err(e) => tracing::error!("Could not fetch txs {e}"),
|
||||
|
|
|
@ -110,6 +110,7 @@ impl SimulationApp {
|
|||
View::new(0),
|
||||
Block::genesis().parent_qc,
|
||||
[].into_iter(),
|
||||
[].into_iter(),
|
||||
leader,
|
||||
RandomBeaconState::Sad {
|
||||
entropy: Box::new([0; 32]),
|
||||
|
|
|
@ -269,6 +269,7 @@ impl<
|
|||
qc.view().next(),
|
||||
qc.clone(),
|
||||
[].into_iter(),
|
||||
[].into_iter(),
|
||||
self.id,
|
||||
RandomBeaconState::generate_happy(qc.view().next(), &self.random_beacon_pk),
|
||||
),
|
||||
|
|
Loading…
Reference in New Issue