Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions crates/apps_lib/src/config/genesis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,8 @@ pub struct Parameters {
pub max_signatures_per_transaction: u8,
/// Fee unshielding gas limit
pub fee_unshielding_gas_limit: u64,
/// Gas scale
pub gas_scale: u64,
/// Map of the cost per gas unit for every token allowed for fee payment
pub minimum_gas_price: BTreeMap<Address, token::Amount>,
}
Expand Down
2 changes: 2 additions & 0 deletions crates/apps_lib/src/config/genesis/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,7 @@ impl Finalized {
masp_epoch_multiplier,
max_signatures_per_transaction,
fee_unshielding_gas_limit,
gas_scale,
max_block_gas,
minimum_gas_price,
max_tx_bytes,
Expand Down Expand Up @@ -351,6 +352,7 @@ impl Finalized {
max_proposal_bytes,
max_signatures_per_transaction,
fee_unshielding_gas_limit,
gas_scale,
max_block_gas,
minimum_gas_price: minimum_gas_price
.iter()
Expand Down
4 changes: 4 additions & 0 deletions crates/apps_lib/src/config/genesis/templates.rs
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,8 @@ pub struct ChainParams<T: TemplateValidation> {
pub max_block_gas: u64,
/// Fee unshielding gas limit
pub fee_unshielding_gas_limit: u64,
/// Gas scale
pub gas_scale: u64,
/// Map of the cost per gas unit for every token allowed for fee payment
pub minimum_gas_price: T::GasMinimums,
}
Expand All @@ -325,6 +327,7 @@ impl ChainParams<Unvalidated> {
max_signatures_per_transaction,
max_block_gas,
fee_unshielding_gas_limit,
gas_scale,
minimum_gas_price,
} = self;
let mut min_gas_prices = BTreeMap::default();
Expand Down Expand Up @@ -371,6 +374,7 @@ impl ChainParams<Unvalidated> {
max_signatures_per_transaction,
max_block_gas,
fee_unshielding_gas_limit,
gas_scale,
minimum_gas_price: min_gas_prices,
})
}
Expand Down
2 changes: 2 additions & 0 deletions crates/core/src/parameters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ pub struct Parameters {
pub max_signatures_per_transaction: u8,
/// Fee unshielding gas limit
pub fee_unshielding_gas_limit: u64,
/// Gas scale
pub gas_scale: u64,
/// Map of the cost per gas unit for every token allowed for fee payment
pub minimum_gas_price: BTreeMap<Address, token::Amount>,
/// Enable the native token transfer if it is true
Expand Down
14 changes: 14 additions & 0 deletions crates/gas/src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,17 @@ impl EventAttributeEntry<'static> for GasUsed {
self.0
}
}

/// Extend a [`namada_events::Event`] with the gas scale data.
pub struct GasScale(pub u64);

impl EventAttributeEntry<'static> for GasScale {
type Value = u64;
type ValueOwned = Self::Value;

const KEY: &'static str = "gas_scale";

fn into_value(self) -> Self::Value {
self.0
}
}
26 changes: 15 additions & 11 deletions crates/gas/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,6 @@ pub const MASP_PARALLEL_GAS_DIVIDER: u64 = PARALLEL_GAS_DIVIDER / 2;
/// Gas module result for functions that may fail
pub type Result<T> = std::result::Result<T, Error>;

/// Decimal scale of Gas units
const SCALE: u64 = 100_000_000;

/// Representation of gas in sub-units. This effectively decouples gas metering
/// from fee payment, allowing higher resolution when accounting for gas while,
/// at the same time, providing a contained gas value when paying fees.
Expand Down Expand Up @@ -155,9 +152,17 @@ impl Gas {

/// Converts the sub gas units to whole ones. If the sub units are not a
/// multiple of the `SCALE` than ceil the quotient
fn get_whole_gas_units(&self) -> u64 {
let quotient = self.sub / SCALE;
if self.sub % SCALE == 0 {
pub fn get_whole_gas_units(&self, scale: u64) -> u64 {
let quotient = self
.sub
.checked_div(scale)
.expect("Gas quotient should not overflow on checked division");
if self
.sub
.checked_rem(scale)
.expect("Gas quotient remainder should not overflow")
== 0
{
quotient
} else {
quotient
Expand All @@ -167,8 +172,8 @@ impl Gas {
}

/// Generates a `Gas` instance from a whole amount
pub fn from_whole_units(whole: u64) -> Option<Self> {
let sub = whole.checked_mul(SCALE)?;
pub fn from_whole_units(whole: u64, scale: u64) -> Option<Self> {
let sub = whole.checked_mul(scale)?;
Some(Self { sub })
}
}
Expand All @@ -188,7 +193,7 @@ impl From<Gas> for u64 {
impl Display for Gas {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
// Display the gas in whole amounts
write!(f, "{}", self.get_whole_gas_units())
write!(f, "{}", self.sub)
}
}

Expand All @@ -197,8 +202,7 @@ impl FromStr for Gas {

fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
let raw: u64 = s.parse().map_err(GasParseError::Parse)?;
let gas = Gas::from_whole_units(raw).ok_or(GasParseError::Overflow)?;
Ok(gas)
Ok(Self { sub: raw })
}
}

Expand Down
13 changes: 9 additions & 4 deletions crates/namada/src/ledger/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ pub use {
mod dry_run_tx {
use std::cell::RefCell;

use namada_gas::Gas;
use namada_sdk::queries::{EncodedResponseQuery, RequestCtx, RequestQuery};
use namada_state::{DBIter, ResultExt, StorageHasher, DB};
use namada_tx::data::{GasLimit, TxResult};
Expand Down Expand Up @@ -57,8 +56,11 @@ mod dry_run_tx {
// Wrapper dry run to allow estimating the gas cost of a transaction
let (mut tx_result, tx_gas_meter) = match tx.header().tx_type {
TxType::Wrapper(wrapper) => {
let gas_limit =
Gas::try_from(wrapper.gas_limit).into_storage_result()?;
let gas_scale = namada_parameters::get_gas_scale(ctx.state)?;
let gas_limit = wrapper
.gas_limit
.as_scaled_gas(gas_scale)
.into_storage_result()?;
let tx_gas_meter = RefCell::new(TxGasMeter::new(gas_limit));
let tx_result = protocol::apply_wrapper_tx(
&tx,
Expand All @@ -77,9 +79,12 @@ mod dry_run_tx {
_ => {
// If dry run only the inner tx, use the max block gas as
// the gas limit
let gas_scale = namada_parameters::get_gas_scale(ctx.state)?;

let max_block_gas =
namada_parameters::get_max_block_gas(ctx.state)?;
let gas_limit = Gas::try_from(GasLimit::from(max_block_gas))
let gas_limit = GasLimit::from(max_block_gas)
.as_scaled_gas(gas_scale)
.into_storage_result()?;
(TxResult::default(), TxGasMeter::new(gas_limit))
}
Expand Down
1 change: 1 addition & 0 deletions crates/namada/src/ledger/protocol/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,7 @@ where
tx_wasm_cache,
},
)?;

Ok(TxResult {
gas_used: tx_gas_meter.borrow().get_tx_consumed_gas(),
batch_results: BatchResults(
Expand Down
68 changes: 49 additions & 19 deletions crates/node/src/shell/finalize_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ use namada::tx::event::{Batch, Code};
use namada::tx::new_tx_event;
use namada::vote_ext::ethereum_events::MultiSignedEthEvent;
use namada::vote_ext::ethereum_tx_data_variants;
use parameters::get_gas_scale;

use super::*;
use crate::facade::tendermint::abci::types::VoteInfo;
Expand Down Expand Up @@ -385,9 +386,17 @@ where
.unwrap_or("<unknown>"),
msg,
);
let gas_scale = get_gas_scale(&self.state)
.expect("Failed to get gas scale from parameters");
let scaled_gas = Gas::from(
tx_data
.tx_gas_meter
.get_tx_consumed_gas()
.get_whole_gas_units(gas_scale),
);
tx_logs
.tx_event
.extend(GasUsed(tx_data.tx_gas_meter.get_tx_consumed_gas()))
.extend(GasUsed(scaled_gas))
.extend(Info(msg.to_string()))
.extend(Code(ResultCode::InvalidTx));
// Make sure to clean the write logs for the next transaction
Expand All @@ -410,9 +419,18 @@ where
msg
);

let gas_scale = get_gas_scale(&self.state)
.expect("Failed to get gas scale from parameters");
let scaled_gas = Gas::from(
tx_data
.tx_gas_meter
.get_tx_consumed_gas()
.get_whole_gas_units(gas_scale),
);

tx_logs
.tx_event
.extend(GasUsed(tx_data.tx_gas_meter.get_tx_consumed_gas()))
.extend(GasUsed(scaled_gas))
.extend(Info(msg.to_string()))
.extend(Code(ResultCode::WasmRuntimeError));

Expand Down Expand Up @@ -487,9 +505,18 @@ where
self.commit_batch_hash(tx_data.replay_protection_hashes);
}

let gas_scale = get_gas_scale(&self.state)
.expect("Failed to get gas scale from parameters");
let scaled_gas = Gas::from(
tx_data
.tx_gas_meter
.get_tx_consumed_gas()
.get_whole_gas_units(gas_scale),
);

tx_logs
.tx_event
.extend(GasUsed(extended_tx_result.tx_result.gas_used))
.extend(GasUsed(scaled_gas))
.extend(Info("Check batch for result.".to_string()))
.extend(Batch(&extended_tx_result.tx_result.to_result_string()));
}
Expand Down Expand Up @@ -669,22 +696,25 @@ where
TxType::Wrapper(wrapper) => {
stats.increment_wrapper_txs();

let gas_limit = match Gas::try_from(wrapper.gas_limit) {
Ok(value) => value,
Err(_) => {
response.events.emit(
new_tx_event(&tx, height.0)
.with(Code(ResultCode::InvalidTx))
.with(Info(
"The wrapper gas limit overflowed gas \
representation"
.to_owned(),
))
.with(GasUsed(0.into())),
);
continue;
}
};
let gas_scale = get_gas_scale(&self.state)
.expect("Failed to get gas scale from parameters");
let gas_limit =
match wrapper.gas_limit.as_scaled_gas(gas_scale) {
Ok(value) => value,
Err(_) => {
response.events.emit(
new_tx_event(&tx, height.0)
.with(Code(ResultCode::InvalidTx))
.with(Info(
"The wrapper gas limit overflowed \
gas representation"
.to_owned(),
))
.with(GasUsed(0.into())),
);
continue;
}
};
let tx_gas_meter = TxGasMeter::new(gas_limit);
for cmt in tx.commitments() {
if let Some(code_sec) = tx
Expand Down
10 changes: 8 additions & 2 deletions crates/node/src/shell/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ use namada::ledger::pos::namada_proof_of_stake::types::{
};
use namada::ledger::protocol::ShellParams;
use namada::ledger::{parameters, protocol};
use namada::parameters::validate_tx_bytes;
use namada::parameters::{get_gas_scale, validate_tx_bytes};
use namada::proof_of_stake::storage::read_pos_params;
use namada::state::tx_queue::ExpiredTx;
use namada::state::{
Expand Down Expand Up @@ -1069,7 +1069,10 @@ where
TxType::Wrapper(wrapper) => {
// Validate wrapper first
// Tx gas limit
let gas_limit = match Gas::try_from(wrapper.gas_limit) {
let gas_scale = get_gas_scale(&self.state)
.expect("Failed to get gas scale from parameters");
let gas_limit = match wrapper.gas_limit.as_scaled_gas(gas_scale)
{
Ok(value) => value,
Err(_) => {
response.code = ResultCode::InvalidTx.into();
Expand All @@ -1089,8 +1092,11 @@ where
}

// Max block gas
let gas_scale = namada::parameters::get_gas_scale(&self.state)
.expect("Failed to get gas scale from parameters");
let block_gas_limit: Gas = Gas::from_whole_units(
namada::parameters::get_max_block_gas(&self.state).unwrap(),
gas_scale,
)
.expect("Gas limit from parameter must not overflow");
if gas_meter.tx_gas_limit > block_gas_limit {
Expand Down
8 changes: 6 additions & 2 deletions crates/node/src/shell/prepare_proposal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ use std::cell::RefCell;

use namada::core::address::Address;
use namada::core::key::tm_raw_hash_to_string;
use namada::gas::{Gas, TxGasMeter};
use namada::gas::TxGasMeter;
use namada::hash::Hash;
use namada::ledger::protocol::{self, ShellParams};
use namada::parameters::get_gas_scale;
use namada::proof_of_stake::storage::find_validator_by_raw_hash;
use namada::state::{DBIter, StorageHasher, TempWlState, DB};
use namada::token::{Amount, DenominatedAmount};
Expand Down Expand Up @@ -288,7 +289,10 @@ where
tx.validate_tx().map_err(|_| ())?;
if let TxType::Wrapper(wrapper) = tx.header().tx_type {
// Check tx gas limit for tx size
let gas_limit = Gas::try_from(wrapper.gas_limit).map_err(|_| ())?;
let gas_scale = get_gas_scale(temp_state)
.expect("Failed to get gas scale from parameters");
let gas_limit =
wrapper.gas_limit.as_scaled_gas(gas_scale).map_err(|_| ())?;
let mut tx_gas_meter = TxGasMeter::new(gas_limit);
tx_gas_meter.add_wrapper_gas(tx_bytes).map_err(|_| ())?;

Expand Down
12 changes: 11 additions & 1 deletion crates/node/src/shell/process_proposal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -410,7 +410,17 @@ where
let allocated_gas =
metadata.user_gas.try_dump(u64::from(wrapper.gas_limit));

let gas_limit = match Gas::try_from(wrapper.gas_limit) {
let gas_scale = match get_gas_scale(temp_state) {
Ok(scale) => scale,
Err(_) => {
return TxResult {
code: ResultCode::TxGasLimit.into(),
info: "Failed to get gas scale".to_owned(),
};
}
};
let gas_limit = match wrapper.gas_limit.as_scaled_gas(gas_scale)
{
Ok(value) => value,
Err(_) => {
return TxResult {
Expand Down
1 change: 1 addition & 0 deletions crates/node/src/storage/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ mod tests {
masp_epoch_multiplier: 2,
max_signatures_per_transaction: 10,
fee_unshielding_gas_limit: 0,
gas_scale: 100_000_000,
minimum_gas_price: Default::default(),
is_native_token_transferable: true,
};
Expand Down
Loading