implement fix past fees RFC with fee shift since genesis (#3629)

This commit is contained in:
John Tromp 2021-05-11 17:39:09 +02:00 committed by GitHub
parent a9f1dd7bcd
commit f51b6e1376
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 133 additions and 203 deletions

View file

@ -13,7 +13,6 @@
// limitations under the License. // limitations under the License.
use crate::chain; use crate::chain;
use crate::core::consensus::YEAR_HEIGHT;
use crate::core::core::hash::Hashed; use crate::core::core::hash::Hashed;
use crate::core::core::merkle_proof::MerkleProof; use crate::core::core::merkle_proof::MerkleProof;
use crate::core::core::{FeeFields, KernelFeatures, TxKernel}; use crate::core::core::{FeeFields, KernelFeatures, TxKernel};
@ -518,13 +517,10 @@ impl TxKernelPrintable {
relative_height, relative_height,
} => (fee, relative_height.into()), } => (fee, relative_height.into()),
}; };
let height = 2 * YEAR_HEIGHT; // print as if post-HF4
let fee = fee_fields.fee(height);
let fee_shift: u8 = fee_fields.fee_shift(height);
TxKernelPrintable { TxKernelPrintable {
features, features,
fee_shift, fee_shift: fee_fields.fee_shift(),
fee, fee: fee_fields.fee(),
lock_height, lock_height,
excess: k.excess.to_hex(), excess: k.excess.to_hex(),
excess_sig: (&k.excess_sig.to_raw_data()[..]).to_hex(), excess_sig: (&k.excess_sig.to_raw_data()[..]).to_hex(),

View file

@ -33,7 +33,7 @@ where
{ {
let prev = chain.head_header().unwrap(); let prev = chain.head_header().unwrap();
let next_header_info = consensus::next_difficulty(1, chain.difficulty_iter().unwrap()); let next_header_info = consensus::next_difficulty(1, chain.difficulty_iter().unwrap());
let fee = txs.iter().map(|x| x.fee(prev.height + 1)).sum(); let fee = txs.iter().map(|x| x.fee()).sum();
let reward = let reward =
reward::output(keychain, &ProofBuilder::new(keychain), key_id, fee, false).unwrap(); reward::output(keychain, &ProofBuilder::new(keychain), key_id, fee, false).unwrap();

View file

@ -1030,8 +1030,7 @@ where
let proof_size = global::proofsize(); let proof_size = global::proofsize();
let key_id = ExtKeychainPath::new(1, key_idx, 0, 0, 0).to_identifier(); let key_id = ExtKeychainPath::new(1, key_idx, 0, 0, 0).to_identifier();
let height = prev.height + 1; let fees = txs.iter().map(|tx| tx.fee()).sum();
let fees = txs.iter().map(|tx| tx.fee(height)).sum();
let reward = let reward =
libtx::reward::output(kc, &libtx::ProofBuilder::new(kc), &key_id, fees, false).unwrap(); libtx::reward::output(kc, &libtx::ProofBuilder::new(kc), &key_id, fees, false).unwrap();
let mut b = match core::core::Block::new(prev, txs, Difficulty::from_num(diff), reward) { let mut b = match core::core::Block::new(prev, txs, Difficulty::from_num(diff), reward) {

View file

@ -54,7 +54,7 @@ where
{ {
let next_header_info = let next_header_info =
consensus::next_difficulty(prev.height, chain.difficulty_iter().unwrap()); consensus::next_difficulty(prev.height, chain.difficulty_iter().unwrap());
let fee = txs.iter().map(|x| x.fee(prev.height + 1)).sum(); let fee = txs.iter().map(|x| x.fee()).sum();
let reward = let reward =
reward::output(keychain, &ProofBuilder::new(keychain), key_id, fee, false).unwrap(); reward::output(keychain, &ProofBuilder::new(keychain), key_id, fee, false).unwrap();

View file

@ -40,7 +40,7 @@ where
let prev = chain.head_header().unwrap(); let prev = chain.head_header().unwrap();
let next_height = prev.height + 1; let next_height = prev.height + 1;
let next_header_info = consensus::next_difficulty(1, chain.difficulty_iter()?); let next_header_info = consensus::next_difficulty(1, chain.difficulty_iter()?);
let fee = txs.iter().map(|x| x.fee(next_height)).sum(); let fee = txs.iter().map(|x| x.fee()).sum();
let key_id = ExtKeychainPath::new(1, next_height as u32, 0, 0, 0).to_identifier(); let key_id = ExtKeychainPath::new(1, next_height as u32, 0, 0, 0).to_identifier();
let reward = let reward =
reward::output(keychain, &ProofBuilder::new(keychain), &key_id, fee, false).unwrap(); reward::output(keychain, &ProofBuilder::new(keychain), &key_id, fee, false).unwrap();
@ -126,9 +126,8 @@ fn process_block_cut_through() -> Result<(), chain::Error> {
.any(|output| output.commitment() == commit)); .any(|output| output.commitment() == commit));
// Transaction is invalid due to cut-through. // Transaction is invalid due to cut-through.
let height = 7;
assert_eq!( assert_eq!(
tx.validate(Weighting::AsTransaction, height), tx.validate(Weighting::AsTransaction),
Err(transaction::Error::CutThrough), Err(transaction::Error::CutThrough),
); );

View file

@ -106,7 +106,7 @@ fn test_coinbase_maturity() {
.unwrap(); .unwrap();
let txs = &[coinbase_txn.clone()]; let txs = &[coinbase_txn.clone()];
let fees = txs.iter().map(|tx| tx.fee(prev.height + 1)).sum(); let fees = txs.iter().map(|tx| tx.fee()).sum();
let reward = libtx::reward::output(&keychain, &builder, &key_id3, fees, false).unwrap(); let reward = libtx::reward::output(&keychain, &builder, &key_id3, fees, false).unwrap();
let next_header_info = let next_header_info =
consensus::next_difficulty(prev.height + 1, chain.difficulty_iter().unwrap()); consensus::next_difficulty(prev.height + 1, chain.difficulty_iter().unwrap());
@ -192,7 +192,7 @@ fn test_coinbase_maturity() {
.unwrap(); .unwrap();
let txs = &[coinbase_txn.clone()]; let txs = &[coinbase_txn.clone()];
let fees = txs.iter().map(|tx| tx.fee(prev.height + 1)).sum(); let fees = txs.iter().map(|tx| tx.fee()).sum();
let reward = libtx::reward::output(&keychain, &builder, &key_id3, fees, false).unwrap(); let reward = libtx::reward::output(&keychain, &builder, &key_id3, fees, false).unwrap();
let next_header_info = let next_header_info =
consensus::next_difficulty(prev.height + 1, chain.difficulty_iter().unwrap()); consensus::next_difficulty(prev.height + 1, chain.difficulty_iter().unwrap());
@ -261,7 +261,7 @@ fn test_coinbase_maturity() {
.unwrap(); .unwrap();
let txs = &[coinbase_txn]; let txs = &[coinbase_txn];
let fees = txs.iter().map(|tx| tx.fee(prev.height + 1)).sum(); let fees = txs.iter().map(|tx| tx.fee()).sum();
let next_header_info = let next_header_info =
consensus::next_difficulty(prev.height + 1, chain.difficulty_iter().unwrap()); consensus::next_difficulty(prev.height + 1, chain.difficulty_iter().unwrap());
let reward = libtx::reward::output(&keychain, &builder, &key_id4, fees, false).unwrap(); let reward = libtx::reward::output(&keychain, &builder, &key_id4, fees, false).unwrap();

View file

@ -694,7 +694,7 @@ impl Block {
/// Sum of all fees (inputs less outputs) in the block /// Sum of all fees (inputs less outputs) in the block
pub fn total_fees(&self) -> u64 { pub fn total_fees(&self) -> u64 {
self.body.fee(self.header.height) self.body.fee()
} }
/// "Lightweight" validation that we can perform quickly during read/deserialization. /// "Lightweight" validation that we can perform quickly during read/deserialization.

View file

@ -14,7 +14,6 @@
//! Transactions //! Transactions
use crate::core::block::HeaderVersion;
use crate::core::hash::{DefaultHashable, Hashed}; use crate::core::hash::{DefaultHashable, Hashed};
use crate::core::{committed, Committed}; use crate::core::{committed, Committed};
use crate::libtx::{aggsig, secp_ser}; use crate::libtx::{aggsig, secp_ser};
@ -161,21 +160,13 @@ impl FeeFields {
} }
/// Extract fee_shift field /// Extract fee_shift field
pub fn fee_shift(&self, height: u64) -> u8 { pub fn fee_shift(&self) -> u8 {
if consensus::header_version(height) < HeaderVersion(5) { ((self.0 >> FeeFields::FEE_BITS) & FeeFields::FEE_SHIFT_MASK) as u8
0
} else {
((self.0 >> FeeFields::FEE_BITS) & FeeFields::FEE_SHIFT_MASK) as u8
}
} }
/// Extract fee field /// Extract fee field
pub fn fee(&self, height: u64) -> u64 { pub fn fee(&self) -> u64 {
if consensus::header_version(height) < HeaderVersion(5) { self.0 & FeeFields::FEE_MASK
self.0
} else {
self.0 & FeeFields::FEE_MASK
}
} }
/// Turn a zero `FeeField` into a `None`, any other value into a `Some`. /// Turn a zero `FeeField` into a `None`, any other value into a `Some`.
@ -1031,7 +1022,7 @@ impl TransactionBody {
} }
/// Total fee for a TransactionBody is the sum of fees of all fee carrying kernels. /// Total fee for a TransactionBody is the sum of fees of all fee carrying kernels.
pub fn fee(&self, height: u64) -> u64 { pub fn fee(&self) -> u64 {
self.kernels self.kernels
.iter() .iter()
.filter_map(|k| match k.features { .filter_map(|k| match k.features {
@ -1040,13 +1031,11 @@ impl TransactionBody {
KernelFeatures::HeightLocked { fee, .. } => Some(fee), KernelFeatures::HeightLocked { fee, .. } => Some(fee),
KernelFeatures::NoRecentDuplicate { fee, .. } => Some(fee), KernelFeatures::NoRecentDuplicate { fee, .. } => Some(fee),
}) })
.fold(0, |acc, fee_fields| { .fold(0, |acc, fee_fields| acc.saturating_add(fee_fields.fee()))
acc.saturating_add(fee_fields.fee(height))
})
} }
/// fee_shift for a TransactionBody is the maximum of fee_shifts of all fee carrying kernels. /// fee_shift for a TransactionBody is the maximum of fee_shifts of all fee carrying kernels.
pub fn fee_shift(&self, height: u64) -> u8 { pub fn fee_shift(&self) -> u8 {
self.kernels self.kernels
.iter() .iter()
.filter_map(|k| match k.features { .filter_map(|k| match k.features {
@ -1055,24 +1044,24 @@ impl TransactionBody {
KernelFeatures::HeightLocked { fee, .. } => Some(fee), KernelFeatures::HeightLocked { fee, .. } => Some(fee),
KernelFeatures::NoRecentDuplicate { fee, .. } => Some(fee), KernelFeatures::NoRecentDuplicate { fee, .. } => Some(fee),
}) })
.fold(0, |acc, fee_fields| max(acc, fee_fields.fee_shift(height))) .fold(0, |acc, fee_fields| max(acc, fee_fields.fee_shift()))
} }
/// Shifted fee for a TransactionBody is the sum of fees shifted right by the maximum fee_shift /// Shifted fee for a TransactionBody is the sum of fees shifted right by the maximum fee_shift
/// this is used to determine whether a tx can be relayed or accepted in a mempool /// this is used to determine whether a tx can be relayed or accepted in a mempool
/// where transactions can specify a higher block-inclusion priority as a positive shift up to 15 /// where transactions can specify a higher block-inclusion priority as a positive shift up to 15
/// but are required to overpay the minimum required fees by a factor of 2^priority /// but are required to overpay the minimum required fees by a factor of 2^priority
pub fn shifted_fee(&self, height: u64) -> u64 { pub fn shifted_fee(&self) -> u64 {
self.fee(height) >> self.fee_shift(height) self.fee() >> self.fee_shift()
} }
/// aggregate fee_fields from all appropriate kernels in TransactionBody into one, if possible /// aggregate fee_fields from all appropriate kernels in TransactionBody into one, if possible
pub fn aggregate_fee_fields(&self, height: u64) -> Result<FeeFields, Error> { pub fn aggregate_fee_fields(&self) -> Result<FeeFields, Error> {
FeeFields::new(self.fee_shift(height) as u64, self.fee(height)) FeeFields::new(self.fee_shift() as u64, self.fee())
} }
fn overage(&self, height: u64) -> i64 { fn overage(&self) -> i64 {
self.fee(height) as i64 self.fee() as i64
} }
/// Calculate weight of transaction using block weighing /// Calculate weight of transaction using block weighing
@ -1413,23 +1402,23 @@ impl Transaction {
} }
/// Total fee for a transaction is the sum of fees of all kernels. /// Total fee for a transaction is the sum of fees of all kernels.
pub fn fee(&self, height: u64) -> u64 { pub fn fee(&self) -> u64 {
self.body.fee(height) self.body.fee()
} }
/// Shifted fee for a transaction is the sum of fees of all kernels shifted right by the maximum fee shift /// Shifted fee for a transaction is the sum of fees of all kernels shifted right by the maximum fee shift
pub fn shifted_fee(&self, height: u64) -> u64 { pub fn shifted_fee(&self) -> u64 {
self.body.shifted_fee(height) self.body.shifted_fee()
} }
/// aggregate fee_fields from all appropriate kernels in transaction into one /// aggregate fee_fields from all appropriate kernels in transaction into one
pub fn aggregate_fee_fields(&self, height: u64) -> Result<FeeFields, Error> { pub fn aggregate_fee_fields(&self) -> Result<FeeFields, Error> {
self.body.aggregate_fee_fields(height) self.body.aggregate_fee_fields()
} }
/// Total overage across all kernels. /// Total overage across all kernels.
pub fn overage(&self, height: u64) -> i64 { pub fn overage(&self) -> i64 {
self.body.overage(height) self.body.overage()
} }
/// Lock height of a transaction is the max lock height of the kernels. /// Lock height of a transaction is the max lock height of the kernels.
@ -1451,17 +1440,17 @@ impl Transaction {
/// Validates all relevant parts of a fully built transaction. Checks the /// Validates all relevant parts of a fully built transaction. Checks the
/// excess value against the signature as well as range proofs for each /// excess value against the signature as well as range proofs for each
/// output. /// output.
pub fn validate(&self, weighting: Weighting, height: u64) -> Result<(), Error> { pub fn validate(&self, weighting: Weighting) -> Result<(), Error> {
self.body.verify_features()?; self.body.verify_features()?;
self.body.validate(weighting)?; self.body.validate(weighting)?;
self.verify_kernel_sums(self.overage(height), self.offset.clone())?; self.verify_kernel_sums(self.overage(), self.offset.clone())?;
Ok(()) Ok(())
} }
/// Can be used to compare txs by their fee/weight ratio, aka feerate. /// Can be used to compare txs by their fee/weight ratio, aka feerate.
/// Don't use these values for anything else though due to precision multiplier. /// Don't use these values for anything else though due to precision multiplier.
pub fn fee_rate(&self, height: u64) -> u64 { pub fn fee_rate(&self) -> u64 {
self.fee(height) / self.weight() as u64 self.fee() / self.weight() as u64
} }
/// Calculate transaction weight /// Calculate transaction weight
@ -1470,16 +1459,8 @@ impl Transaction {
} }
/// Transaction minimum acceptable fee /// Transaction minimum acceptable fee
pub fn accept_fee(&self, height: u64) -> u64 { pub fn accept_fee(&self) -> u64 {
if consensus::header_version(height) < HeaderVersion(5) { self.weight() * global::get_accept_fee_base()
Transaction::old_weight_by_iok(
self.body.inputs.len() as u64,
self.body.outputs.len() as u64,
self.body.kernels.len() as u64,
) * consensus::MILLI_GRIN
} else {
self.weight() * global::get_accept_fee_base()
}
} }
/// Old weight definition for pool acceptance /// Old weight definition for pool acceptance

View file

@ -276,8 +276,7 @@ mod test {
) )
.unwrap(); .unwrap();
let height = 42; // arbitrary tx.validate(Weighting::AsTransaction).unwrap();
tx.validate(Weighting::AsTransaction, height).unwrap();
} }
#[test] #[test]
@ -297,8 +296,7 @@ mod test {
) )
.unwrap(); .unwrap();
let height = 42; // arbitrary tx.validate(Weighting::AsTransaction).unwrap();
tx.validate(Weighting::AsTransaction, height).unwrap();
} }
#[test] #[test]
@ -317,7 +315,6 @@ mod test {
) )
.unwrap(); .unwrap();
let height = 42; // arbitrary tx.validate(Weighting::AsTransaction).unwrap();
tx.validate(Weighting::AsTransaction, height).unwrap();
} }
} }

View file

@ -41,6 +41,6 @@ pub fn tx_fee(input_len: usize, output_len: usize, kernel_len: usize) -> u64 {
} }
/// Transaction fee calculation given transaction /// Transaction fee calculation given transaction
pub fn accept_fee(tx: Transaction, height: u64) -> u64 { pub fn accept_fee(tx: Transaction) -> u64 {
tx.accept_fee(height) tx.accept_fee()
} }

View file

@ -120,10 +120,7 @@ where
K: Keychain, K: Keychain,
B: ProofBuild, B: ProofBuild,
{ {
let fees = txs let fees = txs.iter().map(|tx| tx.fee()).sum();
.iter()
.map(|tx| tx.fee(previous_header.height + 1))
.sum();
let reward_output = reward::output(keychain, builder, &key_id, fees, false).unwrap(); let reward_output = reward::output(keychain, builder, &key_id, fees, false).unwrap();
Block::new(&previous_header, txs, Difficulty::min_dma(), reward_output).unwrap() Block::new(&previous_header, txs, Difficulty::min_dma(), reward_output).unwrap()
} }

View file

@ -94,8 +94,7 @@ fn simple_tx_ser_deser() {
let mut vec = Vec::new(); let mut vec = Vec::new();
ser::serialize_default(&mut vec, &tx).expect("serialization failed"); ser::serialize_default(&mut vec, &tx).expect("serialization failed");
let dtx: Transaction = ser::deserialize_default(&mut &vec[..]).unwrap(); let dtx: Transaction = ser::deserialize_default(&mut &vec[..]).unwrap();
let height = 42; // arbitrary assert_eq!(dtx.fee(), 2);
assert_eq!(dtx.fee(height), 2);
assert_eq!(dtx.inputs().len(), 2); assert_eq!(dtx.inputs().len(), 2);
assert_eq!(dtx.outputs().len(), 1); assert_eq!(dtx.outputs().len(), 1);
assert_eq!(tx.hash(), dtx.hash()); assert_eq!(tx.hash(), dtx.hash());
@ -157,8 +156,7 @@ fn build_tx_kernel() {
.unwrap(); .unwrap();
// check the tx is valid // check the tx is valid
let height = 42; // arbitrary tx.validate(Weighting::AsTransaction).unwrap();
tx.validate(Weighting::AsTransaction, height).unwrap();
// check the kernel is also itself valid // check the kernel is also itself valid
assert_eq!(tx.kernels().len(), 1); assert_eq!(tx.kernels().len(), 1);
@ -166,7 +164,7 @@ fn build_tx_kernel() {
kern.verify().unwrap(); kern.verify().unwrap();
assert_eq!(kern.features, KernelFeatures::Plain { fee: 2.into() }); assert_eq!(kern.features, KernelFeatures::Plain { fee: 2.into() });
assert_eq!(2, tx.fee(height)); assert_eq!(2, tx.fee());
} }
// Proof of concept demonstrating we can build two transactions that share // Proof of concept demonstrating we can build two transactions that share
@ -220,10 +218,9 @@ fn build_two_half_kernels() {
) )
.unwrap(); .unwrap();
let height = 42; // arbitrary assert_eq!(tx1.validate(Weighting::AsTransaction), Ok(()),);
assert_eq!(tx1.validate(Weighting::AsTransaction, height), Ok(()),);
assert_eq!(tx2.validate(Weighting::AsTransaction, height), Ok(()),); assert_eq!(tx2.validate(Weighting::AsTransaction), Ok(()),);
// The transactions share an identical kernel. // The transactions share an identical kernel.
assert_eq!(tx1.kernels()[0], tx2.kernels()[0]); assert_eq!(tx1.kernels()[0], tx2.kernels()[0]);
@ -247,14 +244,14 @@ fn transaction_cut_through() {
let tx1 = tx1i2o(); let tx1 = tx1i2o();
let tx2 = tx2i1o(); let tx2 = tx2i1o();
let height = 42; // arbitrary
assert!(tx1.validate(Weighting::AsTransaction, height).is_ok()); assert!(tx1.validate(Weighting::AsTransaction).is_ok());
assert!(tx2.validate(Weighting::AsTransaction, height).is_ok()); assert!(tx2.validate(Weighting::AsTransaction).is_ok());
// now build a "cut_through" tx from tx1 and tx2 // now build a "cut_through" tx from tx1 and tx2
let tx3 = aggregate(&[tx1, tx2]).unwrap(); let tx3 = aggregate(&[tx1, tx2]).unwrap();
assert!(tx3.validate(Weighting::AsTransaction, height).is_ok()); assert!(tx3.validate(Weighting::AsTransaction).is_ok());
} }
// Attempt to deaggregate a multi-kernel transaction in a different way // Attempt to deaggregate a multi-kernel transaction in a different way
@ -266,30 +263,30 @@ fn multi_kernel_transaction_deaggregation() {
let tx3 = tx1i1o(); let tx3 = tx1i1o();
let tx4 = tx1i1o(); let tx4 = tx1i1o();
let height = 42; // arbitrary assert!(tx1.validate(Weighting::AsTransaction).is_ok());
assert!(tx1.validate(Weighting::AsTransaction, height).is_ok()); assert!(tx2.validate(Weighting::AsTransaction).is_ok());
assert!(tx2.validate(Weighting::AsTransaction, height).is_ok()); assert!(tx3.validate(Weighting::AsTransaction).is_ok());
assert!(tx3.validate(Weighting::AsTransaction, height).is_ok()); assert!(tx4.validate(Weighting::AsTransaction).is_ok());
assert!(tx4.validate(Weighting::AsTransaction, height).is_ok());
let tx1234 = aggregate(&[tx1.clone(), tx2.clone(), tx3.clone(), tx4.clone()]).unwrap(); let tx1234 = aggregate(&[tx1.clone(), tx2.clone(), tx3.clone(), tx4.clone()]).unwrap();
let tx12 = aggregate(&[tx1, tx2]).unwrap(); let tx12 = aggregate(&[tx1, tx2]).unwrap();
let tx34 = aggregate(&[tx3, tx4]).unwrap(); let tx34 = aggregate(&[tx3, tx4]).unwrap();
assert!(tx1234.validate(Weighting::AsTransaction, height).is_ok()); assert!(tx1234.validate(Weighting::AsTransaction).is_ok());
assert!(tx12.validate(Weighting::AsTransaction, height).is_ok()); assert!(tx12.validate(Weighting::AsTransaction).is_ok());
assert!(tx34.validate(Weighting::AsTransaction, height).is_ok()); assert!(tx34.validate(Weighting::AsTransaction).is_ok());
let deaggregated_tx34 = deaggregate(tx1234.clone(), &[tx12.clone()]).unwrap(); let deaggregated_tx34 = deaggregate(tx1234.clone(), &[tx12.clone()]).unwrap();
assert!(deaggregated_tx34 assert!(deaggregated_tx34
.validate(Weighting::AsTransaction, height) .validate(Weighting::AsTransaction)
.is_ok()); .is_ok());
assert_eq!(tx34, deaggregated_tx34); assert_eq!(tx34, deaggregated_tx34);
let deaggregated_tx12 = deaggregate(tx1234, &[tx34]).unwrap(); let deaggregated_tx12 = deaggregate(tx1234, &[tx34]).unwrap();
assert!(deaggregated_tx12 assert!(deaggregated_tx12
.validate(Weighting::AsTransaction, height) .validate(Weighting::AsTransaction)
.is_ok()); .is_ok());
assert_eq!(tx12, deaggregated_tx12); assert_eq!(tx12, deaggregated_tx12);
} }
@ -301,20 +298,19 @@ fn multi_kernel_transaction_deaggregation_2() {
let tx2 = tx1i1o(); let tx2 = tx1i1o();
let tx3 = tx1i1o(); let tx3 = tx1i1o();
let height = 42; // arbitrary assert!(tx1.validate(Weighting::AsTransaction).is_ok());
assert!(tx1.validate(Weighting::AsTransaction, height).is_ok()); assert!(tx2.validate(Weighting::AsTransaction).is_ok());
assert!(tx2.validate(Weighting::AsTransaction, height).is_ok()); assert!(tx3.validate(Weighting::AsTransaction).is_ok());
assert!(tx3.validate(Weighting::AsTransaction, height).is_ok());
let tx123 = aggregate(&[tx1.clone(), tx2.clone(), tx3.clone()]).unwrap(); let tx123 = aggregate(&[tx1.clone(), tx2.clone(), tx3.clone()]).unwrap();
let tx12 = aggregate(&[tx1, tx2]).unwrap(); let tx12 = aggregate(&[tx1, tx2]).unwrap();
assert!(tx123.validate(Weighting::AsTransaction, height).is_ok()); assert!(tx123.validate(Weighting::AsTransaction).is_ok());
assert!(tx12.validate(Weighting::AsTransaction, height).is_ok()); assert!(tx12.validate(Weighting::AsTransaction).is_ok());
let deaggregated_tx3 = deaggregate(tx123, &[tx12]).unwrap(); let deaggregated_tx3 = deaggregate(tx123, &[tx12]).unwrap();
assert!(deaggregated_tx3 assert!(deaggregated_tx3
.validate(Weighting::AsTransaction, height) .validate(Weighting::AsTransaction)
.is_ok()); .is_ok());
assert_eq!(tx3, deaggregated_tx3); assert_eq!(tx3, deaggregated_tx3);
} }
@ -326,21 +322,20 @@ fn multi_kernel_transaction_deaggregation_3() {
let tx2 = tx1i1o(); let tx2 = tx1i1o();
let tx3 = tx1i1o(); let tx3 = tx1i1o();
let height = 42; // arbitrary assert!(tx1.validate(Weighting::AsTransaction).is_ok());
assert!(tx1.validate(Weighting::AsTransaction, height).is_ok()); assert!(tx2.validate(Weighting::AsTransaction).is_ok());
assert!(tx2.validate(Weighting::AsTransaction, height).is_ok()); assert!(tx3.validate(Weighting::AsTransaction).is_ok());
assert!(tx3.validate(Weighting::AsTransaction, height).is_ok());
let tx123 = aggregate(&[tx1.clone(), tx2.clone(), tx3.clone()]).unwrap(); let tx123 = aggregate(&[tx1.clone(), tx2.clone(), tx3.clone()]).unwrap();
let tx13 = aggregate(&[tx1, tx3]).unwrap(); let tx13 = aggregate(&[tx1, tx3]).unwrap();
let tx2 = aggregate(&[tx2]).unwrap(); let tx2 = aggregate(&[tx2]).unwrap();
assert!(tx123.validate(Weighting::AsTransaction, height).is_ok()); assert!(tx123.validate(Weighting::AsTransaction).is_ok());
assert!(tx2.validate(Weighting::AsTransaction, height).is_ok()); assert!(tx2.validate(Weighting::AsTransaction).is_ok());
let deaggregated_tx13 = deaggregate(tx123, &[tx2]).unwrap(); let deaggregated_tx13 = deaggregate(tx123, &[tx2]).unwrap();
assert!(deaggregated_tx13 assert!(deaggregated_tx13
.validate(Weighting::AsTransaction, height) .validate(Weighting::AsTransaction)
.is_ok()); .is_ok());
assert_eq!(tx13, deaggregated_tx13); assert_eq!(tx13, deaggregated_tx13);
} }
@ -354,12 +349,11 @@ fn multi_kernel_transaction_deaggregation_4() {
let tx4 = tx1i1o(); let tx4 = tx1i1o();
let tx5 = tx1i1o(); let tx5 = tx1i1o();
let height = 42; // arbitrary assert!(tx1.validate(Weighting::AsTransaction).is_ok());
assert!(tx1.validate(Weighting::AsTransaction, height).is_ok()); assert!(tx2.validate(Weighting::AsTransaction).is_ok());
assert!(tx2.validate(Weighting::AsTransaction, height).is_ok()); assert!(tx3.validate(Weighting::AsTransaction).is_ok());
assert!(tx3.validate(Weighting::AsTransaction, height).is_ok()); assert!(tx4.validate(Weighting::AsTransaction).is_ok());
assert!(tx4.validate(Weighting::AsTransaction, height).is_ok()); assert!(tx5.validate(Weighting::AsTransaction).is_ok());
assert!(tx5.validate(Weighting::AsTransaction, height).is_ok());
let tx12345 = aggregate(&[ let tx12345 = aggregate(&[
tx1.clone(), tx1.clone(),
@ -369,11 +363,11 @@ fn multi_kernel_transaction_deaggregation_4() {
tx5.clone(), tx5.clone(),
]) ])
.unwrap(); .unwrap();
assert!(tx12345.validate(Weighting::AsTransaction, height).is_ok()); assert!(tx12345.validate(Weighting::AsTransaction).is_ok());
let deaggregated_tx5 = deaggregate(tx12345, &[tx1, tx2, tx3, tx4]).unwrap(); let deaggregated_tx5 = deaggregate(tx12345, &[tx1, tx2, tx3, tx4]).unwrap();
assert!(deaggregated_tx5 assert!(deaggregated_tx5
.validate(Weighting::AsTransaction, height) .validate(Weighting::AsTransaction)
.is_ok()); .is_ok());
assert_eq!(tx5, deaggregated_tx5); assert_eq!(tx5, deaggregated_tx5);
} }
@ -387,12 +381,11 @@ fn multi_kernel_transaction_deaggregation_5() {
let tx4 = tx1i1o(); let tx4 = tx1i1o();
let tx5 = tx1i1o(); let tx5 = tx1i1o();
let height = 42; // arbitrary assert!(tx1.validate(Weighting::AsTransaction).is_ok());
assert!(tx1.validate(Weighting::AsTransaction, height).is_ok()); assert!(tx2.validate(Weighting::AsTransaction).is_ok());
assert!(tx2.validate(Weighting::AsTransaction, height).is_ok()); assert!(tx3.validate(Weighting::AsTransaction).is_ok());
assert!(tx3.validate(Weighting::AsTransaction, height).is_ok()); assert!(tx4.validate(Weighting::AsTransaction).is_ok());
assert!(tx4.validate(Weighting::AsTransaction, height).is_ok()); assert!(tx5.validate(Weighting::AsTransaction).is_ok());
assert!(tx5.validate(Weighting::AsTransaction, height).is_ok());
let tx12345 = aggregate(&[ let tx12345 = aggregate(&[
tx1.clone(), tx1.clone(),
@ -405,11 +398,11 @@ fn multi_kernel_transaction_deaggregation_5() {
let tx12 = aggregate(&[tx1, tx2]).unwrap(); let tx12 = aggregate(&[tx1, tx2]).unwrap();
let tx34 = aggregate(&[tx3, tx4]).unwrap(); let tx34 = aggregate(&[tx3, tx4]).unwrap();
assert!(tx12345.validate(Weighting::AsTransaction, height).is_ok()); assert!(tx12345.validate(Weighting::AsTransaction).is_ok());
let deaggregated_tx5 = deaggregate(tx12345, &[tx12, tx34]).unwrap(); let deaggregated_tx5 = deaggregate(tx12345, &[tx12, tx34]).unwrap();
assert!(deaggregated_tx5 assert!(deaggregated_tx5
.validate(Weighting::AsTransaction, height) .validate(Weighting::AsTransaction)
.is_ok()); .is_ok());
assert_eq!(tx5, deaggregated_tx5); assert_eq!(tx5, deaggregated_tx5);
} }
@ -421,26 +414,25 @@ fn basic_transaction_deaggregation() {
let tx1 = tx1i2o(); let tx1 = tx1i2o();
let tx2 = tx2i1o(); let tx2 = tx2i1o();
let height = 42; // arbitrary assert!(tx1.validate(Weighting::AsTransaction).is_ok());
assert!(tx1.validate(Weighting::AsTransaction, height).is_ok()); assert!(tx2.validate(Weighting::AsTransaction).is_ok());
assert!(tx2.validate(Weighting::AsTransaction, height).is_ok());
// now build a "cut_through" tx from tx1 and tx2 // now build a "cut_through" tx from tx1 and tx2
let tx3 = aggregate(&[tx1.clone(), tx2.clone()]).unwrap(); let tx3 = aggregate(&[tx1.clone(), tx2.clone()]).unwrap();
assert!(tx3.validate(Weighting::AsTransaction, height).is_ok()); assert!(tx3.validate(Weighting::AsTransaction).is_ok());
let deaggregated_tx1 = deaggregate(tx3.clone(), &[tx2.clone()]).unwrap(); let deaggregated_tx1 = deaggregate(tx3.clone(), &[tx2.clone()]).unwrap();
assert!(deaggregated_tx1 assert!(deaggregated_tx1
.validate(Weighting::AsTransaction, height) .validate(Weighting::AsTransaction)
.is_ok()); .is_ok());
assert_eq!(tx1, deaggregated_tx1); assert_eq!(tx1, deaggregated_tx1);
let deaggregated_tx2 = deaggregate(tx3, &[tx1]).unwrap(); let deaggregated_tx2 = deaggregate(tx3, &[tx1]).unwrap();
assert!(deaggregated_tx2 assert!(deaggregated_tx2
.validate(Weighting::AsTransaction, height) .validate(Weighting::AsTransaction)
.is_ok()); .is_ok());
assert_eq!(tx2, deaggregated_tx2); assert_eq!(tx2, deaggregated_tx2);
} }
@ -470,8 +462,7 @@ fn hash_output() {
#[test] #[test]
fn blind_tx() { fn blind_tx() {
let btx = tx2i1o(); let btx = tx2i1o();
let height = 42; // arbitrary assert!(btx.validate(Weighting::AsTransaction).is_ok());
assert!(btx.validate(Weighting::AsTransaction, height).is_ok());
// Ignored for bullet proofs, because calling range_proof_info // Ignored for bullet proofs, because calling range_proof_info
// with a bullet proof causes painful errors // with a bullet proof causes painful errors
@ -541,8 +532,7 @@ fn tx_build_exchange() {
) )
.unwrap(); .unwrap();
let height = 42; // arbitrary tx_final.validate(Weighting::AsTransaction).unwrap();
tx_final.validate(Weighting::AsTransaction, height).unwrap();
} }
#[test] #[test]
@ -568,7 +558,7 @@ fn reward_with_tx_block() {
let tx1 = tx2i1o(); let tx1 = tx2i1o();
let previous_header = BlockHeader::default(); let previous_header = BlockHeader::default();
tx1.validate(Weighting::AsTransaction, previous_header.height + 1) tx1.validate(Weighting::AsTransaction)
.unwrap(); .unwrap();
let block = new_block(&[tx1], &keychain, &builder, &previous_header, &key_id); let block = new_block(&[tx1], &keychain, &builder, &previous_header, &key_id);
@ -652,14 +642,12 @@ fn test_block_with_timelocked_tx() {
pub fn test_verify_1i1o_sig() { pub fn test_verify_1i1o_sig() {
test_setup(); test_setup();
let tx = tx1i1o(); let tx = tx1i1o();
let height = 42; // arbitrary tx.validate(Weighting::AsTransaction).unwrap();
tx.validate(Weighting::AsTransaction, height).unwrap();
} }
#[test] #[test]
pub fn test_verify_2i1o_sig() { pub fn test_verify_2i1o_sig() {
test_setup(); test_setup();
let tx = tx2i1o(); let tx = tx2i1o();
let height = 42; // arbitrary tx.validate(Weighting::AsTransaction).unwrap();
tx.validate(Weighting::AsTransaction, height).unwrap();
} }

View file

@ -109,9 +109,8 @@ fn test_verify_cut_through_plain() -> Result<(), Error> {
.expect("valid tx"); .expect("valid tx");
// Transaction should fail validation due to cut-through. // Transaction should fail validation due to cut-through.
let height = 42; // arbitrary
assert_eq!( assert_eq!(
tx.validate(Weighting::AsTransaction, height), tx.validate(Weighting::AsTransaction),
Err(Error::CutThrough), Err(Error::CutThrough),
); );
@ -129,7 +128,7 @@ fn test_verify_cut_through_plain() -> Result<(), Error> {
.replace_outputs(outputs); .replace_outputs(outputs);
// Transaction validates successfully after applying cut-through. // Transaction validates successfully after applying cut-through.
tx.validate(Weighting::AsTransaction, height)?; tx.validate(Weighting::AsTransaction)?;
// Transaction validates via lightweight "read" validation as well. // Transaction validates via lightweight "read" validation as well.
tx.validate_read()?; tx.validate_read()?;
@ -169,9 +168,8 @@ fn test_verify_cut_through_coinbase() -> Result<(), Error> {
.expect("valid tx"); .expect("valid tx");
// Transaction should fail validation due to cut-through. // Transaction should fail validation due to cut-through.
let height = 42; // arbitrary
assert_eq!( assert_eq!(
tx.validate(Weighting::AsTransaction, height), tx.validate(Weighting::AsTransaction),
Err(Error::CutThrough), Err(Error::CutThrough),
); );
@ -189,7 +187,7 @@ fn test_verify_cut_through_coinbase() -> Result<(), Error> {
.replace_outputs(outputs); .replace_outputs(outputs);
// Transaction validates successfully after applying cut-through. // Transaction validates successfully after applying cut-through.
tx.validate(Weighting::AsTransaction, height)?; tx.validate(Weighting::AsTransaction)?;
// Transaction validates via lightweight "read" validation as well. // Transaction validates via lightweight "read" validation as well.
tx.validate_read()?; tx.validate_read()?;
@ -222,20 +220,9 @@ fn test_fee_fields() -> Result<(), Error> {
) )
.expect("valid tx"); .expect("valid tx");
let hf4_height = 4 * consensus::TESTING_HARD_FORK_INTERVAL; assert_eq!(tx.accept_fee(), (1 * 1 + 1 * 21 + 1 * 3) * 500_000);
assert_eq!( assert_eq!(tx.fee(), 42);
tx.accept_fee(hf4_height), assert_eq!(tx.shifted_fee(), 21);
(1 * 1 + 1 * 21 + 1 * 3) * 500_000
);
assert_eq!(tx.fee(hf4_height), 42);
assert_eq!(tx.fee(hf4_height), 42);
assert_eq!(tx.shifted_fee(hf4_height), 21);
assert_eq!(
tx.accept_fee(hf4_height - 1),
(1 * 4 + 1 * 1 - 1 * 1) * 1_000_000
);
assert_eq!(tx.fee(hf4_height - 1), 42 + (1u64 << 40));
assert_eq!(tx.shifted_fee(hf4_height - 1), 42 + (1u64 << 40));
tx.body.kernels.append(&mut vec![ tx.body.kernels.append(&mut vec![
TxKernel::with_features(KernelFeatures::Plain { TxKernel::with_features(KernelFeatures::Plain {
@ -244,9 +231,9 @@ fn test_fee_fields() -> Result<(), Error> {
TxKernel::with_features(KernelFeatures::Plain { fee: 21.into() }), TxKernel::with_features(KernelFeatures::Plain { fee: 21.into() }),
]); ]);
assert_eq!(tx.fee(hf4_height), 147); assert_eq!(tx.fee(), 147);
assert_eq!(tx.shifted_fee(hf4_height), 36); assert_eq!(tx.shifted_fee(), 36);
assert_eq!(tx.aggregate_fee_fields(hf4_height), FeeFields::new(2, 147)); assert_eq!(tx.aggregate_fee_fields(), FeeFields::new(2, 147));
assert_eq!(tx_fee(1, 1, 3), 15_500_000); assert_eq!(tx_fee(1, 1, 3), 15_500_000);
Ok(()) Ok(())

View file

@ -122,13 +122,13 @@ where
// * maintain dependency ordering // * maintain dependency ordering
// * maximize cut-through // * maximize cut-through
// * maximize overall fees // * maximize overall fees
let header = self.blockchain.chain_head()?;
let txs = self.bucket_transactions(weighting); let txs = self.bucket_transactions(weighting);
// Iteratively apply the txs to the current chain state, // Iteratively apply the txs to the current chain state,
// rejecting any that do not result in a valid state. // rejecting any that do not result in a valid state.
// Verify these txs produce an aggregated tx below max_weight. // Verify these txs produce an aggregated tx below max_weight.
// Return a vec of all the valid txs. // Return a vec of all the valid txs.
let header = self.blockchain.chain_head()?;
let valid_txs = self.validate_raw_txs(&txs, None, &header, weighting)?; let valid_txs = self.validate_raw_txs(&txs, None, &header, weighting)?;
Ok(valid_txs) Ok(valid_txs)
} }
@ -155,8 +155,7 @@ where
let tx = transaction::aggregate(&txs)?; let tx = transaction::aggregate(&txs)?;
// Validate the single aggregate transaction "as pool", not subject to tx weight limits. // Validate the single aggregate transaction "as pool", not subject to tx weight limits.
let header = self.blockchain.chain_head()?; tx.validate(Weighting::NoLimit)?;
tx.validate(Weighting::NoLimit, header.height)?;
Ok(Some(tx)) Ok(Some(tx))
} }
@ -224,7 +223,7 @@ where
) -> Result<BlockSums, PoolError> { ) -> Result<BlockSums, PoolError> {
// Validate the tx, conditionally checking against weight limits, // Validate the tx, conditionally checking against weight limits,
// based on weight verification type. // based on weight verification type.
tx.validate(weighting, header.height)?; tx.validate(weighting)?;
// Validate the tx against current chain state. // Validate the tx against current chain state.
// Check all inputs are in the current UTXO set. // Check all inputs are in the current UTXO set.
@ -299,7 +298,7 @@ where
tx: &Transaction, tx: &Transaction,
header: &BlockHeader, header: &BlockHeader,
) -> Result<BlockSums, PoolError> { ) -> Result<BlockSums, PoolError> {
let overage = tx.overage(header.height); let overage = tx.overage();
let offset = { let offset = {
let secp = static_secp_instance(); let secp = static_secp_instance();
@ -389,14 +388,13 @@ where
continue; continue;
} }
let height = self.blockchain.chain_head().map(|x| x.height).unwrap_or(0);
match insert_pos { match insert_pos {
None => { None => {
// No parent tx, just add to the end in its own bucket. // No parent tx, just add to the end in its own bucket.
// This is the common case for non 0-conf txs in the txpool. // This is the common case for non 0-conf txs in the txpool.
// We assume the tx is valid here as we validated it on the way into the txpool. // We assume the tx is valid here as we validated it on the way into the txpool.
insert_pos = Some(tx_buckets.len()); insert_pos = Some(tx_buckets.len());
tx_buckets.push(Bucket::new(entry.tx.clone(), tx_buckets.len(), height)); tx_buckets.push(Bucket::new(entry.tx.clone(), tx_buckets.len()));
} }
Some(pos) => { Some(pos) => {
// We found a single parent tx, so aggregate in the bucket // We found a single parent tx, so aggregate in the bucket
@ -405,7 +403,7 @@ where
let bucket = &tx_buckets[pos]; let bucket = &tx_buckets[pos];
if let Ok(new_bucket) = if let Ok(new_bucket) =
bucket.aggregate_with_tx(entry.tx.clone(), weighting, height) bucket.aggregate_with_tx(entry.tx.clone(), weighting)
{ {
if new_bucket.fee_rate >= bucket.fee_rate { if new_bucket.fee_rate >= bucket.fee_rate {
// Only aggregate if it would not reduce the fee_rate ratio. // Only aggregate if it would not reduce the fee_rate ratio.
@ -414,11 +412,7 @@ where
// Otherwise put it in its own bucket at the end. // Otherwise put it in its own bucket at the end.
// Note: This bucket will have a lower fee_rate // Note: This bucket will have a lower fee_rate
// than the bucket it depends on. // than the bucket it depends on.
tx_buckets.push(Bucket::new( tx_buckets.push(Bucket::new(entry.tx.clone(), tx_buckets.len()));
entry.tx.clone(),
tx_buckets.len(),
height,
));
} }
} else { } else {
// Aggregation failed so discard this new tx. // Aggregation failed so discard this new tx.
@ -511,9 +505,9 @@ impl Bucket {
/// also specifies an "age_idx" so we can sort buckets by age /// also specifies an "age_idx" so we can sort buckets by age
/// as well as fee_rate. Txs are maintained in the pool in insert order /// as well as fee_rate. Txs are maintained in the pool in insert order
/// so buckets with low age_idx contain oldest txs. /// so buckets with low age_idx contain oldest txs.
fn new(tx: Transaction, age_idx: usize, height: u64) -> Bucket { fn new(tx: Transaction, age_idx: usize) -> Bucket {
Bucket { Bucket {
fee_rate: tx.fee_rate(height), fee_rate: tx.fee_rate(),
raw_txs: vec![tx], raw_txs: vec![tx],
age_idx, age_idx,
} }
@ -523,14 +517,13 @@ impl Bucket {
&self, &self,
new_tx: Transaction, new_tx: Transaction,
weighting: Weighting, weighting: Weighting,
height: u64,
) -> Result<Bucket, PoolError> { ) -> Result<Bucket, PoolError> {
let mut raw_txs = self.raw_txs.clone(); let mut raw_txs = self.raw_txs.clone();
raw_txs.push(new_tx); raw_txs.push(new_tx);
let agg_tx = transaction::aggregate(&raw_txs)?; let agg_tx = transaction::aggregate(&raw_txs)?;
agg_tx.validate(weighting, height)?; agg_tx.validate(weighting)?;
Ok(Bucket { Ok(Bucket {
fee_rate: agg_tx.fee_rate(height), fee_rate: agg_tx.fee_rate(),
raw_txs: raw_txs, raw_txs: raw_txs,
age_idx: self.age_idx, age_idx: self.age_idx,
}) })

View file

@ -179,7 +179,7 @@ where
// Make sure the transaction is valid before anything else. // Make sure the transaction is valid before anything else.
// Validate tx accounting for max tx weight. // Validate tx accounting for max tx weight.
tx.validate(Weighting::AsTransaction, header.height) tx.validate(Weighting::AsTransaction)
.map_err(PoolError::InvalidTx)?; .map_err(PoolError::InvalidTx)?;
// Check the tx lock_time is valid based on current chain state. // Check the tx lock_time is valid based on current chain state.
@ -260,8 +260,7 @@ where
}; };
// Validate the tx to ensure our converted inputs are correct. // Validate the tx to ensure our converted inputs are correct.
let header = self.chain_head()?; tx.validate(Weighting::AsTransaction)?;
tx.validate(Weighting::AsTransaction, header.height)?;
Ok(PoolEntry::new(tx, entry.src)) Ok(PoolEntry::new(tx, entry.src))
} }
@ -352,9 +351,8 @@ where
// weight for a basic transaction (2 inputs, 2 outputs, 1 kernel) - // weight for a basic transaction (2 inputs, 2 outputs, 1 kernel) -
// (2 * 1) + (2 * 21) + (1 * 3) = 47 // (2 * 1) + (2 * 21) + (1 * 3) = 47
// minfees = 47 * 500_000 = 23_500_000 // minfees = 47 * 500_000 = 23_500_000
let header = self.chain_head()?; if tx.shifted_fee() < tx.accept_fee() {
if tx.shifted_fee(header.height) < tx.accept_fee(header.height) { return Err(PoolError::LowFeeTransaction(tx.shifted_fee()));
return Err(PoolError::LowFeeTransaction(tx.shifted_fee(header.height)));
} }
Ok(()) Ok(())
} }

View file

@ -79,7 +79,7 @@ fn test_block_building_max_weight() {
// Fees and weights of our original txs in insert order. // Fees and weights of our original txs in insert order.
assert_eq!( assert_eq!(
txs.iter().map(|x| x.fee(header.height)).collect::<Vec<_>>(), txs.iter().map(|x| x.fee()).collect::<Vec<_>>(),
[2_500_000, 90_000, 80_000, 30_000, 70_000, 60_000] [2_500_000, 90_000, 80_000, 30_000, 70_000, 60_000]
); );
assert_eq!( assert_eq!(
@ -87,9 +87,7 @@ fn test_block_building_max_weight() {
[88, 46, 46, 25, 46, 46] [88, 46, 46, 25, 46, 46]
); );
assert_eq!( assert_eq!(
txs.iter() txs.iter().map(|x| x.fee_rate()).collect::<Vec<_>>(),
.map(|x| x.fee_rate(header.height))
.collect::<Vec<_>>(),
[28409, 1956, 1739, 1200, 1521, 1304] [28409, 1956, 1739, 1200, 1521, 1304]
); );
@ -107,7 +105,7 @@ fn test_block_building_max_weight() {
// Fees and weights of the "mineable" txs. // Fees and weights of the "mineable" txs.
assert_eq!( assert_eq!(
txs.iter().map(|x| x.fee(header.height)).collect::<Vec<_>>(), txs.iter().map(|x| x.fee()).collect::<Vec<_>>(),
[2_500_000, 90_000, 80_000, 70_000] [2_500_000, 90_000, 80_000, 70_000]
); );
assert_eq!( assert_eq!(
@ -115,9 +113,7 @@ fn test_block_building_max_weight() {
[88, 46, 46, 46] [88, 46, 46, 46]
); );
assert_eq!( assert_eq!(
txs.iter() txs.iter().map(|x| x.fee_rate()).collect::<Vec<_>>(),
.map(|x| x.fee_rate(header.height))
.collect::<Vec<_>>(),
[28409, 1956, 1739, 1521] [28409, 1956, 1739, 1521]
); );

View file

@ -75,7 +75,7 @@ where
let prev = chain.head_header().unwrap(); let prev = chain.head_header().unwrap();
let height = prev.height + 1; let height = prev.height + 1;
let next_header_info = consensus::next_difficulty(height, chain.difficulty_iter().unwrap()); let next_header_info = consensus::next_difficulty(height, chain.difficulty_iter().unwrap());
let fee = txs.iter().map(|x| x.fee(height)).sum(); let fee = txs.iter().map(|x| x.fee()).sum();
let key_id = ExtKeychainPath::new(1, height as u32, 0, 0, 0).to_identifier(); let key_id = ExtKeychainPath::new(1, height as u32, 0, 0, 0).to_identifier();
let reward = let reward =
reward::output(keychain, &ProofBuilder::new(keychain), &key_id, fee, false).unwrap(); reward::output(keychain, &ProofBuilder::new(keychain), &key_id, fee, false).unwrap();

View file

@ -187,8 +187,7 @@ fn test_the_transaction_pool() {
// tx4 is the "new" part of this aggregated tx that we care about // tx4 is the "new" part of this aggregated tx that we care about
let agg_tx = transaction::aggregate(&[tx1.clone(), tx2.clone(), tx4]).unwrap(); let agg_tx = transaction::aggregate(&[tx1.clone(), tx2.clone(), tx4]).unwrap();
let height = 12 + 1; agg_tx.validate(Weighting::AsTransaction).unwrap();
agg_tx.validate(Weighting::AsTransaction, height).unwrap();
pool.add_to_pool(test_source(), agg_tx, false, &header) pool.add_to_pool(test_source(), agg_tx, false, &header)
.unwrap(); .unwrap();

View file

@ -139,7 +139,7 @@ fn process_fluff_phase(
); );
let agg_tx = transaction::aggregate(&fluffable_txs)?; let agg_tx = transaction::aggregate(&fluffable_txs)?;
agg_tx.validate(transaction::Weighting::AsTransaction, header.height)?; agg_tx.validate(transaction::Weighting::AsTransaction)?;
tx_pool.add_to_pool(TxSource::Fluff, agg_tx, false, &header)?; tx_pool.add_to_pool(TxSource::Fluff, agg_tx, false, &header)?;
Ok(()) Ok(())

View file

@ -152,7 +152,7 @@ fn build_block(
}; };
// build the coinbase and the block itself // build the coinbase and the block itself
let fees = txs.iter().map(|tx| tx.fee(head.height)).sum(); let fees = txs.iter().map(|tx| tx.fee()).sum();
let height = head.height + 1; let height = head.height + 1;
let block_fees = BlockFees { let block_fees = BlockFees {
fees, fees,