Merkle proofs fee ()

* Refactoring before new functionality

* Simplify and use just count of proofs
This commit is contained in:
hashmap 2018-04-17 19:09:29 +02:00 committed by Antioch Peverell
parent 07c2358562
commit 7bad33d249
5 changed files with 66 additions and 28 deletions

View file

@ -433,6 +433,33 @@ impl Transaction {
Ok(())
}
/// Calculate transaction weight
pub fn tx_weight(&self) -> u32 {
Transaction::weight(
self.inputs.len(),
self.outputs.len(),
self.input_proofs_count(),
)
}
/// Collect input's Merkle proofs
pub fn input_proofs_count(&self) -> usize {
self.inputs
.iter()
.filter(|i| i.merkle_proof.is_some())
.count()
}
/// Calculate transaction weight from transaction details
pub fn weight(input_len: usize, output_len: usize, proof_len: usize) -> u32 {
let mut tx_weight =
-1 * (input_len as i32) + (4 * output_len as i32) + (proof_len as i32) + 1;
if tx_weight < 1 {
tx_weight = 1;
}
tx_weight as u32
}
fn verify_sorted(&self) -> Result<(), Error> {
self.inputs.verify_sort_order()?;
self.outputs.verify_sort_order()?;

View file

@ -786,11 +786,7 @@ where
// (-1 * 1) + (4 * 2) + 1 = 8
// 8 * 10 = 80
if self.config.accept_fee_base > 0 {
let mut tx_weight = -1 * (tx.inputs.len() as i32) + (4 * tx.outputs.len() as i32) + 1;
if tx_weight < 1 {
tx_weight = 1;
}
let threshold = (tx_weight as u64) * self.config.accept_fee_base;
let threshold = (tx.tx_weight() as u64) * self.config.accept_fee_base;
if tx.fee() < threshold {
return Err(PoolError::LowFeeTransaction(threshold));
}

View file

@ -63,7 +63,12 @@ fn handle_sender_initiation(
// double check the fee amount included in the partial tx
// we don't necessarily want to just trust the sender
// we could just overwrite the fee here (but we won't) due to the ecdsa sig
let fee = tx_fee(tx.inputs.len(), tx.outputs.len() + 1, None);
let fee = tx_fee(
tx.inputs.len(),
tx.outputs.len() + 1,
tx.input_proofs_count(),
None,
);
if fee != tx.fee() {
return Err(ErrorKind::FeeDispute {
sender_fee: tx.fee(),
@ -403,7 +408,12 @@ fn build_final_transaction(
// double check the fee amount included in the partial tx
// we don't necessarily want to just trust the sender
// we could just overwrite the fee here (but we won't) due to the ecdsa sig
let fee = tx_fee(tx.inputs.len(), tx.outputs.len() + 1, None);
let fee = tx_fee(
tx.inputs.len(),
tx.outputs.len() + 1,
tx.input_proofs_count(),
None,
);
if fee != tx.fee() {
return Err(ErrorKind::FeeDispute {
sender_fee: tx.fee(),

View file

@ -263,7 +263,7 @@ fn build_send_tx(
// sender is responsible for setting the fee on the partial tx
// recipient should double check the fee calculation and not blindly trust the
// sender
let mut fee = tx_fee(coins.len(), 2, None);
let mut fee = tx_fee(coins.len(), 2, coins_proof_count(&coins), None);
let mut total: u64 = coins.iter().map(|c| c.value).sum();
let mut amount_with_fee = amount + fee;
@ -286,7 +286,7 @@ fn build_send_tx(
selection_strategy_is_use_all,
))
})?;
fee = tx_fee(coins.len(), 2, None);
fee = tx_fee(coins.len(), 2, coins_proof_count(&coins), None);
total = coins.iter().map(|c| c.value).sum();
amount_with_fee = amount + fee;
}
@ -303,6 +303,10 @@ fn build_send_tx(
Ok((tx, blind, coins, change_key, amount_with_fee))
}
fn coins_proof_count(coins: &Vec<OutputData>) -> usize {
coins.iter().filter(|c| c.merkle_proof.is_some()).count()
}
pub fn issue_burn_tx(
config: &WalletConfig,
keychain: &Keychain,
@ -333,7 +337,7 @@ pub fn issue_burn_tx(
debug!(LOGGER, "selected some coins - {}", coins.len());
let fee = tx_fee(coins.len(), 2, None);
let fee = tx_fee(coins.len(), 2, coins_proof_count(&coins), None);
let (mut parts, _) = inputs_and_change(&coins, config, keychain, amount, fee)?;
// add burn output and fees

View file

@ -53,17 +53,13 @@ const SEED_FILE: &'static str = "wallet.seed";
const DEFAULT_BASE_FEE: u64 = consensus::MILLI_GRIN;
/// Transaction fee calculation
pub fn tx_fee(input_len: usize, output_len: usize, base_fee: Option<u64>) -> u64 {
pub fn tx_fee(input_len: usize, output_len: usize, proof_len: usize, base_fee: Option<u64>) -> u64 {
let use_base_fee = match base_fee {
Some(bf) => bf,
None => DEFAULT_BASE_FEE,
};
let mut tx_weight = -1 * (input_len as i32) + 4 * (output_len as i32) + 1;
if tx_weight < 1 {
tx_weight = 1;
}
(tx_weight as u64) * use_base_fee
(Transaction::weight(input_len, output_len, proof_len) as u64) * use_base_fee
}
#[derive(Debug)]
@ -74,13 +70,11 @@ pub struct Error {
/// Wallet errors, mostly wrappers around underlying crypto or I/O errors.
#[derive(Copy, Clone, Eq, PartialEq, Debug, Fail)]
pub enum ErrorKind {
#[fail(display = "Not enough funds")] NotEnoughFunds(u64),
#[fail(display = "Not enough funds")]
NotEnoughFunds(u64),
#[fail(display = "Fee dispute: sender fee {}, recipient fee {}", sender_fee, recipient_fee)]
FeeDispute {
sender_fee: u64,
recipient_fee: u64,
},
FeeDispute { sender_fee: u64, recipient_fee: u64 },
#[fail(display = "Fee exceeds amount: sender amount {}, recipient fee {}", sender_amount,
recipient_fee)]
@ -89,19 +83,24 @@ pub enum ErrorKind {
recipient_fee: u64,
},
#[fail(display = "Keychain error")] Keychain,
#[fail(display = "Keychain error")]
Keychain,
#[fail(display = "Transaction error")] Transaction,
#[fail(display = "Transaction error")]
Transaction,
#[fail(display = "Secp error")] Secp,
#[fail(display = "Secp error")]
Secp,
#[fail(display = "Wallet data error: {}", _0)] WalletData(&'static str),
#[fail(display = "Wallet data error: {}", _0)]
WalletData(&'static str),
/// An error in the format of the JSON structures exchanged by the wallet
#[fail(display = "JSON format error")]
Format,
#[fail(display = "I/O error")] IO,
#[fail(display = "I/O error")]
IO,
/// Error when contacting a node through its API
#[fail(display = "Node API error")]
@ -115,7 +114,8 @@ pub enum ErrorKind {
#[fail(display = "Uri parsing error")]
Uri,
#[fail(display = "Signature error")] Signature(&'static str),
#[fail(display = "Signature error")]
Signature(&'static str),
/// Attempt to use duplicate transaction id in separate transactions
#[fail(display = "Duplicate transaction ID error")]
@ -129,7 +129,8 @@ pub enum ErrorKind {
#[fail(display = "Wallet seed doesn't exist error")]
WalletSeedDoesntExist,
#[fail(display = "Generic error: {}", _0)] GenericError(&'static str),
#[fail(display = "Generic error: {}", _0)]
GenericError(&'static str),
}
impl Fail for Error {