From 7208f91d264b13bee06a622c5f748f4fc60e6965 Mon Sep 17 00:00:00 2001 From: Milosz Muszynski Date: Thu, 18 Jul 2024 16:03:57 +0200 Subject: [PATCH] rusk: gas_per_deploy_byte configuration parameter --- rusk/default.config.toml | 2 + rusk/src/bin/config/chain.rs | 7 ++++ rusk/src/bin/main.rs | 1 + rusk/src/lib/chain.rs | 1 + rusk/src/lib/chain/rusk.rs | 47 ++++++++++++++++------ rusk/tests/common/state.rs | 2 +- rusk/tests/services/contract_deployment.rs | 2 +- 7 files changed, 48 insertions(+), 14 deletions(-) diff --git a/rusk/default.config.toml b/rusk/default.config.toml index 06aec0e087..c0dd6cf904 100644 --- a/rusk/default.config.toml +++ b/rusk/default.config.toml @@ -12,6 +12,8 @@ #db_path = '/home/user/.dusk/rusk' #consensus_keys_path = '/home/user/.dusk/rusk/consensus.keys' #generation_timeout = '3s' +# Note: changing the gas per deploy byte parameter is equivalent to forking the chain. +#gas_per_deploy_byte = 100 [databroker] max_inv_entries = 100 diff --git a/rusk/src/bin/config/chain.rs b/rusk/src/bin/config/chain.rs index 3388223a6f..d16d2e9d10 100644 --- a/rusk/src/bin/config/chain.rs +++ b/rusk/src/bin/config/chain.rs @@ -19,6 +19,9 @@ pub(crate) struct ChainConfig { consensus_keys_path: Option, #[serde(with = "humantime_serde")] generation_timeout: Option, + // Note: changing the gas per deploy byte parameter is equivalent to + // forking the chain. + gas_per_deploy_byte: Option, } impl ChainConfig { @@ -65,4 +68,8 @@ impl ChainConfig { pub(crate) fn generation_timeout(&self) -> Option { self.generation_timeout } + + pub(crate) fn gas_per_deploy_byte(&self) -> Option { + self.gas_per_deploy_byte + } } diff --git a/rusk/src/bin/main.rs b/rusk/src/bin/main.rs index c005ca9e67..ee4b52c98e 100644 --- a/rusk/src/bin/main.rs +++ b/rusk/src/bin/main.rs @@ -106,6 +106,7 @@ async fn main() -> Result<(), Box> { let rusk = Rusk::new( state_dir, config.chain.generation_timeout(), + config.chain.gas_per_deploy_byte(), config.http.feeder_call_gas, _event_sender, )?; diff --git a/rusk/src/lib/chain.rs b/rusk/src/lib/chain.rs index 75a44b9999..1a99636353 100644 --- a/rusk/src/lib/chain.rs +++ b/rusk/src/lib/chain.rs @@ -35,6 +35,7 @@ pub struct Rusk { pub(crate) vm: Arc, dir: PathBuf, pub(crate) generation_timeout: Option, + pub(crate) gas_per_deploy_byte: Option, pub(crate) feeder_gas_limit: u64, pub(crate) event_sender: broadcast::Sender, } diff --git a/rusk/src/lib/chain/rusk.rs b/rusk/src/lib/chain/rusk.rs index fb7c050876..9fbf7f1ab7 100644 --- a/rusk/src/lib/chain/rusk.rs +++ b/rusk/src/lib/chain/rusk.rs @@ -18,6 +18,7 @@ use dusk_bytes::{DeserializableSlice, Serializable}; use dusk_consensus::operations::{ CallParams, VerificationOutput, VoterWithCredits, }; +use execution_core::bytecode::Bytecode; use execution_core::{ stake::StakeData, transfer::Transaction as PhoenixTransaction, BlsScalar, StakePublicKey, @@ -43,12 +44,13 @@ pub static DUSK_KEY: LazyLock = LazyLock::new(|| { .expect("Dusk consensus public key to be valid") }); -const GAS_PER_DEPLOY_BYTE: u64 = 100; +const DEFAULT_GAS_PER_DEPLOY_BYTE: u64 = 100; impl Rusk { pub fn new>( dir: P, generation_timeout: Option, + gas_per_deploy_byte: Option, feeder_gas_limit: u64, event_sender: broadcast::Sender, ) -> Result { @@ -81,6 +83,7 @@ impl Rusk { vm, dir: dir.into(), generation_timeout, + gas_per_deploy_byte, feeder_gas_limit, event_sender, }) @@ -124,7 +127,11 @@ impl Rusk { continue; } - match execute(&mut session, &unspent_tx.inner) { + match execute( + &mut session, + &unspent_tx.inner, + self.gas_per_deploy_byte, + ) { Ok(receipt) => { let gas_spent = receipt.gas_spent; @@ -138,8 +145,11 @@ impl Rusk { for spent_tx in &spent_txs { // We know these transactions were correctly // executed before, so we don't bother checking. - let _ = - execute(&mut session, &spent_tx.inner.inner); + let _ = execute( + &mut session, + &spent_tx.inner.inner, + self.gas_per_deploy_byte, + ); } continue; @@ -213,6 +223,7 @@ impl Rusk { txs, missed_generators, voters, + self.gas_per_deploy_byte, ) .map(|(a, b, _, _)| (a, b)) } @@ -243,6 +254,7 @@ impl Rusk { &txs[..], missed_generators, voters, + self.gas_per_deploy_byte, )?; if let Some(expected_verification) = consistency_check { @@ -418,6 +430,7 @@ fn accept( txs: &[Transaction], missed_generators: &[StakePublicKey], voters: Option<&[VoterWithCredits]>, + gas_per_deploy_byte: Option, ) -> Result<( Vec, VerificationOutput, @@ -436,7 +449,7 @@ fn accept( for unspent_tx in txs { let tx = &unspent_tx.inner; - let receipt = execute(&mut session, tx)?; + let receipt = execute(&mut session, tx, gas_per_deploy_byte)?; update_hasher(&mut event_hasher, &receipt.events); events.extend(receipt.events); @@ -483,6 +496,15 @@ fn accept( )) } +// Returns gas charge for bytecode deployment. +fn bytecode_charge( + bytecode: &Bytecode, + gas_per_deploy_byte: &Option, +) -> u64 { + bytecode.bytes.len() as u64 + * gas_per_deploy_byte.unwrap_or(DEFAULT_GAS_PER_DEPLOY_BYTE) +} + /// Executes a transaction, returning the receipt of the call and the gas spent. /// The following steps are performed: /// @@ -497,11 +519,12 @@ fn accept( fn execute( session: &mut Session, tx: &PhoenixTransaction, + gas_per_deploy_byte: Option, ) -> Result, ContractError>>, PiecrustError> { if let Some(deploy) = tx.payload().contract_deploy() { - let bytecode_charge = - deploy.bytecode.bytes.len() as u64 * GAS_PER_DEPLOY_BYTE; - if tx.payload().fee.gas_limit < bytecode_charge { + let deploy_charge = + bytecode_charge(&deploy.bytecode, &gas_per_deploy_byte); + if tx.payload().fee.gas_limit < deploy_charge { return Err(PiecrustError::Panic( "not enough gas to deploy".into(), )); @@ -521,9 +544,9 @@ fn execute( // Deploy if this is a deployment transaction if let Some(deploy) = tx.payload().contract_deploy() { if receipt.data.is_ok() { - let bytecode_charge = - deploy.bytecode.bytes.len() as u64 * GAS_PER_DEPLOY_BYTE; - let min_gas_limit = receipt.gas_spent + bytecode_charge; + let deploy_charge = + bytecode_charge(&deploy.bytecode, &gas_per_deploy_byte); + let min_gas_limit = receipt.gas_spent + deploy_charge; let hash = blake3::hash(deploy.bytecode.bytes.as_slice()); if tx.payload().fee.gas_limit < min_gas_limit { receipt.data = Err(OutOfGas); @@ -539,7 +562,7 @@ fn execute( ); match result { Ok(_) => { - receipt.gas_spent += bytecode_charge; + receipt.gas_spent += deploy_charge; } Err(err) => { info!("Tx caused deployment error {err:?}"); diff --git a/rusk/tests/common/state.rs b/rusk/tests/common/state.rs index 3491ee9f6d..3b1f60e467 100644 --- a/rusk/tests/common/state.rs +++ b/rusk/tests/common/state.rs @@ -36,7 +36,7 @@ pub fn new_state>(dir: P, snapshot: &Snapshot) -> Result { let (sender, _) = broadcast::channel(10); - let rusk = Rusk::new(dir, None, u64::MAX, sender) + let rusk = Rusk::new(dir, None, None, u64::MAX, sender) .expect("Instantiating rusk should succeed"); assert_eq!( diff --git a/rusk/tests/services/contract_deployment.rs b/rusk/tests/services/contract_deployment.rs index b5878320b4..6f2bd20ae0 100644 --- a/rusk/tests/services/contract_deployment.rs +++ b/rusk/tests/services/contract_deployment.rs @@ -88,7 +88,7 @@ fn initial_state>(dir: P, deploy_bob: bool) -> Result { let (sender, _) = broadcast::channel(10); - let rusk = Rusk::new(dir, None, u64::MAX, sender) + let rusk = Rusk::new(dir, None, None, u64::MAX, sender) .expect("Instantiating rusk should succeed"); Ok(rusk) }