mirror of
https://github.com/mimblewimble/grin.git
synced 2025-05-09 18:51:15 +03:00
Merkle proofs fee (#898)
* Refactoring before new functionality * Simplify and use just count of proofs
This commit is contained in:
parent
07c2358562
commit
7bad33d249
5 changed files with 66 additions and 28 deletions
|
@ -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()?;
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Add table
Reference in a new issue