From 5f219bfa04af9336ba32f3bbc9ae381d01b28bbf Mon Sep 17 00:00:00 2001 From: Marco Granelli Date: Fri, 23 Dec 2022 16:34:34 +0100 Subject: [PATCH 1/6] Adds fee burning and checks --- .../lib/node/ledger/shell/finalize_block.rs | 80 ++++++++++++++++++- apps/src/lib/node/ledger/shell/mod.rs | 28 ++++++- .../lib/node/ledger/shell/process_proposal.rs | 2 +- 3 files changed, 104 insertions(+), 6 deletions(-) diff --git a/apps/src/lib/node/ledger/shell/finalize_block.rs b/apps/src/lib/node/ledger/shell/finalize_block.rs index d762ee91d8..758be0a403 100644 --- a/apps/src/lib/node/ledger/shell/finalize_block.rs +++ b/apps/src/lib/node/ledger/shell/finalize_block.rs @@ -2,7 +2,10 @@ use namada::ledger::pos::types::into_tm_voting_power; use namada::ledger::protocol; +use namada::ledger::storage::write_log::StorageModification; +use namada::ledger::storage_api::StorageRead; use namada::types::storage::{BlockHash, BlockResults, Header}; +use namada::types::token::Amount; use super::governance::execute_governance_proposals; use super::*; @@ -128,9 +131,80 @@ where } let mut tx_event = match &tx_type { - TxType::Wrapper(_wrapper) => { - self.storage.tx_queue.push(_wrapper.clone()); - Event::new_tx_event(&tx_type, height.0) + TxType::Wrapper(wrapper) => { + let mut tx_event = Event::new_tx_event(&tx_type, height.0); + + // Charge fee + let fee_payer = + if wrapper.pk != address::masp_tx_key().ref_to() { + wrapper.fee_payer() + } else { + address::masp() + }; + + let balance_key = token::balance_key( + &self.storage.native_token, + &fee_payer, + ); + let balance: Amount = + match self.write_log.read(&balance_key).0 { + Some(wal_mod) => { + // Read from WAL + if let StorageModification::Write { value } = + wal_mod + { + Amount::try_from_slice(value).unwrap() + } else { + Amount::default() + } + } + None => { + // Read from storage + let balance = StorageRead::read( + &self.storage, + &balance_key, + ); + // Storage read must not fail, but there might + // be no value, in which + // case default (0) is returned + balance + .expect( + "Storage read in the protocol must \ + not fail", + ) + .unwrap_or_default() + } + }; + + let balance: u64 = balance.into(); + match balance.checked_sub(100) { + Some(v) => { + self.write_log + .write( + &balance_key, + Amount::from(v).try_to_vec().unwrap(), + ) + .unwrap(); + } + None => { + // Burn remaining funds + self.write_log + .write( + &balance_key, + Amount::from(0).try_to_vec().unwrap(), + ) + .unwrap(); + tx_event["log"] = + "Insufficient balance for fee".into(); + tx_event["code"] = ErrorCodes::InvalidTx.into(); + + response.events.push(tx_event); + continue; + } + } + + self.storage.tx_queue.push(wrapper.clone()); + tx_event } TxType::Decrypted(inner) => { // We remove the corresponding wrapper tx from the queue diff --git a/apps/src/lib/node/ledger/shell/mod.rs b/apps/src/lib/node/ledger/shell/mod.rs index 4c461568a9..5f17d35e1d 100644 --- a/apps/src/lib/node/ledger/shell/mod.rs +++ b/apps/src/lib/node/ledger/shell/mod.rs @@ -33,16 +33,17 @@ use namada::ledger::storage::{ }; use namada::ledger::{ibc, pos, protocol}; use namada::proto::{self, Tx}; +use namada::types::address; use namada::types::address::{masp, masp_tx_key, Address}; use namada::types::chain::ChainId; use namada::types::key::*; use namada::types::storage::{BlockHeight, Key, TxIndex}; use namada::types::time::{DateTimeUtc, TimeZone, Utc}; +use namada::types::token::{self, Amount}; use namada::types::transaction::{ hash_tx, process_tx, verify_decrypted_correctly, AffineCurve, DecryptedTx, EllipticCurve, PairingEngine, TxType, WrapperTx, }; -use namada::types::{address, token}; use namada::vm::wasm::{TxCache, VpCache}; use namada::vm::WasmCacheRwAccess; use num_derive::{FromPrimitive, ToPrimitive}; @@ -575,7 +576,30 @@ where ) -> response::CheckTx { let mut response = response::CheckTx::default(); match Tx::try_from(tx_bytes).map_err(Error::TxDecoding) { - Ok(_) => response.log = String::from("Mempool validation passed"), + Ok(tx) => { + // Check balance for fee + if let Ok(TxType::Wrapper(wrapper)) = process_tx(tx) { + let fee_payer = if wrapper.pk != masp_tx_key().ref_to() { + wrapper.fee_payer() + } else { + masp() + }; + // check that the fee payer has sufficient balance + let balance = self + .get_balance(&self.storage.native_token, &fee_payer); + + if Amount::from(100) > balance { + response.code = 1; + response.log = String::from( + "The address given does not have sufficient \ + balance to pay fee", + ); + return response; + } + } + + response.log = String::from("Mempool validation passed"); + } Err(msg) => { response.code = 1; response.log = msg.to_string(); diff --git a/apps/src/lib/node/ledger/shell/process_proposal.rs b/apps/src/lib/node/ledger/shell/process_proposal.rs index 67ca13101e..54ed5fc05b 100644 --- a/apps/src/lib/node/ledger/shell/process_proposal.rs +++ b/apps/src/lib/node/ledger/shell/process_proposal.rs @@ -162,7 +162,7 @@ where let balance = self.get_balance(&tx.fee.token, &fee_payer); - if tx.fee.amount <= balance { + if Amount::from(100) <= balance { TxResult { code: ErrorCodes::Ok.into(), info: "Process proposal accepted this \ From 0b511299339ae400761e3e1a2d29832e169c4f3a Mon Sep 17 00:00:00 2001 From: Marco Granelli Date: Fri, 23 Dec 2022 17:32:50 +0100 Subject: [PATCH 2/6] Fixes fee value in tx contruction --- apps/src/lib/client/signing.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/src/lib/client/signing.rs b/apps/src/lib/client/signing.rs index ed7ab484a9..fc67d6a329 100644 --- a/apps/src/lib/client/signing.rs +++ b/apps/src/lib/client/signing.rs @@ -6,6 +6,7 @@ use namada::proto::Tx; use namada::types::address::{Address, ImplicitAddress}; use namada::types::key::*; use namada::types::storage::Epoch; +use namada::types::token::Amount; use namada::types::transaction::{hash_tx, Fee, WrapperTx}; use super::rpc; @@ -174,7 +175,7 @@ pub async fn sign_wrapper( let tx = { WrapperTx::new( Fee { - amount: args.fee_amount, + amount: Amount::from(100), token: ctx.get(&args.fee_token), }, keypair, From b93463636b8d876d610e1d2722042d35bf026498 Mon Sep 17 00:00:00 2001 From: Marco Granelli Date: Fri, 23 Dec 2022 17:44:55 +0100 Subject: [PATCH 3/6] Fixes process proposal fee token --- apps/src/lib/node/ledger/shell/process_proposal.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/src/lib/node/ledger/shell/process_proposal.rs b/apps/src/lib/node/ledger/shell/process_proposal.rs index 54ed5fc05b..ebe219d39a 100644 --- a/apps/src/lib/node/ledger/shell/process_proposal.rs +++ b/apps/src/lib/node/ledger/shell/process_proposal.rs @@ -159,8 +159,10 @@ where masp() }; // check that the fee payer has sufficient balance - let balance = - self.get_balance(&tx.fee.token, &fee_payer); + let balance = self.get_balance( + &self.storage.native_token, + &fee_payer, + ); if Amount::from(100) <= balance { TxResult { From 0081be6122a29cd8778f5952a45b747599ec8743 Mon Sep 17 00:00:00 2001 From: Marco Granelli Date: Sat, 24 Dec 2022 00:21:14 +0100 Subject: [PATCH 4/6] Fixes unit tests --- .../lib/node/ledger/shell/finalize_block.rs | 29 ++++++++++++++++--- .../lib/node/ledger/shell/process_proposal.rs | 9 ++++++ 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/apps/src/lib/node/ledger/shell/finalize_block.rs b/apps/src/lib/node/ledger/shell/finalize_block.rs index 758be0a403..b54f00199a 100644 --- a/apps/src/lib/node/ledger/shell/finalize_block.rs +++ b/apps/src/lib/node/ledger/shell/finalize_block.rs @@ -422,15 +422,26 @@ mod test_finalize_block { let keypair = gen_keypair(); let mut processed_txs = vec![]; let mut valid_wrappers = vec![]; + + // Add unshielded balance for fee paymenty + let balance_key = token::balance_key( + &shell.storage.native_token, + &Address::from(&keypair.ref_to()), + ); + shell + .storage + .write(&balance_key, Amount::from(1000).try_to_vec().unwrap()) + .unwrap(); + // create some wrapper txs - for i in 1..5 { + for i in 1u64..5 { let raw_tx = Tx::new( "wasm_code".as_bytes().to_owned(), Some(format!("transaction data: {}", i).as_bytes().to_owned()), ); let wrapper = WrapperTx::new( Fee { - amount: i.into(), + amount: 100.into(), token: shell.storage.native_token.clone(), }, &keypair, @@ -603,6 +614,16 @@ mod test_finalize_block { let mut processed_txs = vec![]; let mut valid_txs = vec![]; + // Add unshielded balance for fee paymenty + let balance_key = token::balance_key( + &shell.storage.native_token, + &Address::from(&keypair.ref_to()), + ); + shell + .storage + .write(&balance_key, Amount::from(1000).try_to_vec().unwrap()) + .unwrap(); + // create two decrypted txs let mut wasm_path = top_level_directory(); wasm_path.push("wasm_for_tests/tx_no_op.wasm"); @@ -619,7 +640,7 @@ mod test_finalize_block { ); let wrapper_tx = WrapperTx::new( Fee { - amount: 0.into(), + amount: 100.into(), token: shell.storage.native_token.clone(), }, &keypair, @@ -650,7 +671,7 @@ mod test_finalize_block { ); let wrapper_tx = WrapperTx::new( Fee { - amount: 0.into(), + amount: 100.into(), token: shell.storage.native_token.clone(), }, &keypair, diff --git a/apps/src/lib/node/ledger/shell/process_proposal.rs b/apps/src/lib/node/ledger/shell/process_proposal.rs index ebe219d39a..0004db48e5 100644 --- a/apps/src/lib/node/ledger/shell/process_proposal.rs +++ b/apps/src/lib/node/ledger/shell/process_proposal.rs @@ -400,6 +400,15 @@ mod test_process_proposal { ..Default::default() }); let keypair = crate::wallet::defaults::daewon_keypair(); + // reduce address balance to match the 100 token fee + let balance_key = token::balance_key( + &shell.storage.native_token, + &Address::from(&keypair.ref_to()), + ); + shell + .storage + .write(&balance_key, Amount::from(99).try_to_vec().unwrap()) + .unwrap(); let tx = Tx::new( "wasm_code".as_bytes().to_owned(), From db0cac3151c7ffa585eef5733176746e6bc34d5d Mon Sep 17 00:00:00 2001 From: Marco Granelli Date: Tue, 27 Dec 2022 17:08:57 +0100 Subject: [PATCH 5/6] changelog: add #962 --- .changelog/unreleased/improvements/962-basic-fee.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .changelog/unreleased/improvements/962-basic-fee.md diff --git a/.changelog/unreleased/improvements/962-basic-fee.md b/.changelog/unreleased/improvements/962-basic-fee.md new file mode 100644 index 0000000000..d1fa27df87 --- /dev/null +++ b/.changelog/unreleased/improvements/962-basic-fee.md @@ -0,0 +1,2 @@ +- Added a basic fee implementation for testnet. + ([#962](https://github.com/anoma/namada/pull/962)) \ No newline at end of file From d5cb262e4495f30a1d6abbefe03a4d1bf24d8ba2 Mon Sep 17 00:00:00 2001 From: Marco Granelli Date: Fri, 30 Dec 2022 15:19:12 +0100 Subject: [PATCH 6/6] Adds const and default token to basic fee --- apps/src/lib/client/signing.rs | 4 ++-- apps/src/lib/node/ledger/shell/finalize_block.rs | 15 +++++++-------- apps/src/lib/node/ledger/shell/mod.rs | 8 ++++---- .../src/lib/node/ledger/shell/process_proposal.rs | 8 +++----- core/src/types/transaction/wrapper.rs | 2 ++ 5 files changed, 18 insertions(+), 19 deletions(-) diff --git a/apps/src/lib/client/signing.rs b/apps/src/lib/client/signing.rs index fc67d6a329..6d61cfa9ce 100644 --- a/apps/src/lib/client/signing.rs +++ b/apps/src/lib/client/signing.rs @@ -7,7 +7,7 @@ use namada::types::address::{Address, ImplicitAddress}; use namada::types::key::*; use namada::types::storage::Epoch; use namada::types::token::Amount; -use namada::types::transaction::{hash_tx, Fee, WrapperTx}; +use namada::types::transaction::{hash_tx, Fee, WrapperTx, MIN_FEE}; use super::rpc; use crate::cli::context::{WalletAddress, WalletKeypair}; @@ -175,7 +175,7 @@ pub async fn sign_wrapper( let tx = { WrapperTx::new( Fee { - amount: Amount::from(100), + amount: Amount::from(MIN_FEE), token: ctx.get(&args.fee_token), }, keypair, diff --git a/apps/src/lib/node/ledger/shell/finalize_block.rs b/apps/src/lib/node/ledger/shell/finalize_block.rs index b54f00199a..0541c287b5 100644 --- a/apps/src/lib/node/ledger/shell/finalize_block.rs +++ b/apps/src/lib/node/ledger/shell/finalize_block.rs @@ -6,6 +6,7 @@ use namada::ledger::storage::write_log::StorageModification; use namada::ledger::storage_api::StorageRead; use namada::types::storage::{BlockHash, BlockResults, Header}; use namada::types::token::Amount; +use namada::types::transaction::MIN_FEE; use super::governance::execute_governance_proposals; use super::*; @@ -142,10 +143,8 @@ where address::masp() }; - let balance_key = token::balance_key( - &self.storage.native_token, - &fee_payer, - ); + let balance_key = + token::balance_key(&wrapper.fee.token, &fee_payer); let balance: Amount = match self.write_log.read(&balance_key).0 { Some(wal_mod) => { @@ -177,7 +176,7 @@ where }; let balance: u64 = balance.into(); - match balance.checked_sub(100) { + match balance.checked_sub(MIN_FEE) { Some(v) => { self.write_log .write( @@ -441,7 +440,7 @@ mod test_finalize_block { ); let wrapper = WrapperTx::new( Fee { - amount: 100.into(), + amount: MIN_FEE.into(), token: shell.storage.native_token.clone(), }, &keypair, @@ -640,7 +639,7 @@ mod test_finalize_block { ); let wrapper_tx = WrapperTx::new( Fee { - amount: 100.into(), + amount: MIN_FEE.into(), token: shell.storage.native_token.clone(), }, &keypair, @@ -671,7 +670,7 @@ mod test_finalize_block { ); let wrapper_tx = WrapperTx::new( Fee { - amount: 100.into(), + amount: MIN_FEE.into(), token: shell.storage.native_token.clone(), }, &keypair, diff --git a/apps/src/lib/node/ledger/shell/mod.rs b/apps/src/lib/node/ledger/shell/mod.rs index 5f17d35e1d..7bfd8bdb5c 100644 --- a/apps/src/lib/node/ledger/shell/mod.rs +++ b/apps/src/lib/node/ledger/shell/mod.rs @@ -42,7 +42,7 @@ use namada::types::time::{DateTimeUtc, TimeZone, Utc}; use namada::types::token::{self, Amount}; use namada::types::transaction::{ hash_tx, process_tx, verify_decrypted_correctly, AffineCurve, DecryptedTx, - EllipticCurve, PairingEngine, TxType, WrapperTx, + EllipticCurve, PairingEngine, TxType, WrapperTx, MIN_FEE, }; use namada::vm::wasm::{TxCache, VpCache}; use namada::vm::WasmCacheRwAccess; @@ -585,10 +585,10 @@ where masp() }; // check that the fee payer has sufficient balance - let balance = self - .get_balance(&self.storage.native_token, &fee_payer); + let balance = + self.get_balance(&wrapper.fee.token, &fee_payer); - if Amount::from(100) > balance { + if Amount::from(MIN_FEE) > balance { response.code = 1; response.log = String::from( "The address given does not have sufficient \ diff --git a/apps/src/lib/node/ledger/shell/process_proposal.rs b/apps/src/lib/node/ledger/shell/process_proposal.rs index 0004db48e5..0c4a1f0a8e 100644 --- a/apps/src/lib/node/ledger/shell/process_proposal.rs +++ b/apps/src/lib/node/ledger/shell/process_proposal.rs @@ -159,12 +159,10 @@ where masp() }; // check that the fee payer has sufficient balance - let balance = self.get_balance( - &self.storage.native_token, - &fee_payer, - ); + let balance = + self.get_balance(&tx.fee.token, &fee_payer); - if Amount::from(100) <= balance { + if Amount::from(MIN_FEE) <= balance { TxResult { code: ErrorCodes::Ok.into(), info: "Process proposal accepted this \ diff --git a/core/src/types/transaction/wrapper.rs b/core/src/types/transaction/wrapper.rs index e0e6dab6be..7d9493960d 100644 --- a/core/src/types/transaction/wrapper.rs +++ b/core/src/types/transaction/wrapper.rs @@ -21,6 +21,8 @@ pub mod wrapper_tx { hash_tx, EncryptionKey, Hash, TxError, TxType, }; + /// Minimum fee amount in micro NAMs + pub const MIN_FEE: u64 = 100; /// TODO: Determine a sane number for this const GAS_LIMIT_RESOLUTION: u64 = 1_000_000;