Skip to content

Commit 65e8e6b

Browse files
committed
Provide suffix txs in initial template
1 parent 817fd28 commit 65e8e6b

2 files changed

Lines changed: 105 additions & 44 deletions

File tree

lib/cusf_block_producer.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,9 @@ where typewit::const_marker::Bool<COINBASE_TXN>: CoinbaseTxn
4747
pub coinbase_txouts: <typewit::const_marker::Bool<COINBASE_TXN> as CoinbaseTxn>::CoinbaseTxouts,
4848
/// Prefix txs, with absolute fee
4949
pub prefix_txs: Vec<(Transaction, bitcoin::Amount)>,
50-
/// prefix txs do not need to be included here
50+
/// Suffix txs, with absolute fee
51+
pub suffix_txs: Vec<(Transaction, bitcoin::Amount)>,
52+
/// prefix/suffix txs do not need to be included here
5153
pub exclude_mempool_txs: HashSet<Txid>,
5254
}
5355

@@ -170,7 +172,7 @@ where
170172
}
171173
typewit::const_marker::BoolWit::False(_) => (),
172174
}
173-
template.prefix_txs.extend(suffix_left.txs.iter().cloned());
175+
template.suffix_txs.extend(suffix_left.txs.iter().cloned());
174176
let suffix_right = self
175177
.1
176178
.block_template_suffix(

lib/server.rs

Lines changed: 101 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,33 @@ where
169169
)
170170
}
171171

172+
#[repr(transparent)]
173+
struct DisplayList<'a, T>(&'a T);
174+
175+
impl<'a, T> std::fmt::Display for DisplayList<'a, T>
176+
where
177+
&'a T: IntoIterator,
178+
<&'a T as IntoIterator>::Item: std::fmt::Display,
179+
{
180+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
181+
#[repr(transparent)]
182+
struct DebugDisplay<T>(T);
183+
184+
impl<T> std::fmt::Debug for DebugDisplay<T>
185+
where
186+
T: std::fmt::Display,
187+
{
188+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
189+
std::fmt::Display::fmt(&self.0, f)
190+
}
191+
}
192+
193+
f.debug_list()
194+
.entries(self.0.into_iter().map(DebugDisplay))
195+
.finish()
196+
}
197+
}
198+
172199
/// Compute the block reward for the specified height
173200
fn get_block_reward(height: u32, fees: Amount, network: Network) -> Amount {
174201
let subsidy_sats = 50 * Amount::ONE_BTC.to_sat();
@@ -336,6 +363,8 @@ where
336363
MempoolRemove(#[from] crate::mempool::MempoolRemoveError),
337364
#[error(transparent)]
338365
SuffixTxs(BP::SuffixTxsError),
366+
#[error("weight overflow")]
367+
WeightOverflow,
339368
}
340369

341370
// select block txs, and coinbase txouts if coinbasetxn is set
@@ -368,16 +397,16 @@ async fn block_txs<const COINBASE_TXN: bool, BP>(
368397
.iter()
369398
.map(|(tx, _fee)| tx.compute_txid())
370399
.collect();
400+
let suffix_txids: hashlink::LinkedHashSet<Txid> = initial_block_template
401+
.suffix_txs
402+
.iter()
403+
.map(|(tx, _fee)| tx.compute_txid())
404+
.collect();
371405
{
372-
let prefix_txids: String = format!(
373-
"[{}]",
374-
prefix_txids
375-
.iter()
376-
.map(|txid| txid.to_string())
377-
.collect::<Vec<_>>()
378-
.join(", ")
406+
tracing::debug!(
407+
prefix_txids = %DisplayList(&prefix_txids),
408+
suffix_txids = %DisplayList(&suffix_txids),
379409
);
380-
tracing::debug!(%prefix_txids);
381410
}
382411
let mut mempool = mempool.clone();
383412
tracing::debug!("Inserting prefix txs into cloned mempool");
@@ -407,7 +436,7 @@ async fn block_txs<const COINBASE_TXN: bool, BP>(
407436
})
408437
.collect()
409438
};
410-
// Remove prefix txs
439+
// Remove prefix/excluded/suffix txs
411440
{
412441
tracing::debug!("Removing prefix txs");
413442
let _removed_txs = mempool
@@ -418,41 +447,41 @@ async fn block_txs<const COINBASE_TXN: bool, BP>(
418447
.map_err(|err| match err {
419448
either::Either::Left(err) => err,
420449
})?;
421-
{
422-
let excluded_txids: String = format!(
423-
"[{}]",
424-
initial_block_template
425-
.exclude_mempool_txs
426-
.iter()
427-
.map(|txid| txid.to_string())
428-
.collect::<Vec<_>>()
429-
.join(", ")
430-
);
431-
tracing::debug!(%excluded_txids, "Removing excluded txs");
432-
}
450+
tracing::debug!("Removing prefix txs");
451+
tracing::debug!(
452+
excluded_txids = %DisplayList(
453+
&initial_block_template.exclude_mempool_txs
454+
),
455+
"Removing excluded/suffix txs"
456+
);
433457
let _removed_txs = mempool
434458
.try_filter(true, |tx, _| {
435459
let txid = tx.compute_txid();
436-
Result::<_, Infallible>::Ok(
437-
!initial_block_template.exclude_mempool_txs.contains(&txid),
438-
)
460+
let excluded =
461+
initial_block_template.exclude_mempool_txs.contains(&txid)
462+
|| suffix_txids.contains(&txid);
463+
Result::<_, Infallible>::Ok(!excluded)
439464
})
440465
.map_err(|err| match err {
441466
either::Either::Left(err) => err,
442467
})?;
443468
}
444469
tracing::debug!("Proposing txs for inclusion in block");
445470
let coinbase_txouts_weight = {
446-
let txouts_weight = match typewit::MakeTypeWitness::MAKE {
471+
let mut txouts_weight = Weight::ZERO;
472+
match typewit::MakeTypeWitness::MAKE {
447473
typewit::const_marker::BoolWit::True(wit) => {
448474
let wit = wit.map(cusf_block_producer::CoinbaseTxouts);
449-
wit.in_ref()
475+
for tx_out in wit
476+
.in_ref()
450477
.to_right(&initial_block_template.coinbase_txouts)
451-
.iter()
452-
.map(|tx_out| tx_out.weight())
453-
.sum()
478+
{
479+
txouts_weight = txouts_weight
480+
.checked_add(tx_out.weight())
481+
.ok_or(BuildBlockError::WeightOverflow)?;
482+
}
454483
}
455-
typewit::const_marker::BoolWit::False(_) => Weight::ZERO,
484+
typewit::const_marker::BoolWit::False(_) => (),
456485
};
457486
const COINBASE_WITNESS_COMMITMENT_TXOUT_WEIGHT: Weight = {
458487
let weight_wu = Weight::from_non_witness_data_size(Amount::SIZE as u64).to_wu()
@@ -461,20 +490,39 @@ async fn block_txs<const COINBASE_TXN: bool, BP>(
461490
Weight::from_wu(weight_wu)
462491
};
463492
Weight::from_wu(
464-
txouts_weight.to_wu()
465-
+ COINBASE_WITNESS_COMMITMENT_TXOUT_WEIGHT.to_wu(),
493+
txouts_weight
494+
.to_wu()
495+
.checked_add(COINBASE_WITNESS_COMMITMENT_TXOUT_WEIGHT.to_wu())
496+
.ok_or(BuildBlockError::WeightOverflow)?,
466497
)
467498
};
468-
let prefix_txs_weight = initial_block_template
469-
.prefix_txs
470-
.iter()
471-
.map(|(tx, _)| tx.weight())
472-
.sum();
473-
let initial_block_template_weight =
474-
coinbase_txouts_weight + prefix_txs_weight;
475-
let mempool_txs = mempool.propose_txs(Some(
476-
mempool::MAX_USABLE_BLOCK_WEIGHT - initial_block_template_weight,
477-
))?;
499+
let prefix_txs_weight = {
500+
let mut weight = Weight::ZERO;
501+
for (tx, _) in &initial_block_template.prefix_txs {
502+
weight = weight
503+
.checked_add(tx.weight())
504+
.ok_or(BuildBlockError::WeightOverflow)?;
505+
}
506+
weight
507+
};
508+
let suffix_txs_weight = {
509+
let mut weight = Weight::ZERO;
510+
for (tx, _) in &initial_block_template.suffix_txs {
511+
weight = weight
512+
.checked_add(tx.weight())
513+
.ok_or(BuildBlockError::WeightOverflow)?;
514+
}
515+
weight
516+
};
517+
let initial_block_template_weight = coinbase_txouts_weight
518+
.checked_add(prefix_txs_weight)
519+
.and_then(|weight| weight.checked_add(suffix_txs_weight))
520+
.ok_or(BuildBlockError::WeightOverflow)?;
521+
let mempool_txs = mempool.propose_txs(Some(Weight::from_wu(
522+
mempool::MAX_USABLE_BLOCK_WEIGHT
523+
.to_wu()
524+
.saturating_sub(initial_block_template_weight.to_wu()),
525+
)))?;
478526
{
479527
let proposed_txids: String = {
480528
use std::fmt::Write;
@@ -531,6 +579,17 @@ async fn block_txs<const COINBASE_TXN: bool, BP>(
531579
typewit::const_marker::BoolWit::False(_) => (),
532580
}
533581
res_txs.extend(mempool_txs);
582+
res_txs.extend(initial_block_template.suffix_txs.iter().map(
583+
|(tx, fee)| BlockTemplateTransaction {
584+
data: bitcoin::consensus::serialize(tx),
585+
txid: tx.compute_txid(),
586+
hash: tx.compute_wtxid(),
587+
depends: Vec::new(),
588+
fee: (*fee).try_into().unwrap(),
589+
sigops: None,
590+
weight: tx.weight().to_wu(),
591+
},
592+
));
534593
res_txs.extend(template_suffix.txs.iter().map(|(tx, fee)| {
535594
BlockTemplateTransaction {
536595
data: bitcoin::consensus::serialize(tx),

0 commit comments

Comments
 (0)