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.
use crate::chain;
use crate::core::consensus::YEAR_HEIGHT;
use crate::core::core::hash::Hashed;
use crate::core::core::merkle_proof::MerkleProof;
use crate::core::core::{FeeFields, KernelFeatures, TxKernel};
@ -518,13 +517,10 @@ impl TxKernelPrintable {
relative_height,
} => (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 {
features,
fee_shift,
fee,
fee_shift: fee_fields.fee_shift(),
fee: fee_fields.fee(),
lock_height,
excess: k.excess.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 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 =
reward::output(keychain, &ProofBuilder::new(keychain), key_id, fee, false).unwrap();

View file

@ -1030,8 +1030,7 @@ where
let proof_size = global::proofsize();
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(height)).sum();
let fees = txs.iter().map(|tx| tx.fee()).sum();
let reward =
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) {

View file

@ -54,7 +54,7 @@ where
{
let next_header_info =
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 =
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 next_height = prev.height + 1;
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 reward =
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));
// Transaction is invalid due to cut-through.
let height = 7;
assert_eq!(
tx.validate(Weighting::AsTransaction, height),
tx.validate(Weighting::AsTransaction),
Err(transaction::Error::CutThrough),
);

View file

@ -106,7 +106,7 @@ fn test_coinbase_maturity() {
.unwrap();
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 next_header_info =
consensus::next_difficulty(prev.height + 1, chain.difficulty_iter().unwrap());
@ -192,7 +192,7 @@ fn test_coinbase_maturity() {
.unwrap();
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 next_header_info =
consensus::next_difficulty(prev.height + 1, chain.difficulty_iter().unwrap());
@ -261,7 +261,7 @@ fn test_coinbase_maturity() {
.unwrap();
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 =
consensus::next_difficulty(prev.height + 1, chain.difficulty_iter().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
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.

View file

@ -14,7 +14,6 @@
//! Transactions
use crate::core::block::HeaderVersion;
use crate::core::hash::{DefaultHashable, Hashed};
use crate::core::{committed, Committed};
use crate::libtx::{aggsig, secp_ser};
@ -161,22 +160,14 @@ impl FeeFields {
}
/// Extract fee_shift field
pub fn fee_shift(&self, height: u64) -> u8 {
if consensus::header_version(height) < HeaderVersion(5) {
0
} else {
pub fn fee_shift(&self) -> u8 {
((self.0 >> FeeFields::FEE_BITS) & FeeFields::FEE_SHIFT_MASK) as u8
}
}
/// Extract fee field
pub fn fee(&self, height: u64) -> u64 {
if consensus::header_version(height) < HeaderVersion(5) {
self.0
} else {
pub fn fee(&self) -> u64 {
self.0 & FeeFields::FEE_MASK
}
}
/// Turn a zero `FeeField` into a `None`, any other value into a `Some`.
/// We need this because a zero `FeeField` cannot be deserialized.
@ -1031,7 +1022,7 @@ impl TransactionBody {
}
/// 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
.iter()
.filter_map(|k| match k.features {
@ -1040,13 +1031,11 @@ impl TransactionBody {
KernelFeatures::HeightLocked { fee, .. } => Some(fee),
KernelFeatures::NoRecentDuplicate { fee, .. } => Some(fee),
})
.fold(0, |acc, fee_fields| {
acc.saturating_add(fee_fields.fee(height))
})
.fold(0, |acc, fee_fields| acc.saturating_add(fee_fields.fee()))
}
/// 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
.iter()
.filter_map(|k| match k.features {
@ -1055,24 +1044,24 @@ impl TransactionBody {
KernelFeatures::HeightLocked { 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
/// 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
/// but are required to overpay the minimum required fees by a factor of 2^priority
pub fn shifted_fee(&self, height: u64) -> u64 {
self.fee(height) >> self.fee_shift(height)
pub fn shifted_fee(&self) -> u64 {
self.fee() >> self.fee_shift()
}
/// aggregate fee_fields from all appropriate kernels in TransactionBody into one, if possible
pub fn aggregate_fee_fields(&self, height: u64) -> Result<FeeFields, Error> {
FeeFields::new(self.fee_shift(height) as u64, self.fee(height))
pub fn aggregate_fee_fields(&self) -> Result<FeeFields, Error> {
FeeFields::new(self.fee_shift() as u64, self.fee())
}
fn overage(&self, height: u64) -> i64 {
self.fee(height) as i64
fn overage(&self) -> i64 {
self.fee() as i64
}
/// 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.
pub fn fee(&self, height: u64) -> u64 {
self.body.fee(height)
pub fn fee(&self) -> u64 {
self.body.fee()
}
/// 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 {
self.body.shifted_fee(height)
pub fn shifted_fee(&self) -> u64 {
self.body.shifted_fee()
}
/// aggregate fee_fields from all appropriate kernels in transaction into one
pub fn aggregate_fee_fields(&self, height: u64) -> Result<FeeFields, Error> {
self.body.aggregate_fee_fields(height)
pub fn aggregate_fee_fields(&self) -> Result<FeeFields, Error> {
self.body.aggregate_fee_fields()
}
/// Total overage across all kernels.
pub fn overage(&self, height: u64) -> i64 {
self.body.overage(height)
pub fn overage(&self) -> i64 {
self.body.overage()
}
/// 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
/// excess value against the signature as well as range proofs for each
/// 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.validate(weighting)?;
self.verify_kernel_sums(self.overage(height), self.offset.clone())?;
self.verify_kernel_sums(self.overage(), self.offset.clone())?;
Ok(())
}
/// 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.
pub fn fee_rate(&self, height: u64) -> u64 {
self.fee(height) / self.weight() as u64
pub fn fee_rate(&self) -> u64 {
self.fee() / self.weight() as u64
}
/// Calculate transaction weight
@ -1470,17 +1459,9 @@ impl Transaction {
}
/// Transaction minimum acceptable fee
pub fn accept_fee(&self, height: u64) -> u64 {
if consensus::header_version(height) < HeaderVersion(5) {
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 {
pub fn accept_fee(&self) -> u64 {
self.weight() * global::get_accept_fee_base()
}
}
/// Old weight definition for pool acceptance
pub fn old_weight_by_iok(num_inputs: u64, num_outputs: u64, num_kernels: u64) -> u64 {

View file

@ -276,8 +276,7 @@ mod test {
)
.unwrap();
let height = 42; // arbitrary
tx.validate(Weighting::AsTransaction, height).unwrap();
tx.validate(Weighting::AsTransaction).unwrap();
}
#[test]
@ -297,8 +296,7 @@ mod test {
)
.unwrap();
let height = 42; // arbitrary
tx.validate(Weighting::AsTransaction, height).unwrap();
tx.validate(Weighting::AsTransaction).unwrap();
}
#[test]
@ -317,7 +315,6 @@ mod test {
)
.unwrap();
let height = 42; // arbitrary
tx.validate(Weighting::AsTransaction, height).unwrap();
tx.validate(Weighting::AsTransaction).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
pub fn accept_fee(tx: Transaction, height: u64) -> u64 {
tx.accept_fee(height)
pub fn accept_fee(tx: Transaction) -> u64 {
tx.accept_fee()
}

View file

@ -120,10 +120,7 @@ where
K: Keychain,
B: ProofBuild,
{
let fees = txs
.iter()
.map(|tx| tx.fee(previous_header.height + 1))
.sum();
let fees = txs.iter().map(|tx| tx.fee()).sum();
let reward_output = reward::output(keychain, builder, &key_id, fees, false).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();
ser::serialize_default(&mut vec, &tx).expect("serialization failed");
let dtx: Transaction = ser::deserialize_default(&mut &vec[..]).unwrap();
let height = 42; // arbitrary
assert_eq!(dtx.fee(height), 2);
assert_eq!(dtx.fee(), 2);
assert_eq!(dtx.inputs().len(), 2);
assert_eq!(dtx.outputs().len(), 1);
assert_eq!(tx.hash(), dtx.hash());
@ -157,8 +156,7 @@ fn build_tx_kernel() {
.unwrap();
// check the tx is valid
let height = 42; // arbitrary
tx.validate(Weighting::AsTransaction, height).unwrap();
tx.validate(Weighting::AsTransaction).unwrap();
// check the kernel is also itself valid
assert_eq!(tx.kernels().len(), 1);
@ -166,7 +164,7 @@ fn build_tx_kernel() {
kern.verify().unwrap();
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
@ -220,10 +218,9 @@ fn build_two_half_kernels() {
)
.unwrap();
let height = 42; // arbitrary
assert_eq!(tx1.validate(Weighting::AsTransaction, height), Ok(()),);
assert_eq!(tx1.validate(Weighting::AsTransaction), Ok(()),);
assert_eq!(tx2.validate(Weighting::AsTransaction, height), Ok(()),);
assert_eq!(tx2.validate(Weighting::AsTransaction), Ok(()),);
// The transactions share an identical kernel.
assert_eq!(tx1.kernels()[0], tx2.kernels()[0]);
@ -247,14 +244,14 @@ fn transaction_cut_through() {
let tx1 = tx1i2o();
let tx2 = tx2i1o();
let height = 42; // arbitrary
assert!(tx1.validate(Weighting::AsTransaction, height).is_ok());
assert!(tx2.validate(Weighting::AsTransaction, height).is_ok());
assert!(tx1.validate(Weighting::AsTransaction).is_ok());
assert!(tx2.validate(Weighting::AsTransaction).is_ok());
// now build a "cut_through" tx from tx1 and tx2
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
@ -266,30 +263,30 @@ fn multi_kernel_transaction_deaggregation() {
let tx3 = tx1i1o();
let tx4 = tx1i1o();
let height = 42; // arbitrary
assert!(tx1.validate(Weighting::AsTransaction, height).is_ok());
assert!(tx2.validate(Weighting::AsTransaction, height).is_ok());
assert!(tx3.validate(Weighting::AsTransaction, height).is_ok());
assert!(tx4.validate(Weighting::AsTransaction, height).is_ok());
assert!(tx1.validate(Weighting::AsTransaction).is_ok());
assert!(tx2.validate(Weighting::AsTransaction).is_ok());
assert!(tx3.validate(Weighting::AsTransaction).is_ok());
assert!(tx4.validate(Weighting::AsTransaction).is_ok());
let tx1234 = aggregate(&[tx1.clone(), tx2.clone(), tx3.clone(), tx4.clone()]).unwrap();
let tx12 = aggregate(&[tx1, tx2]).unwrap();
let tx34 = aggregate(&[tx3, tx4]).unwrap();
assert!(tx1234.validate(Weighting::AsTransaction, height).is_ok());
assert!(tx12.validate(Weighting::AsTransaction, height).is_ok());
assert!(tx34.validate(Weighting::AsTransaction, height).is_ok());
assert!(tx1234.validate(Weighting::AsTransaction).is_ok());
assert!(tx12.validate(Weighting::AsTransaction).is_ok());
assert!(tx34.validate(Weighting::AsTransaction).is_ok());
let deaggregated_tx34 = deaggregate(tx1234.clone(), &[tx12.clone()]).unwrap();
assert!(deaggregated_tx34
.validate(Weighting::AsTransaction, height)
.validate(Weighting::AsTransaction)
.is_ok());
assert_eq!(tx34, deaggregated_tx34);
let deaggregated_tx12 = deaggregate(tx1234, &[tx34]).unwrap();
assert!(deaggregated_tx12
.validate(Weighting::AsTransaction, height)
.validate(Weighting::AsTransaction)
.is_ok());
assert_eq!(tx12, deaggregated_tx12);
}
@ -301,20 +298,19 @@ fn multi_kernel_transaction_deaggregation_2() {
let tx2 = tx1i1o();
let tx3 = tx1i1o();
let height = 42; // arbitrary
assert!(tx1.validate(Weighting::AsTransaction, height).is_ok());
assert!(tx2.validate(Weighting::AsTransaction, height).is_ok());
assert!(tx3.validate(Weighting::AsTransaction, height).is_ok());
assert!(tx1.validate(Weighting::AsTransaction).is_ok());
assert!(tx2.validate(Weighting::AsTransaction).is_ok());
assert!(tx3.validate(Weighting::AsTransaction).is_ok());
let tx123 = aggregate(&[tx1.clone(), tx2.clone(), tx3.clone()]).unwrap();
let tx12 = aggregate(&[tx1, tx2]).unwrap();
assert!(tx123.validate(Weighting::AsTransaction, height).is_ok());
assert!(tx12.validate(Weighting::AsTransaction, height).is_ok());
assert!(tx123.validate(Weighting::AsTransaction).is_ok());
assert!(tx12.validate(Weighting::AsTransaction).is_ok());
let deaggregated_tx3 = deaggregate(tx123, &[tx12]).unwrap();
assert!(deaggregated_tx3
.validate(Weighting::AsTransaction, height)
.validate(Weighting::AsTransaction)
.is_ok());
assert_eq!(tx3, deaggregated_tx3);
}
@ -326,21 +322,20 @@ fn multi_kernel_transaction_deaggregation_3() {
let tx2 = tx1i1o();
let tx3 = tx1i1o();
let height = 42; // arbitrary
assert!(tx1.validate(Weighting::AsTransaction, height).is_ok());
assert!(tx2.validate(Weighting::AsTransaction, height).is_ok());
assert!(tx3.validate(Weighting::AsTransaction, height).is_ok());
assert!(tx1.validate(Weighting::AsTransaction).is_ok());
assert!(tx2.validate(Weighting::AsTransaction).is_ok());
assert!(tx3.validate(Weighting::AsTransaction).is_ok());
let tx123 = aggregate(&[tx1.clone(), tx2.clone(), tx3.clone()]).unwrap();
let tx13 = aggregate(&[tx1, tx3]).unwrap();
let tx2 = aggregate(&[tx2]).unwrap();
assert!(tx123.validate(Weighting::AsTransaction, height).is_ok());
assert!(tx2.validate(Weighting::AsTransaction, height).is_ok());
assert!(tx123.validate(Weighting::AsTransaction).is_ok());
assert!(tx2.validate(Weighting::AsTransaction).is_ok());
let deaggregated_tx13 = deaggregate(tx123, &[tx2]).unwrap();
assert!(deaggregated_tx13
.validate(Weighting::AsTransaction, height)
.validate(Weighting::AsTransaction)
.is_ok());
assert_eq!(tx13, deaggregated_tx13);
}
@ -354,12 +349,11 @@ fn multi_kernel_transaction_deaggregation_4() {
let tx4 = tx1i1o();
let tx5 = tx1i1o();
let height = 42; // arbitrary
assert!(tx1.validate(Weighting::AsTransaction, height).is_ok());
assert!(tx2.validate(Weighting::AsTransaction, height).is_ok());
assert!(tx3.validate(Weighting::AsTransaction, height).is_ok());
assert!(tx4.validate(Weighting::AsTransaction, height).is_ok());
assert!(tx5.validate(Weighting::AsTransaction, height).is_ok());
assert!(tx1.validate(Weighting::AsTransaction).is_ok());
assert!(tx2.validate(Weighting::AsTransaction).is_ok());
assert!(tx3.validate(Weighting::AsTransaction).is_ok());
assert!(tx4.validate(Weighting::AsTransaction).is_ok());
assert!(tx5.validate(Weighting::AsTransaction).is_ok());
let tx12345 = aggregate(&[
tx1.clone(),
@ -369,11 +363,11 @@ fn multi_kernel_transaction_deaggregation_4() {
tx5.clone(),
])
.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();
assert!(deaggregated_tx5
.validate(Weighting::AsTransaction, height)
.validate(Weighting::AsTransaction)
.is_ok());
assert_eq!(tx5, deaggregated_tx5);
}
@ -387,12 +381,11 @@ fn multi_kernel_transaction_deaggregation_5() {
let tx4 = tx1i1o();
let tx5 = tx1i1o();
let height = 42; // arbitrary
assert!(tx1.validate(Weighting::AsTransaction, height).is_ok());
assert!(tx2.validate(Weighting::AsTransaction, height).is_ok());
assert!(tx3.validate(Weighting::AsTransaction, height).is_ok());
assert!(tx4.validate(Weighting::AsTransaction, height).is_ok());
assert!(tx5.validate(Weighting::AsTransaction, height).is_ok());
assert!(tx1.validate(Weighting::AsTransaction).is_ok());
assert!(tx2.validate(Weighting::AsTransaction).is_ok());
assert!(tx3.validate(Weighting::AsTransaction).is_ok());
assert!(tx4.validate(Weighting::AsTransaction).is_ok());
assert!(tx5.validate(Weighting::AsTransaction).is_ok());
let tx12345 = aggregate(&[
tx1.clone(),
@ -405,11 +398,11 @@ fn multi_kernel_transaction_deaggregation_5() {
let tx12 = aggregate(&[tx1, tx2]).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();
assert!(deaggregated_tx5
.validate(Weighting::AsTransaction, height)
.validate(Weighting::AsTransaction)
.is_ok());
assert_eq!(tx5, deaggregated_tx5);
}
@ -421,26 +414,25 @@ fn basic_transaction_deaggregation() {
let tx1 = tx1i2o();
let tx2 = tx2i1o();
let height = 42; // arbitrary
assert!(tx1.validate(Weighting::AsTransaction, height).is_ok());
assert!(tx2.validate(Weighting::AsTransaction, height).is_ok());
assert!(tx1.validate(Weighting::AsTransaction).is_ok());
assert!(tx2.validate(Weighting::AsTransaction).is_ok());
// now build a "cut_through" tx from tx1 and tx2
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();
assert!(deaggregated_tx1
.validate(Weighting::AsTransaction, height)
.validate(Weighting::AsTransaction)
.is_ok());
assert_eq!(tx1, deaggregated_tx1);
let deaggregated_tx2 = deaggregate(tx3, &[tx1]).unwrap();
assert!(deaggregated_tx2
.validate(Weighting::AsTransaction, height)
.validate(Weighting::AsTransaction)
.is_ok());
assert_eq!(tx2, deaggregated_tx2);
}
@ -470,8 +462,7 @@ fn hash_output() {
#[test]
fn blind_tx() {
let btx = tx2i1o();
let height = 42; // arbitrary
assert!(btx.validate(Weighting::AsTransaction, height).is_ok());
assert!(btx.validate(Weighting::AsTransaction).is_ok());
// Ignored for bullet proofs, because calling range_proof_info
// with a bullet proof causes painful errors
@ -541,8 +532,7 @@ fn tx_build_exchange() {
)
.unwrap();
let height = 42; // arbitrary
tx_final.validate(Weighting::AsTransaction, height).unwrap();
tx_final.validate(Weighting::AsTransaction).unwrap();
}
#[test]
@ -568,7 +558,7 @@ fn reward_with_tx_block() {
let tx1 = tx2i1o();
let previous_header = BlockHeader::default();
tx1.validate(Weighting::AsTransaction, previous_header.height + 1)
tx1.validate(Weighting::AsTransaction)
.unwrap();
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() {
test_setup();
let tx = tx1i1o();
let height = 42; // arbitrary
tx.validate(Weighting::AsTransaction, height).unwrap();
tx.validate(Weighting::AsTransaction).unwrap();
}
#[test]
pub fn test_verify_2i1o_sig() {
test_setup();
let tx = tx2i1o();
let height = 42; // arbitrary
tx.validate(Weighting::AsTransaction, height).unwrap();
tx.validate(Weighting::AsTransaction).unwrap();
}

View file

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

View file

@ -122,13 +122,13 @@ where
// * maintain dependency ordering
// * maximize cut-through
// * maximize overall fees
let header = self.blockchain.chain_head()?;
let txs = self.bucket_transactions(weighting);
// Iteratively apply the txs to the current chain state,
// rejecting any that do not result in a valid state.
// Verify these txs produce an aggregated tx below max_weight.
// 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)?;
Ok(valid_txs)
}
@ -155,8 +155,7 @@ where
let tx = transaction::aggregate(&txs)?;
// Validate the single aggregate transaction "as pool", not subject to tx weight limits.
let header = self.blockchain.chain_head()?;
tx.validate(Weighting::NoLimit, header.height)?;
tx.validate(Weighting::NoLimit)?;
Ok(Some(tx))
}
@ -224,7 +223,7 @@ where
) -> Result<BlockSums, PoolError> {
// Validate the tx, conditionally checking against weight limits,
// based on weight verification type.
tx.validate(weighting, header.height)?;
tx.validate(weighting)?;
// Validate the tx against current chain state.
// Check all inputs are in the current UTXO set.
@ -299,7 +298,7 @@ where
tx: &Transaction,
header: &BlockHeader,
) -> Result<BlockSums, PoolError> {
let overage = tx.overage(header.height);
let overage = tx.overage();
let offset = {
let secp = static_secp_instance();
@ -389,14 +388,13 @@ where
continue;
}
let height = self.blockchain.chain_head().map(|x| x.height).unwrap_or(0);
match insert_pos {
None => {
// 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.
// We assume the tx is valid here as we validated it on the way into the txpool.
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) => {
// We found a single parent tx, so aggregate in the bucket
@ -405,7 +403,7 @@ where
let bucket = &tx_buckets[pos];
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 {
// 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.
// Note: This bucket will have a lower fee_rate
// than the bucket it depends on.
tx_buckets.push(Bucket::new(
entry.tx.clone(),
tx_buckets.len(),
height,
));
tx_buckets.push(Bucket::new(entry.tx.clone(), tx_buckets.len()));
}
} else {
// 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
/// as well as fee_rate. Txs are maintained in the pool in insert order
/// 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 {
fee_rate: tx.fee_rate(height),
fee_rate: tx.fee_rate(),
raw_txs: vec![tx],
age_idx,
}
@ -523,14 +517,13 @@ impl Bucket {
&self,
new_tx: Transaction,
weighting: Weighting,
height: u64,
) -> Result<Bucket, PoolError> {
let mut raw_txs = self.raw_txs.clone();
raw_txs.push(new_tx);
let agg_tx = transaction::aggregate(&raw_txs)?;
agg_tx.validate(weighting, height)?;
agg_tx.validate(weighting)?;
Ok(Bucket {
fee_rate: agg_tx.fee_rate(height),
fee_rate: agg_tx.fee_rate(),
raw_txs: raw_txs,
age_idx: self.age_idx,
})

View file

@ -179,7 +179,7 @@ where
// Make sure the transaction is valid before anything else.
// Validate tx accounting for max tx weight.
tx.validate(Weighting::AsTransaction, header.height)
tx.validate(Weighting::AsTransaction)
.map_err(PoolError::InvalidTx)?;
// 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.
let header = self.chain_head()?;
tx.validate(Weighting::AsTransaction, header.height)?;
tx.validate(Weighting::AsTransaction)?;
Ok(PoolEntry::new(tx, entry.src))
}
@ -352,9 +351,8 @@ where
// weight for a basic transaction (2 inputs, 2 outputs, 1 kernel) -
// (2 * 1) + (2 * 21) + (1 * 3) = 47
// minfees = 47 * 500_000 = 23_500_000
let header = self.chain_head()?;
if tx.shifted_fee(header.height) < tx.accept_fee(header.height) {
return Err(PoolError::LowFeeTransaction(tx.shifted_fee(header.height)));
if tx.shifted_fee() < tx.accept_fee() {
return Err(PoolError::LowFeeTransaction(tx.shifted_fee()));
}
Ok(())
}

View file

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

View file

@ -75,7 +75,7 @@ where
let prev = chain.head_header().unwrap();
let height = prev.height + 1;
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 reward =
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
let agg_tx = transaction::aggregate(&[tx1.clone(), tx2.clone(), tx4]).unwrap();
let height = 12 + 1;
agg_tx.validate(Weighting::AsTransaction, height).unwrap();
agg_tx.validate(Weighting::AsTransaction).unwrap();
pool.add_to_pool(test_source(), agg_tx, false, &header)
.unwrap();

View file

@ -139,7 +139,7 @@ fn process_fluff_phase(
);
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)?;
Ok(())

View file

@ -152,7 +152,7 @@ fn build_block(
};
// 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 block_fees = BlockFees {
fees,