diff --git a/Cargo.lock b/Cargo.lock index dfe2957a583..5d710053b85 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2558,7 +2558,7 @@ dependencies = [ [[package]] name = "massa-proto-rs" version = "0.1.0" -source = "git+https://github.com/massalabs/massa-proto-rs?rev=1cce8ec75e0df66af6ce3c5a86350adaea8ac463#1cce8ec75e0df66af6ce3c5a86350adaea8ac463" +source = "git+https://github.com/massalabs/massa-proto-rs?rev=67c331c10a1a3f0a9985b3b16c50e31d63074b83#67c331c10a1a3f0a9985b3b16c50e31d63074b83" dependencies = [ "glob", "prost", @@ -2571,7 +2571,7 @@ dependencies = [ [[package]] name = "massa-sc-runtime" version = "0.10.0" -source = "git+https://github.com/massalabs/massa-sc-runtime?rev=f5fd64c9e05c6d7cc01a30d1ef1dc0c202456a4b#f5fd64c9e05c6d7cc01a30d1ef1dc0c202456a4b" +source = "git+https://github.com/massalabs/massa-sc-runtime?rev=7289367b2cb490ae1c6c74190d6d36b8d65b30cf#7289367b2cb490ae1c6c74190d6d36b8d65b30cf" dependencies = [ "anyhow", "as-ffi-bindings", diff --git a/Cargo.toml b/Cargo.toml index faecffa0288..4bf711de9fb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -107,8 +107,8 @@ massa_versioning = { path = "./massa-versioning" } massa_wallet = { path = "./massa-wallet" } # Massa projects dependencies -massa-proto-rs = { git = "https://github.com/massalabs/massa-proto-rs", "rev" = "1cce8ec75e0df66af6ce3c5a86350adaea8ac463" } -massa-sc-runtime = { git = "https://github.com/massalabs/massa-sc-runtime", "rev" = "f5fd64c9e05c6d7cc01a30d1ef1dc0c202456a4b" } +massa-proto-rs = { git = "https://github.com/massalabs/massa-proto-rs", "rev" = "67c331c10a1a3f0a9985b3b16c50e31d63074b83" } +massa-sc-runtime = { git = "https://github.com/massalabs/massa-sc-runtime", "rev" = "7289367b2cb490ae1c6c74190d6d36b8d65b30cf" } peernet = { git = "https://github.com/massalabs/PeerNet", "rev" = "04b05ddd320fbe76cc858115af7b5fc28bdb8310" } diff --git a/massa-api-exports/src/execution.rs b/massa-api-exports/src/execution.rs index e43cdf89f0a..527d3cb574e 100644 --- a/massa-api-exports/src/execution.rs +++ b/massa-api-exports/src/execution.rs @@ -130,6 +130,8 @@ pub struct DeferredCallsQuoteRequest { pub target_slot: Slot, /// The maximum gas requested. pub max_gas_request: u64, + /// Size of parameters + pub params_size: u64, } /// The response to a request for a deferred call quote. diff --git a/massa-api/src/public.rs b/massa-api/src/public.rs index 32b238a74da..810af088027 100644 --- a/massa-api/src/public.rs +++ b/massa-api/src/public.rs @@ -1169,6 +1169,7 @@ impl MassaRpcServer for API { .map(|call| ExecutionQueryRequestItem::DeferredCallQuote { target_slot: call.target_slot, max_gas_request: call.max_gas_request, + params_size: call.params_size, }) .collect(); diff --git a/massa-deferred-calls/src/config.rs b/massa-deferred-calls/src/config.rs index e0e4f1b8ef2..8f1264e73e0 100644 --- a/massa-deferred-calls/src/config.rs +++ b/massa-deferred-calls/src/config.rs @@ -5,7 +5,7 @@ use massa_models::{ DEFERRED_CALL_GLOBAL_OVERBOOKING_PENALTY, DEFERRED_CALL_MAX_ASYNC_GAS, DEFERRED_CALL_MAX_FUTURE_SLOTS, DEFERRED_CALL_MAX_POOL_CHANGES, DEFERRED_CALL_MIN_GAS_COST, DEFERRED_CALL_MIN_GAS_INCREMENT, DEFERRED_CALL_SLOT_OVERBOOKING_PENALTY, - MAX_FUNCTION_NAME_LENGTH, MAX_PARAMETERS_SIZE, THREAD_COUNT, + LEDGER_COST_PER_BYTE, MAX_FUNCTION_NAME_LENGTH, MAX_PARAMETERS_SIZE, THREAD_COUNT, }, }; use serde::Deserialize; @@ -37,6 +37,8 @@ pub struct DeferredCallsConfig { pub max_pool_changes: u64, pub max_gas: u64, + + pub ledger_cost_per_byte: Amount, } impl Default for DeferredCallsConfig { @@ -54,6 +56,7 @@ impl Default for DeferredCallsConfig { global_overbooking_penalty: DEFERRED_CALL_GLOBAL_OVERBOOKING_PENALTY, slot_overbooking_penalty: DEFERRED_CALL_SLOT_OVERBOOKING_PENALTY, call_cst_gas_cost: DEFERRED_CALL_CST_GAS_COST, + ledger_cost_per_byte: LEDGER_COST_PER_BYTE, } } } diff --git a/massa-execution-exports/src/mapping_grpc.rs b/massa-execution-exports/src/mapping_grpc.rs index 20130a9e4f7..5f53b04cd95 100644 --- a/massa-execution-exports/src/mapping_grpc.rs +++ b/massa-execution-exports/src/mapping_grpc.rs @@ -142,7 +142,8 @@ pub fn to_querystate_filter( "target slot is required".to_string(), ))? .into(), - max_gas_request: value.max_gas_request, + max_gas_request: value.max_gas, + params_size: value.params_size, }) } exec::RequestItem::DeferredCallInfo(info) => { diff --git a/massa-execution-exports/src/types.rs b/massa-execution-exports/src/types.rs index 2a55a098fec..ce92ad62aab 100644 --- a/massa-execution-exports/src/types.rs +++ b/massa-execution-exports/src/types.rs @@ -108,6 +108,8 @@ pub enum ExecutionQueryRequestItem { target_slot: Slot, /// gas request max_gas_request: u64, + /// params size + params_size: u64, }, /// get info of deferred calls DeferredCallInfo(DeferredCallId), diff --git a/massa-execution-worker/src/context.rs b/massa-execution-worker/src/context.rs index a86f7f053e0..6a02a478135 100644 --- a/massa-execution-worker/src/context.rs +++ b/massa-execution-worker/src/context.rs @@ -1140,15 +1140,20 @@ impl ExecutionContext { self.speculative_deferred_calls.advance_slot(current_slot) } - /// Get the price it would cost to reserve "gas" at target slot "slot". + /// Get the price it would cost to reserve "gas" with params at target slot "slot". pub fn deferred_calls_compute_call_fee( &self, target_slot: Slot, max_gas_request: u64, current_slot: Slot, + params_size: u64, ) -> Result { - self.speculative_deferred_calls - .compute_call_fee(target_slot, max_gas_request, current_slot) + self.speculative_deferred_calls.compute_call_fee( + target_slot, + max_gas_request, + current_slot, + params_size, + ) } pub fn deferred_call_register( diff --git a/massa-execution-worker/src/controller.rs b/massa-execution-worker/src/controller.rs index 051487efef0..626718eee66 100644 --- a/massa-execution-worker/src/controller.rs +++ b/massa-execution-worker/src/controller.rs @@ -334,8 +334,13 @@ impl ExecutionController for ExecutionControllerImpl { ExecutionQueryRequestItem::DeferredCallQuote { target_slot, max_gas_request, + params_size, } => { - let result = execution_lock.deferred_call_quote(target_slot, max_gas_request); + let result = execution_lock.deferred_call_quote( + target_slot, + max_gas_request, + params_size, + ); Ok(ExecutionQueryResponseItem::DeferredCallQuote( result.0, result.1, result.2, result.3, )) diff --git a/massa-execution-worker/src/execution.rs b/massa-execution-worker/src/execution.rs index 0273ea84f39..ed983a1c02b 100644 --- a/massa-execution-worker/src/execution.rs +++ b/massa-execution-worker/src/execution.rs @@ -2442,12 +2442,18 @@ impl ExecutionState { &self, target_slot: Slot, max_request_gas: u64, + params_size: u64, ) -> (Slot, u64, bool, Amount) { let gas_request = max_request_gas.saturating_add(self.config.deferred_calls_config.call_cst_gas_cost); let context = context_guard!(self); - match context.deferred_calls_compute_call_fee(target_slot, gas_request, context.slot) { + match context.deferred_calls_compute_call_fee( + target_slot, + gas_request, + context.slot, + params_size, + ) { Ok(fee) => (target_slot, gas_request, true, fee), Err(_) => (target_slot, gas_request, false, Amount::zero()), } diff --git a/massa-execution-worker/src/interface_impl.rs b/massa-execution-worker/src/interface_impl.rs index 1bb39d2d611..9fabcd580b6 100644 --- a/massa-execution-worker/src/interface_impl.rs +++ b/massa-execution-worker/src/interface_impl.rs @@ -1345,6 +1345,7 @@ impl Interface for InterfaceImpl { &self, target_slot: (u64, u8), gas_limit: u64, + params_size: u64, ) -> Result<(bool, u64)> { // write-lock context @@ -1357,7 +1358,12 @@ impl Interface for InterfaceImpl { let gas_request = gas_limit.saturating_add(self.config.deferred_calls_config.call_cst_gas_cost); - match context.deferred_calls_compute_call_fee(target_slot, gas_request, current_slot) { + match context.deferred_calls_compute_call_fee( + target_slot, + gas_request, + current_slot, + params_size, + ) { Ok(fee) => Ok((true, fee.to_raw())), Err(_) => Ok((false, 0)), } @@ -1402,7 +1408,8 @@ impl Interface for InterfaceImpl { } // check fee, slot, gas - let (available, fee_raw) = self.get_deferred_call_quote(target_slot, max_gas)?; + let (available, fee_raw) = + self.get_deferred_call_quote(target_slot, max_gas, params.len() as u64)?; if !available { bail!("The Deferred call cannot be registered. Ensure that the target slot is not before/at the current slot nor too far in the future, and that it has at least max_gas available gas."); } diff --git a/massa-execution-worker/src/speculative_deferred_calls.rs b/massa-execution-worker/src/speculative_deferred_calls.rs index a3e6711a6a1..37ea08ed332 100644 --- a/massa-execution-worker/src/speculative_deferred_calls.rs +++ b/massa-execution-worker/src/speculative_deferred_calls.rs @@ -422,6 +422,7 @@ impl SpeculativeDeferredCallRegistry { target_slot: Slot, max_gas_request: u64, current_slot: Slot, + params_size: u64, ) -> Result { // Check that the slot is not in the past if target_slot <= current_slot { @@ -450,6 +451,12 @@ impl SpeculativeDeferredCallRegistry { )); } + if params_size > self.config.max_parameter_size.into() { + return Err(ExecutionError::DeferredCallsError( + "Parameters size is too big.".into(), + )); + } + // We perform Dynamic Pricing of slot gas booking using a Proportional-Integral controller (https://en.wikipedia.org/wiki/Proportional–integral–derivative_controller). // It regulates the average slot async gas usage towards `target_async_gas` by adjusting fees. @@ -486,10 +493,22 @@ impl SpeculativeDeferredCallRegistry { self.config.slot_overbooking_penalty, // total_initial_coin_supply/10000 )?; + // Storage cost for the parameters + let storage_cost = self + .config + .ledger_cost_per_byte + .checked_mul_u64(params_size) + .ok_or_else(|| { + ExecutionError::DeferredCallsError( + "overflow when calculating storage cost".to_string(), + ) + })?; + // return the fee Ok(integral_fee .saturating_add(global_overbooking_fee) - .saturating_add(slot_overbooking_fee)) + .saturating_add(slot_overbooking_fee) + .saturating_add(storage_cost)) } /// Register a new call @@ -562,13 +581,13 @@ impl SpeculativeDeferredCallRegistry { #[cfg(test)] mod tests { - use std::sync::Arc; + use std::{str::FromStr, sync::Arc}; use massa_db_exports::{MassaDBConfig, MassaDBController}; use massa_db_worker::MassaDB; use massa_deferred_calls::{config::DeferredCallsConfig, DeferredCallRegistry}; use massa_final_state::MockFinalStateController; - use massa_models::{config::THREAD_COUNT, slot::Slot}; + use massa_models::{amount::Amount, config::THREAD_COUNT, slot::Slot}; use parking_lot::RwLock; use tempfile::TempDir; @@ -627,6 +646,7 @@ mod tests { period: 1, thread: 1, }, + 1_000 ) .is_err()); @@ -642,6 +662,7 @@ mod tests { period: 5, thread: 1, }, + 1000 ) .is_err()); @@ -658,9 +679,55 @@ mod tests { period: 1, thread: 1, }, + 1000 ) .is_err()); + // params too big + assert!(speculative + .compute_call_fee( + good_slot, + 1_000_000, + Slot { + period: 1, + thread: 1, + }, + 50_000_000 + ) + .is_err()); + + // no params + assert_eq!( + speculative + .compute_call_fee( + good_slot, + 200_000, + Slot { + period: 1, + thread: 1, + }, + 0, + ) + .unwrap(), + Amount::from_str("0.000000079").unwrap() + ); + + // 10Ko params size + assert_eq!( + speculative + .compute_call_fee( + good_slot, + 200_000, + Slot { + period: 1, + thread: 1, + }, + 10_000, + ) + .unwrap(), + Amount::from_str("1.000000079").unwrap() + ); + // TODO : add more tests with different values and check the results of the fee } } diff --git a/massa-node/base_config/openrpc.json b/massa-node/base_config/openrpc.json index 9f4309de115..174f940ada7 100644 --- a/massa-node/base_config/openrpc.json +++ b/massa-node/base_config/openrpc.json @@ -2155,7 +2155,8 @@ "type": "object", "required": [ "target_slot", - "max_gas_request" + "max_gas_request", + "params_size" ], "properties": { "target_slot": { @@ -2163,6 +2164,9 @@ }, "max_gas_request": { "type": "number" + }, + "params_size": { + "type": "number" } } }, diff --git a/massa-node/src/main.rs b/massa-node/src/main.rs index 4424cf21e57..db5d327db73 100644 --- a/massa-node/src/main.rs +++ b/massa-node/src/main.rs @@ -208,6 +208,7 @@ async fn launch( global_overbooking_penalty: DEFERRED_CALL_GLOBAL_OVERBOOKING_PENALTY, slot_overbooking_penalty: DEFERRED_CALL_SLOT_OVERBOOKING_PENALTY, call_cst_gas_cost: DEFERRED_CALL_CST_GAS_COST, + ledger_cost_per_byte: LEDGER_COST_PER_BYTE, }; let final_state_config = FinalStateConfig { ledger_config: ledger_config.clone(),