Skip to content

Commit

Permalink
rusk: improved deployment charging
Browse files Browse the repository at this point in the history
  • Loading branch information
miloszm committed Sep 6, 2024
1 parent 60158c1 commit 5473990
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 29 deletions.
2 changes: 2 additions & 0 deletions rusk/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Allow state transitions to be executed in parallel with queries [#970]
- Change dependencies declarations enforce bytecheck [#1371]
- Fixed tests passing incorrect arguments [#1371]
- Adjusted deployment charging [#2207]

### Added

Expand Down Expand Up @@ -211,6 +212,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Add linking between Rusk and Protobuff structs
- Add build system that generates keys for circuits and caches them.

[#2207]: https://github.com/dusk-network/rusk/issues/2207
[#1884]: https://github.com/dusk-network/rusk/issues/1884
[#1882]: https://github.com/dusk-network/rusk/issues/1882
[#1675]: https://github.com/dusk-network/rusk/issues/1675
Expand Down
8 changes: 4 additions & 4 deletions rusk/src/bin/config/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ pub(crate) struct ChainConfig {

max_queue_size: Option<usize>,

// NB: changing the gas_per_deploy_byte/block_gas_limit is equivalent to
// NB: changing the charge_per_deploy_byte/block_gas_limit is equivalent to
// forking the chain.
gas_per_deploy_byte: Option<u64>,
charge_per_deploy_byte: Option<u64>,
block_gas_limit: Option<u64>,
}

Expand Down Expand Up @@ -75,8 +75,8 @@ impl ChainConfig {
self.generation_timeout
}

pub(crate) fn gas_per_deploy_byte(&self) -> Option<u64> {
self.gas_per_deploy_byte
pub(crate) fn charge_per_deploy_byte(&self) -> Option<u64> {
self.charge_per_deploy_byte
}

pub(crate) fn max_queue_size(&self) -> usize {
Expand Down
2 changes: 1 addition & 1 deletion rusk/src/bin/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
state_dir,
config.kadcast.chain_id(),
config.chain.generation_timeout(),
config.chain.gas_per_deploy_byte(),
config.chain.charge_per_deploy_byte(),
config.chain.block_gas_limit(),
config.http.feeder_call_gas,
_event_sender.clone(),
Expand Down
2 changes: 1 addition & 1 deletion rusk/src/lib/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ pub struct Rusk {
dir: PathBuf,
pub(crate) chain_id: u8,
pub(crate) generation_timeout: Option<Duration>,
pub(crate) gas_per_deploy_byte: Option<u64>,
pub(crate) charge_per_deploy_byte: Option<u64>,
pub(crate) feeder_gas_limit: u64,
pub(crate) block_gas_limit: u64,
pub(crate) event_sender: broadcast::Sender<RuesEvent>,
Expand Down
57 changes: 34 additions & 23 deletions rusk/src/lib/node/rusk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
//
// Copyright (c) DUSK NETWORK. All rights reserved.

use std::cmp::max;
use std::path::Path;
use std::sync::{mpsc, Arc, LazyLock};
use std::time::{Duration, Instant};
Expand Down Expand Up @@ -49,14 +50,14 @@ pub static DUSK_KEY: LazyLock<BlsPublicKey> = LazyLock::new(|| {
.expect("Dusk consensus public key to be valid")
});

const DEFAULT_GAS_PER_DEPLOY_BYTE: u64 = 100;
const DEFAULT_CHARGE_PER_DEPLOY_BYTE: u64 = 200000;

impl Rusk {
pub fn new<P: AsRef<Path>>(
dir: P,
chain_id: u8,
generation_timeout: Option<Duration>,
gas_per_deploy_byte: Option<u64>,
charge_per_deploy_byte: Option<u64>,
block_gas_limit: u64,
feeder_gas_limit: u64,
event_sender: broadcast::Sender<RuesEvent>,
Expand Down Expand Up @@ -91,7 +92,7 @@ impl Rusk {
dir: dir.into(),
chain_id,
generation_timeout,
gas_per_deploy_byte,
charge_per_deploy_byte,
feeder_gas_limit,
event_sender,
block_gas_limit,
Expand Down Expand Up @@ -140,7 +141,7 @@ impl Rusk {
match execute(
&mut session,
&unspent_tx.inner,
self.gas_per_deploy_byte,
self.charge_per_deploy_byte,
) {
Ok(receipt) => {
let gas_spent = receipt.gas_spent;
Expand All @@ -158,7 +159,7 @@ impl Rusk {
let _ = execute(
&mut session,
&spent_tx.inner.inner,
self.gas_per_deploy_byte,
self.charge_per_deploy_byte,
);
}

Expand Down Expand Up @@ -243,7 +244,7 @@ impl Rusk {
txs,
slashing,
voters,
self.gas_per_deploy_byte,
self.charge_per_deploy_byte,
)
.map(|(a, b, _, _)| (a, b))
}
Expand Down Expand Up @@ -274,7 +275,7 @@ impl Rusk {
&txs[..],
slashing,
voters,
self.gas_per_deploy_byte,
self.charge_per_deploy_byte,
)?;

if let Some(expected_verification) = consistency_check {
Expand Down Expand Up @@ -466,7 +467,7 @@ fn accept(
txs: &[Transaction],
slashing: Vec<Slash>,
voters: Option<&[Voter]>,
gas_per_deploy_byte: Option<u64>,
charge_per_deploy_byte: Option<u64>,
) -> Result<(
Vec<SpentTransaction>,
VerificationOutput,
Expand All @@ -485,7 +486,7 @@ fn accept(

for unspent_tx in txs {
let tx = &unspent_tx.inner;
let receipt = execute(&mut session, tx, gas_per_deploy_byte)?;
let receipt = execute(&mut session, tx, charge_per_deploy_byte)?;

update_hasher(&mut event_hasher, &receipt.events);
events.extend(receipt.events);
Expand Down Expand Up @@ -532,13 +533,17 @@ fn accept(
))
}

// Returns gas charge for bytecode deployment.
// Returns (economic) charge and gas charge for a given bytecode deployment.
fn bytecode_charge(
bytecode: &ContractBytecode,
gas_per_deploy_byte: &Option<u64>,
) -> u64 {
bytecode.bytes.len() as u64
* gas_per_deploy_byte.unwrap_or(DEFAULT_GAS_PER_DEPLOY_BYTE)
charge_per_deploy_byte: &Option<u64>,
gas_price: u64,
) -> (u64, u64) {
let charge = bytecode.bytes.len() as u64
* charge_per_deploy_byte.unwrap_or(DEFAULT_CHARGE_PER_DEPLOY_BYTE);
assert_ne!(gas_price, 0);
let gas_charge = max(charge / gas_price, 1);
(charge, gas_charge)
}

// Contract deployment will fail and charge full gas limit in the
Expand All @@ -554,11 +559,13 @@ fn contract_deploy(
session: &mut Session,
deploy: &ContractDeploy,
gas_limit: u64,
gas_per_deploy_byte: Option<u64>,
gas_price: u64,
charge_per_deploy_byte: Option<u64>,
receipt: &mut CallReceipt<Result<Vec<u8>, ContractError>>,
) {
let deploy_charge = bytecode_charge(&deploy.bytecode, &gas_per_deploy_byte);
let min_gas_limit = receipt.gas_spent + deploy_charge;
let (_, deploy_gas_charge) =
bytecode_charge(&deploy.bytecode, &charge_per_deploy_byte, gas_price);
let min_gas_limit = receipt.gas_spent + deploy_gas_charge;
let hash = blake3::hash(deploy.bytecode.bytes.as_slice());
if gas_limit < min_gas_limit {
receipt.data = Err(ContractError::OutOfGas);
Expand All @@ -578,7 +585,7 @@ fn contract_deploy(
gas_limit - receipt.gas_spent,
);
match result {
Ok(_) => receipt.gas_spent += deploy_charge,
Ok(_) => receipt.gas_spent += deploy_gas_charge,
Err(err) => {
info!("Tx caused deployment error {err:?}");
receipt.data =
Expand Down Expand Up @@ -624,14 +631,17 @@ fn contract_deploy(
fn execute(
session: &mut Session,
tx: &ProtocolTransaction,
gas_per_deploy_byte: Option<u64>,
charge_per_deploy_byte: Option<u64>,
) -> Result<CallReceipt<Result<Vec<u8>, ContractError>>, PiecrustError> {
// Transaction will be discarded if it is a deployment transaction
// with gas limit smaller than deploy charge.
if let Some(deploy) = tx.deploy() {
let deploy_charge =
bytecode_charge(&deploy.bytecode, &gas_per_deploy_byte);
if tx.gas_limit() < deploy_charge {
let (deploy_charge, _) = bytecode_charge(
&deploy.bytecode,
&charge_per_deploy_byte,
tx.gas_price(),
);
if tx.gas_limit() * tx.gas_price() < deploy_charge {
return Err(PiecrustError::Panic(
"not enough gas to deploy".into(),
));
Expand All @@ -655,7 +665,8 @@ fn execute(
session,
deploy,
tx.gas_limit(),
gas_per_deploy_byte,
tx.gas_price(),
charge_per_deploy_byte,
&mut receipt,
);
}
Expand Down

0 comments on commit 5473990

Please sign in to comment.