Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
- Include the gas scale as a protocol parameter that is
mutable via governance rather than as a hard-coded constant.
([\#3391](https://github.com/anoma/namada/pull/3391))
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
29 changes: 17 additions & 12 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 @@ -187,8 +192,9 @@ 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())
// Need to do this now that the gas scale is a parameter. Should
// manually scale gas first before calling this
write!(f, "{}", self.sub)
}
}

Expand All @@ -197,8 +203,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
18 changes: 14 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 @@ -54,11 +53,15 @@ mod dry_run_tx {
let tx = Tx::try_from(&request.data[..]).into_storage_result()?;
tx.validate_tx().into_storage_result()?;

let gas_scale = namada_parameters::get_gas_scale(ctx.state)?;

// 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_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 @@ -79,7 +82,8 @@ mod dry_run_tx {
// the gas limit
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 Expand Up @@ -187,6 +191,12 @@ mod test {
.expect(
"Max block gas parameter must be initialized in storage",
);
// Initialize mock gas scale
let gas_scale_key = namada_parameters::storage::get_gas_scale_key();
state
.db_write(&gas_scale_key, 100_000_000_u64.serialize_to_vec())
.expect("Gas scale parameter must be initialized in storage");

let event_log = EventLog::default();
let (vp_wasm_cache, vp_cache_dir) =
wasm::compilation_cache::common::testing::cache();
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
18 changes: 16 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 @@ -1067,9 +1067,22 @@ where
}
},
TxType::Wrapper(wrapper) => {
// Get the gas scale first
let gas_scale = match get_gas_scale(&self.state) {
Ok(scale) => scale,
Err(_) => {
response.code = ResultCode::InvalidTx.into();
response.log = "The gas scale could not be found in \
the parameters storage"
.to_string();
return response;
}
};

// Validate wrapper first
// Tx gas limit
let gas_limit = match Gas::try_from(wrapper.gas_limit) {
let gas_limit = match wrapper.gas_limit.as_scaled_gas(gas_scale)
{
Ok(value) => value,
Err(_) => {
response.code = ResultCode::InvalidTx.into();
Expand All @@ -1091,6 +1104,7 @@ where
// Max block gas
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
7 changes: 5 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,9 @@ 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).map_err(|_| ())?;
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