diff --git a/.changelog/unreleased/improvements/3391-parameterize-gas-scale.md b/.changelog/unreleased/improvements/3391-parameterize-gas-scale.md
new file mode 100644
index 0000000000..2729821cb7
--- /dev/null
+++ b/.changelog/unreleased/improvements/3391-parameterize-gas-scale.md
@@ -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))
\ No newline at end of file
diff --git a/crates/apps_lib/src/config/genesis.rs b/crates/apps_lib/src/config/genesis.rs
index cbd89f1130..dcf193ca4b 100644
--- a/crates/apps_lib/src/config/genesis.rs
+++ b/crates/apps_lib/src/config/genesis.rs
@@ -311,6 +311,8 @@ pub struct Parameters {
pub masp_epoch_multiplier: 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: BTreeMap
,
}
diff --git a/crates/apps_lib/src/config/genesis/chain.rs b/crates/apps_lib/src/config/genesis/chain.rs
index 827d7df9ad..a7bd75a22c 100644
--- a/crates/apps_lib/src/config/genesis/chain.rs
+++ b/crates/apps_lib/src/config/genesis/chain.rs
@@ -303,6 +303,7 @@ impl Finalized {
epochs_per_year,
masp_epoch_multiplier,
fee_unshielding_gas_limit,
+ gas_scale,
max_block_gas,
minimum_gas_price,
max_tx_bytes,
@@ -344,6 +345,7 @@ impl Finalized {
masp_epoch_multiplier,
max_proposal_bytes,
fee_unshielding_gas_limit,
+ gas_scale,
max_block_gas,
minimum_gas_price: minimum_gas_price
.iter()
diff --git a/crates/apps_lib/src/config/genesis/templates.rs b/crates/apps_lib/src/config/genesis/templates.rs
index e21e1fc1c7..377bb8ba70 100644
--- a/crates/apps_lib/src/config/genesis/templates.rs
+++ b/crates/apps_lib/src/config/genesis/templates.rs
@@ -296,6 +296,8 @@ pub struct ChainParams {
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,
}
@@ -318,6 +320,7 @@ impl ChainParams {
masp_epoch_multiplier,
max_block_gas,
fee_unshielding_gas_limit,
+ gas_scale,
minimum_gas_price,
} = self;
let mut min_gas_prices = BTreeMap::default();
@@ -362,6 +365,7 @@ impl ChainParams {
masp_epoch_multiplier,
max_block_gas,
fee_unshielding_gas_limit,
+ gas_scale,
minimum_gas_price: min_gas_prices,
})
}
diff --git a/crates/core/src/parameters.rs b/crates/core/src/parameters.rs
index e1faea6885..8e4a1d779d 100644
--- a/crates/core/src/parameters.rs
+++ b/crates/core/src/parameters.rs
@@ -49,6 +49,8 @@ pub struct Parameters {
pub masp_epoch_multiplier: 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: BTreeMap,
/// Enable the native token transfer if it is true
diff --git a/crates/gas/src/lib.rs b/crates/gas/src/lib.rs
index 89e24209ff..dc9c4c0a20 100644
--- a/crates/gas/src/lib.rs
+++ b/crates/gas/src/lib.rs
@@ -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 = std::result::Result;
-/// 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.
@@ -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
@@ -167,8 +172,8 @@ impl Gas {
}
/// Generates a `Gas` instance from a whole amount
- pub fn from_whole_units(whole: u64) -> Option {
- let sub = whole.checked_mul(SCALE)?;
+ pub fn from_whole_units(whole: u64, scale: u64) -> Option {
+ let sub = whole.checked_mul(scale)?;
Some(Self { sub })
}
}
@@ -187,8 +192,9 @@ impl From 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)
}
}
@@ -197,8 +203,7 @@ impl FromStr for Gas {
fn from_str(s: &str) -> std::result::Result {
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 })
}
}
diff --git a/crates/namada/src/ledger/mod.rs b/crates/namada/src/ledger/mod.rs
index b9c81a2ed6..11a6e59348 100644
--- a/crates/namada/src/ledger/mod.rs
+++ b/crates/namada/src/ledger/mod.rs
@@ -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};
@@ -54,43 +53,47 @@ mod dry_run_tx {
let tx = Tx::try_from(&request.data[..]).into_storage_result()?;
tx.validate_tx().into_storage_result()?;
- // Wrapper dry run to allow estimating the gas cost of a transaction
- let (wrapper_hash, 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 tx_gas_meter = RefCell::new(TxGasMeter::new(gas_limit));
- let tx_result = protocol::apply_wrapper_tx(
- &tx,
- &wrapper,
- &request.data,
- &tx_gas_meter,
- &mut temp_state,
- None,
- )
- .into_storage_result()?;
+ let gas_scale = namada_parameters::get_gas_scale(ctx.state)?;
- temp_state.write_log_mut().commit_tx();
- let available_gas = tx_gas_meter.borrow().get_available_gas();
- (
- Some(tx.header_hash()),
- tx_result,
- TxGasMeter::new_from_sub_limit(available_gas),
- )
- }
- _ => {
- // If dry run only the inner tx, use the max block gas as
- // 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))
+ // Wrapper dry run to allow estimating the gas cost of a transaction
+ let (wrapper_hash, mut tx_result, tx_gas_meter) =
+ match tx.header().tx_type {
+ TxType::Wrapper(wrapper) => {
+ 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,
+ &wrapper,
+ &request.data,
+ &tx_gas_meter,
+ &mut temp_state,
+ None,
+ )
.into_storage_result()?;
- (None, TxResult::default(), TxGasMeter::new(gas_limit))
- }
- };
+
+ temp_state.write_log_mut().commit_tx();
+ let available_gas =
+ tx_gas_meter.borrow().get_available_gas();
+ (
+ Some(tx.header_hash()),
+ tx_result,
+ TxGasMeter::new_from_sub_limit(available_gas),
+ )
+ }
+ _ => {
+ // If dry run only the inner tx, use the max block gas as
+ // the gas limit
+ let max_block_gas =
+ namada_parameters::get_max_block_gas(ctx.state)?;
+ let gas_limit = GasLimit::from(max_block_gas)
+ .as_scaled_gas(gas_scale)
+ .into_storage_result()?;
+ (None, TxResult::default(), TxGasMeter::new(gas_limit))
+ }
+ };
let tx_gas_meter = RefCell::new(tx_gas_meter);
for cmt in tx.commitments() {
@@ -195,6 +198,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();
diff --git a/crates/namada/src/ledger/protocol/mod.rs b/crates/namada/src/ledger/protocol/mod.rs
index b66cb28c2b..f459822dde 100644
--- a/crates/namada/src/ledger/protocol/mod.rs
+++ b/crates/namada/src/ledger/protocol/mod.rs
@@ -266,6 +266,7 @@ where
tx_wasm_cache,
},
)?;
+
Ok(TxResult {
gas_used: tx_gas_meter.borrow().get_tx_consumed_gas(),
batch_results: {
diff --git a/crates/node/src/shell/finalize_block.rs b/crates/node/src/shell/finalize_block.rs
index baa91e6b76..df19a749b5 100644
--- a/crates/node/src/shell/finalize_block.rs
+++ b/crates/node/src/shell/finalize_block.rs
@@ -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;
@@ -385,9 +386,17 @@ where
.unwrap_or(""),
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
@@ -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));
@@ -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()));
}
@@ -667,22 +694,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
diff --git a/crates/node/src/shell/mod.rs b/crates/node/src/shell/mod.rs
index 4f9eae585e..ca388843ec 100644
--- a/crates/node/src/shell/mod.rs
+++ b/crates/node/src/shell/mod.rs
@@ -50,7 +50,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::{
@@ -1095,9 +1095,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();
@@ -1119,6 +1132,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 {
diff --git a/crates/node/src/shell/prepare_proposal.rs b/crates/node/src/shell/prepare_proposal.rs
index 6cc2f22392..aa6fe39b5f 100644
--- a/crates/node/src/shell/prepare_proposal.rs
+++ b/crates/node/src/shell/prepare_proposal.rs
@@ -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};
@@ -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(|_| ())?;
diff --git a/crates/node/src/shell/process_proposal.rs b/crates/node/src/shell/process_proposal.rs
index f226097c11..7554be9e50 100644
--- a/crates/node/src/shell/process_proposal.rs
+++ b/crates/node/src/shell/process_proposal.rs
@@ -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 {
diff --git a/crates/node/src/storage/mod.rs b/crates/node/src/storage/mod.rs
index 5b084133ee..569bb7cbe7 100644
--- a/crates/node/src/storage/mod.rs
+++ b/crates/node/src/storage/mod.rs
@@ -174,6 +174,7 @@ mod tests {
epochs_per_year: 365,
masp_epoch_multiplier: 2,
fee_unshielding_gas_limit: 0,
+ gas_scale: 100_000_000,
minimum_gas_price: Default::default(),
is_native_token_transferable: true,
};
diff --git a/crates/parameters/src/lib.rs b/crates/parameters/src/lib.rs
index fe6424d843..9a82ab4d70 100644
--- a/crates/parameters/src/lib.rs
+++ b/crates/parameters/src/lib.rs
@@ -29,7 +29,7 @@ use namada_core::storage::{BlockHeight, Key};
use namada_core::time::DurationSecs;
use namada_core::{hints, token};
use namada_storage::{ResultExt, StorageRead, StorageWrite};
-pub use storage::get_max_block_gas;
+pub use storage::{get_gas_scale, get_max_block_gas};
use thiserror::Error;
pub use wasm_allowlist::{is_tx_allowed, is_vp_allowed};
@@ -77,6 +77,7 @@ where
masp_epoch_multiplier,
minimum_gas_price,
fee_unshielding_gas_limit,
+ gas_scale,
is_native_token_transferable,
} = parameters;
@@ -101,6 +102,10 @@ where
storage::get_fee_unshielding_gas_limit_key();
storage.write(&fee_unshielding_gas_limit_key, fee_unshielding_gas_limit)?;
+ // write the gas scale
+ let gas_scale_key = storage::get_gas_scale_key();
+ storage.write(&gas_scale_key, gas_scale)?;
+
// write vp allowlist parameter
let vp_allowlist_key = storage::get_vp_allowlist_storage_key();
let vp_allowlist = vp_allowlist
@@ -333,6 +338,13 @@ where
.ok_or(ReadError::ParametersMissing)
.into_storage_result()?;
+ // read gas scale
+ let gas_scale_key = storage::get_gas_scale_key();
+ let value = storage.read(&gas_scale_key)?;
+ let gas_scale: u64 = value
+ .ok_or(ReadError::ParametersMissing)
+ .into_storage_result()?;
+
// read epochs per year
let epochs_per_year_key = storage::get_epochs_per_year_key();
let value = storage.read(&epochs_per_year_key)?;
@@ -376,6 +388,7 @@ where
masp_epoch_multiplier,
minimum_gas_price,
fee_unshielding_gas_limit,
+ gas_scale,
is_native_token_transferable,
})
}
@@ -419,6 +432,7 @@ where
epochs_per_year: 365,
masp_epoch_multiplier: 2,
fee_unshielding_gas_limit: 0,
+ gas_scale: 100_000_000,
minimum_gas_price: Default::default(),
is_native_token_transferable: true,
};
diff --git a/crates/parameters/src/storage.rs b/crates/parameters/src/storage.rs
index 19caeb0114..500aa1ff6c 100644
--- a/crates/parameters/src/storage.rs
+++ b/crates/parameters/src/storage.rs
@@ -38,6 +38,7 @@ struct Keys {
max_block_gas: &'static str,
minimum_gas_price: &'static str,
fee_unshielding_gas_limit: &'static str,
+ gas_scale: &'static str,
native_token_transferable: &'static str,
}
@@ -114,6 +115,11 @@ pub fn get_fee_unshielding_gas_limit_key() -> Key {
get_fee_unshielding_gas_limit_key_at_addr(ADDRESS)
}
+/// Storage key used for the gas scale
+pub fn get_gas_scale_key() -> Key {
+ get_gas_scale_key_at_addr(ADDRESS)
+}
+
/// Storage key used for implicit VP parameter.
pub fn get_implicit_vp_key() -> Key {
get_implicit_vp_key_at_addr(ADDRESS)
@@ -161,6 +167,18 @@ pub fn get_max_block_gas(
)
}
+/// Helper function to retrieve the `gas_scale` protocol parameter from
+/// storage
+pub fn get_gas_scale(
+ storage: &impl StorageRead,
+) -> std::result::Result {
+ storage.read(&get_gas_scale_key())?.ok_or(
+ namada_storage::Error::SimpleMessage(
+ "Missing gas_scale parameter from storage",
+ ),
+ )
+}
+
/// Storage key used for the flag to enable the native token transfer
pub fn get_native_token_transferable_key() -> Key {
get_native_token_transferable_key_at_addr(ADDRESS)
diff --git a/crates/proof_of_stake/src/lib.rs b/crates/proof_of_stake/src/lib.rs
index 5c5a6b43c7..ca8b0a36ab 100644
--- a/crates/proof_of_stake/src/lib.rs
+++ b/crates/proof_of_stake/src/lib.rs
@@ -2725,6 +2725,7 @@ pub mod test_utils {
epochs_per_year: 10000000,
masp_epoch_multiplier: 2,
fee_unshielding_gas_limit: 10000,
+ gas_scale: 100_000_000,
minimum_gas_price: BTreeMap::new(),
is_native_token_transferable: true,
};
diff --git a/crates/sdk/src/rpc.rs b/crates/sdk/src/rpc.rs
index 989ae6ace1..4c3a6f80c1 100644
--- a/crates/sdk/src/rpc.rs
+++ b/crates/sdk/src/rpc.rs
@@ -559,6 +559,7 @@ pub async fn dry_run_tx(
)?
.data;
let result_str = format!("Transaction consumed {} gas", result.gas_used);
+
let mut cmt_result_str = String::new();
for (inner_hash, cmt_result) in result.batch_results.iter() {
match cmt_result {
diff --git a/crates/sdk/src/tx.rs b/crates/sdk/src/tx.rs
index 6f60c069ba..d84814a25b 100644
--- a/crates/sdk/src/tx.rs
+++ b/crates/sdk/src/tx.rs
@@ -420,9 +420,11 @@ pub fn display_batch_resp(context: &impl Namada, resp: &TxResponse) {
InnerTxResult::Success(_) => {
display_line!(
context.io(),
- "Transaction {} was successfully applied at height {}.",
+ "Transaction {} was successfully applied at height {}, \
+ consuming {} gas units.",
inner_hash,
resp.height,
+ resp.gas_used
);
}
InnerTxResult::VpsRejected(inner) => {
diff --git a/crates/state/src/lib.rs b/crates/state/src/lib.rs
index 37832d46e5..071a8d1a19 100644
--- a/crates/state/src/lib.rs
+++ b/crates/state/src/lib.rs
@@ -755,6 +755,7 @@ mod tests {
epochs_per_year: 100,
masp_epoch_multiplier: 2,
fee_unshielding_gas_limit: 20_000,
+ gas_scale: 100_000_000,
minimum_gas_price: BTreeMap::default(),
is_native_token_transferable: true,
};
diff --git a/crates/tests/src/e2e/ibc_tests.rs b/crates/tests/src/e2e/ibc_tests.rs
index 4e8dc13a2a..92124cfca9 100644
--- a/crates/tests/src/e2e/ibc_tests.rs
+++ b/crates/tests/src/e2e/ibc_tests.rs
@@ -2215,13 +2215,13 @@ fn transfer_from_gaia(
fn check_tx_height(test: &Test, client: &mut NamadaCmd) -> Result {
let (_unread, matched) = client.exp_regex(r"height .*")?;
- // Expecting e.g. "height 1337."
+ // Expecting e.g. "height 1337, consuming x gas units."
let height_str = matched
.trim()
.split_once(' ')
.unwrap()
.1
- .split_once('.')
+ .split_once(',')
.unwrap()
.0;
let height: u32 = height_str.parse().unwrap();
diff --git a/crates/tx/src/data/mod.rs b/crates/tx/src/data/mod.rs
index 6792acc83c..8c6c1b4095 100644
--- a/crates/tx/src/data/mod.rs
+++ b/crates/tx/src/data/mod.rs
@@ -496,7 +496,7 @@ pub struct VpsResult {
impl fmt::Display for TxResult {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if f.alternate() {
- write!(f, "Transaction is valid. Gas used: {}", self.gas_used,)
+ write!(f, "Transaction is valid. Gas used: {}", self.gas_used)
} else {
write!(f, "{}", serde_json::to_string(self).unwrap())
}
diff --git a/crates/tx/src/data/wrapper.rs b/crates/tx/src/data/wrapper.rs
index 23bd4c53f1..3a2f1ebcc7 100644
--- a/crates/tx/src/data/wrapper.rs
+++ b/crates/tx/src/data/wrapper.rs
@@ -111,13 +111,10 @@ impl From for Amount {
}
}
-impl TryFrom for Gas {
- type Error = std::io::Error;
-
- /// Derive a Gas instance with a sub amount which is exactly a whole
- /// amount since the limit represents gas in whole units
- fn try_from(value: GasLimit) -> Result {
- Self::from_whole_units(u64::from(value)).ok_or_else(|| {
+impl GasLimit {
+ /// Convert the gas limit into scaled gas
+ pub fn as_scaled_gas(&self, scale: u64) -> Result {
+ Gas::from_whole_units(u64::from(*self), scale).ok_or_else(|| {
std::io::Error::new(
std::io::ErrorKind::InvalidInput,
"gas overflow",
diff --git a/genesis/localnet/parameters.toml b/genesis/localnet/parameters.toml
index 17c03b9c62..f2d16129d2 100644
--- a/genesis/localnet/parameters.toml
+++ b/genesis/localnet/parameters.toml
@@ -22,6 +22,8 @@ masp_epoch_multiplier = 2
max_block_gas = 20000000
# Fee unshielding gas limit
fee_unshielding_gas_limit = 20000
+# Gas scale
+gas_scale = 100_000_000
# Map of the cost per gas unit for every token allowed for fee payment
[parameters.minimum_gas_price]
diff --git a/genesis/starter/parameters.toml b/genesis/starter/parameters.toml
index 6889b8125e..1541779cd0 100644
--- a/genesis/starter/parameters.toml
+++ b/genesis/starter/parameters.toml
@@ -24,6 +24,8 @@ max_signatures_per_transaction = 15
max_block_gas = 20000000
# Fee unshielding gas limit
fee_unshielding_gas_limit = 20000
+# Gas scale
+gas_scale = 100_000_000
# Map of the cost per gas unit for every token allowed for fee payment
[parameters.minimum_gas_price]