Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improved deployment pricing #2290

Merged
merged 3 commits into from
Sep 6, 2024
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
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
1 change: 1 addition & 0 deletions rusk/default.config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#generation_timeout = '3s'
# Note: changing the gas per deploy byte parameter is equivalent to forking the chain.
#gas_per_deploy_byte = 100
#min_deployment_gas_price = 2000

[databroker]
max_inv_entries = 100
Expand Down
5 changes: 5 additions & 0 deletions rusk/src/bin/config/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ pub(crate) struct ChainConfig {
// NB: changing the gas_per_deploy_byte/block_gas_limit is equivalent to
// forking the chain.
gas_per_deploy_byte: Option<u64>,
min_deployment_gas_price: Option<u64>,
block_gas_limit: Option<u64>,
}

Expand Down Expand Up @@ -79,6 +80,10 @@ impl ChainConfig {
self.gas_per_deploy_byte
}

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

pub(crate) fn max_queue_size(&self) -> usize {
self.max_queue_size.unwrap_or(10_000)
}
Expand Down
1 change: 1 addition & 0 deletions rusk/src/bin/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
config.kadcast.chain_id(),
config.chain.generation_timeout(),
config.chain.gas_per_deploy_byte(),
config.chain.min_deployment_gas_price(),
config.chain.block_gas_limit(),
config.http.feeder_call_gas,
_event_sender.clone(),
Expand Down
1 change: 1 addition & 0 deletions rusk/src/lib/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ pub struct Rusk {
pub(crate) chain_id: u8,
pub(crate) generation_timeout: Option<Duration>,
pub(crate) gas_per_deploy_byte: Option<u64>,
pub(crate) min_deployment_gas_price: Option<u64>,
pub(crate) feeder_gas_limit: u64,
pub(crate) block_gas_limit: u64,
pub(crate) event_sender: broadcast::Sender<RuesEvent>,
Expand Down
28 changes: 26 additions & 2 deletions rusk/src/lib/node/rusk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,16 @@ pub static DUSK_KEY: LazyLock<BlsPublicKey> = LazyLock::new(|| {
});

const DEFAULT_GAS_PER_DEPLOY_BYTE: u64 = 100;
const DEFAULT_MIN_DEPLOYMENT_GAS_PRICE: u64 = 2000;

impl Rusk {
#[allow(clippy::too_many_arguments)]
pub fn new<P: AsRef<Path>>(
dir: P,
chain_id: u8,
generation_timeout: Option<Duration>,
gas_per_deploy_byte: Option<u64>,
min_deployment_gas_price: Option<u64>,
block_gas_limit: u64,
feeder_gas_limit: u64,
event_sender: broadcast::Sender<RuesEvent>,
Expand Down Expand Up @@ -92,6 +95,7 @@ impl Rusk {
chain_id,
generation_timeout,
gas_per_deploy_byte,
min_deployment_gas_price,
feeder_gas_limit,
event_sender,
block_gas_limit,
Expand Down Expand Up @@ -141,6 +145,7 @@ impl Rusk {
&mut session,
&unspent_tx.inner,
self.gas_per_deploy_byte,
self.min_deployment_gas_price,
) {
Ok(receipt) => {
let gas_spent = receipt.gas_spent;
Expand All @@ -159,6 +164,7 @@ impl Rusk {
&mut session,
&spent_tx.inner.inner,
self.gas_per_deploy_byte,
self.min_deployment_gas_price,
);
}

Expand Down Expand Up @@ -244,6 +250,7 @@ impl Rusk {
slashing,
voters,
self.gas_per_deploy_byte,
self.min_deployment_gas_price,
)
.map(|(a, b, _, _)| (a, b))
}
Expand Down Expand Up @@ -275,6 +282,7 @@ impl Rusk {
slashing,
voters,
self.gas_per_deploy_byte,
self.min_deployment_gas_price,
)?;

if let Some(expected_verification) = consistency_check {
Expand Down Expand Up @@ -467,6 +475,7 @@ fn accept(
slashing: Vec<Slash>,
voters: Option<&[Voter]>,
gas_per_deploy_byte: Option<u64>,
min_deployment_gas_price: Option<u64>,
) -> Result<(
Vec<SpentTransaction>,
VerificationOutput,
Expand All @@ -485,7 +494,12 @@ 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,
gas_per_deploy_byte,
min_deployment_gas_price,
)?;

update_hasher(&mut event_hasher, &receipt.events);
events.extend(receipt.events);
Expand Down Expand Up @@ -592,7 +606,8 @@ fn contract_deploy(
/// The following steps are performed:
///
/// 1. Check if the transaction contains contract deployment data, and if so,
/// verifies if gas limit is enough for deployment. If gas limit is not
/// verifies if gas limit is enough for deployment and if the gas price is
/// sufficient for deployment. If either gas price or gas limit is not
/// sufficient for deployment, transaction is discarded.
///
/// 2. Call the "spend_and_execute" function on the transfer contract with
Expand Down Expand Up @@ -625,12 +640,21 @@ fn execute(
session: &mut Session,
tx: &ProtocolTransaction,
gas_per_deploy_byte: Option<u64>,
min_deployment_gas_price: 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_price()
< min_deployment_gas_price
.unwrap_or(DEFAULT_MIN_DEPLOYMENT_GAS_PRICE)
{
return Err(PiecrustError::Panic(
"gas price too low to deploy".into(),
));
}
if tx.gas_limit() < deploy_charge {
return Err(PiecrustError::Panic(
"not enough gas to deploy".into(),
Expand Down
14 changes: 11 additions & 3 deletions rusk/tests/common/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,17 @@ pub fn new_state<P: AsRef<Path>>(

let (sender, _) = broadcast::channel(10);

let rusk =
Rusk::new(dir, CHAIN_ID, None, None, block_gas_limit, u64::MAX, sender)
.expect("Instantiating rusk should succeed");
let rusk = Rusk::new(
dir,
CHAIN_ID,
None,
None,
None,
block_gas_limit,
u64::MAX,
sender,
)
.expect("Instantiating rusk should succeed");

assert_eq!(
commit_id,
Expand Down
2 changes: 1 addition & 1 deletion rusk/tests/config/contract_deployment.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[[phoenix_balance]]
address = "ivmscertKgRyX8wNMJJsQcSVEyPsfSMUQXSAgeAPQXsndqFq9Pmknzhm61QvcEEdxPaGgxDS4RHpb6KKccrnSKN"
seed = 57005
notes = [10_000_000_000]
notes = [1_000_000_000_000]
50 changes: 31 additions & 19 deletions rusk/tests/services/contract_deployment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,8 @@ const BLOCK_HEIGHT: u64 = 1;
const BLOCK_GAS_LIMIT: u64 = 1_000_000_000_000;
const GAS_LIMIT: u64 = 200_000_000;
const GAS_LIMIT_NOT_ENOUGH_TO_SPEND: u64 = 10_000_000;
const GAS_LIMIT_NOT_ENOUGH_TO_SPEND_AND_DEPLOY: u64 = 11_000_000;
const GAS_LIMIT_NOT_ENOUGH_TO_DEPLOY: u64 = 1_200_000;
const GAS_PRICE: u64 = 2;
const GAS_PRICE: u64 = 2000;
const POINT_LIMIT: u64 = 0x10000000;
const SENDER_INDEX: u8 = 0;

Expand Down Expand Up @@ -81,7 +80,7 @@ fn initial_state<P: AsRef<Path>>(dir: P, deploy_bob: bool) -> Result<Rusk> {
bob_bytecode,
ContractData::builder()
.owner(OWNER)
.constructor_arg(&BOB_INIT_VALUE)
.init_arg(&BOB_INIT_VALUE)
.contract_id(gen_contract_id(
&bob_bytecode,
0u64,
Expand All @@ -96,9 +95,17 @@ fn initial_state<P: AsRef<Path>>(dir: P, deploy_bob: bool) -> Result<Rusk> {

let (sender, _) = broadcast::channel(10);

let rusk =
Rusk::new(dir, CHAIN_ID, None, None, BLOCK_GAS_LIMIT, u64::MAX, sender)
.expect("Instantiating rusk should succeed");
let rusk = Rusk::new(
dir,
CHAIN_ID,
None,
None,
None,
BLOCK_GAS_LIMIT,
u64::MAX,
sender,
)
.expect("Instantiating rusk should succeed");
Ok(rusk)
}

Expand All @@ -115,6 +122,7 @@ fn make_and_execute_transaction_deploy(
init_value: u8,
should_fail: bool,
should_discard: bool,
gas_price: u64,
) {
let mut rng = StdRng::seed_from_u64(0xcafe);

Expand All @@ -126,7 +134,7 @@ fn make_and_execute_transaction_deploy(
&mut rng,
SENDER_INDEX,
gas_limit,
GAS_PRICE,
gas_price,
0u64,
TransactionData::Deploy(ContractDeploy {
bytecode: ContractBytecode {
Expand Down Expand Up @@ -282,6 +290,7 @@ pub async fn contract_deploy() {
BOB_INIT_VALUE,
false,
false,
GAS_PRICE,
);
let after_balance = f.wallet_balance();
f.assert_bob_contract_is_deployed();
Expand All @@ -307,6 +316,7 @@ pub async fn contract_already_deployed() {
BOB_INIT_VALUE,
true,
false,
GAS_PRICE,
);
let after_balance = f.wallet_balance();
let funds_spent = before_balance - after_balance;
Expand Down Expand Up @@ -334,6 +344,7 @@ pub async fn contract_deploy_corrupted_bytecode() {
BOB_INIT_VALUE,
true,
false,
GAS_PRICE,
);
let after_balance = f.wallet_balance();
let funds_spent = before_balance - after_balance;
Expand All @@ -360,6 +371,7 @@ pub async fn contract_deploy_charge() {
BOB_INIT_VALUE,
false,
false,
GAS_PRICE,
);
let after_bob_balance = f.wallet_balance();
make_and_execute_transaction_deploy(
Expand All @@ -370,6 +382,7 @@ pub async fn contract_deploy_charge() {
0,
false,
false,
GAS_PRICE,
);
let after_license_balance = f.wallet_balance();
let bob_deployment_cost = before_balance - after_bob_balance;
Expand All @@ -396,19 +409,19 @@ pub async fn contract_deploy_not_enough_to_spend() {
BOB_INIT_VALUE,
false,
true,
GAS_PRICE,
);
let after_balance = f.wallet_balance();
f.assert_bob_contract_is_not_deployed();
let funds_spent = before_balance - after_balance;
assert_eq!(funds_spent, 0);
}

/// We deploy a contract with insufficient gas limit.
/// The limit is such that it is enough to spend but not enough to deploy.
/// Transaction won't be discarded and all limit will be spent by the wallet.
/// Wallet will spend GAS_LIMIT_NOT_ENOUGH_TO_DEPLOY x GAS_PRICE of funds.
/// We deploy a contract with insufficient gas price.
/// Transaction will be discarded.
#[tokio::test(flavor = "multi_thread")]
pub async fn contract_deploy_not_enough_to_spend_and_deploy() {
pub async fn contract_deploy_gas_price_too_low() {
const LOW_GAS_PRICE: u64 = 10;
logger();
let f = Fixture::build(false);

Expand All @@ -418,25 +431,23 @@ pub async fn contract_deploy_not_enough_to_spend_and_deploy() {
&f.rusk,
&f.wallet,
f.bob_bytecode.clone(),
GAS_LIMIT_NOT_ENOUGH_TO_SPEND_AND_DEPLOY,
GAS_LIMIT,
BOB_INIT_VALUE,
true,
false,
true,
LOW_GAS_PRICE,
);
let after_balance = f.wallet_balance();
f.assert_bob_contract_is_not_deployed();
let funds_spent = before_balance - after_balance;
assert_eq!(
funds_spent,
GAS_LIMIT_NOT_ENOUGH_TO_SPEND_AND_DEPLOY * GAS_PRICE
);
assert_eq!(funds_spent, 0);
}

/// We deploy a contract with insufficient gas limit.
/// The limit is such that it is not enough to deploy.
/// Transaction will be discarded and no funds will be spent by the wallet.
#[tokio::test(flavor = "multi_thread")]
pub async fn contract_deploy_not_enough_to_deploy() {
pub async fn contract_deploy_gas_limit_too_low() {
logger();
let f = Fixture::build(false);

Expand All @@ -450,6 +461,7 @@ pub async fn contract_deploy_not_enough_to_deploy() {
BOB_INIT_VALUE,
false,
true,
GAS_PRICE,
);
let after_balance = f.wallet_balance();
f.assert_bob_contract_is_not_deployed();
Expand Down
16 changes: 12 additions & 4 deletions rusk/tests/services/owner_calls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ fn initial_state<P: AsRef<Path>>(
bob_bytecode,
ContractData::builder()
.owner(owner.as_ref())
.constructor_arg(&BOB_INIT_VALUE)
.init_arg(&BOB_INIT_VALUE)
.contract_id(gen_contract_id(&bob_bytecode, 0u64, owner)),
POINT_LIMIT,
)
Expand All @@ -74,9 +74,17 @@ fn initial_state<P: AsRef<Path>>(

let (sender, _) = broadcast::channel(10);

let rusk =
Rusk::new(dir, CHAIN_ID, None, None, BLOCK_GAS_LIMIT, u64::MAX, sender)
.expect("Instantiating rusk should succeed");
let rusk = Rusk::new(
dir,
CHAIN_ID,
None,
None,
None,
BLOCK_GAS_LIMIT,
u64::MAX,
sender,
)
.expect("Instantiating rusk should succeed");
Ok(rusk)
}

Expand Down
Loading