From 19e89b4b56d7eceb50dfe3d6d26e76869bb2b595 Mon Sep 17 00:00:00 2001 From: AurelienFT Date: Thu, 9 May 2024 18:13:40 +0200 Subject: [PATCH 001/100] Add structure async call and async call id --- Cargo.lock | 14 +- Cargo.toml | 3 +- massa-asc/Cargo.toml | 16 + massa-asc/src/call.rs | 218 ++++++++++++++ massa-asc/src/lib.rs | 35 +++ massa-execution-worker/Cargo.toml | 1 + massa-execution-worker/src/interface_impl.rs | 113 +++++++ massa-execution-worker/src/lib.rs | 1 + massa-execution-worker/src/speculative_asc.rs | 140 +++++++++ massa-models/src/asc_call_id.rs | 280 ++++++++++++++++++ massa-models/src/lib.rs | 2 + 11 files changed, 821 insertions(+), 2 deletions(-) create mode 100644 massa-asc/Cargo.toml create mode 100644 massa-asc/src/call.rs create mode 100644 massa-asc/src/lib.rs create mode 100644 massa-execution-worker/src/speculative_asc.rs create mode 100644 massa-models/src/asc_call_id.rs diff --git a/Cargo.lock b/Cargo.lock index 35955c0f2b7..3549dd54af5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2579,7 +2579,7 @@ dependencies = [ [[package]] name = "massa-sc-runtime" version = "0.10.0" -source = "git+https://github.com/massalabs/massa-sc-runtime?rev=e95066a6d3a963ff0125616f404a84e5abb63d63#e95066a6d3a963ff0125616f404a84e5abb63d63" +source = "git+https://github.com/AurelienFT/massa-sc-runtime?rev=e19017b54d5ef8ed86e4da9098fdd4ecb4294459#e19017b54d5ef8ed86e4da9098fdd4ecb4294459" dependencies = [ "anyhow", "as-ffi-bindings", @@ -2670,6 +2670,17 @@ dependencies = [ "thiserror", ] +[[package]] +name = "massa_asc" +version = "28.3.0" +dependencies = [ + "massa_db_exports", + "massa_ledger_exports", + "massa_models", + "massa_serialization", + "nom", +] + [[package]] name = "massa_async_pool" version = "28.3.0" @@ -2889,6 +2900,7 @@ dependencies = [ "libsecp256k1", "massa-proto-rs", "massa-sc-runtime", + "massa_asc", "massa_async_pool", "massa_channel", "massa_db_exports", diff --git a/Cargo.toml b/Cargo.toml index 79222cfb105..0b53282bcb4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -66,6 +66,7 @@ lto = true # Enables Link Time Optimization, enabling more aggressive # The saved snapshot can then be used to restart the network from the snapshot. [workspace.dependencies] # Internal packages +massa_asc = { path = "./massa-asc" } massa_api = { path = "./massa-api" } massa_api_exports = { path = "./massa-api-exports" } massa_async_pool = { path = "./massa-async-pool" } @@ -107,7 +108,7 @@ massa_wallet = { path = "./massa-wallet" } # Massa projects dependencies massa-proto-rs = { git = "https://github.com/massalabs/massa-proto-rs", "rev" = "426fd325a55dfcc4033920bed2de075a7e7ad4b7" } -massa-sc-runtime = { git = "https://github.com/massalabs/massa-sc-runtime", "rev" = "e95066a6d3a963ff0125616f404a84e5abb63d63" } +massa-sc-runtime = { git = "https://github.com/AurelienFT/massa-sc-runtime", "rev" = "e19017b54d5ef8ed86e4da9098fdd4ecb4294459" } peernet = { git = "https://github.com/massalabs/PeerNet", "rev" = "04b05ddd320fbe76cc858115af7b5fc28bdb8310" } # Common dependencies diff --git a/massa-asc/Cargo.toml b/massa-asc/Cargo.toml new file mode 100644 index 00000000000..cc63af172da --- /dev/null +++ b/massa-asc/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "massa_asc" +version = "28.3.0" +authors = ["Massa Labs "] +edition = "2021" + +[features] +test-exports = [] +sandbox = [] + +[dependencies] +nom = { workspace = true } +massa_db_exports = { workspace = true } +massa_ledger_exports = { workspace = true } +massa_models = { workspace = true } +massa_serialization = { workspace = true } \ No newline at end of file diff --git a/massa-asc/src/call.rs b/massa-asc/src/call.rs new file mode 100644 index 00000000000..c5884ad99cc --- /dev/null +++ b/massa-asc/src/call.rs @@ -0,0 +1,218 @@ +use massa_models::{ + address::{Address, AddressDeserializer, AddressSerializer}, + amount::{Amount, AmountDeserializer, AmountSerializer}, + serialization::{StringDeserializer, StringSerializer, VecU8Deserializer, VecU8Serializer}, + slot::{Slot, SlotDeserializer, SlotSerializer}, +}; +use massa_serialization::{ + Deserializer, SerializeError, Serializer, U16VarIntDeserializer, U16VarIntSerializer, + U64VarIntDeserializer, U64VarIntSerializer, +}; +use nom::{ + error::{context, ContextError, ParseError}, + sequence::tuple, + IResult, Parser, +}; +use std::ops::Bound; + +/// Definition of a call in the future +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct AsyncCall { + // The slot in which the call will be executed + pub target_slot: Slot, + // The address of the contract to call + pub target_address: Address, + // The function to call + pub target_function: String, + // The parameters of the call + pub parameters: Vec, + // The amount of coins to send to the contract + pub coins: Amount, + // The maximum amount of gas usable + pub max_gas: u64, + // The fee to pay for the reservation of the space for the call + pub fee: Amount, +} + +impl AsyncCall { + pub fn new( + target_slot: Slot, + target_address: Address, + target_function: String, + parameters: Vec, + coins: Amount, + max_gas: u64, + fee: Amount, + ) -> Self { + Self { + target_slot, + target_address, + target_function, + parameters, + coins, + max_gas, + fee, + } + } +} + +/// Serializer for `AsyncCall` +#[derive(Clone)] +pub struct AsyncCallSerializer { + slot_serializer: SlotSerializer, + address_serializer: AddressSerializer, + string_serializer: StringSerializer, + vec_u8_serializer: VecU8Serializer, + amount_serializer: AmountSerializer, + u64_var_int_serializer: U64VarIntSerializer, +} + +impl AsyncCallSerializer { + /// Serializes an `AsyncCall` into a `Vec` + pub fn new() -> Self { + Self { + slot_serializer: SlotSerializer::new(), + address_serializer: AddressSerializer::new(), + string_serializer: StringSerializer::new(U16VarIntSerializer::new()), + vec_u8_serializer: VecU8Serializer::new(), + amount_serializer: AmountSerializer::new(), + u64_var_int_serializer: U64VarIntSerializer::new(), + } + } +} + +impl Serializer for AsyncCallSerializer { + fn serialize(&self, value: &AsyncCall, buffer: &mut Vec) -> Result<(), SerializeError> { + self.slot_serializer.serialize(&value.target_slot, buffer)?; + self.address_serializer + .serialize(&value.target_address, buffer)?; + self.string_serializer + .serialize(&value.target_function, buffer)?; + self.vec_u8_serializer + .serialize(&value.parameters, buffer)?; + self.amount_serializer.serialize(&value.coins, buffer)?; + self.amount_serializer.serialize(&value.fee, buffer)?; + self.u64_var_int_serializer + .serialize(&value.max_gas, buffer)?; + Ok(()) + } +} + +/// Deserializer for `AsyncCall` +#[derive(Clone)] +pub struct AsyncCallDeserializer { + slot_deserializer: SlotDeserializer, + address_deserializer: AddressDeserializer, + string_deserializer: StringDeserializer, + vec_u8_deserializer: VecU8Deserializer, + amount_deserializer: AmountDeserializer, + u64_var_int_deserializer: U64VarIntDeserializer, +} + +impl AsyncCallDeserializer { + /// Deserializes a `Vec` into an `AsyncCall` + pub fn new(thread_count: u8) -> Self { + Self { + slot_deserializer: SlotDeserializer::new( + (Bound::Included(0), Bound::Included(u64::MAX)), + (Bound::Included(0), Bound::Excluded(thread_count)), + ), + address_deserializer: AddressDeserializer::new(), + string_deserializer: StringDeserializer::new(U16VarIntDeserializer::new( + Bound::Included(0), + Bound::Included(u16::MAX), + )), + vec_u8_deserializer: VecU8Deserializer::new( + std::ops::Bound::Included(0), + std::ops::Bound::Included(u16::MAX as u64), + ), + amount_deserializer: AmountDeserializer::new( + Bound::Included(Amount::MIN), + Bound::Included(Amount::MAX), + ), + u64_var_int_deserializer: U64VarIntDeserializer::new( + Bound::Included(0), + Bound::Included(u64::MAX), + ), + } + } +} + +impl Deserializer for AsyncCallDeserializer { + fn deserialize<'a, E: ParseError<&'a [u8]> + ContextError<&'a [u8]>>( + &self, + buffer: &'a [u8], + ) -> IResult<&'a [u8], AsyncCall, E> { + context( + "Failed AsyncCall deserialization", + tuple(( + context("Failed target_slot deserialization", |input| { + self.slot_deserializer.deserialize(input) + }), + context("Failed target_address deserialization", |input| { + self.address_deserializer.deserialize(input) + }), + context("Failed target_function deserialization", |input| { + self.string_deserializer.deserialize(input) + }), + context("Failed parameters deserialization", |input| { + self.vec_u8_deserializer.deserialize(input) + }), + context("Failed coins deserialization", |input| { + self.amount_deserializer.deserialize(input) + }), + context("Failed fee deserialization", |input| { + self.amount_deserializer.deserialize(input) + }), + context("Failed max_gas deserialization", |input| { + self.u64_var_int_deserializer.deserialize(input) + }), + )), + ) + .map( + |(target_slot, target_address, target_function, parameters, coins, fee, max_gas)| { + AsyncCall::new( + target_slot, + target_address, + target_function, + parameters, + coins, + max_gas, + fee, + ) + }, + ) + .parse(buffer) + } +} + +#[cfg(test)] +mod tests { + use std::str::FromStr; + + use massa_serialization::DeserializeError; + + use super::*; + + #[test] + fn test_serialization_deserialization() { + let call = AsyncCall::new( + Slot::new(42, 0), + Address::from_str("AU12dG5xP1RDEB5ocdHkymNVvvSJmUL9BgHwCksDowqmGWxfpm93x").unwrap(), + "function".to_string(), + vec![0, 1, 2, 3], + Amount::from_raw(42), + 42, + Amount::from_raw(42), + ); + let serializer = AsyncCallSerializer::new(); + let deserializer = AsyncCallDeserializer::new(1); + let mut buffer = Vec::new(); + serializer.serialize(&call, &mut buffer).unwrap(); + let (rest, deserialized_call) = deserializer + .deserialize::(&buffer) + .unwrap(); + assert_eq!(call, deserialized_call); + assert!(rest.is_empty()); + } +} diff --git a/massa-asc/src/lib.rs b/massa-asc/src/lib.rs new file mode 100644 index 00000000000..f732a09d9d9 --- /dev/null +++ b/massa-asc/src/lib.rs @@ -0,0 +1,35 @@ +use massa_db_exports::ShareableMassaDBController; + +/// This module implements a new version of the Autonomous Smart Contracts. (ASC) +/// This new version allow asynchronous calls to be registered for a specific slot and ensure his execution. +mod call; + +pub use call::AsyncCall; +use massa_models::{asc_call_id::AsyncCallId, slot::Slot}; +use std::collections::BTreeMap; + +pub struct AsyncCallRegistry { + db: ShareableMassaDBController, +} + +impl AsyncCallRegistry { + pub fn new(db: ShareableMassaDBController) -> Self { + Self { db } + } + + pub fn get_slot_calls(slot: Slot) -> Vec { + todo!() + } + + pub fn get_message_by_id(id: AsyncCallId) -> Option { + todo!() + } +} + +pub struct AsyncRegistryChanges { + pub by_slot: BTreeMap, +} + +pub struct AsyncRegistrySlotChanges { + pub changes: BTreeMap, +} diff --git a/massa-execution-worker/Cargo.toml b/massa-execution-worker/Cargo.toml index 60e5de5c9fd..ea6e466fb9f 100644 --- a/massa-execution-worker/Cargo.toml +++ b/massa-execution-worker/Cargo.toml @@ -60,6 +60,7 @@ sha2 = { workspace = true } sha3 = { workspace = true } libsecp256k1 = { workspace = true } criterion = { workspace = true, "optional" = true } +massa_asc = { workspace = true } massa_pos_worker = { workspace = true, "optional" = true } massa_async_pool = { workspace = true } massa_channel = { workspace = true } diff --git a/massa-execution-worker/src/interface_impl.rs b/massa-execution-worker/src/interface_impl.rs index 57c34aff00c..ce8e5ffa676 100644 --- a/massa-execution-worker/src/interface_impl.rs +++ b/massa-execution-worker/src/interface_impl.rs @@ -7,6 +7,7 @@ use crate::context::ExecutionContext; use anyhow::{anyhow, bail, Result}; +use massa_asc::AsyncCall; use massa_async_pool::{AsyncMessage, AsyncMessageTrigger}; use massa_execution_exports::ExecutionConfig; use massa_execution_exports::ExecutionStackElement; @@ -1329,6 +1330,118 @@ impl Interface for InterfaceImpl { Ok(blake3::hash(bytes).into()) } + /// Get the number of fees needed to reserve space in the target slot + /// + /// # Arguments + /// * target_slot: tuple containing the period and thread of the target slot + /// * gas_limit: the gas limit for the call + /// + /// # Returns + /// A tuple containing a boolean indicating if the call is possible and the amount of fees needed + fn get_asc_call_fee(&self, target_slot: (u64, u8), gas_limit: u64) -> Result<(bool, u64)> { + // write-lock context + let mut context = context_guard!(self); + + //TODO: interrogate the context to check for target slot availability and fees + + todo!() + } + + /// Register an asynchronous call + /// + /// # Arguments + /// * target_slot: tuple containing the period and thread of the target slot + /// * target_addr: string representation of the target address + /// * target_func: string representation of the target function + /// * params: byte array of the parameters + /// * coins: the amount of coins to send + /// * max_gas: the gas limit for the call + /// + /// # Returns + /// The id of the call + fn asc_call_register( + &self, + target_slot: (u64, u8), + target_addr: &str, + target_func: &str, + params: &[u8], + coins: u64, + max_gas: u64, + ) -> Result> { + let target_addr = Address::from_str(target_addr)?; + + // check that the target address is an SC address + if !matches!(target_addr, Address::SC(..)) { + bail!("target address is not a smart contract address") + } + + // Length verifications + if target_func.len() > self.config.max_function_length as usize { + bail!("Function name is too large"); + } + if params.len() > self.config.max_parameter_length as usize { + bail!("Parameter size is too large"); + } + + // check fee, slot, gas + let (available, fee_raw) = self.get_asc_call_fee(target_slot, max_gas)?; + if !available { + bail!("The ASC 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."); + } + let fee = Amount::from_raw(fee_raw); + let coins = Amount::from_raw(coins); + + let call = AsyncCall::new( + Slot::new(target_slot.0, target_slot.1), + target_addr, + target_func.to_string(), + params.to_vec(), + coins, + max_gas, + fee, + ); + + // write-lock context + let mut context = context_guard!(self); + + /* + TODO: + * ask the context to register the call + * return the id of the call + */ + + todo!() + } + + /// Check if an asynchronous call exists + /// + /// # Arguments + /// * id: the id of the call + /// + /// # Returns + /// true if the call exists, false otherwise + fn asc_call_exists(&self, id: &[u8]) -> Result { + // write-lock context + let mut context = context_guard!(self); + + //TODO: ask the context if the call exists + + todo!() + } + + /// Cancel an asynchronous call + /// + /// # Arguments + /// * id: the id of the call + fn asc_call_cancel(&self, id: &[u8]) -> Result<()> { + // write-lock context + let mut context = context_guard!(self); + + //TODO: ask the context to cancel the call + + todo!() + } + #[allow(unused_variables)] fn init_call_wasmv1(&self, address: &str, raw_coins: NativeAmount) -> Result> { // get target address diff --git a/massa-execution-worker/src/lib.rs b/massa-execution-worker/src/lib.rs index 030bb929e5e..9878a83e637 100644 --- a/massa-execution-worker/src/lib.rs +++ b/massa-execution-worker/src/lib.rs @@ -86,6 +86,7 @@ mod execution; mod interface_impl; mod request_queue; mod slot_sequencer; +mod speculative_asc; mod speculative_async_pool; mod speculative_executed_denunciations; mod speculative_executed_ops; diff --git a/massa-execution-worker/src/speculative_asc.rs b/massa-execution-worker/src/speculative_asc.rs new file mode 100644 index 00000000000..30e2f0ab49c --- /dev/null +++ b/massa-execution-worker/src/speculative_asc.rs @@ -0,0 +1,140 @@ +//! Speculative async call registry. + +use crate::active_history::{ActiveHistory, HistorySearchResult::Present}; +use crate::ExecutionError; +use massa_asc::{AsyncCall, AsyncRegistryChanges}; +use massa_final_state::FinalStateController; +use massa_ledger_exports::{Applicable, LedgerChanges, SetUpdateOrDelete}; +use massa_models::{asc_call_id::AsyncCallId, slot::Slot}; +use parking_lot::RwLock; +use std::{ + collections::{BTreeMap, HashMap}, + sync::Arc, +}; + +pub(crate) struct SpeculativeAsyncCallRegistry { + final_state: Arc>, + active_history: Arc>, + // current speculative registry changes + current_changes: AsyncRegistryChanges, +} + +impl SpeculativeAsyncCallRegistry { + /// Creates a new `SpeculativeAsyncCallRegistry` + /// + /// # Arguments + pub fn new( + final_state: Arc>, + active_history: Arc>, + ) -> Self { + AsyncRegistryChanges { + final_state, + active_history, + current_changes: Default::default(), + } + } + + /// Takes a snapshot (clone) of the message states + pub fn get_snapshot(&self) -> AsyncRegistryChanges { + self.current_changes.clone() + } + + /// Resets the `SpeculativeAsyncCallRegistry` to a snapshot (see `get_snapshot` method) + pub fn reset_to_snapshot(&mut self, snapshot: AsyncRegistryChanges) { + self.current_changes = snapshot; + } + + /// Add a new call to the list of changes of this `SpeculativeAsyncCallRegistry` + pub fn push_new_call(&mut self, id: AsyncCallId, call: AsyncCall) { + self.current_changes.push_new_call(id, call); + } + + /// Removes the next call to be executed at the given slot and returns it. + /// Returns None if there is no call to be executed at the given slot. + pub fn take_next_call(&mut self, slot: Slot) -> Option<(AsyncCallId, AsyncCall)> { + // Note: calls can only be added. So we want to look from old to new and return the first one. + + let mut res = None; + + // check final state + if res.is_none() { + res = self + .final_state + .read() + .get_asc_registry() + .get_best_call(slot); // note: includes cancelled calls + } + + // check active history from oldest to newest + if res.is_none() { + let history = self.active_history.read(); + for history_item in &history.0 { + res = history_item + .state_changes + .async_call_registry_changes + .get_best_call(slot); + if res.is_some() { + break; + } + } + } + + // check current changes + if res.is_none() { + res = self.current_changes.get_best_call(slot); + } + + // remove from current changes + if let Some((id, _)) = res.as_ref() { + self.current_changes.remove_call(id); + } + + res + } + + /// Check that a call exists and is not cancelled + pub fn call_exists(&mut self, id: AsyncCallId) -> bool { + // Check if the call was cancelled or deleted in the current changes + match self.current_changes.call_status(id) { + CallStatus::Emitted => return true, + CallStatus::Cancelled | CallStatus::Deleted => return false, + CallStatus::Unknown => {} + } + + // List history from most recent to oldest, and check if the call was cancelled or deleted + { + let history = self.active_history.read(); + for history_item in history.0.iter().rev() { + match history_item + .state_changes + .async_call_registry_changes + .get_status(id) + { + CallStatus::Emitted => return true, + CallStatus::Cancelled | CallStatus::Deleted => return false, + CallStatus::Unknown => {} + } + } + } + + // Check the final state: return true if the call is present and not cancelled + { + let final_state = self.final_state.read(); + match final_state.get_asc_registry().is_call_cancelled(id) { + None => false, // not found + Some(true) => false, // found, cancelled + Some(false) => true, // found, not cancelled + } + } + } + + /// Cancel a call + pub fn cancel_call(&mut self, id: AsyncCallId) -> Result<(), ExecutionError> { + if (!self.call_exists(id)) { + return Err(ExecutionError::TODO("Call ID does not exist.")); + } + // Add a cancellation to the current changes + self.current_changes.cancel_call(id); + Ok(()) + } +} diff --git a/massa-models/src/asc_call_id.rs b/massa-models/src/asc_call_id.rs new file mode 100644 index 00000000000..525f0b2839e --- /dev/null +++ b/massa-models/src/asc_call_id.rs @@ -0,0 +1,280 @@ +use std::str::FromStr; + +use massa_serialization::{ + Deserializer, SerializeError, Serializer, U64VarIntDeserializer, U64VarIntSerializer, +}; +use nom::{ + error::{ContextError, ErrorKind, ParseError}, + IResult, +}; +use transition::Versioned; + +use crate::{ + error::ModelsError, + serialization::{VecU8Deserializer, VecU8Serializer}, + slot::{Slot, SlotSerializer}, +}; + +const ASC_CALL_ID_PREFIX: &str = "ASC"; + +/// block id +#[allow(missing_docs)] +#[transition::versioned(versions("0"))] +#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] +pub struct AsyncCallId(Vec); + +/// Serializer for `AsyncCallId` +#[derive(Default, Clone)] +pub struct AsyncCallIdSerializer { + bytes_serializer: VecU8Serializer, +} + +impl AsyncCallIdSerializer { + /// Serializes an `AsyncCallId` into a `Vec` + pub fn new() -> Self { + Self { + bytes_serializer: VecU8Serializer::new(), + } + } +} + +impl Serializer for AsyncCallIdSerializer { + fn serialize(&self, value: &AsyncCallId, buffer: &mut Vec) -> Result<(), SerializeError> { + match value { + AsyncCallId::AsyncCallIdV0(id) => { + self.bytes_serializer.serialize(&id.0, buffer)?; + } + } + Ok(()) + } +} + +/// Deserializer for `AsyncCallId` +pub struct AsyncCallIdDeserializer { + bytes_deserializer: VecU8Deserializer, +} + +impl AsyncCallIdDeserializer { + /// Deserializes a `Vec` into an `AsyncCallId` + pub fn new() -> Self { + Self { + bytes_deserializer: VecU8Deserializer::new( + std::ops::Bound::Included(0), + std::ops::Bound::Included(u64::MAX), + ), + } + } +} + +impl Deserializer for AsyncCallIdDeserializer { + fn deserialize<'a, E: ParseError<&'a [u8]> + ContextError<&'a [u8]>>( + &self, + buffer: &'a [u8], + ) -> IResult<&'a [u8], AsyncCallId, E> { + let (rest, bytes) = self.bytes_deserializer.deserialize(buffer)?; + Ok((rest, AsyncCallId::AsyncCallIdV0(AsyncCallIdV0(bytes)))) + } +} + +impl FromStr for AsyncCallId { + type Err = ModelsError; + + fn from_str(s: &str) -> Result { + if !s.starts_with(ASC_CALL_ID_PREFIX) { + return Err(ModelsError::DeserializeError(format!( + "Invalid prefix for AsyncCallId: {}", + s + ))); + } + let s = &s[ASC_CALL_ID_PREFIX.len()..]; + let bytes = bs58::decode(s).with_check(None).into_vec().map_err(|_| { + ModelsError::DeserializeError(format!("Invalid base58 string for AsyncCallId: {}", s)) + })?; + AsyncCallId::from_bytes(&bytes) + } +} + +impl std::fmt::Display for AsyncCallId { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{}{}", + ASC_CALL_ID_PREFIX, + bs58::encode(self.as_bytes()).with_check().into_string() + ) + } +} + +impl ::serde::Serialize for AsyncCallId { + fn serialize(&self, serializer: S) -> Result + where + S: ::serde::Serializer, + { + if serializer.is_human_readable() { + serializer.collect_str(&self.to_string()) + } else { + serializer.serialize_bytes(&self.as_bytes()) + } + } +} + +impl<'de> ::serde::Deserialize<'de> for AsyncCallId { + fn deserialize>(d: D) -> Result { + if d.is_human_readable() { + struct AsyncCallIdVisitor; + + impl<'de> ::serde::de::Visitor<'de> for AsyncCallIdVisitor { + type Value = AsyncCallId; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("ASC + base58::encode(bytes)") + } + + fn visit_bytes(self, v: &[u8]) -> Result + where + E: ::serde::de::Error, + { + if let Ok(v_str) = std::str::from_utf8(v) { + AsyncCallId::from_str(v_str).map_err(E::custom) + } else { + Err(E::invalid_value(::serde::de::Unexpected::Bytes(v), &self)) + } + } + + fn visit_str(self, v: &str) -> Result + where + E: ::serde::de::Error, + { + AsyncCallId::from_str(v).map_err(E::custom) + } + } + d.deserialize_str(AsyncCallIdVisitor) + } else { + struct BytesVisitor; + + impl<'de> ::serde::de::Visitor<'de> for BytesVisitor { + type Value = AsyncCallId; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("[u64varint-of-addr-variant][u64varint-of-version][bytes]") + } + + fn visit_bytes(self, v: &[u8]) -> Result + where + E: ::serde::de::Error, + { + AsyncCallId::from_bytes(v).map_err(E::custom) + } + } + + d.deserialize_bytes(BytesVisitor) + } + } +} + +impl AsyncCallId { + /// Create a new `AsyncCallId` + pub fn new( + version: u64, + target_slot: Slot, + index: u64, + trail_hash: &[u8], + ) -> Result { + let mut id = Vec::new(); + match version { + 0 => { + let version_serializer = U64VarIntSerializer::new(); + let slot_serializer = SlotSerializer::new(); + version_serializer.serialize(&version, &mut id)?; + slot_serializer.serialize(&target_slot, &mut id)?; + id.extend(index.to_be_bytes()); + id.extend(trail_hash); + Ok(AsyncCallId::AsyncCallIdV0(AsyncCallIdV0(id))) + } + _ => { + return Err(ModelsError::InvalidVersionError(format!( + "Invalid version to create an AsyncCallId: {}", + version + ))) + } + } + } + + /// Return the version of the `AsyncCallId` as bytes + pub fn as_bytes(&self) -> &[u8] { + match self { + AsyncCallId::AsyncCallIdV0(block_id) => block_id.as_bytes(), + } + } + + /// Create an `AsyncCallId` from bytes + pub fn from_bytes(bytes: &[u8]) -> Result { + if bytes.is_empty() { + return Err(ModelsError::SerializeError("Empty bytes".to_string())); + } + let version = U64VarIntDeserializer::new( + std::ops::Bound::Included(0), + std::ops::Bound::Included(u64::MAX), + ); + let (_, version) = version.deserialize(bytes)?; + match version { + 0 => { + let id = AsyncCallIdV0::from_bytes(bytes)?; + Ok(AsyncCallId::AsyncCallIdV0(id)) + } + _ => Err(ModelsError::InvalidVersionError(format!( + "Invalid version to create an AsyncCallId: {}", + version + ))), + } + } +} + +#[transition::impl_version(versions("0"))] +impl AsyncCallId { + /// Return the version of the `AsyncCallId` as bytes + pub fn as_bytes(&self) -> &[u8] { + &self.0 + } + + /// Create an `AsyncCallId` from bytes + pub fn from_bytes(bytes: &[u8]) -> Result { + Ok(AsyncCallIdV0(bytes.to_vec())) + } +} + +#[cfg(test)] +mod tests { + use massa_serialization::DeserializeError; + + use super::*; + use crate::slot::Slot; + + #[test] + fn test_async_call_id_ser_deser() { + let slot = Slot::new(1, 2); + let index = 3; + let trail_hash = [4, 5, 6]; + let id = AsyncCallId::new(0, slot, index, &trail_hash).unwrap(); + let serializer = AsyncCallIdSerializer::new(); + let mut buffer = Vec::new(); + serializer.serialize(&id, &mut buffer).unwrap(); + let deserializer = AsyncCallIdDeserializer::new(); + let (rest, deserialized_id) = deserializer + .deserialize::(&buffer) + .unwrap(); + assert_eq!(deserialized_id, id); + assert!(rest.is_empty()); + } + + #[test] + fn test_async_call_id_from_str() { + let slot = Slot::new(1, 2); + let index = 3; + let trail_hash = [4, 5, 6]; + let id = AsyncCallId::new(0, slot, index, &trail_hash).unwrap(); + let id_str = id.to_string(); + let deserialized_id = AsyncCallId::from_str(&id_str).unwrap(); + assert_eq!(deserialized_id, id); + } +} diff --git a/massa-models/src/lib.rs b/massa-models/src/lib.rs index ba80ecf5b4d..9db32d9fb70 100644 --- a/massa-models/src/lib.rs +++ b/massa-models/src/lib.rs @@ -12,6 +12,8 @@ pub mod active_block; pub mod address; /// amount related structures pub mod amount; +/// async call id +pub mod asc_call_id; /// block structure pub mod block; /// block-related structure: block_header From 4407e860a0f2f8080d3e35b8f526740cfdaf6e2c Mon Sep 17 00:00:00 2001 From: Damir Vodenicarevic Date: Thu, 9 May 2024 19:02:08 +0200 Subject: [PATCH 002/100] progress --- massa-asc/src/call.rs | 33 ++++- massa-asc/src/lib.rs | 132 +++++++++++++++++- massa-execution-exports/src/error.rs | 3 + massa-execution-worker/src/interface_impl.rs | 1 + massa-execution-worker/src/speculative_asc.rs | 26 ++-- 5 files changed, 173 insertions(+), 22 deletions(-) diff --git a/massa-asc/src/call.rs b/massa-asc/src/call.rs index c5884ad99cc..4519a473571 100644 --- a/massa-asc/src/call.rs +++ b/massa-asc/src/call.rs @@ -5,8 +5,8 @@ use massa_models::{ slot::{Slot, SlotDeserializer, SlotSerializer}, }; use massa_serialization::{ - Deserializer, SerializeError, Serializer, U16VarIntDeserializer, U16VarIntSerializer, - U64VarIntDeserializer, U64VarIntSerializer, + BoolDeserializer, BoolSerializer, Deserializer, SerializeError, Serializer, + U16VarIntDeserializer, U16VarIntSerializer, U64VarIntDeserializer, U64VarIntSerializer, }; use nom::{ error::{context, ContextError, ParseError}, @@ -32,6 +32,8 @@ pub struct AsyncCall { pub max_gas: u64, // The fee to pay for the reservation of the space for the call pub fee: Amount, + // Whether the call is cancelled + pub cancelled: bool, } impl AsyncCall { @@ -43,6 +45,7 @@ impl AsyncCall { coins: Amount, max_gas: u64, fee: Amount, + cancelled: bool, ) -> Self { Self { target_slot, @@ -52,6 +55,7 @@ impl AsyncCall { coins, max_gas, fee, + cancelled, } } } @@ -65,6 +69,7 @@ pub struct AsyncCallSerializer { vec_u8_serializer: VecU8Serializer, amount_serializer: AmountSerializer, u64_var_int_serializer: U64VarIntSerializer, + bool_serializer: BoolSerializer, } impl AsyncCallSerializer { @@ -73,10 +78,11 @@ impl AsyncCallSerializer { Self { slot_serializer: SlotSerializer::new(), address_serializer: AddressSerializer::new(), - string_serializer: StringSerializer::new(U16VarIntSerializer::new()), - vec_u8_serializer: VecU8Serializer::new(), + string_serializer: StringSerializer::new(U16VarIntSerializer::new()), // TODO: use max function name length + vec_u8_serializer: VecU8Serializer::new(), // TODO: use max parameters length amount_serializer: AmountSerializer::new(), u64_var_int_serializer: U64VarIntSerializer::new(), + bool_serializer: BoolSerializer::new(), } } } @@ -94,6 +100,7 @@ impl Serializer for AsyncCallSerializer { self.amount_serializer.serialize(&value.fee, buffer)?; self.u64_var_int_serializer .serialize(&value.max_gas, buffer)?; + self.bool_serializer.serialize(&value.cancelled, buffer)?; Ok(()) } } @@ -107,6 +114,7 @@ pub struct AsyncCallDeserializer { vec_u8_deserializer: VecU8Deserializer, amount_deserializer: AmountDeserializer, u64_var_int_deserializer: U64VarIntDeserializer, + bool_deserializer: BoolDeserializer, } impl AsyncCallDeserializer { @@ -134,6 +142,7 @@ impl AsyncCallDeserializer { Bound::Included(0), Bound::Included(u64::MAX), ), + bool_deserializer: BoolDeserializer::new(), } } } @@ -167,10 +176,22 @@ impl Deserializer for AsyncCallDeserializer { context("Failed max_gas deserialization", |input| { self.u64_var_int_deserializer.deserialize(input) }), + context("Failed cancelled deserialization", |input| { + self.bool_deserializer.deserialize(input) + }), )), ) .map( - |(target_slot, target_address, target_function, parameters, coins, fee, max_gas)| { + |( + target_slot, + target_address, + target_function, + parameters, + coins, + fee, + max_gas, + cancelled, + )| { AsyncCall::new( target_slot, target_address, @@ -179,6 +200,7 @@ impl Deserializer for AsyncCallDeserializer { coins, max_gas, fee, + cancelled, ) }, ) @@ -204,6 +226,7 @@ mod tests { Amount::from_raw(42), 42, Amount::from_raw(42), + false, ); let serializer = AsyncCallSerializer::new(); let deserializer = AsyncCallDeserializer::new(1); diff --git a/massa-asc/src/lib.rs b/massa-asc/src/lib.rs index f732a09d9d9..40b949fc171 100644 --- a/massa-asc/src/lib.rs +++ b/massa-asc/src/lib.rs @@ -8,6 +8,7 @@ pub use call::AsyncCall; use massa_models::{asc_call_id::AsyncCallId, slot::Slot}; use std::collections::BTreeMap; +#[derive(Debug)] pub struct AsyncCallRegistry { db: ShareableMassaDBController, } @@ -26,10 +27,137 @@ impl AsyncCallRegistry { } } +#[derive(Debug, Clone)] +pub enum CallStatus { + Emitted, + Cancelled, + Removed, + Unknown +} + +#[derive(Debug, Clone)] +pub enum AsyncRegistryCallChange { + Emitted(AsyncCall), + Cancelled(AsyncCall), + Removed, +} + + +impl AsyncRegistryCallChange { + pub fn merge(&mut self, other: AsyncRegistryCallChange) { + *self = other; + } + + pub fn remove_call(&mut self) -> Option { + let mut v = AsyncRegistryCallChange::Removed; + std::mem::swap(self, &mut v); + match v { + AsyncRegistryCallChange::Emitted(call) => Some(call), + AsyncRegistryCallChange::Cancelled(call) => Some(call), + AsyncRegistryCallChange::Removed => None + } + } +} + +#[derive(Default, Debug, Clone)] +pub struct AsyncRegistrySlotChanges { + pub changes: BTreeMap, +} + +impl AsyncRegistrySlotChanges { + pub fn merge(&mut self, other: AsyncRegistrySlotChanges) { + for (id, change) in other.changes { + match self.changes.entry(id) { + std::collections::btree_map::Entry::Occupied(mut entry) => { + entry.get_mut().merge(change); + } + std::collections::btree_map::Entry::Vacant(entry) => { + entry.insert(change); + } + } + } + } + + pub fn remove_call(&mut self, id: &AsyncCallId) -> Option { + match self.changes.entry(id.clone()) { + std::collections::btree_map::Entry::Occupied(mut v) => { + v.get_mut().remove_call() + } + std::collections::btree_map::Entry::Vacant(v) => { + v.insert(AsyncRegistryCallChange::Removed); + None + } + } + } + + pub fn push_new_call(&mut self, id: AsyncCallId, call: AsyncCall) { + self.changes.insert(id, AsyncRegistryCallChange::Emitted(call)); + } +} + +#[derive(Default, Debug, Clone)] pub struct AsyncRegistryChanges { pub by_slot: BTreeMap, } -pub struct AsyncRegistrySlotChanges { - pub changes: BTreeMap, +impl AsyncRegistryChanges { + pub fn merge(&mut self, other: AsyncRegistryChanges) { + for (slot, changes) in other.by_slot { + match self.by_slot.entry(slot) { + std::collections::btree_map::Entry::Occupied(mut entry) => { + entry.get_mut().merge(changes); + } + std::collections::btree_map::Entry::Vacant(entry) => { + entry.insert(changes); + } + } + } + } + + pub fn get_best_call(&self, slot: Slot) -> Option<(AsyncCallId, AsyncCall)> { + if let Some(slot_changes) = self.by_slot.get(&slot) { + for (id, change) in &slot_changes.changes { + match change { + AsyncRegistryCallChange::Emitted(call) => { + return Some((id.clone(), call.clone())); + }, + AsyncRegistryCallChange::Cancelled(call) => { + return Some((id.clone(), call.clone())); + } + AsyncRegistryCallChange::Removed => {} + } + } + } + None + } + + pub fn remove_call(&mut self, target_slot: Slot, id: &AsyncCallId) -> Option { + self.by_slot.entry(target_slot).or_default().remove_call(id) + } + + pub fn push_new_call(&mut self, id: AsyncCallId, call: AsyncCall) { + self.by_slot + .entry(call.target_slot.clone()) + .or_default() + .push_new_call(id, call); + } + + pub fn call_status(&self, slot: Slot, id: &AsyncCallId) -> CallStatus { + if let Some(slot_changes) = self.by_slot.get(&slot) { + if let Some(change) = slot_changes.changes.get(id) { + match change { + AsyncRegistryCallChange::Emitted(_) => CallStatus::Emitted, + AsyncRegistryCallChange::Cancelled(_) => CallStatus::Cancelled, + AsyncRegistryCallChange::Removed => CallStatus::Removed, + } + } else { + CallStatus::Unknown + } + } else { + CallStatus::Unknown + } + } + } + + diff --git a/massa-execution-exports/src/error.rs b/massa-execution-exports/src/error.rs index 21fcbe3f85d..4220fcfe59c 100644 --- a/massa-execution-exports/src/error.rs +++ b/massa-execution-exports/src/error.rs @@ -67,6 +67,9 @@ pub enum ExecutionError { /// Factory error: {0} FactoryError(#[from] FactoryError), + + /// Autonomous smart contract call error: {0} + AscError(String), } /// Execution query errors diff --git a/massa-execution-worker/src/interface_impl.rs b/massa-execution-worker/src/interface_impl.rs index ce8e5ffa676..ca78e2571f4 100644 --- a/massa-execution-worker/src/interface_impl.rs +++ b/massa-execution-worker/src/interface_impl.rs @@ -1399,6 +1399,7 @@ impl Interface for InterfaceImpl { coins, max_gas, fee, + false, ); // write-lock context diff --git a/massa-execution-worker/src/speculative_asc.rs b/massa-execution-worker/src/speculative_asc.rs index 30e2f0ab49c..0ae5258749f 100644 --- a/massa-execution-worker/src/speculative_asc.rs +++ b/massa-execution-worker/src/speculative_asc.rs @@ -1,16 +1,12 @@ //! Speculative async call registry. -use crate::active_history::{ActiveHistory, HistorySearchResult::Present}; -use crate::ExecutionError; -use massa_asc::{AsyncCall, AsyncRegistryChanges}; +use crate::active_history::ActiveHistory; +use massa_execution_exports::ExecutionError; +use massa_asc::{AsyncCall, AsyncRegistryChanges, CallStatus}; use massa_final_state::FinalStateController; -use massa_ledger_exports::{Applicable, LedgerChanges, SetUpdateOrDelete}; use massa_models::{asc_call_id::AsyncCallId, slot::Slot}; use parking_lot::RwLock; -use std::{ - collections::{BTreeMap, HashMap}, - sync::Arc, -}; +use std::sync::Arc; pub(crate) struct SpeculativeAsyncCallRegistry { final_state: Arc>, @@ -27,7 +23,7 @@ impl SpeculativeAsyncCallRegistry { final_state: Arc>, active_history: Arc>, ) -> Self { - AsyncRegistryChanges { + SpeculativeAsyncCallRegistry { final_state, active_history, current_changes: Default::default(), @@ -86,7 +82,7 @@ impl SpeculativeAsyncCallRegistry { // remove from current changes if let Some((id, _)) = res.as_ref() { - self.current_changes.remove_call(id); + self.current_changes.remove_call(slot, id); } res @@ -95,9 +91,9 @@ impl SpeculativeAsyncCallRegistry { /// Check that a call exists and is not cancelled pub fn call_exists(&mut self, id: AsyncCallId) -> bool { // Check if the call was cancelled or deleted in the current changes - match self.current_changes.call_status(id) { + match self.current_changes.call_status(id.get_slot(), id) { CallStatus::Emitted => return true, - CallStatus::Cancelled | CallStatus::Deleted => return false, + CallStatus::Cancelled | CallStatus::Removed => return false, CallStatus::Unknown => {} } @@ -111,7 +107,7 @@ impl SpeculativeAsyncCallRegistry { .get_status(id) { CallStatus::Emitted => return true, - CallStatus::Cancelled | CallStatus::Deleted => return false, + CallStatus::Cancelled | CallStatus::Removed => return false, CallStatus::Unknown => {} } } @@ -130,8 +126,8 @@ impl SpeculativeAsyncCallRegistry { /// Cancel a call pub fn cancel_call(&mut self, id: AsyncCallId) -> Result<(), ExecutionError> { - if (!self.call_exists(id)) { - return Err(ExecutionError::TODO("Call ID does not exist.")); + if !self.call_exists(id) { + return Err(ExecutionError::AscError("Call ID does not exist.".into())); } // Add a cancellation to the current changes self.current_changes.cancel_call(id); From b6948d0a8fe6f683c2e8e5084c06de63082e84d3 Mon Sep 17 00:00:00 2001 From: Damir Vodenicarevic Date: Thu, 9 May 2024 19:25:54 +0200 Subject: [PATCH 003/100] progress --- massa-asc/src/lib.rs | 81 +++++++++++++------ massa-execution-worker/src/speculative_asc.rs | 6 +- 2 files changed, 58 insertions(+), 29 deletions(-) diff --git a/massa-asc/src/lib.rs b/massa-asc/src/lib.rs index 40b949fc171..dbcdd40a5b9 100644 --- a/massa-asc/src/lib.rs +++ b/massa-asc/src/lib.rs @@ -32,30 +32,39 @@ pub enum CallStatus { Emitted, Cancelled, Removed, - Unknown + Unknown, } #[derive(Debug, Clone)] pub enum AsyncRegistryCallChange { Emitted(AsyncCall), - Cancelled(AsyncCall), + Cancelled(Option), // content is Some when the call was emitted AND cancelled in the same change, to not lose the call content Removed, } - impl AsyncRegistryCallChange { pub fn merge(&mut self, other: AsyncRegistryCallChange) { - *self = other; + match other { + AsyncRegistryCallChange::Emitted(call) => { + *self = AsyncRegistryCallChange::Emitted(call); + } + AsyncRegistryCallChange::Cancelled(mut opt_call) => { + if opt_call.is_none() { + if let AsyncRegistryCallChange::Cancelled(v) = self { + // preserve the value if we have it already + opt_call = v.take(); + } + } + *self = AsyncRegistryCallChange::Cancelled(opt_call); + } + AsyncRegistryCallChange::Removed => { + *self = AsyncRegistryCallChange::Removed; + } + } } - pub fn remove_call(&mut self) -> Option { - let mut v = AsyncRegistryCallChange::Removed; - std::mem::swap(self, &mut v); - match v { - AsyncRegistryCallChange::Emitted(call) => Some(call), - AsyncRegistryCallChange::Cancelled(call) => Some(call), - AsyncRegistryCallChange::Removed => None - } + pub fn remove_call(&mut self) { + *self = AsyncRegistryCallChange::Removed; } } @@ -78,20 +87,39 @@ impl AsyncRegistrySlotChanges { } } - pub fn remove_call(&mut self, id: &AsyncCallId) -> Option { + /// Adds a "remove" change for the target + pub fn remove_call(&mut self, id: &AsyncCallId) { match self.changes.entry(id.clone()) { - std::collections::btree_map::Entry::Occupied(mut v) => { - v.get_mut().remove_call() - } + std::collections::btree_map::Entry::Occupied(mut v) => v.get_mut().remove_call(), std::collections::btree_map::Entry::Vacant(v) => { v.insert(AsyncRegistryCallChange::Removed); - None } } } pub fn push_new_call(&mut self, id: AsyncCallId, call: AsyncCall) { - self.changes.insert(id, AsyncRegistryCallChange::Emitted(call)); + self.changes + .insert(id, AsyncRegistryCallChange::Emitted(call)); + } + + pub fn cancel_call(&mut self, id: AsyncCallId) { + self.changes + .entry(id) + .and_modify(|v| { + let mut v_n = AsyncRegistryCallChange::Cancelled(None); + std::mem::swap(v, &mut v_n); + match v_n { + AsyncRegistryCallChange::Emitted(call) => { + *v = AsyncRegistryCallChange::Cancelled(Some(call)); + } + AsyncRegistryCallChange::Cancelled(Some(call)) => { + *v = AsyncRegistryCallChange::Cancelled(Some(call)); + } + AsyncRegistryCallChange::Cancelled(None) => {} + AsyncRegistryCallChange::Removed => {} + } + }) + .or_insert_with(|| AsyncRegistryCallChange::Cancelled(None)); } } @@ -114,15 +142,15 @@ impl AsyncRegistryChanges { } } - pub fn get_best_call(&self, slot: Slot) -> Option<(AsyncCallId, AsyncCall)> { + pub fn get_best_call(&self, slot: Slot) -> Option<(AsyncCallId, Option)> { if let Some(slot_changes) = self.by_slot.get(&slot) { for (id, change) in &slot_changes.changes { match change { AsyncRegistryCallChange::Emitted(call) => { - return Some((id.clone(), call.clone())); - }, - AsyncRegistryCallChange::Cancelled(call) => { - return Some((id.clone(), call.clone())); + return Some((id.clone(), Some(call.clone()))); + } + AsyncRegistryCallChange::Cancelled(opt_call) => { + return Some((id.clone(), opt_call.clone())); } AsyncRegistryCallChange::Removed => {} } @@ -131,7 +159,7 @@ impl AsyncRegistryChanges { None } - pub fn remove_call(&mut self, target_slot: Slot, id: &AsyncCallId) -> Option { + pub fn remove_call(&mut self, target_slot: Slot, id: &AsyncCallId) { self.by_slot.entry(target_slot).or_default().remove_call(id) } @@ -158,6 +186,7 @@ impl AsyncRegistryChanges { } } + pub fn cancel_call(&mut self, slot: Slot, id: AsyncCallId) { + self.by_slot.entry(slot).or_default().cancel_call(id); + } } - - diff --git a/massa-execution-worker/src/speculative_asc.rs b/massa-execution-worker/src/speculative_asc.rs index 0ae5258749f..ef1f0336bad 100644 --- a/massa-execution-worker/src/speculative_asc.rs +++ b/massa-execution-worker/src/speculative_asc.rs @@ -1,8 +1,8 @@ //! Speculative async call registry. use crate::active_history::ActiveHistory; -use massa_execution_exports::ExecutionError; use massa_asc::{AsyncCall, AsyncRegistryChanges, CallStatus}; +use massa_execution_exports::ExecutionError; use massa_final_state::FinalStateController; use massa_models::{asc_call_id::AsyncCallId, slot::Slot}; use parking_lot::RwLock; @@ -91,7 +91,7 @@ impl SpeculativeAsyncCallRegistry { /// Check that a call exists and is not cancelled pub fn call_exists(&mut self, id: AsyncCallId) -> bool { // Check if the call was cancelled or deleted in the current changes - match self.current_changes.call_status(id.get_slot(), id) { + match self.current_changes.call_status(id.get_slot(), &id) { CallStatus::Emitted => return true, CallStatus::Cancelled | CallStatus::Removed => return false, CallStatus::Unknown => {} @@ -130,7 +130,7 @@ impl SpeculativeAsyncCallRegistry { return Err(ExecutionError::AscError("Call ID does not exist.".into())); } // Add a cancellation to the current changes - self.current_changes.cancel_call(id); + self.current_changes.cancel_call(id.get_slot(), id); Ok(()) } } From bcfaed35fc3b1702a3c9cfaf6d218f59ab22b42a Mon Sep 17 00:00:00 2001 From: Damir Vodenicarevic Date: Fri, 10 May 2024 00:11:09 +0200 Subject: [PATCH 004/100] todos --- massa-asc/src/lib.rs | 2 +- massa-execution-worker/src/speculative_asc.rs | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/massa-asc/src/lib.rs b/massa-asc/src/lib.rs index dbcdd40a5b9..a58a38f54bc 100644 --- a/massa-asc/src/lib.rs +++ b/massa-asc/src/lib.rs @@ -38,7 +38,7 @@ pub enum CallStatus { #[derive(Debug, Clone)] pub enum AsyncRegistryCallChange { Emitted(AsyncCall), - Cancelled(Option), // content is Some when the call was emitted AND cancelled in the same change, to not lose the call content + Cancelled(Option), Removed, } diff --git a/massa-execution-worker/src/speculative_asc.rs b/massa-execution-worker/src/speculative_asc.rs index ef1f0336bad..ff0bbbd4578 100644 --- a/massa-execution-worker/src/speculative_asc.rs +++ b/massa-execution-worker/src/speculative_asc.rs @@ -47,7 +47,7 @@ impl SpeculativeAsyncCallRegistry { /// Removes the next call to be executed at the given slot and returns it. /// Returns None if there is no call to be executed at the given slot. - pub fn take_next_call(&mut self, slot: Slot) -> Option<(AsyncCallId, AsyncCall)> { + pub fn take_next_call(&mut self, slot: Slot) -> Option<(AsyncCallId, Option)> { // Note: calls can only be added. So we want to look from old to new and return the first one. let mut res = None; @@ -97,7 +97,7 @@ impl SpeculativeAsyncCallRegistry { CallStatus::Unknown => {} } - // List history from most recent to oldest, and check if the call was cancelled or deleted + // List history from most recent to oldest, and check if the call was emitted, cancelled or deleted { let history = self.active_history.read(); for history_item in history.0.iter().rev() { @@ -129,8 +129,13 @@ impl SpeculativeAsyncCallRegistry { if !self.call_exists(id) { return Err(ExecutionError::AscError("Call ID does not exist.".into())); } + // Add a cancellation to the current changes self.current_changes.cancel_call(id.get_slot(), id); + + // TODO: reimburse coins + todo!(); + Ok(()) } } From eb59c84fd62c0b54dcc03ac66f45f3e841dbbdd3 Mon Sep 17 00:00:00 2001 From: damip Date: Fri, 10 May 2024 08:26:28 +0200 Subject: [PATCH 005/100] Improve general behavior --- massa-asc/src/call.rs | 12 ++ massa-asc/src/lib.rs | 175 +++++++----------- massa-execution-worker/src/interface_impl.rs | 13 +- massa-execution-worker/src/speculative_asc.rs | 123 ++++++------ massa-models/src/asc_call_id.rs | 4 + 5 files changed, 154 insertions(+), 173 deletions(-) diff --git a/massa-asc/src/call.rs b/massa-asc/src/call.rs index 4519a473571..0c50eccc14d 100644 --- a/massa-asc/src/call.rs +++ b/massa-asc/src/call.rs @@ -18,6 +18,8 @@ use std::ops::Bound; /// Definition of a call in the future #[derive(Debug, Clone, PartialEq, Eq)] pub struct AsyncCall { + // Sender address + pub sender_address: Address, // The slot in which the call will be executed pub target_slot: Slot, // The address of the contract to call @@ -38,6 +40,7 @@ pub struct AsyncCall { impl AsyncCall { pub fn new( + sender_address: Address, target_slot: Slot, target_address: Address, target_function: String, @@ -48,6 +51,7 @@ impl AsyncCall { cancelled: bool, ) -> Self { Self { + sender_address, target_slot, target_address, target_function, @@ -89,6 +93,8 @@ impl AsyncCallSerializer { impl Serializer for AsyncCallSerializer { fn serialize(&self, value: &AsyncCall, buffer: &mut Vec) -> Result<(), SerializeError> { + self.address_serializer + .serialize(&value.sender_address, buffer)?; self.slot_serializer.serialize(&value.target_slot, buffer)?; self.address_serializer .serialize(&value.target_address, buffer)?; @@ -155,6 +161,9 @@ impl Deserializer for AsyncCallDeserializer { context( "Failed AsyncCall deserialization", tuple(( + context("Failed sender_address deserialization", |input| { + self.address_deserializer.deserialize(input) + }), context("Failed target_slot deserialization", |input| { self.slot_deserializer.deserialize(input) }), @@ -183,6 +192,7 @@ impl Deserializer for AsyncCallDeserializer { ) .map( |( + sender_address, target_slot, target_address, target_function, @@ -193,6 +203,7 @@ impl Deserializer for AsyncCallDeserializer { cancelled, )| { AsyncCall::new( + sender_address, target_slot, target_address, target_function, @@ -219,6 +230,7 @@ mod tests { #[test] fn test_serialization_deserialization() { let call = AsyncCall::new( + Address::from_str("AU12dG5xP1RDEB5ocdHkymNVvvSJmUL9BgHwCksDowqmGWxfpm93x").unwrap(), Slot::new(42, 0), Address::from_str("AU12dG5xP1RDEB5ocdHkymNVvvSJmUL9BgHwCksDowqmGWxfpm93x").unwrap(), "function".to_string(), diff --git a/massa-asc/src/lib.rs b/massa-asc/src/lib.rs index a58a38f54bc..0a9613baf8d 100644 --- a/massa-asc/src/lib.rs +++ b/massa-asc/src/lib.rs @@ -27,56 +27,40 @@ impl AsyncCallRegistry { } } -#[derive(Debug, Clone)] -pub enum CallStatus { - Emitted, - Cancelled, - Removed, - Unknown, -} - #[derive(Debug, Clone)] pub enum AsyncRegistryCallChange { - Emitted(AsyncCall), - Cancelled(Option), - Removed, + Set(AsyncCall), + Delete, } impl AsyncRegistryCallChange { pub fn merge(&mut self, other: AsyncRegistryCallChange) { - match other { - AsyncRegistryCallChange::Emitted(call) => { - *self = AsyncRegistryCallChange::Emitted(call); - } - AsyncRegistryCallChange::Cancelled(mut opt_call) => { - if opt_call.is_none() { - if let AsyncRegistryCallChange::Cancelled(v) = self { - // preserve the value if we have it already - opt_call = v.take(); - } - } - *self = AsyncRegistryCallChange::Cancelled(opt_call); - } - AsyncRegistryCallChange::Removed => { - *self = AsyncRegistryCallChange::Removed; - } - } + *self = other; + } + + pub fn delete_call(&mut self) { + *self = AsyncRegistryCallChange::Delete; } - pub fn remove_call(&mut self) { - *self = AsyncRegistryCallChange::Removed; + pub fn set_call(&mut self, call: AsyncCall) { + *self = AsyncRegistryCallChange::Set(call); + } + + pub fn get_call(&self) -> Option<&AsyncCall> { + match self { + AsyncRegistryCallChange::Set(v) => Some(v), + AsyncRegistryCallChange::Delete => None, + } } } #[derive(Default, Debug, Clone)] -pub struct AsyncRegistrySlotChanges { - pub changes: BTreeMap, -} +pub struct AsyncRegistrySlotChanges(BTreeMap); impl AsyncRegistrySlotChanges { pub fn merge(&mut self, other: AsyncRegistrySlotChanges) { - for (id, change) in other.changes { - match self.changes.entry(id) { + for (id, change) in other.0 { + match self.0.entry(id) { std::collections::btree_map::Entry::Occupied(mut entry) => { entry.get_mut().merge(change); } @@ -87,51 +71,31 @@ impl AsyncRegistrySlotChanges { } } - /// Adds a "remove" change for the target - pub fn remove_call(&mut self, id: &AsyncCallId) { - match self.changes.entry(id.clone()) { - std::collections::btree_map::Entry::Occupied(mut v) => v.get_mut().remove_call(), + pub fn delete_call(&mut self, id: &AsyncCallId) { + match self.0.entry(id.clone()) { + std::collections::btree_map::Entry::Occupied(mut v) => v.get_mut().delete_call(), std::collections::btree_map::Entry::Vacant(v) => { - v.insert(AsyncRegistryCallChange::Removed); + v.insert(AsyncRegistryCallChange::Delete); } } } - pub fn push_new_call(&mut self, id: AsyncCallId, call: AsyncCall) { - self.changes - .insert(id, AsyncRegistryCallChange::Emitted(call)); - } - - pub fn cancel_call(&mut self, id: AsyncCallId) { - self.changes - .entry(id) - .and_modify(|v| { - let mut v_n = AsyncRegistryCallChange::Cancelled(None); - std::mem::swap(v, &mut v_n); - match v_n { - AsyncRegistryCallChange::Emitted(call) => { - *v = AsyncRegistryCallChange::Cancelled(Some(call)); - } - AsyncRegistryCallChange::Cancelled(Some(call)) => { - *v = AsyncRegistryCallChange::Cancelled(Some(call)); - } - AsyncRegistryCallChange::Cancelled(None) => {} - AsyncRegistryCallChange::Removed => {} - } - }) - .or_insert_with(|| AsyncRegistryCallChange::Cancelled(None)); + pub fn set_call(&mut self, id: AsyncCallId, call: AsyncCall) { + self.0.insert(id, AsyncRegistryCallChange::Set(call)); + } + + pub fn get_call(&self, id: &AsyncCallId) -> Option<&AsyncCall> { + self.0.get(id).and_then(|change| change.get_call()) } } #[derive(Default, Debug, Clone)] -pub struct AsyncRegistryChanges { - pub by_slot: BTreeMap, -} +pub struct AsyncRegistryChanges(pub BTreeMap); impl AsyncRegistryChanges { pub fn merge(&mut self, other: AsyncRegistryChanges) { - for (slot, changes) in other.by_slot { - match self.by_slot.entry(slot) { + for (slot, changes) in other.0 { + match self.0.entry(slot) { std::collections::btree_map::Entry::Occupied(mut entry) => { entry.get_mut().merge(changes); } @@ -142,51 +106,52 @@ impl AsyncRegistryChanges { } } - pub fn get_best_call(&self, slot: Slot) -> Option<(AsyncCallId, Option)> { - if let Some(slot_changes) = self.by_slot.get(&slot) { - for (id, change) in &slot_changes.changes { - match change { - AsyncRegistryCallChange::Emitted(call) => { - return Some((id.clone(), Some(call.clone()))); - } - AsyncRegistryCallChange::Cancelled(opt_call) => { - return Some((id.clone(), opt_call.clone())); - } - AsyncRegistryCallChange::Removed => {} - } - } - } - None - } - - pub fn remove_call(&mut self, target_slot: Slot, id: &AsyncCallId) { - self.by_slot.entry(target_slot).or_default().remove_call(id) + pub fn delete_call(&mut self, target_slot: Slot, id: &AsyncCallId) { + self.0.entry(target_slot).or_default().delete_call(id) } - pub fn push_new_call(&mut self, id: AsyncCallId, call: AsyncCall) { - self.by_slot + pub fn set_call(&mut self, id: AsyncCallId, call: AsyncCall) { + self.0 .entry(call.target_slot.clone()) .or_default() - .push_new_call(id, call); + .set_call(id, call); } - pub fn call_status(&self, slot: Slot, id: &AsyncCallId) -> CallStatus { - if let Some(slot_changes) = self.by_slot.get(&slot) { - if let Some(change) = slot_changes.changes.get(id) { - match change { - AsyncRegistryCallChange::Emitted(_) => CallStatus::Emitted, - AsyncRegistryCallChange::Cancelled(_) => CallStatus::Cancelled, - AsyncRegistryCallChange::Removed => CallStatus::Removed, - } - } else { - CallStatus::Unknown - } - } else { - CallStatus::Unknown + pub fn get_call(&self, target_slot: &Slot, id: &AsyncCallId) -> Option<&AsyncCall> { + self.0 + .get(target_slot) + .and_then(|slot_changes| slot_changes.get_call(id)) + } +} + +/// A structure that lists slot calls for a given slot +#[derive(Debug, Clone)] +pub struct AsyncSlotCallsMap { + pub slot: Slot, + pub calls: BTreeMap, +} + +impl AsyncSlotCallsMap { + pub fn new(slot: Slot) -> Self { + Self { + slot, + calls: BTreeMap::new(), } } - pub fn cancel_call(&mut self, slot: Slot, id: AsyncCallId) { - self.by_slot.entry(slot).or_default().cancel_call(id); + pub fn apply_changes(&mut self, changes: &AsyncRegistryChanges) { + let Some(slot_changes) = changes.0.get(&self.slot) else { + return; + }; + for (id, change) in &slot_changes.0 { + match change { + AsyncRegistryCallChange::Set(call) => { + self.calls.insert(id.clone(), call.clone()); + } + AsyncRegistryCallChange::Delete => { + self.calls.remove(id); + } + } + } } } diff --git a/massa-execution-worker/src/interface_impl.rs b/massa-execution-worker/src/interface_impl.rs index ca78e2571f4..325f3fa2152 100644 --- a/massa-execution-worker/src/interface_impl.rs +++ b/massa-execution-worker/src/interface_impl.rs @@ -1391,7 +1391,17 @@ impl Interface for InterfaceImpl { let fee = Amount::from_raw(fee_raw); let coins = Amount::from_raw(coins); + // write-lock context + let mut context = context_guard!(self); + + // get caller address + let sender_address = match context.stack.last() { + Some(addr) => addr.address, + _ => bail!("failed to read call stack sender address"), + }; + let call = AsyncCall::new( + sender_address, Slot::new(target_slot.0, target_slot.1), target_addr, target_func.to_string(), @@ -1402,9 +1412,6 @@ impl Interface for InterfaceImpl { false, ); - // write-lock context - let mut context = context_guard!(self); - /* TODO: * ask the context to register the call diff --git a/massa-execution-worker/src/speculative_asc.rs b/massa-execution-worker/src/speculative_asc.rs index ff0bbbd4578..8b3f185b705 100644 --- a/massa-execution-worker/src/speculative_asc.rs +++ b/massa-execution-worker/src/speculative_asc.rs @@ -1,10 +1,10 @@ //! Speculative async call registry. use crate::active_history::ActiveHistory; -use massa_asc::{AsyncCall, AsyncRegistryChanges, CallStatus}; +use massa_asc::{AsyncCall, AsyncRegistryChanges, AsyncSlotCallsMap, CallStatus}; use massa_execution_exports::ExecutionError; use massa_final_state::FinalStateController; -use massa_models::{asc_call_id::AsyncCallId, slot::Slot}; +use massa_models::{address::Address, amount::Amount, asc_call_id::AsyncCallId, slot::Slot}; use parking_lot::RwLock; use std::sync::Arc; @@ -42,100 +42,93 @@ impl SpeculativeAsyncCallRegistry { /// Add a new call to the list of changes of this `SpeculativeAsyncCallRegistry` pub fn push_new_call(&mut self, id: AsyncCallId, call: AsyncCall) { - self.current_changes.push_new_call(id, call); + self.current_changes.set_call(id, call); } - /// Removes the next call to be executed at the given slot and returns it. - /// Returns None if there is no call to be executed at the given slot. - pub fn take_next_call(&mut self, slot: Slot) -> Option<(AsyncCallId, Option)> { - // Note: calls can only be added. So we want to look from old to new and return the first one. - - let mut res = None; - - // check final state - if res.is_none() { - res = self - .final_state - .read() - .get_asc_registry() - .get_best_call(slot); // note: includes cancelled calls - } - - // check active history from oldest to newest - if res.is_none() { - let history = self.active_history.read(); - for history_item in &history.0 { - res = history_item - .state_changes - .async_call_registry_changes - .get_best_call(slot); - if res.is_some() { - break; - } - } + /// Consumes all calls targeting a given slot, deletes them + pub fn take_calls_targeting_slot(&mut self, slot: Slot) -> AsyncSlotCallsMap { + // add calls coming from the final state + let mut slot_calls_map: AsyncSlotCallsMap = self + .final_state + .read() + .get_asc_registry() + .get_slot_calls(slot); + + // traverse history to add extra calls and apply changes to others + for hist_item in self.active_history.read().0.iter() { + slot_calls_map.apply_changes(&hist_item.state_changes.async_call_registry_changes); } - // check current changes - if res.is_none() { - res = self.current_changes.get_best_call(slot); - } + // apply current changes + slot_calls_map.apply_changes(&self.current_changes); - // remove from current changes - if let Some((id, _)) = res.as_ref() { - self.current_changes.remove_call(slot, id); + // add call deletion to current changes + for id in slot_calls_map.calls.keys() { + self.current_changes.delete_call(slot, id); } - res + slot_calls_map } - /// Check that a call exists and is not cancelled - pub fn call_exists(&mut self, id: AsyncCallId) -> bool { - // Check if the call was cancelled or deleted in the current changes - match self.current_changes.call_status(id.get_slot(), &id) { - CallStatus::Emitted => return true, - CallStatus::Cancelled | CallStatus::Removed => return false, - CallStatus::Unknown => {} + pub fn get_call(&self, id: &AsyncCallId) -> Option { + let slot: Slot = id.get_slot(); + + // check from latest to earliest changes + + // check in current changes + if let Some(v) = self.current_changes.get_call(&slot, id) { + return Some(v.clone()); } - // List history from most recent to oldest, and check if the call was emitted, cancelled or deleted + // check history from the most recent to the oldest item { let history = self.active_history.read(); for history_item in history.0.iter().rev() { - match history_item + if let Some(v) = history_item .state_changes .async_call_registry_changes - .get_status(id) + .get_call(&slot, id) { - CallStatus::Emitted => return true, - CallStatus::Cancelled | CallStatus::Removed => return false, - CallStatus::Unknown => {} + return Some(v.clone()); } } } - // Check the final state: return true if the call is present and not cancelled + // check final state { let final_state = self.final_state.read(); - match final_state.get_asc_registry().is_call_cancelled(id) { - None => false, // not found - Some(true) => false, // found, cancelled - Some(false) => true, // found, not cancelled + if let Some(v) = final_state.get_asc_registry().get_call(&slot, id) { + return Some(v.clone()); } } + + None } /// Cancel a call - pub fn cancel_call(&mut self, id: AsyncCallId) -> Result<(), ExecutionError> { - if !self.call_exists(id) { + /// Returns the sender address and the amount of coins to reimburse them + pub fn cancel_call(&mut self, id: &AsyncCallId) -> Result<(Address, Amount), ExecutionError> { + // get call, fail if it does not exist + let Some(mut call) = self.get_call(id) else { return Err(ExecutionError::AscError("Call ID does not exist.".into())); + }; + + // check if the call is already cancelled + if call.cancelled { + return Err(ExecutionError::AscError( + "Call ID is already cancelled.".into(), + )); } - - // Add a cancellation to the current changes - self.current_changes.cancel_call(id.get_slot(), id); - // TODO: reimburse coins - todo!(); + // set call as cancelled + call.cancelled = true; + + // we need to reimburse coins to the sender + let res = (call.sender_address, call.coins); + + // Add a cancellation to the current changes + self.current_changes.set_call(id.clone(), call); - Ok(()) + Ok(res) } } diff --git a/massa-models/src/asc_call_id.rs b/massa-models/src/asc_call_id.rs index 525f0b2839e..7eb9436d5bb 100644 --- a/massa-models/src/asc_call_id.rs +++ b/massa-models/src/asc_call_id.rs @@ -173,6 +173,10 @@ impl<'de> ::serde::Deserialize<'de> for AsyncCallId { } impl AsyncCallId { + pub fn get_slot(&self) -> Slot { + todo!(); + } + /// Create a new `AsyncCallId` pub fn new( version: u64, From 5315ea4eaf22d4054c8332b01c36f0eda1a0899c Mon Sep 17 00:00:00 2001 From: damip Date: Fri, 10 May 2024 08:27:57 +0200 Subject: [PATCH 006/100] typo --- massa-execution-worker/src/speculative_asc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/massa-execution-worker/src/speculative_asc.rs b/massa-execution-worker/src/speculative_asc.rs index 8b3f185b705..a42c21c73d5 100644 --- a/massa-execution-worker/src/speculative_asc.rs +++ b/massa-execution-worker/src/speculative_asc.rs @@ -1,7 +1,7 @@ //! Speculative async call registry. use crate::active_history::ActiveHistory; -use massa_asc::{AsyncCall, AsyncRegistryChanges, AsyncSlotCallsMap, CallStatus}; +use massa_asc::{AsyncCall, AsyncRegistryChanges, AsyncSlotCallsMap}; use massa_execution_exports::ExecutionError; use massa_final_state::FinalStateController; use massa_models::{address::Address, amount::Amount, asc_call_id::AsyncCallId, slot::Slot}; From d4300c355beefc182e2461432b785373d886481d Mon Sep 17 00:00:00 2001 From: damip Date: Fri, 10 May 2024 08:32:26 +0200 Subject: [PATCH 007/100] reformat registry --- massa-asc/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/massa-asc/src/lib.rs b/massa-asc/src/lib.rs index 0a9613baf8d..0ebd2e7d3e1 100644 --- a/massa-asc/src/lib.rs +++ b/massa-asc/src/lib.rs @@ -18,11 +18,11 @@ impl AsyncCallRegistry { Self { db } } - pub fn get_slot_calls(slot: Slot) -> Vec { + pub fn get_slot_calls(slot: Slot) -> AsyncSlotCallsMap { todo!() } - pub fn get_message_by_id(id: AsyncCallId) -> Option { + pub fn get_call(id: &AsyncCallId) -> Option { todo!() } } From 60cbf2885e3bee167c14d267b79070d6f3617b96 Mon Sep 17 00:00:00 2001 From: damip Date: Fri, 10 May 2024 08:40:17 +0200 Subject: [PATCH 008/100] make things compile --- massa-execution-worker/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/massa-execution-worker/src/lib.rs b/massa-execution-worker/src/lib.rs index 9878a83e637..b4931a44930 100644 --- a/massa-execution-worker/src/lib.rs +++ b/massa-execution-worker/src/lib.rs @@ -86,7 +86,7 @@ mod execution; mod interface_impl; mod request_queue; mod slot_sequencer; -mod speculative_asc; +// mod speculative_asc; mod speculative_async_pool; mod speculative_executed_denunciations; mod speculative_executed_ops; From 42c47cd3aa1f1c58d8fed8b5c07331607b3b49bd Mon Sep 17 00:00:00 2001 From: Damir Vodenicarevic Date: Tue, 21 May 2024 12:48:44 +0200 Subject: [PATCH 009/100] updates --- massa-asc/src/lib.rs | 182 +++++++++++-- massa-execution-worker/src/lib.rs | 2 +- massa-execution-worker/src/speculative_asc.rs | 241 +++++++++++++++++- massa-models/src/slot.rs | 27 ++ 4 files changed, 414 insertions(+), 38 deletions(-) diff --git a/massa-asc/src/lib.rs b/massa-asc/src/lib.rs index 0ebd2e7d3e1..a43ba6a8d74 100644 --- a/massa-asc/src/lib.rs +++ b/massa-asc/src/lib.rs @@ -5,7 +5,7 @@ use massa_db_exports::ShareableMassaDBController; mod call; pub use call::AsyncCall; -use massa_models::{asc_call_id::AsyncCallId, slot::Slot}; +use massa_models::{amount::Amount, asc_call_id::AsyncCallId, slot::Slot}; use std::collections::BTreeMap; #[derive(Debug)] @@ -14,17 +14,47 @@ pub struct AsyncCallRegistry { } impl AsyncCallRegistry { + /* + DB layout: + [ASYNC_CALL_TOTAL_GAS_PREFIX] -> u64 // total currently booked gas + [ASYNC_CAL_SLOT_PREFIX][slot][TOTAL_GAS_TAG] -> u64 // total gas booked for a slot (optional, default 0, deleted when set to 0) + [ASYNC_CAL_SLOT_PREFIX][slot][CALLS_TAG][id][ASYNC_CALL_FIELD_X_TAG] -> AsyncCall.x // call data + */ + pub fn new(db: ShareableMassaDBController) -> Self { Self { db } } - pub fn get_slot_calls(slot: Slot) -> AsyncSlotCallsMap { + pub fn get_slot_calls(slot: Slot) -> AsyncSlotCalls { todo!() } pub fn get_call(id: &AsyncCallId) -> Option { todo!() } + + /// Returns the total amount of gas booked for a slot + pub fn get_slot_gas(slot: Slot) -> u64 { + // By default, if it is absent, it is 0 + todo!() + } + + /// Returns the base fee for a slot + pub fn get_slot_base_fee(slot: Slot) -> Amount { + // By default, if it is absent, it is 0 + todo!() + } + + /// Returns the total amount of gas booked + pub fn get_total_gas() -> u128 { + todo!() + } + + pub fn apply_changes(changes: AsyncRegistryChanges) { + //Note: if a slot gas is zet to 0, delete the slot gas entry + // same for base fee + todo!() + } } #[derive(Debug, Clone)] @@ -54,13 +84,29 @@ impl AsyncRegistryCallChange { } } +#[derive(Debug, Clone)] +pub enum AsyncRegistryGasChange { + Set(V), + Keep, +} + +impl Default for AsyncRegistryGasChange { + fn default() -> Self { + AsyncRegistryGasChange::Keep + } +} + #[derive(Default, Debug, Clone)] -pub struct AsyncRegistrySlotChanges(BTreeMap); +pub struct AsyncRegistrySlotChanges { + calls: BTreeMap, + gas: AsyncRegistryGasChange, + base_fee: AsyncRegistryGasChange, +} impl AsyncRegistrySlotChanges { pub fn merge(&mut self, other: AsyncRegistrySlotChanges) { - for (id, change) in other.0 { - match self.0.entry(id) { + for (id, change) in other.calls { + match self.calls.entry(id) { std::collections::btree_map::Entry::Occupied(mut entry) => { entry.get_mut().merge(change); } @@ -69,10 +115,18 @@ impl AsyncRegistrySlotChanges { } } } + match other.gas { + AsyncRegistryGasChange::Set(v) => self.gas = AsyncRegistryGasChange::Set(v), + AsyncRegistryGasChange::Keep => {} + } + match other.base_fee { + AsyncRegistryGasChange::Set(v) => self.base_fee = AsyncRegistryGasChange::Set(v), + AsyncRegistryGasChange::Keep => {} + } } pub fn delete_call(&mut self, id: &AsyncCallId) { - match self.0.entry(id.clone()) { + match self.calls.entry(id.clone()) { std::collections::btree_map::Entry::Occupied(mut v) => v.get_mut().delete_call(), std::collections::btree_map::Entry::Vacant(v) => { v.insert(AsyncRegistryCallChange::Delete); @@ -81,21 +135,46 @@ impl AsyncRegistrySlotChanges { } pub fn set_call(&mut self, id: AsyncCallId, call: AsyncCall) { - self.0.insert(id, AsyncRegistryCallChange::Set(call)); + self.calls.insert(id, AsyncRegistryCallChange::Set(call)); } pub fn get_call(&self, id: &AsyncCallId) -> Option<&AsyncCall> { - self.0.get(id).and_then(|change| change.get_call()) + self.calls.get(id).and_then(|change| change.get_call()) + } + + pub fn set_gas(&mut self, gas: u64) { + self.gas = AsyncRegistryGasChange::Set(gas); + } + + pub fn get_gas(&self) -> Option { + match self.gas { + AsyncRegistryGasChange::Set(v) => Some(v), + AsyncRegistryGasChange::Keep => None, + } + } + + pub fn get_base_fee(&self) -> Option { + match self.base_fee { + AsyncRegistryGasChange::Set(v) => Some(v), + AsyncRegistryGasChange::Keep => None, + } + } + + pub fn set_base_fee(&mut self, base_fee: Amount) { + self.base_fee = AsyncRegistryGasChange::Set(base_fee); } } #[derive(Default, Debug, Clone)] -pub struct AsyncRegistryChanges(pub BTreeMap); +pub struct AsyncRegistryChanges { + pub slots: BTreeMap, + pub total_gas: AsyncRegistryGasChange, +} impl AsyncRegistryChanges { pub fn merge(&mut self, other: AsyncRegistryChanges) { - for (slot, changes) in other.0 { - match self.0.entry(slot) { + for (slot, changes) in other.slots { + match self.slots.entry(slot) { std::collections::btree_map::Entry::Occupied(mut entry) => { entry.get_mut().merge(changes); } @@ -104,54 +183,111 @@ impl AsyncRegistryChanges { } } } + match other.total_gas { + AsyncRegistryGasChange::Set(v) => self.total_gas = AsyncRegistryGasChange::Set(v), + AsyncRegistryGasChange::Keep => {} + } } pub fn delete_call(&mut self, target_slot: Slot, id: &AsyncCallId) { - self.0.entry(target_slot).or_default().delete_call(id) + self.slots.entry(target_slot).or_default().delete_call(id) } pub fn set_call(&mut self, id: AsyncCallId, call: AsyncCall) { - self.0 + self.slots .entry(call.target_slot.clone()) .or_default() .set_call(id, call); } pub fn get_call(&self, target_slot: &Slot, id: &AsyncCallId) -> Option<&AsyncCall> { - self.0 + self.slots .get(target_slot) .and_then(|slot_changes| slot_changes.get_call(id)) } + + pub fn get_slot_gas(&self, target_slot: &Slot) -> Option { + self.slots + .get(target_slot) + .and_then(|slot_changes| slot_changes.get_gas()) + } + + pub fn set_slot_gas(&mut self, target_slot: Slot, gas: u64) { + self.slots.entry(target_slot).or_default().set_gas(gas); + } + + pub fn set_slot_base_fee(&mut self, target_slot: Slot, base_fee: Amount) { + self.slots + .entry(target_slot) + .or_default() + .set_base_fee(base_fee); + } + + pub fn get_slot_base_fee(&self, target_slot: &Slot) -> Option { + self.slots + .get(target_slot) + .and_then(|slot_changes| slot_changes.get_base_fee()) + } + + pub fn set_total_gas(&mut self, gas: u128) { + self.total_gas = AsyncRegistryGasChange::Set(gas); + } + + pub fn get_total_gas(&self) -> Option { + match self.total_gas { + AsyncRegistryGasChange::Set(v) => Some(v), + AsyncRegistryGasChange::Keep => None, + } + } } -/// A structure that lists slot calls for a given slot +/// A structure that lists slot calls for a given slot, +/// as well as global gas usage statistics. #[derive(Debug, Clone)] -pub struct AsyncSlotCallsMap { +pub struct AsyncSlotCalls { pub slot: Slot, - pub calls: BTreeMap, + pub slot_calls: BTreeMap, + pub slot_gas: u64, + pub slot_base_fee: Amount, + pub total_gas: u128, } -impl AsyncSlotCallsMap { +impl AsyncSlotCalls { pub fn new(slot: Slot) -> Self { Self { slot, - calls: BTreeMap::new(), + slot_calls: BTreeMap::new(), + slot_gas: 0, + slot_base_fee: Amount::zero(), + total_gas: 0, } } pub fn apply_changes(&mut self, changes: &AsyncRegistryChanges) { - let Some(slot_changes) = changes.0.get(&self.slot) else { + let Some(slot_changes) = changes.slots.get(&self.slot) else { return; }; - for (id, change) in &slot_changes.0 { + for (id, change) in &slot_changes.calls { match change { AsyncRegistryCallChange::Set(call) => { - self.calls.insert(id.clone(), call.clone()); + self.slot_calls.insert(id.clone(), call.clone()); } AsyncRegistryCallChange::Delete => { - self.calls.remove(id); + self.slot_calls.remove(id); } } } + match slot_changes.gas { + AsyncRegistryGasChange::Set(v) => self.slot_gas = v, + AsyncRegistryGasChange::Keep => {} + } + match slot_changes.base_fee { + AsyncRegistryGasChange::Set(v) => self.slot_base_fee = v, + AsyncRegistryGasChange::Keep => {} + } + match changes.total_gas { + AsyncRegistryGasChange::Set(v) => self.total_gas = v, + AsyncRegistryGasChange::Keep => {} + } } } diff --git a/massa-execution-worker/src/lib.rs b/massa-execution-worker/src/lib.rs index b4931a44930..8171fc15e45 100644 --- a/massa-execution-worker/src/lib.rs +++ b/massa-execution-worker/src/lib.rs @@ -86,7 +86,7 @@ mod execution; mod interface_impl; mod request_queue; mod slot_sequencer; -// mod speculative_asc; +//mod speculative_asc; mod speculative_async_pool; mod speculative_executed_denunciations; mod speculative_executed_ops; diff --git a/massa-execution-worker/src/speculative_asc.rs b/massa-execution-worker/src/speculative_asc.rs index a42c21c73d5..f691ca6004a 100644 --- a/massa-execution-worker/src/speculative_asc.rs +++ b/massa-execution-worker/src/speculative_asc.rs @@ -1,7 +1,7 @@ //! Speculative async call registry. use crate::active_history::ActiveHistory; -use massa_asc::{AsyncCall, AsyncRegistryChanges, AsyncSlotCallsMap}; +use massa_asc::{AsyncCall, AsyncRegistryChanges, AsyncSlotCalls}; use massa_execution_exports::ExecutionError; use massa_final_state::FinalStateController; use massa_models::{address::Address, amount::Amount, asc_call_id::AsyncCallId, slot::Slot}; @@ -45,29 +45,101 @@ impl SpeculativeAsyncCallRegistry { self.current_changes.set_call(id, call); } - /// Consumes all calls targeting a given slot, deletes them - pub fn take_calls_targeting_slot(&mut self, slot: Slot) -> AsyncSlotCallsMap { - // add calls coming from the final state - let mut slot_calls_map: AsyncSlotCallsMap = self + pub fn get_slot_gas(&self, slot: &Slot) -> u64 { + // get slot gas from current changes + if let Some(v) = self.current_changes.get_slot_gas(slot) { + return v; + } + + // check in history backwards + { + let history = self.active_history.read(); + for history_item in history.0.iter().rev() { + if let Some(v) = history_item + .state_changes + .async_call_registry_changes + .get_slot_gas(slot) + { + return v; + } + } + } + + // check in final state + return self .final_state .read() .get_asc_registry() - .get_slot_calls(slot); + .get_slot_gas(slot); + } + + pub fn get_slot_base_fee(&self, slot: &Slot) -> Amount { + // get slot base fee from current changes + if let Some(v) = self.current_changes.get_slot_base_fee(slot) { + return v; + } - // traverse history to add extra calls and apply changes to others + // check in history backwards + { + let history = self.active_history.read(); + for history_item in history.0.iter().rev() { + if let Some(v) = history_item + .state_changes + .async_call_registry_changes + .get_slot_base_fee(slot) + { + return v; + } + } + } + + // check in final state + return self + .final_state + .read() + .get_asc_registry() + .get_slot_base_fee(slot); + } + + /// Consumes and deletes the current slot, prepares a new slot in the future + /// and returns the calls that need to be executed in the current slot + pub fn advance_slot( + &mut self, + current_slot: Slot, + async_call_max_booking_slots: u64, + thread_count: u8, + ) -> AsyncSlotCalls { + // get the state of the current slot + let mut slot_calls: AsyncSlotCalls = self + .final_state + .read() + .get_asc_registry() + .get_slot_calls(current_slot); for hist_item in self.active_history.read().0.iter() { - slot_calls_map.apply_changes(&hist_item.state_changes.async_call_registry_changes); + slot_calls.apply_changes(&hist_item.state_changes.async_call_registry_changes); } + slot_calls.apply_changes(&self.current_changes); + + // select the slot that is newly made available and set its base fee + let mut new_slot = current_slot + .skip(async_call_max_booking_slots, thread_count) + .expect("could not skip enough slots"); + todo!(); + self.current_changes.set_slot_base_fee(new_slot, todo!()); - // apply current changes - slot_calls_map.apply_changes(&self.current_changes); + // subtract the current slot gas from the total gas + self.current_changes + .set_total_gas(slot_calls.total_gas.saturating_sub(slot_calls.slot_gas)); - // add call deletion to current changes - for id in slot_calls_map.calls.keys() { - self.current_changes.delete_call(slot, id); + // delete the current slot + for (id, call) in &slot_calls.calls { + self.current_changes.delete_call(current_slot, id); } + self.current_changes.set_slot_gas(current_slot, 0); + self.current_changes + .set_slot_base_fee(current_slot, Amount::zero()); - slot_calls_map + slot_calls } pub fn get_call(&self, id: &AsyncCallId) -> Option { @@ -131,4 +203,145 @@ impl SpeculativeAsyncCallRegistry { Ok(res) } + + // This function assumes that we have a resource with a total supply `resource_supply`. + // Below a certain target occupancy `target_occupancy` of that resource, the overbooking penalty for using a unit of the resource is zero. + // Above the target, the resource unit cost grows linearly with occupancy. + // The linear fee growth is chosen so that if someone occupies all the resource, they incur a `max_penalty` cost. + fn overbooking_fee( + resource_supply: u128, + target_occupancy: u128, + current_occupancy: u128, + resource_request: u128, + max_penalty: Amount, + ) -> Amount { + // linear part of the occupancy before booking the requested amount + let relu_occupancy_before = + std::cmp::max(current_occupancy, target_occupancy) - target_occupancy; + + // linear part of the occupancy after booking the requested amount + let relu_occupancy_after = std::cmp::max( + current_occupancy.saturating_add(resource_request), + target_occupancy, + ) - target_occupancy; + + // denominator for the linear fee + let denominator = resource_supply - target_occupancy; + + // compute using the raw fee and u128 to avoid u64 overflows + let raw_max_penalty = max_penalty.to_raw() as u128; + + let raw_fee = (raw_max_penalty * relu_occupancy_after / denominator * relu_occupancy_after + / denominator) + .saturating_sub( + raw_max_penalty * relu_occupancy_before / denominator * relu_occupancy_before + / denominator, + ); + + Amount::from_raw(std::cmp::min(raw_fee, u64::MAX as u128) as u64) + } + + pub fn get_slot_base_fee(&self, slot: &Slot) -> Amount { + // get slot base fee from current changes + if let Some(v) = self.current_changes.get_slot_base_fee(slot) { + return v; + } + + // check in history backwards + { + let history = self.active_history.read(); + for history_item in history.0.iter().rev() { + if let Some(v) = history_item + .state_changes + .async_call_registry_changes + .get_slot_base_fee(slot) + { + return v; + } + } + } + + // check in final state + return self + .final_state + .read() + .get_asc_registry() + .get_slot_base_fee(slot); + } + + /// Compute call fee + pub fn compute_call_fee( + &self, + target_slot: Slot, + max_gas: u64, + thread_count: u8, + async_call_max_booking_slots: u64, + max_async_gas: u64, + async_gas_target: u64, + global_overbooking_penalty: Amount, + slot_overbooking_penalty: Amount, + current_slot: Slot, + ) -> Result { + // Check that the slot is not in the past + if target_slot <= current_slot { + return Err(ExecutionError::AscError( + "Target slot is in the past.".into(), + )); + } + + // Check that the slot is not in the future + if target_slot + .slots_since(¤t_slot, thread_count) + .unwrap_or(u64::MAX) + > async_call_max_booking_slots + { + // note: the current slot is not counted + return Err(ExecutionError::AscError( + "Target slot is too far in the future.".into(), + )); + } + + // Check that the gas is not too high for the target slot + let slot_occupancy = self.get_slot_gas(&target_slot); + if slot_occupancy.saturating_add(max_gas) > max_async_gas { + return Err(ExecutionError::AscError( + "Not enough gas available in the target slot.".into(), + )); + } + + // Integral fee + let integral_fee = self + .get_slot_base_fee(&target_slot) + .saturating_mul_u64(max_gas); + + // Slot overbooking fee + let slot_overbooking_fee = Self::overbooking_fee( + max_async_gas as u128, + async_gas_target as u128, + slot_occupancy as u128, + max_gas as u128, + slot_overbooking_penalty, + ); + + // Global overbooking fee + let global_occupancy = self.get_total_gas(); + let global_overbooking_fee = Self::overbooking_fee( + (max_async_gas as u128).saturating_mul(async_call_max_booking_slots as u128), + (async_gas_target as u128).saturating_mul(async_call_max_booking_slots as u128), + global_occupancy, + max_gas as u128, + global_overbooking_penalty, + ); + + // return the fee + Ok(integral_fee + .saturating_add(global_overbooking_fee) + .saturating_add(slot_overbooking_fee)) + } +} + +#[cfg(test)] +mod tests { + #[test] + fn test_compute_call_fee() {} } diff --git a/massa-models/src/slot.rs b/massa-models/src/slot.rs index 65b1015a611..a21a5af2a22 100644 --- a/massa-models/src/slot.rs +++ b/massa-models/src/slot.rs @@ -325,6 +325,33 @@ impl Slot { .ok_or(ModelsError::PeriodOverflowError)? .saturating_sub(s.thread as u64)) } + + /// Returns the n-th slot after the current one + /// + /// ## Example + /// ```rust + /// # use massa_models::slot::Slot; + /// let slot = Slot::new(10,3); + /// assert_eq!(slot.skip(62, 32).unwrap(), Slot::new(12, 1)); + /// ``` + pub fn skip(&self, n: u64, thread_count: u8) -> Result { + let mut res_period = self + .period + .checked_add(n / (thread_count as u64)) + .ok_or(ModelsError::PeriodOverflowError)?; + let mut res_thread = (self.thread as u64) + .checked_add(n % (thread_count as u64)) + .ok_or(ModelsError::PeriodOverflowError)?; + + if res_thread >= thread_count as u64 { + res_period = res_period + .checked_add(1) + .ok_or(ModelsError::PeriodOverflowError)?; + res_thread -= thread_count as u64; + } + + Ok(Slot::new(res_period, res_thread as u8)) + } } /// When an address is drawn to create an endorsement it is selected for a specific index From 94016cb7ab93238731263d9e855ae62cb9b76a8b Mon Sep 17 00:00:00 2001 From: modship Date: Mon, 8 Jul 2024 10:47:11 +0200 Subject: [PATCH 010/100] update new interface --- Cargo.lock | 37 +++----------------- massa-execution-worker/src/interface_impl.rs | 18 ++++++---- 2 files changed, 15 insertions(+), 40 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 79092cc6ac4..8d072d58ab4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2051,15 +2051,6 @@ dependencies = [ "either", ] -[[package]] -name = "itertools" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" -dependencies = [ - "either", -] - [[package]] name = "itertools" version = "0.12.0" @@ -2198,7 +2189,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29110019693a4fa2dbda04876499d098fa16d70eba06b1e6e2b3f1b251419515" dependencies = [ "heck", - "proc-macro-crate 1.3.1", + "proc-macro-crate", "proc-macro2 1.0.71", "quote 1.0.33", "syn 1.0.109", @@ -3754,7 +3745,7 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c11e44798ad209ccdd91fc192f0526a369a01234f7373e1b141c96d7cee4f0e" dependencies = [ - "proc-macro-crate 2.0.0", + "proc-macro-crate", "proc-macro2 1.0.71", "quote 1.0.33", "syn 2.0.43", @@ -4153,15 +4144,6 @@ dependencies = [ "toml_edit 0.19.15", ] -[[package]] -name = "proc-macro-crate" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e8366a6159044a37876a2b9817124296703c586a5c92e2c53751fa06d8d43e8" -dependencies = [ - "toml_edit 0.20.7", -] - [[package]] name = "proc-macro-error" version = "1.0.4" @@ -4252,7 +4234,7 @@ checksum = "c55e02e35260070b6f716a2423c2ff1c3bb1642ddca6f99e1f26d06268a0e2d2" dependencies = [ "bytes", "heck", - "itertools 0.11.0", + "itertools 0.10.5", "log", "multimap", "once_cell", @@ -4273,7 +4255,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "efb6c9a1dd1def8e2124d17e83a20af56f1570d6c2d2bd9e266ccb768df3840e" dependencies = [ "anyhow", - "itertools 0.11.0", + "itertools 0.10.5", "proc-macro2 1.0.71", "quote 1.0.33", "syn 2.0.43", @@ -5531,17 +5513,6 @@ dependencies = [ "winnow", ] -[[package]] -name = "toml_edit" -version = "0.20.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81" -dependencies = [ - "indexmap 2.1.0", - "toml_datetime", - "winnow", -] - [[package]] name = "toml_edit" version = "0.21.0" diff --git a/massa-execution-worker/src/interface_impl.rs b/massa-execution-worker/src/interface_impl.rs index 9c1976f08bf..588e53c0f1f 100644 --- a/massa-execution-worker/src/interface_impl.rs +++ b/massa-execution-worker/src/interface_impl.rs @@ -1339,7 +1339,11 @@ impl Interface for InterfaceImpl { /// /// # Returns /// A tuple containing a boolean indicating if the call is possible and the amount of fees needed - fn get_asc_call_fee(&self, target_slot: (u64, u8), gas_limit: u64) -> Result<(bool, u64)> { + fn get_deferred_call_quote( + &self, + target_slot: (u64, u8), + gas_limit: u64, + ) -> Result<(bool, u64)> { // write-lock context let mut context = context_guard!(self); @@ -1348,7 +1352,7 @@ impl Interface for InterfaceImpl { todo!() } - /// Register an asynchronous call + /// Register deferred call /// /// # Arguments /// * target_slot: tuple containing the period and thread of the target slot @@ -1360,7 +1364,7 @@ impl Interface for InterfaceImpl { /// /// # Returns /// The id of the call - fn asc_call_register( + fn deferred_call_register( &self, target_slot: (u64, u8), target_addr: &str, @@ -1385,7 +1389,7 @@ impl Interface for InterfaceImpl { } // check fee, slot, gas - let (available, fee_raw) = self.get_asc_call_fee(target_slot, max_gas)?; + let (available, fee_raw) = self.get_deferred_call_quote(target_slot, max_gas)?; if !available { bail!("The ASC 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."); } @@ -1422,14 +1426,14 @@ impl Interface for InterfaceImpl { todo!() } - /// Check if an asynchronous call exists + /// Check if an deferred call exists /// /// # Arguments /// * id: the id of the call /// /// # Returns /// true if the call exists, false otherwise - fn asc_call_exists(&self, id: &[u8]) -> Result { + fn deferred_call_exists(&self, id: &[u8]) -> Result { // write-lock context let mut context = context_guard!(self); @@ -1442,7 +1446,7 @@ impl Interface for InterfaceImpl { /// /// # Arguments /// * id: the id of the call - fn asc_call_cancel(&self, id: &[u8]) -> Result<()> { + fn deferred_call_cancel(&self, id: &[u8]) -> Result<()> { // write-lock context let mut context = context_guard!(self); From d62dbee9f6d0a46ea32644b78fdf6fa9d44db14e Mon Sep 17 00:00:00 2001 From: modship Date: Tue, 9 Jul 2024 17:47:17 +0200 Subject: [PATCH 011/100] deferred calls first step --- Cargo.lock | 2 + massa-asc/Cargo.toml | 3 +- massa-asc/src/call.rs | 31 +- massa-asc/src/lib.rs | 366 ++++++++++++------ massa-execution-worker/src/context.rs | 9 + massa-execution-worker/src/execution.rs | 46 +++ massa-execution-worker/src/interface_impl.rs | 4 +- massa-execution-worker/src/lib.rs | 2 +- ...e_asc.rs => speculative_deferred_calls.rs} | 202 +++++----- massa-final-state/Cargo.toml | 1 + massa-final-state/src/controller_trait.rs | 4 + massa-final-state/src/final_state.rs | 10 + massa-final-state/src/state_changes.rs | 18 + massa-ledger-exports/src/lib.rs | 5 +- .../{asc_call_id.rs => deferred_call_id.rs} | 123 +++--- massa-models/src/lib.rs | 4 +- 16 files changed, 549 insertions(+), 281 deletions(-) rename massa-execution-worker/src/{speculative_asc.rs => speculative_deferred_calls.rs} (63%) rename massa-models/src/{asc_call_id.rs => deferred_call_id.rs} (65%) diff --git a/Cargo.lock b/Cargo.lock index 8d072d58ab4..5a01c8d0f6f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2669,6 +2669,7 @@ dependencies = [ "massa_models", "massa_serialization", "nom", + "serde", ] [[package]] @@ -2979,6 +2980,7 @@ dependencies = [ "bs58", "displaydoc", "massa-proto-rs", + "massa_asc", "massa_async_pool", "massa_db_exports", "massa_db_worker", diff --git a/massa-asc/Cargo.toml b/massa-asc/Cargo.toml index cc63af172da..8f8501db8e7 100644 --- a/massa-asc/Cargo.toml +++ b/massa-asc/Cargo.toml @@ -9,8 +9,9 @@ test-exports = [] sandbox = [] [dependencies] +serde = { workspace = true, "features" = ["derive"] } nom = { workspace = true } massa_db_exports = { workspace = true } massa_ledger_exports = { workspace = true } massa_models = { workspace = true } -massa_serialization = { workspace = true } \ No newline at end of file +massa_serialization = { workspace = true } diff --git a/massa-asc/src/call.rs b/massa-asc/src/call.rs index 0c50eccc14d..a76364cd8de 100644 --- a/massa-asc/src/call.rs +++ b/massa-asc/src/call.rs @@ -13,11 +13,12 @@ use nom::{ sequence::tuple, IResult, Parser, }; +use serde::{Deserialize, Serialize}; use std::ops::Bound; /// Definition of a call in the future -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct AsyncCall { +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub struct DeferredCall { // Sender address pub sender_address: Address, // The slot in which the call will be executed @@ -38,7 +39,7 @@ pub struct AsyncCall { pub cancelled: bool, } -impl AsyncCall { +impl DeferredCall { pub fn new( sender_address: Address, target_slot: Slot, @@ -66,7 +67,7 @@ impl AsyncCall { /// Serializer for `AsyncCall` #[derive(Clone)] -pub struct AsyncCallSerializer { +pub struct DeferredCallSerializer { slot_serializer: SlotSerializer, address_serializer: AddressSerializer, string_serializer: StringSerializer, @@ -76,7 +77,7 @@ pub struct AsyncCallSerializer { bool_serializer: BoolSerializer, } -impl AsyncCallSerializer { +impl DeferredCallSerializer { /// Serializes an `AsyncCall` into a `Vec` pub fn new() -> Self { Self { @@ -91,8 +92,8 @@ impl AsyncCallSerializer { } } -impl Serializer for AsyncCallSerializer { - fn serialize(&self, value: &AsyncCall, buffer: &mut Vec) -> Result<(), SerializeError> { +impl Serializer for DeferredCallSerializer { + fn serialize(&self, value: &DeferredCall, buffer: &mut Vec) -> Result<(), SerializeError> { self.address_serializer .serialize(&value.sender_address, buffer)?; self.slot_serializer.serialize(&value.target_slot, buffer)?; @@ -113,7 +114,7 @@ impl Serializer for AsyncCallSerializer { /// Deserializer for `AsyncCall` #[derive(Clone)] -pub struct AsyncCallDeserializer { +pub struct DeferredCallDeserializer { slot_deserializer: SlotDeserializer, address_deserializer: AddressDeserializer, string_deserializer: StringDeserializer, @@ -123,7 +124,7 @@ pub struct AsyncCallDeserializer { bool_deserializer: BoolDeserializer, } -impl AsyncCallDeserializer { +impl DeferredCallDeserializer { /// Deserializes a `Vec` into an `AsyncCall` pub fn new(thread_count: u8) -> Self { Self { @@ -153,11 +154,11 @@ impl AsyncCallDeserializer { } } -impl Deserializer for AsyncCallDeserializer { +impl Deserializer for DeferredCallDeserializer { fn deserialize<'a, E: ParseError<&'a [u8]> + ContextError<&'a [u8]>>( &self, buffer: &'a [u8], - ) -> IResult<&'a [u8], AsyncCall, E> { + ) -> IResult<&'a [u8], DeferredCall, E> { context( "Failed AsyncCall deserialization", tuple(( @@ -202,7 +203,7 @@ impl Deserializer for AsyncCallDeserializer { max_gas, cancelled, )| { - AsyncCall::new( + DeferredCall::new( sender_address, target_slot, target_address, @@ -229,7 +230,7 @@ mod tests { #[test] fn test_serialization_deserialization() { - let call = AsyncCall::new( + let call = DeferredCall::new( Address::from_str("AU12dG5xP1RDEB5ocdHkymNVvvSJmUL9BgHwCksDowqmGWxfpm93x").unwrap(), Slot::new(42, 0), Address::from_str("AU12dG5xP1RDEB5ocdHkymNVvvSJmUL9BgHwCksDowqmGWxfpm93x").unwrap(), @@ -240,8 +241,8 @@ mod tests { Amount::from_raw(42), false, ); - let serializer = AsyncCallSerializer::new(); - let deserializer = AsyncCallDeserializer::new(1); + let serializer = DeferredCallSerializer::new(); + let deserializer = DeferredCallDeserializer::new(1); let mut buffer = Vec::new(); serializer.serialize(&call, &mut buffer).unwrap(); let (rest, deserialized_call) = deserializer diff --git a/massa-asc/src/lib.rs b/massa-asc/src/lib.rs index a43ba6a8d74..614e6c29c39 100644 --- a/massa-asc/src/lib.rs +++ b/massa-asc/src/lib.rs @@ -1,19 +1,39 @@ +use call::{DeferredCallDeserializer, DeferredCallSerializer}; use massa_db_exports::ShareableMassaDBController; /// This module implements a new version of the Autonomous Smart Contracts. (ASC) /// This new version allow asynchronous calls to be registered for a specific slot and ensure his execution. mod call; -pub use call::AsyncCall; -use massa_models::{amount::Amount, asc_call_id::AsyncCallId, slot::Slot}; +pub use call::DeferredCall; +use massa_ledger_exports::{ + SetOrDelete, SetOrDeleteDeserializer, SetOrDeleteSerializer, SetOrKeep, SetOrKeepDeserializer, + SetOrKeepSerializer, +}; +use massa_models::{ + amount::{Amount, AmountDeserializer, AmountSerializer}, + deferred_call_id::{DeferredCallId, DeferredCallIdDeserializer, DeferredCallIdSerializer}, + slot::Slot, +}; +use massa_serialization::{ + Deserializer, SerializeError, Serializer, U64VarIntDeserializer, U64VarIntSerializer, +}; +use nom::{ + error::{context, ContextError, ParseError}, + multi::length_count, + sequence::tuple, + IResult, +}; +use serde::{Deserialize, Serialize}; use std::collections::BTreeMap; +use std::ops::Bound::Included; #[derive(Debug)] -pub struct AsyncCallRegistry { +pub struct DeferredCallRegistry { db: ShareableMassaDBController, } -impl AsyncCallRegistry { +impl DeferredCallRegistry { /* DB layout: [ASYNC_CALL_TOTAL_GAS_PREFIX] -> u64 // total currently booked gas @@ -25,11 +45,11 @@ impl AsyncCallRegistry { Self { db } } - pub fn get_slot_calls(slot: Slot) -> AsyncSlotCalls { + pub fn get_slot_calls(&self, slot: Slot) -> DeferredSlotCalls { todo!() } - pub fn get_call(id: &AsyncCallId) -> Option { + pub fn get_call(&self, slot: &Slot, id: &DeferredCallId) -> Option { todo!() } @@ -40,7 +60,7 @@ impl AsyncCallRegistry { } /// Returns the base fee for a slot - pub fn get_slot_base_fee(slot: Slot) -> Amount { + pub fn get_slot_base_fee(&self, slot: &Slot) -> Amount { // By default, if it is absent, it is 0 todo!() } @@ -50,129 +70,251 @@ impl AsyncCallRegistry { todo!() } - pub fn apply_changes(changes: AsyncRegistryChanges) { + pub fn apply_changes(changes: DeferredRegistryChanges) { //Note: if a slot gas is zet to 0, delete the slot gas entry // same for base fee todo!() } } -#[derive(Debug, Clone)] -pub enum AsyncRegistryCallChange { - Set(AsyncCall), - Delete, +// #[derive(Debug, Clone, Serialize, Deserialize)] +// pub enum DeferredRegistryCallChange { +// Set(DeferredCall), +// Delete, +// } + +// todo put SetOrDelete dans models +pub type DeferredRegistryCallChange = SetOrDelete; +pub type DeferredRegistryGasChange = SetOrKeep; +pub type DeferredRegistryBaseFeeChange = SetOrKeep; + +// impl DeferredRegistryCallChange { +// pub fn merge(&mut self, other: DeferredRegistryCallChange) { +// *self = other; +// } + +// pub fn delete_call(&mut self) { +// *self = DeferredRegistryCallChange::Delete; +// } + +// pub fn set_call(&mut self, call: DeferredCall) { +// *self = DeferredRegistryCallChange::Set(call); +// } + +// pub fn get_call(&self) -> Option<&DeferredCall> { +// match self { +// DeferredRegistryCallChange::Set(v) => Some(v), +// DeferredRegistryCallChange::Delete => None, +// } +// } +// } + +// #[derive(Debug, Clone, Serialize, Deserialize)] +// pub enum DeferredRegistryGasChange { +// Set(V), +// Keep, +// } + +// impl Default for DeferredRegistryGasChange { +// fn default() -> Self { +// DeferredRegistryGasChange::Keep +// } +// } + +#[derive(Default, Debug, Clone, Serialize, Deserialize)] +pub struct DeferredRegistrySlotChanges { + calls: BTreeMap, + gas: DeferredRegistryGasChange, + base_fee: DeferredRegistryBaseFeeChange, } -impl AsyncRegistryCallChange { - pub fn merge(&mut self, other: AsyncRegistryCallChange) { - *self = other; +impl DeferredRegistrySlotChanges { + pub fn merge(&mut self, other: DeferredRegistrySlotChanges) { + unimplemented!("DeferredRegistrySlotChanges::merge") + // for (id, change) in other.calls { + // match self.calls.entry(id) { + // std::collections::btree_map::Entry::Occupied(mut entry) => { + // entry.get_mut().merge(change); + // } + // std::collections::btree_map::Entry::Vacant(entry) => { + // entry.insert(change); + // } + // } + // } + // match other.gas { + // DeferredRegistryGasChange::Set(v) => self.gas = DeferredRegistryGasChange::Set(v), + // DeferredRegistryGasChange::Keep => {} + // } + // match other.base_fee { + // DeferredRegistryGasChange::Set(v) => self.base_fee = DeferredRegistryGasChange::Set(v), + // DeferredRegistryGasChange::Keep => {} + // } + } + + pub fn delete_call(&mut self, id: &DeferredCallId) { + unimplemented!("DeferredRegistrySlotChanges::delete_call") + // match self.calls.entry(id.clone()) { + // std::collections::btree_map::Entry::Occupied(mut v) => v.get_mut().delete_call(), + // std::collections::btree_map::Entry::Vacant(v) => { + // v.insert(DeferredRegistryCallChange::Delete); + // } + // } + } + + pub fn set_call(&mut self, id: DeferredCallId, call: DeferredCall) { + self.calls.insert(id, DeferredRegistryCallChange::Set(call)); + } + + pub fn get_call(&self, id: &DeferredCallId) -> Option<&DeferredCall> { + unimplemented!("DeferredRegistrySlotChanges::get_call") + // self.calls.get(id).and_then(|change| change.get_call()) } - pub fn delete_call(&mut self) { - *self = AsyncRegistryCallChange::Delete; + pub fn set_gas(&mut self, gas: u64) { + self.gas = DeferredRegistryGasChange::Set(gas); } - pub fn set_call(&mut self, call: AsyncCall) { - *self = AsyncRegistryCallChange::Set(call); + pub fn get_gas(&self) -> Option { + match self.gas { + DeferredRegistryGasChange::Set(v) => Some(v), + DeferredRegistryGasChange::Keep => None, + } } - pub fn get_call(&self) -> Option<&AsyncCall> { - match self { - AsyncRegistryCallChange::Set(v) => Some(v), - AsyncRegistryCallChange::Delete => None, + pub fn get_base_fee(&self) -> Option { + match self.base_fee { + DeferredRegistryGasChange::Set(v) => Some(v), + DeferredRegistryGasChange::Keep => None, } } -} - -#[derive(Debug, Clone)] -pub enum AsyncRegistryGasChange { - Set(V), - Keep, -} -impl Default for AsyncRegistryGasChange { - fn default() -> Self { - AsyncRegistryGasChange::Keep + pub fn set_base_fee(&mut self, base_fee: Amount) { + self.base_fee = DeferredRegistryGasChange::Set(base_fee); } } -#[derive(Default, Debug, Clone)] -pub struct AsyncRegistrySlotChanges { - calls: BTreeMap, - gas: AsyncRegistryGasChange, - base_fee: AsyncRegistryGasChange, +pub struct DeferredRegistrySlotChangesSerializer { + deferred_registry_slot_changes_length: U64VarIntSerializer, + call_id_serializer: DeferredCallIdSerializer, + calls_set_or_delete_serializer: SetOrDeleteSerializer, + gas_serializer: SetOrKeepSerializer, + base_fee_serializer: SetOrKeepSerializer, } -impl AsyncRegistrySlotChanges { - pub fn merge(&mut self, other: AsyncRegistrySlotChanges) { - for (id, change) in other.calls { - match self.calls.entry(id) { - std::collections::btree_map::Entry::Occupied(mut entry) => { - entry.get_mut().merge(change); - } - std::collections::btree_map::Entry::Vacant(entry) => { - entry.insert(change); - } - } - } - match other.gas { - AsyncRegistryGasChange::Set(v) => self.gas = AsyncRegistryGasChange::Set(v), - AsyncRegistryGasChange::Keep => {} - } - match other.base_fee { - AsyncRegistryGasChange::Set(v) => self.base_fee = AsyncRegistryGasChange::Set(v), - AsyncRegistryGasChange::Keep => {} +impl DeferredRegistrySlotChangesSerializer { + pub fn new() -> Self { + Self { + deferred_registry_slot_changes_length: U64VarIntSerializer::new(), + call_id_serializer: DeferredCallIdSerializer::new(), + calls_set_or_delete_serializer: SetOrDeleteSerializer::new( + DeferredCallSerializer::new(), + ), + gas_serializer: SetOrKeepSerializer::new(U64VarIntSerializer::new()), + base_fee_serializer: SetOrKeepSerializer::new(AmountSerializer::new()), } } +} - pub fn delete_call(&mut self, id: &AsyncCallId) { - match self.calls.entry(id.clone()) { - std::collections::btree_map::Entry::Occupied(mut v) => v.get_mut().delete_call(), - std::collections::btree_map::Entry::Vacant(v) => { - v.insert(AsyncRegistryCallChange::Delete); - } +impl Serializer for DeferredRegistrySlotChangesSerializer { + fn serialize( + &self, + value: &DeferredRegistrySlotChanges, + buffer: &mut Vec, + ) -> Result<(), massa_serialization::SerializeError> { + self.deferred_registry_slot_changes_length.serialize( + &(value.calls.len().try_into().map_err(|_| { + SerializeError::GeneralError("Fail to transform usize to u64".to_string()) + })?), + buffer, + )?; + for (id, call) in &value.calls { + self.call_id_serializer.serialize(id, buffer)?; + self.calls_set_or_delete_serializer + .serialize(call, buffer)?; } - } - - pub fn set_call(&mut self, id: AsyncCallId, call: AsyncCall) { - self.calls.insert(id, AsyncRegistryCallChange::Set(call)); - } + self.gas_serializer.serialize(&value.gas, buffer)?; + self.base_fee_serializer + .serialize(&value.base_fee, buffer)?; - pub fn get_call(&self, id: &AsyncCallId) -> Option<&AsyncCall> { - self.calls.get(id).and_then(|change| change.get_call()) - } - - pub fn set_gas(&mut self, gas: u64) { - self.gas = AsyncRegistryGasChange::Set(gas); + Ok(()) } +} - pub fn get_gas(&self) -> Option { - match self.gas { - AsyncRegistryGasChange::Set(v) => Some(v), - AsyncRegistryGasChange::Keep => None, - } - } +pub struct DeferredRegistrySlotChangesDeserializer { + deferred_registry_slot_changes_length: U64VarIntDeserializer, + call_id_deserializer: DeferredCallIdDeserializer, + calls_set_or_delete_deserializer: + SetOrDeleteDeserializer, + gas_deserializer: SetOrKeepDeserializer, + base_fee_deserializer: SetOrKeepDeserializer, +} - pub fn get_base_fee(&self) -> Option { - match self.base_fee { - AsyncRegistryGasChange::Set(v) => Some(v), - AsyncRegistryGasChange::Keep => None, +impl DeferredRegistrySlotChangesDeserializer { + pub fn new(thread_count: u8, max_gas: u64, max_deferred_calls_pool_changes: u64) -> Self { + Self { + deferred_registry_slot_changes_length: U64VarIntDeserializer::new( + Included(u64::MIN), + Included(max_deferred_calls_pool_changes), + ), + call_id_deserializer: DeferredCallIdDeserializer::new(), + calls_set_or_delete_deserializer: SetOrDeleteDeserializer::new( + DeferredCallDeserializer::new(thread_count), + ), + gas_deserializer: SetOrKeepDeserializer::new(U64VarIntDeserializer::new( + Included(0), + Included(max_gas), + )), + base_fee_deserializer: SetOrKeepDeserializer::new(AmountDeserializer::new( + Included(Amount::MIN), + Included(Amount::MAX), + )), } } +} - pub fn set_base_fee(&mut self, base_fee: Amount) { - self.base_fee = AsyncRegistryGasChange::Set(base_fee); +impl Deserializer for DeferredRegistrySlotChangesDeserializer { + fn deserialize<'a, E: ParseError<&'a [u8]> + ContextError<&'a [u8]>>( + &self, + buffer: &'a [u8], + ) -> IResult<&'a [u8], DeferredRegistrySlotChanges, E> { + unimplemented!("DeferredRegistrySlotChangesDeserializer::deserialize") + // context( + // "Failed DeferredRegistrySlotChanges deserialization", + // length_count( + // context("Failed length deserialization", |input| { + // self.async_pool_changes_length.deserialize(input) + // }), + // |input: &'a [u8]| { + // tuple(( + // context("Failed id deserialization", |input| { + // self.call_id_deserializer.deserialize(input) + // }), + // context( + // "Failed set_update_or_delete_message deserialization", + // |input| { + // self.set_update_or_delete_message_deserializer + // .deserialize(input) + // }, + // ), + // ))(input) + // }, + // ), + // ) + // .map(|vec| { + // DeferredRegistrySlotChanges(vec.into_iter().map(|data| (data.0, data.1)).collect()) + // }) + // .parse(buffer) } } -#[derive(Default, Debug, Clone)] -pub struct AsyncRegistryChanges { - pub slots: BTreeMap, - pub total_gas: AsyncRegistryGasChange, +#[derive(Default, Debug, Clone, Serialize, Deserialize)] +pub struct DeferredRegistryChanges { + pub slots: BTreeMap, + pub total_gas: DeferredRegistryGasChange, } -impl AsyncRegistryChanges { - pub fn merge(&mut self, other: AsyncRegistryChanges) { +impl DeferredRegistryChanges { + pub fn merge(&mut self, other: DeferredRegistryChanges) { for (slot, changes) in other.slots { match self.slots.entry(slot) { std::collections::btree_map::Entry::Occupied(mut entry) => { @@ -184,23 +326,23 @@ impl AsyncRegistryChanges { } } match other.total_gas { - AsyncRegistryGasChange::Set(v) => self.total_gas = AsyncRegistryGasChange::Set(v), - AsyncRegistryGasChange::Keep => {} + DeferredRegistryGasChange::Set(v) => self.total_gas = DeferredRegistryGasChange::Set(v), + DeferredRegistryGasChange::Keep => {} } } - pub fn delete_call(&mut self, target_slot: Slot, id: &AsyncCallId) { + pub fn delete_call(&mut self, target_slot: Slot, id: &DeferredCallId) { self.slots.entry(target_slot).or_default().delete_call(id) } - pub fn set_call(&mut self, id: AsyncCallId, call: AsyncCall) { + pub fn set_call(&mut self, id: DeferredCallId, call: DeferredCall) { self.slots .entry(call.target_slot.clone()) .or_default() .set_call(id, call); } - pub fn get_call(&self, target_slot: &Slot, id: &AsyncCallId) -> Option<&AsyncCall> { + pub fn get_call(&self, target_slot: &Slot, id: &DeferredCallId) -> Option<&DeferredCall> { self.slots .get(target_slot) .and_then(|slot_changes| slot_changes.get_call(id)) @@ -230,13 +372,13 @@ impl AsyncRegistryChanges { } pub fn set_total_gas(&mut self, gas: u128) { - self.total_gas = AsyncRegistryGasChange::Set(gas); + self.total_gas = DeferredRegistryGasChange::Set(gas); } pub fn get_total_gas(&self) -> Option { match self.total_gas { - AsyncRegistryGasChange::Set(v) => Some(v), - AsyncRegistryGasChange::Keep => None, + DeferredRegistryGasChange::Set(v) => Some(v), + DeferredRegistryGasChange::Keep => None, } } } @@ -244,15 +386,15 @@ impl AsyncRegistryChanges { /// A structure that lists slot calls for a given slot, /// as well as global gas usage statistics. #[derive(Debug, Clone)] -pub struct AsyncSlotCalls { +pub struct DeferredSlotCalls { pub slot: Slot, - pub slot_calls: BTreeMap, + pub slot_calls: BTreeMap, pub slot_gas: u64, pub slot_base_fee: Amount, pub total_gas: u128, } -impl AsyncSlotCalls { +impl DeferredSlotCalls { pub fn new(slot: Slot) -> Self { Self { slot, @@ -263,31 +405,31 @@ impl AsyncSlotCalls { } } - pub fn apply_changes(&mut self, changes: &AsyncRegistryChanges) { + pub fn apply_changes(&mut self, changes: &DeferredRegistryChanges) { let Some(slot_changes) = changes.slots.get(&self.slot) else { return; }; for (id, change) in &slot_changes.calls { match change { - AsyncRegistryCallChange::Set(call) => { + DeferredRegistryCallChange::Set(call) => { self.slot_calls.insert(id.clone(), call.clone()); } - AsyncRegistryCallChange::Delete => { + DeferredRegistryCallChange::Delete => { self.slot_calls.remove(id); } } } match slot_changes.gas { - AsyncRegistryGasChange::Set(v) => self.slot_gas = v, - AsyncRegistryGasChange::Keep => {} + DeferredRegistryGasChange::Set(v) => self.slot_gas = v, + DeferredRegistryGasChange::Keep => {} } match slot_changes.base_fee { - AsyncRegistryGasChange::Set(v) => self.slot_base_fee = v, - AsyncRegistryGasChange::Keep => {} + DeferredRegistryGasChange::Set(v) => self.slot_base_fee = v, + DeferredRegistryGasChange::Keep => {} } match changes.total_gas { - AsyncRegistryGasChange::Set(v) => self.total_gas = v, - AsyncRegistryGasChange::Keep => {} + DeferredRegistryGasChange::Set(v) => self.total_gas = v, + DeferredRegistryGasChange::Keep => {} } } } diff --git a/massa-execution-worker/src/context.rs b/massa-execution-worker/src/context.rs index a58576577b9..8b3cc4f1530 100644 --- a/massa-execution-worker/src/context.rs +++ b/massa-execution-worker/src/context.rs @@ -9,6 +9,7 @@ use crate::active_history::HistorySearchResult; use crate::speculative_async_pool::SpeculativeAsyncPool; +use crate::speculative_deferred_calls::SpeculativeDeferredCallRegistry; use crate::speculative_executed_denunciations::SpeculativeExecutedDenunciations; use crate::speculative_executed_ops::SpeculativeExecutedOps; use crate::speculative_ledger::SpeculativeLedger; @@ -121,6 +122,9 @@ pub struct ExecutionContext { /// as seen after everything that happened so far in the context speculative_async_pool: SpeculativeAsyncPool, + /// speculative deferred calls state, + speculative_deferred_calls: SpeculativeDeferredCallRegistry, + /// speculative roll state, /// as seen after everything that happened so far in the context speculative_roll_state: SpeculativeRollState, @@ -214,6 +218,10 @@ impl ExecutionContext { final_state.clone(), active_history.clone(), ), + speculative_deferred_calls: SpeculativeDeferredCallRegistry::new( + final_state.clone(), + active_history.clone(), + ), speculative_roll_state: SpeculativeRollState::new( final_state.clone(), active_history.clone(), @@ -937,6 +945,7 @@ impl ExecutionContext { let state_changes = StateChanges { ledger_changes, async_pool_changes: self.speculative_async_pool.take(), + deferred_call_changes: self.speculative_deferred_calls.take(), pos_changes: self.speculative_roll_state.take(), executed_ops_changes: self.speculative_executed_ops.take(), executed_denunciations_changes: self.speculative_executed_denunciations.take(), diff --git a/massa-execution-worker/src/execution.rs b/massa-execution-worker/src/execution.rs index 297538ff8e9..b1f10f3f623 100644 --- a/massa-execution-worker/src/execution.rs +++ b/massa-execution-worker/src/execution.rs @@ -2271,4 +2271,50 @@ impl ExecutionState { .map(|i| (i.current_version, i.announced_version)), ); } + + // // Get the price it would cost to reserve "gas" at target slot "slot". + // pub fn deferred_call_quote(&self, slot: Slot, gas: u64) -> Result { + // let current_slot = self.active_cursor; + + // // check if the slot is valid + // if (slot <= current_slot || slot > current_slot + deferred_call_max_future_slots) { + + // return Err(ExecutionError::("Invalid target slot")); + // } + + // // check if there is enough gas available at the target slot + // if (gas > max_async_gas - slot.async_gas_booked) { + // return Err("No enough gas available at target slot"); + // } + + // // 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. + + // // Constant part of the fee: directly depends on the base async gas cost for the target slot. + // // This is the "Integral" part of the Proportional-Integral controller. + // // When a new slot `S` is made available for booking, the `S.base_async_gas_cost` is increased or decreased compared to `(S-1).base_async_gas_cost` depending on the average gas usage over the `deferred_call_max_future_slots` slots before `S`. + // let integral_fee = slot.base_deferred_call_gas_cost * gas; + + // // The integral fee is not enough to respond to quick demand surges within the long booking period `deferred_call_max_future_slots`. Proportional regulation is also necessary. + + // // A fee that linearly depends on the total load over `deferred_call_max_future_slots` slots but only when the average load is above `target_async_gas` to not penalize normal use. Booking all the gas from all slots within the booking period requires using the whole initial coin supply. + // let proportional_fee = compute_overbooking_fee( + // deferred_call_max_future_slots * max_async_gas, // total available async gas during the booking period + // deferred_call_max_future_slots * max_async_gas / 2, // target a 50% async gas usage over the booking period + // get_current_total_booked_async_gas(), // total amount of async gas currently booked in the booking period + // gas, // amount of gas to book + // total_initial_coin_supply, // fully booking all slots of the booking period requires spending the whole initial supply of coins + // ); + + // // Finally, a per-slot proportional fee is also added to prevent attackers from denying significant ranges of consecutive slots within the long booking period. + // let proportional_slot_fee = compute_overbooking_fee( + // max_async_gas, // total available async gas during the target slot + // max_async_gas / 2, // target a 50% async gas usage during the target slot + // slot.async_gas_booked, // total amount of async gas currently booked in the target slot + // gas, // amount of gas to book in the target slot + // total_initial_coin_supply / 10000, // fully booking 10000 consecutive slots (~1h40 of slots) requires spending the whole initial supply of coins + // ); + + // return Ok(integral_fee + proportional_fee + proportional_slot_fee); + // } } diff --git a/massa-execution-worker/src/interface_impl.rs b/massa-execution-worker/src/interface_impl.rs index 588e53c0f1f..b2eece633e9 100644 --- a/massa-execution-worker/src/interface_impl.rs +++ b/massa-execution-worker/src/interface_impl.rs @@ -7,7 +7,7 @@ use crate::context::ExecutionContext; use anyhow::{anyhow, bail, Result}; -use massa_asc::AsyncCall; +use massa_asc::DeferredCall; use massa_async_pool::{AsyncMessage, AsyncMessageTrigger}; use massa_execution_exports::ExecutionConfig; use massa_execution_exports::ExecutionStackElement; @@ -1405,7 +1405,7 @@ impl Interface for InterfaceImpl { _ => bail!("failed to read call stack sender address"), }; - let call = AsyncCall::new( + let call = DeferredCall::new( sender_address, Slot::new(target_slot.0, target_slot.1), target_addr, diff --git a/massa-execution-worker/src/lib.rs b/massa-execution-worker/src/lib.rs index b2463974a7f..f3b76ea8d7d 100644 --- a/massa-execution-worker/src/lib.rs +++ b/massa-execution-worker/src/lib.rs @@ -86,8 +86,8 @@ mod execution; mod interface_impl; mod request_queue; mod slot_sequencer; -//mod speculative_asc; mod speculative_async_pool; +mod speculative_deferred_calls; mod speculative_executed_denunciations; mod speculative_executed_ops; mod speculative_ledger; diff --git a/massa-execution-worker/src/speculative_asc.rs b/massa-execution-worker/src/speculative_deferred_calls.rs similarity index 63% rename from massa-execution-worker/src/speculative_asc.rs rename to massa-execution-worker/src/speculative_deferred_calls.rs index f691ca6004a..8b5d7ccbffc 100644 --- a/massa-execution-worker/src/speculative_asc.rs +++ b/massa-execution-worker/src/speculative_deferred_calls.rs @@ -1,81 +1,85 @@ //! Speculative async call registry. use crate::active_history::ActiveHistory; -use massa_asc::{AsyncCall, AsyncRegistryChanges, AsyncSlotCalls}; +use massa_asc::{DeferredCall, DeferredRegistryChanges, DeferredSlotCalls}; use massa_execution_exports::ExecutionError; use massa_final_state::FinalStateController; -use massa_models::{address::Address, amount::Amount, asc_call_id::AsyncCallId, slot::Slot}; +use massa_models::{ + address::Address, amount::Amount, deferred_call_id::DeferredCallId, slot::Slot, +}; use parking_lot::RwLock; use std::sync::Arc; -pub(crate) struct SpeculativeAsyncCallRegistry { +pub(crate) struct SpeculativeDeferredCallRegistry { final_state: Arc>, active_history: Arc>, // current speculative registry changes - current_changes: AsyncRegistryChanges, + deferred_calls_changes: DeferredRegistryChanges, } -impl SpeculativeAsyncCallRegistry { - /// Creates a new `SpeculativeAsyncCallRegistry` +impl SpeculativeDeferredCallRegistry { + /// Creates a new `SpeculativeDeferredCallRegistry` /// /// # Arguments pub fn new( final_state: Arc>, active_history: Arc>, ) -> Self { - SpeculativeAsyncCallRegistry { + SpeculativeDeferredCallRegistry { final_state, active_history, - current_changes: Default::default(), + deferred_calls_changes: Default::default(), } } /// Takes a snapshot (clone) of the message states - pub fn get_snapshot(&self) -> AsyncRegistryChanges { - self.current_changes.clone() + pub fn get_snapshot(&self) -> DeferredRegistryChanges { + self.deferred_calls_changes.clone() } - /// Resets the `SpeculativeAsyncCallRegistry` to a snapshot (see `get_snapshot` method) - pub fn reset_to_snapshot(&mut self, snapshot: AsyncRegistryChanges) { - self.current_changes = snapshot; + /// Resets the `SpeculativeDeferredCallRegistry` to a snapshot (see `get_snapshot` method) + pub fn reset_to_snapshot(&mut self, snapshot: DeferredRegistryChanges) { + self.deferred_calls_changes = snapshot; } - /// Add a new call to the list of changes of this `SpeculativeAsyncCallRegistry` - pub fn push_new_call(&mut self, id: AsyncCallId, call: AsyncCall) { - self.current_changes.set_call(id, call); + /// Add a new call to the list of changes of this `SpeculativeDeferredCallRegistry` + pub fn push_new_call(&mut self, id: DeferredCallId, call: DeferredCall) { + self.deferred_calls_changes.set_call(id, call); } pub fn get_slot_gas(&self, slot: &Slot) -> u64 { - // get slot gas from current changes - if let Some(v) = self.current_changes.get_slot_gas(slot) { - return v; - } - - // check in history backwards - { - let history = self.active_history.read(); - for history_item in history.0.iter().rev() { - if let Some(v) = history_item - .state_changes - .async_call_registry_changes - .get_slot_gas(slot) - { - return v; - } - } - } - - // check in final state - return self - .final_state - .read() - .get_asc_registry() - .get_slot_gas(slot); + unimplemented!("get_slot_gas"); + + // // get slot gas from current changes + // if let Some(v) = self.current_changes.get_slot_gas(slot) { + // return v; + // } + + // // check in history backwards + // { + // let history = self.active_history.read(); + // for history_item in history.0.iter().rev() { + // if let Some(v) = history_item + // .state_changes + // .async_call_registry_changes + // .get_slot_gas(slot) + // { + // return v; + // } + // } + // } + + // // check in final state + // return self + // .final_state + // .read() + // .get_asc_registry() + // .get_slot_gas(slot); } pub fn get_slot_base_fee(&self, slot: &Slot) -> Amount { // get slot base fee from current changes - if let Some(v) = self.current_changes.get_slot_base_fee(slot) { + if let Some(v) = self.deferred_calls_changes.get_slot_base_fee(slot) { return v; } @@ -85,7 +89,7 @@ impl SpeculativeAsyncCallRegistry { for history_item in history.0.iter().rev() { if let Some(v) = history_item .state_changes - .async_call_registry_changes + .deferred_call_changes .get_slot_base_fee(slot) { return v; @@ -94,10 +98,11 @@ impl SpeculativeAsyncCallRegistry { } // check in final state + // todo check if that is correct return self .final_state .read() - .get_asc_registry() + .get_deferred_call_registry() .get_slot_base_fee(slot); } @@ -108,47 +113,51 @@ impl SpeculativeAsyncCallRegistry { current_slot: Slot, async_call_max_booking_slots: u64, thread_count: u8, - ) -> AsyncSlotCalls { + ) -> DeferredSlotCalls { // get the state of the current slot - let mut slot_calls: AsyncSlotCalls = self + let mut slot_calls: DeferredSlotCalls = self .final_state .read() - .get_asc_registry() + .get_deferred_call_registry() .get_slot_calls(current_slot); for hist_item in self.active_history.read().0.iter() { - slot_calls.apply_changes(&hist_item.state_changes.async_call_registry_changes); + slot_calls.apply_changes(&hist_item.state_changes.deferred_call_changes); } - slot_calls.apply_changes(&self.current_changes); + slot_calls.apply_changes(&self.deferred_calls_changes); // select the slot that is newly made available and set its base fee let mut new_slot = current_slot .skip(async_call_max_booking_slots, thread_count) .expect("could not skip enough slots"); todo!(); - self.current_changes.set_slot_base_fee(new_slot, todo!()); + self.deferred_calls_changes + .set_slot_base_fee(new_slot, todo!()); // subtract the current slot gas from the total gas - self.current_changes - .set_total_gas(slot_calls.total_gas.saturating_sub(slot_calls.slot_gas)); + self.deferred_calls_changes.set_total_gas( + slot_calls + .total_gas + .saturating_sub(slot_calls.slot_gas.into()), + ); // delete the current slot - for (id, call) in &slot_calls.calls { - self.current_changes.delete_call(current_slot, id); + for (id, call) in &slot_calls.slot_calls { + self.deferred_calls_changes.delete_call(current_slot, id); } - self.current_changes.set_slot_gas(current_slot, 0); - self.current_changes + self.deferred_calls_changes.set_slot_gas(current_slot, 0); + self.deferred_calls_changes .set_slot_base_fee(current_slot, Amount::zero()); slot_calls } - pub fn get_call(&self, id: &AsyncCallId) -> Option { + pub fn get_call(&self, id: &DeferredCallId) -> Option { let slot: Slot = id.get_slot(); // check from latest to earliest changes // check in current changes - if let Some(v) = self.current_changes.get_call(&slot, id) { + if let Some(v) = self.deferred_calls_changes.get_call(&slot, id) { return Some(v.clone()); } @@ -158,7 +167,7 @@ impl SpeculativeAsyncCallRegistry { for history_item in history.0.iter().rev() { if let Some(v) = history_item .state_changes - .async_call_registry_changes + .deferred_call_changes .get_call(&slot, id) { return Some(v.clone()); @@ -169,7 +178,8 @@ impl SpeculativeAsyncCallRegistry { // check final state { let final_state = self.final_state.read(); - if let Some(v) = final_state.get_asc_registry().get_call(&slot, id) { + // if let Some(v) = final_state.get_deferred_call_registry().get_call(&slot, id) { + if let Some(v) = final_state.get_deferred_call_registry().get_call(&slot, id) { return Some(v.clone()); } } @@ -179,7 +189,10 @@ impl SpeculativeAsyncCallRegistry { /// Cancel a call /// Returns the sender address and the amount of coins to reimburse them - pub fn cancel_call(&mut self, id: &AsyncCallId) -> Result<(Address, Amount), ExecutionError> { + pub fn cancel_call( + &mut self, + id: &DeferredCallId, + ) -> Result<(Address, Amount), ExecutionError> { // get call, fail if it does not exist let Some(mut call) = self.get_call(id) else { return Err(ExecutionError::AscError("Call ID does not exist.".into())); @@ -199,7 +212,7 @@ impl SpeculativeAsyncCallRegistry { let res = (call.sender_address, call.coins); // Add a cancellation to the current changes - self.current_changes.set_call(id.clone(), call); + self.deferred_calls_changes.set_call(id.clone(), call); Ok(res) } @@ -241,33 +254,33 @@ impl SpeculativeAsyncCallRegistry { Amount::from_raw(std::cmp::min(raw_fee, u64::MAX as u128) as u64) } - pub fn get_slot_base_fee(&self, slot: &Slot) -> Amount { - // get slot base fee from current changes - if let Some(v) = self.current_changes.get_slot_base_fee(slot) { - return v; - } - - // check in history backwards - { - let history = self.active_history.read(); - for history_item in history.0.iter().rev() { - if let Some(v) = history_item - .state_changes - .async_call_registry_changes - .get_slot_base_fee(slot) - { - return v; - } - } - } - - // check in final state - return self - .final_state - .read() - .get_asc_registry() - .get_slot_base_fee(slot); - } + // pub fn get_slot_base_fee(&self, slot: &Slot) -> Amount { + // // get slot base fee from current changes + // if let Some(v) = self.current_changes.get_slot_base_fee(slot) { + // return v; + // } + + // // check in history backwards + // { + // let history = self.active_history.read(); + // for history_item in history.0.iter().rev() { + // if let Some(v) = history_item + // .state_changes + // .async_call_registry_changes + // .get_slot_base_fee(slot) + // { + // return v; + // } + // } + // } + + // // check in final state + // return self + // .final_state + // .read() + // .get_asc_registry() + // .get_slot_base_fee(slot); + // } /// Compute call fee pub fn compute_call_fee( @@ -324,7 +337,11 @@ impl SpeculativeAsyncCallRegistry { ); // Global overbooking fee - let global_occupancy = self.get_total_gas(); + // todo check if this is correct + let global_occupancy = self + .deferred_calls_changes + .get_total_gas() + .unwrap_or_default(); let global_overbooking_fee = Self::overbooking_fee( (max_async_gas as u128).saturating_mul(async_call_max_booking_slots as u128), (async_gas_target as u128).saturating_mul(async_call_max_booking_slots as u128), @@ -338,6 +355,11 @@ impl SpeculativeAsyncCallRegistry { .saturating_add(global_overbooking_fee) .saturating_add(slot_overbooking_fee)) } + + /// Take the deferred registry slot changes + pub(crate) fn take(&mut self) -> DeferredRegistryChanges { + std::mem::take(&mut self.deferred_calls_changes) + } } #[cfg(test)] diff --git a/massa-final-state/Cargo.toml b/massa-final-state/Cargo.toml index beedc2e4e19..027d9bb7419 100644 --- a/massa-final-state/Cargo.toml +++ b/massa-final-state/Cargo.toml @@ -42,6 +42,7 @@ massa-proto-rs = { workspace = true, "features" = ["tonic"] } massa_versioning = { workspace = true } massa_time = { workspace = true } massa_hash = { workspace = true } +massa_asc = { workspace = true } serde_json = { workspace = true, optional = true } parking_lot = { workspace = true, "features" = [ diff --git a/massa-final-state/src/controller_trait.rs b/massa-final-state/src/controller_trait.rs index fd32c400695..3b6ffc70010 100644 --- a/massa-final-state/src/controller_trait.rs +++ b/massa-final-state/src/controller_trait.rs @@ -1,3 +1,4 @@ +use massa_asc::DeferredCallRegistry; use massa_async_pool::AsyncPool; use massa_db_exports::{DBBatch, ShareableMassaDBController}; use massa_executed_ops::ExecutedDenunciations; @@ -90,4 +91,7 @@ pub trait FinalStateController: Send + Sync { /// Get mutable reference to MIP Store fn get_mip_store_mut(&mut self) -> &mut MipStore; + + /// Get deferred call registry + fn get_deferred_call_registry(&self) -> &DeferredCallRegistry; } diff --git a/massa-final-state/src/final_state.rs b/massa-final-state/src/final_state.rs index 0396a663764..50f4e544816 100644 --- a/massa-final-state/src/final_state.rs +++ b/massa-final-state/src/final_state.rs @@ -9,6 +9,7 @@ use crate::controller_trait::FinalStateController; use crate::{config::FinalStateConfig, error::FinalStateError, state_changes::StateChanges}; use anyhow::{anyhow, Result as AnyResult}; +use massa_asc::DeferredCallRegistry; use massa_async_pool::AsyncPool; use massa_db_exports::{ DBBatch, MassaIteratorMode, ShareableMassaDBController, ASYNC_POOL_PREFIX, @@ -36,6 +37,8 @@ pub struct FinalState { pub ledger: Box, /// asynchronous pool containing messages sorted by priority and their data pub async_pool: AsyncPool, + /// deferred calls + pub deferred_call_registry: DeferredCallRegistry, /// proof of stake state containing cycle history and deferred credits pub pos_state: PoSFinalState, /// executed operations @@ -106,9 +109,12 @@ impl FinalState { let executed_denunciations = ExecutedDenunciations::new(config.executed_denunciations_config.clone(), db.clone()); + let deferred_call_registry = DeferredCallRegistry::new(db.clone()); + let mut final_state = FinalState { ledger, async_pool, + deferred_call_registry, pos_state, config, executed_ops, @@ -917,6 +923,10 @@ impl FinalStateController for FinalState { fn get_mip_store(&self) -> &MipStore { &self.mip_store } + + fn get_deferred_call_registry(&self) -> &DeferredCallRegistry { + &self.deferred_call_registry + } } #[cfg(test)] diff --git a/massa-final-state/src/state_changes.rs b/massa-final-state/src/state_changes.rs index 85dd5b9b3df..7b38046e443 100644 --- a/massa-final-state/src/state_changes.rs +++ b/massa-final-state/src/state_changes.rs @@ -2,6 +2,9 @@ //! This file provides structures representing changes to the final state +use massa_asc::{ + DeferredRegistryChanges, DeferredRegistrySlotChanges, DeferredRegistrySlotChangesDeserializer, +}; use massa_async_pool::{ AsyncPoolChanges, AsyncPoolChangesDeserializer, AsyncPoolChangesSerializer, }; @@ -31,6 +34,8 @@ pub struct StateChanges { pub ledger_changes: LedgerChanges, /// asynchronous pool changes pub async_pool_changes: AsyncPoolChanges, + /// deferred call changes + pub deferred_call_changes: DeferredRegistryChanges, /// roll state changes pub pos_changes: PoSChanges, /// executed operations changes @@ -93,6 +98,7 @@ impl Serializer for StateChangesSerializer { pub struct StateChangesDeserializer { ledger_changes_deserializer: LedgerChangesDeserializer, async_pool_changes_deserializer: AsyncPoolChangesDeserializer, + deferred_call_changes_deserializer: DeferredRegistrySlotChangesDeserializer, pos_changes_deserializer: PoSChangesDeserializer, ops_changes_deserializer: ExecutedOpsChangesDeserializer, de_changes_deserializer: ExecutedDenunciationsChangesDeserializer, @@ -133,6 +139,12 @@ impl StateChangesDeserializer { max_function_params_length, max_datastore_key_length as u32, ), + // todo pass max gas && max deferred call changes + deferred_call_changes_deserializer: DeferredRegistrySlotChangesDeserializer::new( + thread_count, + u64::MAX, + 100_000, + ), pos_changes_deserializer: PoSChangesDeserializer::new( thread_count, max_rolls_length, @@ -169,6 +181,10 @@ impl Deserializer for StateChangesDeserializer { context("Failed async_pool_changes deserialization", |input| { self.async_pool_changes_deserializer.deserialize(input) }), + context("Failed deferred_call_changes deserialization", |input| { + todo!("Deferred call changes deserialization not implemented") + // self.def.deserialize(input) + }), context("Failed roll_state_changes deserialization", |input| { self.pos_changes_deserializer.deserialize(input) }), @@ -191,6 +207,7 @@ impl Deserializer for StateChangesDeserializer { |( ledger_changes, async_pool_changes, + deferred_call_changes, pos_changes, executed_ops_changes, executed_denunciations_changes, @@ -198,6 +215,7 @@ impl Deserializer for StateChangesDeserializer { )| StateChanges { ledger_changes, async_pool_changes, + deferred_call_changes, pos_changes, executed_ops_changes, executed_denunciations_changes, diff --git a/massa-ledger-exports/src/lib.rs b/massa-ledger-exports/src/lib.rs index 9a2dadd65eb..161301dc26b 100644 --- a/massa-ledger-exports/src/lib.rs +++ b/massa-ledger-exports/src/lib.rs @@ -25,8 +25,9 @@ pub use ledger_changes::{ }; pub use ledger_entry::{LedgerEntry, LedgerEntryDeserializer, LedgerEntrySerializer}; pub use types::{ - Applicable, SetOrDelete, SetOrKeep, SetOrKeepDeserializer, SetOrKeepSerializer, - SetUpdateOrDelete, SetUpdateOrDeleteDeserializer, SetUpdateOrDeleteSerializer, + Applicable, SetOrDelete, SetOrDeleteDeserializer, SetOrDeleteSerializer, SetOrKeep, + SetOrKeepDeserializer, SetOrKeepSerializer, SetUpdateOrDelete, SetUpdateOrDeleteDeserializer, + SetUpdateOrDeleteSerializer, }; #[cfg(feature = "test-exports")] diff --git a/massa-models/src/asc_call_id.rs b/massa-models/src/deferred_call_id.rs similarity index 65% rename from massa-models/src/asc_call_id.rs rename to massa-models/src/deferred_call_id.rs index 7eb9436d5bb..111ac7a3450 100644 --- a/massa-models/src/asc_call_id.rs +++ b/massa-models/src/deferred_call_id.rs @@ -15,22 +15,22 @@ use crate::{ slot::{Slot, SlotSerializer}, }; -const ASC_CALL_ID_PREFIX: &str = "ASC"; +const DEFERRED_CALL_ID_PREFIX: &str = "D"; /// block id #[allow(missing_docs)] #[transition::versioned(versions("0"))] #[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] -pub struct AsyncCallId(Vec); +pub struct DeferredCallId(Vec); -/// Serializer for `AsyncCallId` +/// Serializer for `DeferredCallId` #[derive(Default, Clone)] -pub struct AsyncCallIdSerializer { +pub struct DeferredCallIdSerializer { bytes_serializer: VecU8Serializer, } -impl AsyncCallIdSerializer { - /// Serializes an `AsyncCallId` into a `Vec` +impl DeferredCallIdSerializer { + /// Serializes an `DeferredCallId` into a `Vec` pub fn new() -> Self { Self { bytes_serializer: VecU8Serializer::new(), @@ -38,10 +38,14 @@ impl AsyncCallIdSerializer { } } -impl Serializer for AsyncCallIdSerializer { - fn serialize(&self, value: &AsyncCallId, buffer: &mut Vec) -> Result<(), SerializeError> { +impl Serializer for DeferredCallIdSerializer { + fn serialize( + &self, + value: &DeferredCallId, + buffer: &mut Vec, + ) -> Result<(), SerializeError> { match value { - AsyncCallId::AsyncCallIdV0(id) => { + DeferredCallId::DeferredCallIdV0(id) => { self.bytes_serializer.serialize(&id.0, buffer)?; } } @@ -49,13 +53,14 @@ impl Serializer for AsyncCallIdSerializer { } } -/// Deserializer for `AsyncCallId` -pub struct AsyncCallIdDeserializer { +/// Deserializer for `DeferredCallId` +#[derive(Clone)] +pub struct DeferredCallIdDeserializer { bytes_deserializer: VecU8Deserializer, } -impl AsyncCallIdDeserializer { - /// Deserializes a `Vec` into an `AsyncCallId` +impl DeferredCallIdDeserializer { + /// Deserializes a `Vec` into an `DeferredCallId` pub fn new() -> Self { Self { bytes_deserializer: VecU8Deserializer::new( @@ -66,46 +71,52 @@ impl AsyncCallIdDeserializer { } } -impl Deserializer for AsyncCallIdDeserializer { +impl Deserializer for DeferredCallIdDeserializer { fn deserialize<'a, E: ParseError<&'a [u8]> + ContextError<&'a [u8]>>( &self, buffer: &'a [u8], - ) -> IResult<&'a [u8], AsyncCallId, E> { + ) -> IResult<&'a [u8], DeferredCallId, E> { let (rest, bytes) = self.bytes_deserializer.deserialize(buffer)?; - Ok((rest, AsyncCallId::AsyncCallIdV0(AsyncCallIdV0(bytes)))) + Ok(( + rest, + DeferredCallId::DeferredCallIdV0(DeferredCallIdV0(bytes)), + )) } } -impl FromStr for AsyncCallId { +impl FromStr for DeferredCallId { type Err = ModelsError; fn from_str(s: &str) -> Result { - if !s.starts_with(ASC_CALL_ID_PREFIX) { + if !s.starts_with(DEFERRED_CALL_ID_PREFIX) { return Err(ModelsError::DeserializeError(format!( - "Invalid prefix for AsyncCallId: {}", + "Invalid prefix for DeferredCallId: {}", s ))); } - let s = &s[ASC_CALL_ID_PREFIX.len()..]; + let s = &s[DEFERRED_CALL_ID_PREFIX.len()..]; let bytes = bs58::decode(s).with_check(None).into_vec().map_err(|_| { - ModelsError::DeserializeError(format!("Invalid base58 string for AsyncCallId: {}", s)) + ModelsError::DeserializeError(format!( + "Invalid base58 string for DeferredCallId: {}", + s + )) })?; - AsyncCallId::from_bytes(&bytes) + DeferredCallId::from_bytes(&bytes) } } -impl std::fmt::Display for AsyncCallId { +impl std::fmt::Display for DeferredCallId { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( f, "{}{}", - ASC_CALL_ID_PREFIX, + DEFERRED_CALL_ID_PREFIX, bs58::encode(self.as_bytes()).with_check().into_string() ) } } -impl ::serde::Serialize for AsyncCallId { +impl ::serde::Serialize for DeferredCallId { fn serialize(&self, serializer: S) -> Result where S: ::serde::Serializer, @@ -118,13 +129,13 @@ impl ::serde::Serialize for AsyncCallId { } } -impl<'de> ::serde::Deserialize<'de> for AsyncCallId { - fn deserialize>(d: D) -> Result { +impl<'de> ::serde::Deserialize<'de> for DeferredCallId { + fn deserialize>(d: D) -> Result { if d.is_human_readable() { - struct AsyncCallIdVisitor; + struct DeferredCallIdVisitor; - impl<'de> ::serde::de::Visitor<'de> for AsyncCallIdVisitor { - type Value = AsyncCallId; + impl<'de> ::serde::de::Visitor<'de> for DeferredCallIdVisitor { + type Value = DeferredCallId; fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { formatter.write_str("ASC + base58::encode(bytes)") @@ -135,7 +146,7 @@ impl<'de> ::serde::Deserialize<'de> for AsyncCallId { E: ::serde::de::Error, { if let Ok(v_str) = std::str::from_utf8(v) { - AsyncCallId::from_str(v_str).map_err(E::custom) + DeferredCallId::from_str(v_str).map_err(E::custom) } else { Err(E::invalid_value(::serde::de::Unexpected::Bytes(v), &self)) } @@ -145,15 +156,15 @@ impl<'de> ::serde::Deserialize<'de> for AsyncCallId { where E: ::serde::de::Error, { - AsyncCallId::from_str(v).map_err(E::custom) + DeferredCallId::from_str(v).map_err(E::custom) } } - d.deserialize_str(AsyncCallIdVisitor) + d.deserialize_str(DeferredCallIdVisitor) } else { struct BytesVisitor; impl<'de> ::serde::de::Visitor<'de> for BytesVisitor { - type Value = AsyncCallId; + type Value = DeferredCallId; fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { formatter.write_str("[u64varint-of-addr-variant][u64varint-of-version][bytes]") @@ -163,7 +174,7 @@ impl<'de> ::serde::Deserialize<'de> for AsyncCallId { where E: ::serde::de::Error, { - AsyncCallId::from_bytes(v).map_err(E::custom) + DeferredCallId::from_bytes(v).map_err(E::custom) } } @@ -172,12 +183,12 @@ impl<'de> ::serde::Deserialize<'de> for AsyncCallId { } } -impl AsyncCallId { +impl DeferredCallId { pub fn get_slot(&self) -> Slot { todo!(); } - /// Create a new `AsyncCallId` + /// Create a new `DeferredCallId` pub fn new( version: u64, target_slot: Slot, @@ -193,25 +204,25 @@ impl AsyncCallId { slot_serializer.serialize(&target_slot, &mut id)?; id.extend(index.to_be_bytes()); id.extend(trail_hash); - Ok(AsyncCallId::AsyncCallIdV0(AsyncCallIdV0(id))) + Ok(DeferredCallId::DeferredCallIdV0(DeferredCallIdV0(id))) } _ => { return Err(ModelsError::InvalidVersionError(format!( - "Invalid version to create an AsyncCallId: {}", + "Invalid version to create an DeferredCallId: {}", version ))) } } } - /// Return the version of the `AsyncCallId` as bytes + /// Return the version of the `DeferredCallId` as bytes pub fn as_bytes(&self) -> &[u8] { match self { - AsyncCallId::AsyncCallIdV0(block_id) => block_id.as_bytes(), + DeferredCallId::DeferredCallIdV0(block_id) => block_id.as_bytes(), } } - /// Create an `AsyncCallId` from bytes + /// Create an `DeferredCallId` from bytes pub fn from_bytes(bytes: &[u8]) -> Result { if bytes.is_empty() { return Err(ModelsError::SerializeError("Empty bytes".to_string())); @@ -223,11 +234,11 @@ impl AsyncCallId { let (_, version) = version.deserialize(bytes)?; match version { 0 => { - let id = AsyncCallIdV0::from_bytes(bytes)?; - Ok(AsyncCallId::AsyncCallIdV0(id)) + let id = DeferredCallIdV0::from_bytes(bytes)?; + Ok(DeferredCallId::DeferredCallIdV0(id)) } _ => Err(ModelsError::InvalidVersionError(format!( - "Invalid version to create an AsyncCallId: {}", + "Invalid version to create an DeferredCallId: {}", version ))), } @@ -235,15 +246,15 @@ impl AsyncCallId { } #[transition::impl_version(versions("0"))] -impl AsyncCallId { - /// Return the version of the `AsyncCallId` as bytes +impl DeferredCallId { + /// Return the version of the `DeferredCallId` as bytes pub fn as_bytes(&self) -> &[u8] { &self.0 } - /// Create an `AsyncCallId` from bytes + /// Create an `DeferredCallId` from bytes pub fn from_bytes(bytes: &[u8]) -> Result { - Ok(AsyncCallIdV0(bytes.to_vec())) + Ok(DeferredCallId(bytes.to_vec())) } } @@ -255,15 +266,15 @@ mod tests { use crate::slot::Slot; #[test] - fn test_async_call_id_ser_deser() { + fn test_deferred_call_id_ser_deser() { let slot = Slot::new(1, 2); let index = 3; let trail_hash = [4, 5, 6]; - let id = AsyncCallId::new(0, slot, index, &trail_hash).unwrap(); - let serializer = AsyncCallIdSerializer::new(); + let id = DeferredCallId::new(0, slot, index, &trail_hash).unwrap(); + let serializer = DeferredCallIdSerializer::new(); let mut buffer = Vec::new(); serializer.serialize(&id, &mut buffer).unwrap(); - let deserializer = AsyncCallIdDeserializer::new(); + let deserializer = DeferredCallIdDeserializer::new(); let (rest, deserialized_id) = deserializer .deserialize::(&buffer) .unwrap(); @@ -272,13 +283,13 @@ mod tests { } #[test] - fn test_async_call_id_from_str() { + fn test_deferred_call_id_from_str() { let slot = Slot::new(1, 2); let index = 3; let trail_hash = [4, 5, 6]; - let id = AsyncCallId::new(0, slot, index, &trail_hash).unwrap(); + let id = DeferredCallId::new(0, slot, index, &trail_hash).unwrap(); let id_str = id.to_string(); - let deserialized_id = AsyncCallId::from_str(&id_str).unwrap(); + let deserialized_id = DeferredCallId::from_str(&id_str).unwrap(); assert_eq!(deserialized_id, id); } } diff --git a/massa-models/src/lib.rs b/massa-models/src/lib.rs index 9db32d9fb70..4aede396e25 100644 --- a/massa-models/src/lib.rs +++ b/massa-models/src/lib.rs @@ -12,8 +12,6 @@ pub mod active_block; pub mod address; /// amount related structures pub mod amount; -/// async call id -pub mod asc_call_id; /// block structure pub mod block; /// block-related structure: block_header @@ -30,6 +28,8 @@ pub mod composite; pub mod config; /// datastore serialization / deserialization pub mod datastore; +/// deferred call id +pub mod deferred_call_id; /// denunciation pub mod denunciation; /// endorsements From d18ed1b136f92af24ff8d47567b323ef697cdd23 Mon Sep 17 00:00:00 2001 From: modship Date: Tue, 9 Jul 2024 17:56:36 +0200 Subject: [PATCH 012/100] rename massa_asc package to massa_deferred_calls --- Cargo.lock | 28 +++++++++---------- Cargo.toml | 2 +- .../Cargo.toml | 4 +-- .../src/call.rs | 0 .../src/lib.rs | 0 massa-execution-worker/Cargo.toml | 2 +- massa-execution-worker/src/interface_impl.rs | 2 +- .../src/speculative_deferred_calls.rs | 2 +- massa-final-state/Cargo.toml | 2 +- massa-final-state/src/controller_trait.rs | 2 +- massa-final-state/src/final_state.rs | 2 +- massa-final-state/src/state_changes.rs | 6 ++-- 12 files changed, 26 insertions(+), 26 deletions(-) rename {massa-asc => massa-deferred-calls}/Cargo.toml (88%) rename {massa-asc => massa-deferred-calls}/src/call.rs (100%) rename {massa-asc => massa-deferred-calls}/src/lib.rs (100%) diff --git a/Cargo.lock b/Cargo.lock index 5a01c8d0f6f..42faa190fa7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2660,18 +2660,6 @@ dependencies = [ "thiserror", ] -[[package]] -name = "massa_asc" -version = "28.3.0" -dependencies = [ - "massa_db_exports", - "massa_ledger_exports", - "massa_models", - "massa_serialization", - "nom", - "serde", -] - [[package]] name = "massa_async_pool" version = "2.2.0" @@ -2843,6 +2831,18 @@ dependencies = [ "tempfile", ] +[[package]] +name = "massa_deferred_calls" +version = "2.2.0" +dependencies = [ + "massa_db_exports", + "massa_ledger_exports", + "massa_models", + "massa_serialization", + "nom", + "serde", +] + [[package]] name = "massa_executed_ops" version = "2.2.0" @@ -2893,11 +2893,11 @@ dependencies = [ "libsecp256k1", "massa-proto-rs", "massa-sc-runtime", - "massa_asc", "massa_async_pool", "massa_channel", "massa_db_exports", "massa_db_worker", + "massa_deferred_calls", "massa_executed_ops", "massa_execution_exports", "massa_final_state", @@ -2980,10 +2980,10 @@ dependencies = [ "bs58", "displaydoc", "massa-proto-rs", - "massa_asc", "massa_async_pool", "massa_db_exports", "massa_db_worker", + "massa_deferred_calls", "massa_executed_ops", "massa_hash", "massa_ledger_exports", diff --git a/Cargo.toml b/Cargo.toml index bf4bb3b00fa..997715243d3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -66,7 +66,6 @@ lto = true # Enables Link Time Optimization, enabling more aggressive # The saved snapshot can then be used to restart the network from the snapshot. [workspace.dependencies] # Internal packages -massa_asc = { path = "./massa-asc" } massa_api = { path = "./massa-api" } massa_api_exports = { path = "./massa-api-exports" } massa_async_pool = { path = "./massa-async-pool" } @@ -77,6 +76,7 @@ massa_consensus_exports = { path = "./massa-consensus-exports" } massa_consensus_worker = { path = "./massa-consensus-worker" } massa_db_exports = { path = "./massa-db-exports" } massa_db_worker = { path = "./massa-db-worker" } +massa_deferred_calls = { path = "./massa-deferred-calls" } massa_executed_ops = { path = "./massa-executed-ops" } massa_execution_exports = { path = "./massa-execution-exports" } massa_execution_worker = { path = "./massa-execution-worker" } diff --git a/massa-asc/Cargo.toml b/massa-deferred-calls/Cargo.toml similarity index 88% rename from massa-asc/Cargo.toml rename to massa-deferred-calls/Cargo.toml index 8f8501db8e7..1ef255172c5 100644 --- a/massa-asc/Cargo.toml +++ b/massa-deferred-calls/Cargo.toml @@ -1,6 +1,6 @@ [package] -name = "massa_asc" -version = "28.3.0" +name = "massa_deferred_calls" +version = "2.2.0" authors = ["Massa Labs "] edition = "2021" diff --git a/massa-asc/src/call.rs b/massa-deferred-calls/src/call.rs similarity index 100% rename from massa-asc/src/call.rs rename to massa-deferred-calls/src/call.rs diff --git a/massa-asc/src/lib.rs b/massa-deferred-calls/src/lib.rs similarity index 100% rename from massa-asc/src/lib.rs rename to massa-deferred-calls/src/lib.rs diff --git a/massa-execution-worker/Cargo.toml b/massa-execution-worker/Cargo.toml index 2993bcf05ab..06b4450a0a8 100644 --- a/massa-execution-worker/Cargo.toml +++ b/massa-execution-worker/Cargo.toml @@ -66,10 +66,10 @@ sha2 = { workspace = true } sha3 = { workspace = true } libsecp256k1 = { workspace = true } criterion = { workspace = true, "optional" = true } -massa_asc = { workspace = true } massa_pos_worker = { workspace = true, "optional" = true } massa_async_pool = { workspace = true } massa_channel = { workspace = true } +massa_deferred_calls = { workspace = true } massa_executed_ops = { workspace = true } massa_execution_exports = { workspace = true } massa_models = { workspace = true } diff --git a/massa-execution-worker/src/interface_impl.rs b/massa-execution-worker/src/interface_impl.rs index b2eece633e9..ba7d8451f09 100644 --- a/massa-execution-worker/src/interface_impl.rs +++ b/massa-execution-worker/src/interface_impl.rs @@ -7,8 +7,8 @@ use crate::context::ExecutionContext; use anyhow::{anyhow, bail, Result}; -use massa_asc::DeferredCall; use massa_async_pool::{AsyncMessage, AsyncMessageTrigger}; +use massa_deferred_calls::DeferredCall; use massa_execution_exports::ExecutionConfig; use massa_execution_exports::ExecutionStackElement; use massa_models::bytecode::Bytecode; diff --git a/massa-execution-worker/src/speculative_deferred_calls.rs b/massa-execution-worker/src/speculative_deferred_calls.rs index 8b5d7ccbffc..647982f4e3f 100644 --- a/massa-execution-worker/src/speculative_deferred_calls.rs +++ b/massa-execution-worker/src/speculative_deferred_calls.rs @@ -1,7 +1,7 @@ //! Speculative async call registry. use crate::active_history::ActiveHistory; -use massa_asc::{DeferredCall, DeferredRegistryChanges, DeferredSlotCalls}; +use massa_deferred_calls::{DeferredCall, DeferredRegistryChanges, DeferredSlotCalls}; use massa_execution_exports::ExecutionError; use massa_final_state::FinalStateController; use massa_models::{ diff --git a/massa-final-state/Cargo.toml b/massa-final-state/Cargo.toml index 027d9bb7419..d32d634a835 100644 --- a/massa-final-state/Cargo.toml +++ b/massa-final-state/Cargo.toml @@ -42,7 +42,7 @@ massa-proto-rs = { workspace = true, "features" = ["tonic"] } massa_versioning = { workspace = true } massa_time = { workspace = true } massa_hash = { workspace = true } -massa_asc = { workspace = true } +massa_deferred_calls = { workspace = true } serde_json = { workspace = true, optional = true } parking_lot = { workspace = true, "features" = [ diff --git a/massa-final-state/src/controller_trait.rs b/massa-final-state/src/controller_trait.rs index 3b6ffc70010..52506c90454 100644 --- a/massa-final-state/src/controller_trait.rs +++ b/massa-final-state/src/controller_trait.rs @@ -1,6 +1,6 @@ -use massa_asc::DeferredCallRegistry; use massa_async_pool::AsyncPool; use massa_db_exports::{DBBatch, ShareableMassaDBController}; +use massa_deferred_calls::DeferredCallRegistry; use massa_executed_ops::ExecutedDenunciations; use massa_hash::Hash; use massa_ledger_exports::LedgerController; diff --git a/massa-final-state/src/final_state.rs b/massa-final-state/src/final_state.rs index 50f4e544816..b7f7ddd7b27 100644 --- a/massa-final-state/src/final_state.rs +++ b/massa-final-state/src/final_state.rs @@ -9,7 +9,6 @@ use crate::controller_trait::FinalStateController; use crate::{config::FinalStateConfig, error::FinalStateError, state_changes::StateChanges}; use anyhow::{anyhow, Result as AnyResult}; -use massa_asc::DeferredCallRegistry; use massa_async_pool::AsyncPool; use massa_db_exports::{ DBBatch, MassaIteratorMode, ShareableMassaDBController, ASYNC_POOL_PREFIX, @@ -17,6 +16,7 @@ use massa_db_exports::{ EXECUTED_OPS_PREFIX, LEDGER_PREFIX, MIP_STORE_PREFIX, STATE_CF, }; use massa_db_exports::{EXECUTION_TRAIL_HASH_PREFIX, MIP_STORE_STATS_PREFIX, VERSIONING_CF}; +use massa_deferred_calls::DeferredCallRegistry; use massa_executed_ops::ExecutedDenunciations; use massa_executed_ops::ExecutedOps; use massa_hash::Hash; diff --git a/massa-final-state/src/state_changes.rs b/massa-final-state/src/state_changes.rs index 7b38046e443..ba6ab8d53d0 100644 --- a/massa-final-state/src/state_changes.rs +++ b/massa-final-state/src/state_changes.rs @@ -2,12 +2,12 @@ //! This file provides structures representing changes to the final state -use massa_asc::{ - DeferredRegistryChanges, DeferredRegistrySlotChanges, DeferredRegistrySlotChangesDeserializer, -}; use massa_async_pool::{ AsyncPoolChanges, AsyncPoolChangesDeserializer, AsyncPoolChangesSerializer, }; +use massa_deferred_calls::{ + DeferredRegistryChanges, DeferredRegistrySlotChanges, DeferredRegistrySlotChangesDeserializer, +}; use massa_executed_ops::{ ExecutedDenunciationsChanges, ExecutedDenunciationsChangesDeserializer, ExecutedDenunciationsChangesSerializer, ExecutedOpsChanges, ExecutedOpsChangesDeserializer, From 8b3b2da2e52d982c8fc77ebdf2779308c2e7c936 Mon Sep 17 00:00:00 2001 From: modship Date: Wed, 10 Jul 2024 12:36:07 +0200 Subject: [PATCH 013/100] TDD for ser_deser validation --- massa-bootstrap/src/tests/tools.rs | 4 + massa-deferred-calls/src/lib.rs | 286 +----------------- massa-deferred-calls/src/registry_changes.rs | 199 ++++++++++++ massa-deferred-calls/src/slot_changes.rs | 274 +++++++++++++++++ .../src/speculative_deferred_calls.rs | 4 +- .../src/tests/tests_active_history.rs | 1 + massa-final-state/src/state_changes.rs | 20 +- massa-final-state/src/test_exports/config.rs | 2 + massa-final-state/src/test_exports/mock.rs | 6 +- massa-serialization/src/lib.rs | 3 +- 10 files changed, 507 insertions(+), 292 deletions(-) create mode 100644 massa-deferred-calls/src/registry_changes.rs create mode 100644 massa-deferred-calls/src/slot_changes.rs diff --git a/massa-bootstrap/src/tests/tools.rs b/massa-bootstrap/src/tests/tools.rs index ddfabd23734..01af04d4c1e 100644 --- a/massa-bootstrap/src/tests/tools.rs +++ b/massa-bootstrap/src/tests/tools.rs @@ -9,6 +9,7 @@ use massa_consensus_exports::{ bootstrapable_graph::BootstrapableGraph, export_active_block::ExportActiveBlock, }; use massa_db_exports::{DBBatch, ShareableMassaDBController, StreamBatch}; +use massa_deferred_calls::DeferredCallRegistry; use massa_executed_ops::{ ExecutedDenunciations, ExecutedDenunciationsChanges, ExecutedDenunciationsConfig, ExecutedOps, ExecutedOpsConfig, @@ -275,6 +276,8 @@ pub fn get_random_final_state_bootstrap( .write() .write_batch(batch, versioning_batch, None); + let deferred_call_registry = DeferredCallRegistry::new(db.clone()); + let executed_ops = get_random_executed_ops( r_limit, slot, @@ -304,6 +307,7 @@ pub fn get_random_final_state_bootstrap( config, Box::new(final_ledger), async_pool, + deferred_call_registry, pos_state, executed_ops, executed_denunciations, diff --git a/massa-deferred-calls/src/lib.rs b/massa-deferred-calls/src/lib.rs index 614e6c29c39..78144bf3805 100644 --- a/massa-deferred-calls/src/lib.rs +++ b/massa-deferred-calls/src/lib.rs @@ -1,32 +1,20 @@ -use call::{DeferredCallDeserializer, DeferredCallSerializer}; use massa_db_exports::ShareableMassaDBController; +use registry_changes::DeferredRegistryChanges; /// This module implements a new version of the Autonomous Smart Contracts. (ASC) /// This new version allow asynchronous calls to be registered for a specific slot and ensure his execution. mod call; +pub mod registry_changes; +pub mod slot_changes; pub use call::DeferredCall; -use massa_ledger_exports::{ - SetOrDelete, SetOrDeleteDeserializer, SetOrDeleteSerializer, SetOrKeep, SetOrKeepDeserializer, - SetOrKeepSerializer, -}; +use massa_ledger_exports::{SetOrDelete, SetOrKeep}; use massa_models::{ - amount::{Amount, AmountDeserializer, AmountSerializer}, + amount::Amount, deferred_call_id::{DeferredCallId, DeferredCallIdDeserializer, DeferredCallIdSerializer}, - slot::Slot, -}; -use massa_serialization::{ - Deserializer, SerializeError, Serializer, U64VarIntDeserializer, U64VarIntSerializer, -}; -use nom::{ - error::{context, ContextError, ParseError}, - multi::length_count, - sequence::tuple, - IResult, + slot::{Slot, SlotSerializer}, }; -use serde::{Deserialize, Serialize}; use std::collections::BTreeMap; -use std::ops::Bound::Included; #[derive(Debug)] pub struct DeferredCallRegistry { @@ -121,268 +109,6 @@ pub type DeferredRegistryBaseFeeChange = SetOrKeep; // } // } -#[derive(Default, Debug, Clone, Serialize, Deserialize)] -pub struct DeferredRegistrySlotChanges { - calls: BTreeMap, - gas: DeferredRegistryGasChange, - base_fee: DeferredRegistryBaseFeeChange, -} - -impl DeferredRegistrySlotChanges { - pub fn merge(&mut self, other: DeferredRegistrySlotChanges) { - unimplemented!("DeferredRegistrySlotChanges::merge") - // for (id, change) in other.calls { - // match self.calls.entry(id) { - // std::collections::btree_map::Entry::Occupied(mut entry) => { - // entry.get_mut().merge(change); - // } - // std::collections::btree_map::Entry::Vacant(entry) => { - // entry.insert(change); - // } - // } - // } - // match other.gas { - // DeferredRegistryGasChange::Set(v) => self.gas = DeferredRegistryGasChange::Set(v), - // DeferredRegistryGasChange::Keep => {} - // } - // match other.base_fee { - // DeferredRegistryGasChange::Set(v) => self.base_fee = DeferredRegistryGasChange::Set(v), - // DeferredRegistryGasChange::Keep => {} - // } - } - - pub fn delete_call(&mut self, id: &DeferredCallId) { - unimplemented!("DeferredRegistrySlotChanges::delete_call") - // match self.calls.entry(id.clone()) { - // std::collections::btree_map::Entry::Occupied(mut v) => v.get_mut().delete_call(), - // std::collections::btree_map::Entry::Vacant(v) => { - // v.insert(DeferredRegistryCallChange::Delete); - // } - // } - } - - pub fn set_call(&mut self, id: DeferredCallId, call: DeferredCall) { - self.calls.insert(id, DeferredRegistryCallChange::Set(call)); - } - - pub fn get_call(&self, id: &DeferredCallId) -> Option<&DeferredCall> { - unimplemented!("DeferredRegistrySlotChanges::get_call") - // self.calls.get(id).and_then(|change| change.get_call()) - } - - pub fn set_gas(&mut self, gas: u64) { - self.gas = DeferredRegistryGasChange::Set(gas); - } - - pub fn get_gas(&self) -> Option { - match self.gas { - DeferredRegistryGasChange::Set(v) => Some(v), - DeferredRegistryGasChange::Keep => None, - } - } - - pub fn get_base_fee(&self) -> Option { - match self.base_fee { - DeferredRegistryGasChange::Set(v) => Some(v), - DeferredRegistryGasChange::Keep => None, - } - } - - pub fn set_base_fee(&mut self, base_fee: Amount) { - self.base_fee = DeferredRegistryGasChange::Set(base_fee); - } -} - -pub struct DeferredRegistrySlotChangesSerializer { - deferred_registry_slot_changes_length: U64VarIntSerializer, - call_id_serializer: DeferredCallIdSerializer, - calls_set_or_delete_serializer: SetOrDeleteSerializer, - gas_serializer: SetOrKeepSerializer, - base_fee_serializer: SetOrKeepSerializer, -} - -impl DeferredRegistrySlotChangesSerializer { - pub fn new() -> Self { - Self { - deferred_registry_slot_changes_length: U64VarIntSerializer::new(), - call_id_serializer: DeferredCallIdSerializer::new(), - calls_set_or_delete_serializer: SetOrDeleteSerializer::new( - DeferredCallSerializer::new(), - ), - gas_serializer: SetOrKeepSerializer::new(U64VarIntSerializer::new()), - base_fee_serializer: SetOrKeepSerializer::new(AmountSerializer::new()), - } - } -} - -impl Serializer for DeferredRegistrySlotChangesSerializer { - fn serialize( - &self, - value: &DeferredRegistrySlotChanges, - buffer: &mut Vec, - ) -> Result<(), massa_serialization::SerializeError> { - self.deferred_registry_slot_changes_length.serialize( - &(value.calls.len().try_into().map_err(|_| { - SerializeError::GeneralError("Fail to transform usize to u64".to_string()) - })?), - buffer, - )?; - for (id, call) in &value.calls { - self.call_id_serializer.serialize(id, buffer)?; - self.calls_set_or_delete_serializer - .serialize(call, buffer)?; - } - self.gas_serializer.serialize(&value.gas, buffer)?; - self.base_fee_serializer - .serialize(&value.base_fee, buffer)?; - - Ok(()) - } -} - -pub struct DeferredRegistrySlotChangesDeserializer { - deferred_registry_slot_changes_length: U64VarIntDeserializer, - call_id_deserializer: DeferredCallIdDeserializer, - calls_set_or_delete_deserializer: - SetOrDeleteDeserializer, - gas_deserializer: SetOrKeepDeserializer, - base_fee_deserializer: SetOrKeepDeserializer, -} - -impl DeferredRegistrySlotChangesDeserializer { - pub fn new(thread_count: u8, max_gas: u64, max_deferred_calls_pool_changes: u64) -> Self { - Self { - deferred_registry_slot_changes_length: U64VarIntDeserializer::new( - Included(u64::MIN), - Included(max_deferred_calls_pool_changes), - ), - call_id_deserializer: DeferredCallIdDeserializer::new(), - calls_set_or_delete_deserializer: SetOrDeleteDeserializer::new( - DeferredCallDeserializer::new(thread_count), - ), - gas_deserializer: SetOrKeepDeserializer::new(U64VarIntDeserializer::new( - Included(0), - Included(max_gas), - )), - base_fee_deserializer: SetOrKeepDeserializer::new(AmountDeserializer::new( - Included(Amount::MIN), - Included(Amount::MAX), - )), - } - } -} - -impl Deserializer for DeferredRegistrySlotChangesDeserializer { - fn deserialize<'a, E: ParseError<&'a [u8]> + ContextError<&'a [u8]>>( - &self, - buffer: &'a [u8], - ) -> IResult<&'a [u8], DeferredRegistrySlotChanges, E> { - unimplemented!("DeferredRegistrySlotChangesDeserializer::deserialize") - // context( - // "Failed DeferredRegistrySlotChanges deserialization", - // length_count( - // context("Failed length deserialization", |input| { - // self.async_pool_changes_length.deserialize(input) - // }), - // |input: &'a [u8]| { - // tuple(( - // context("Failed id deserialization", |input| { - // self.call_id_deserializer.deserialize(input) - // }), - // context( - // "Failed set_update_or_delete_message deserialization", - // |input| { - // self.set_update_or_delete_message_deserializer - // .deserialize(input) - // }, - // ), - // ))(input) - // }, - // ), - // ) - // .map(|vec| { - // DeferredRegistrySlotChanges(vec.into_iter().map(|data| (data.0, data.1)).collect()) - // }) - // .parse(buffer) - } -} - -#[derive(Default, Debug, Clone, Serialize, Deserialize)] -pub struct DeferredRegistryChanges { - pub slots: BTreeMap, - pub total_gas: DeferredRegistryGasChange, -} - -impl DeferredRegistryChanges { - pub fn merge(&mut self, other: DeferredRegistryChanges) { - for (slot, changes) in other.slots { - match self.slots.entry(slot) { - std::collections::btree_map::Entry::Occupied(mut entry) => { - entry.get_mut().merge(changes); - } - std::collections::btree_map::Entry::Vacant(entry) => { - entry.insert(changes); - } - } - } - match other.total_gas { - DeferredRegistryGasChange::Set(v) => self.total_gas = DeferredRegistryGasChange::Set(v), - DeferredRegistryGasChange::Keep => {} - } - } - - pub fn delete_call(&mut self, target_slot: Slot, id: &DeferredCallId) { - self.slots.entry(target_slot).or_default().delete_call(id) - } - - pub fn set_call(&mut self, id: DeferredCallId, call: DeferredCall) { - self.slots - .entry(call.target_slot.clone()) - .or_default() - .set_call(id, call); - } - - pub fn get_call(&self, target_slot: &Slot, id: &DeferredCallId) -> Option<&DeferredCall> { - self.slots - .get(target_slot) - .and_then(|slot_changes| slot_changes.get_call(id)) - } - - pub fn get_slot_gas(&self, target_slot: &Slot) -> Option { - self.slots - .get(target_slot) - .and_then(|slot_changes| slot_changes.get_gas()) - } - - pub fn set_slot_gas(&mut self, target_slot: Slot, gas: u64) { - self.slots.entry(target_slot).or_default().set_gas(gas); - } - - pub fn set_slot_base_fee(&mut self, target_slot: Slot, base_fee: Amount) { - self.slots - .entry(target_slot) - .or_default() - .set_base_fee(base_fee); - } - - pub fn get_slot_base_fee(&self, target_slot: &Slot) -> Option { - self.slots - .get(target_slot) - .and_then(|slot_changes| slot_changes.get_base_fee()) - } - - pub fn set_total_gas(&mut self, gas: u128) { - self.total_gas = DeferredRegistryGasChange::Set(gas); - } - - pub fn get_total_gas(&self) -> Option { - match self.total_gas { - DeferredRegistryGasChange::Set(v) => Some(v), - DeferredRegistryGasChange::Keep => None, - } - } -} - /// A structure that lists slot calls for a given slot, /// as well as global gas usage statistics. #[derive(Debug, Clone)] diff --git a/massa-deferred-calls/src/registry_changes.rs b/massa-deferred-calls/src/registry_changes.rs new file mode 100644 index 00000000000..bd97b1af0b2 --- /dev/null +++ b/massa-deferred-calls/src/registry_changes.rs @@ -0,0 +1,199 @@ +use std::{collections::BTreeMap, ops::Bound}; + +use massa_ledger_exports::{SetOrKeepDeserializer, SetOrKeepSerializer}; +use massa_models::{ + amount::Amount, + deferred_call_id::DeferredCallId, + slot::{Slot, SlotDeserializer, SlotSerializer}, +}; +use massa_serialization::{ + Deserializer, SerializeError, Serializer, U128VarIntDeserializer, U128VarIntSerializer, + U64VarIntDeserializer, U64VarIntSerializer, +}; +use nom::{ + error::{context, ContextError, ParseError}, + multi::length_count, + IResult, +}; +use serde::{Deserialize, Serialize}; + +use crate::{ + slot_changes::{ + DeferredRegistrySlotChanges, DeferredRegistrySlotChangesDeserializer, + DeferredRegistrySlotChangesSerializer, + }, + DeferredCall, DeferredRegistryGasChange, +}; +use std::ops::Bound::Included; + +#[derive(Default, Debug, Clone, Serialize, Deserialize)] +pub struct DeferredRegistryChanges { + pub slots: BTreeMap, + pub total_gas: DeferredRegistryGasChange, +} + +impl DeferredRegistryChanges { + pub fn merge(&mut self, other: DeferredRegistryChanges) { + for (slot, changes) in other.slots { + match self.slots.entry(slot) { + std::collections::btree_map::Entry::Occupied(mut entry) => { + entry.get_mut().merge(changes); + } + std::collections::btree_map::Entry::Vacant(entry) => { + entry.insert(changes); + } + } + } + match other.total_gas { + DeferredRegistryGasChange::Set(v) => self.total_gas = DeferredRegistryGasChange::Set(v), + DeferredRegistryGasChange::Keep => {} + } + } + + pub fn delete_call(&mut self, target_slot: Slot, id: &DeferredCallId) { + self.slots.entry(target_slot).or_default().delete_call(id) + } + + pub fn set_call(&mut self, id: DeferredCallId, call: DeferredCall) { + self.slots + .entry(call.target_slot.clone()) + .or_default() + .set_call(id, call); + } + + pub fn get_call(&self, target_slot: &Slot, id: &DeferredCallId) -> Option<&DeferredCall> { + self.slots + .get(target_slot) + .and_then(|slot_changes| slot_changes.get_call(id)) + } + + pub fn get_slot_gas(&self, target_slot: &Slot) -> Option { + self.slots + .get(target_slot) + .and_then(|slot_changes| slot_changes.get_gas()) + } + + pub fn set_slot_gas(&mut self, target_slot: Slot, gas: u64) { + self.slots.entry(target_slot).or_default().set_gas(gas); + } + + pub fn set_slot_base_fee(&mut self, target_slot: Slot, base_fee: Amount) { + self.slots + .entry(target_slot) + .or_default() + .set_base_fee(base_fee); + } + + pub fn get_slot_base_fee(&self, target_slot: &Slot) -> Option { + self.slots + .get(target_slot) + .and_then(|slot_changes| slot_changes.get_base_fee()) + } + + pub fn set_total_gas(&mut self, gas: u128) { + self.total_gas = DeferredRegistryGasChange::Set(gas); + } + + pub fn get_total_gas(&self) -> Option { + match self.total_gas { + DeferredRegistryGasChange::Set(v) => Some(v), + DeferredRegistryGasChange::Keep => None, + } + } +} + +pub struct DeferredRegistryChangesSerializer { + slots_length: U64VarIntSerializer, + slot_changes_serializer: DeferredRegistrySlotChangesSerializer, + slot_serializer: SlotSerializer, + total_gas_serializer: SetOrKeepSerializer, +} + +impl DeferredRegistryChangesSerializer { + pub fn new() -> Self { + Self { + slots_length: U64VarIntSerializer::new(), + slot_changes_serializer: DeferredRegistrySlotChangesSerializer::new(), + slot_serializer: SlotSerializer::new(), + total_gas_serializer: SetOrKeepSerializer::new(U128VarIntSerializer::new()), + } + } +} + +impl Serializer for DeferredRegistryChangesSerializer { + fn serialize( + &self, + value: &DeferredRegistryChanges, + buffer: &mut Vec, + ) -> Result<(), SerializeError> { + self.slots_length.serialize( + &(value.slots.len().try_into().map_err(|_| { + SerializeError::GeneralError("Fail to transform usize to u64".to_string()) + })?), + buffer, + )?; + + for (slot, changes) in &value.slots { + self.slot_serializer.serialize(slot, buffer)?; + self.slot_changes_serializer.serialize(changes, buffer)?; + } + + self.total_gas_serializer + .serialize(&value.total_gas, buffer)?; + + Ok(()) + } +} + +// todo deserialize + +pub struct DeferredRegistryChangesDeserializer { + slots_length: U64VarIntDeserializer, + slot_changes_deserializer: DeferredRegistrySlotChangesDeserializer, + slot_deserializer: SlotDeserializer, + total_gas_deserializer: SetOrKeepDeserializer, +} + +impl DeferredRegistryChangesDeserializer { + pub fn new(thread_count: u8, max_gas: u64, max_deferred_calls_pool_changes: u64) -> Self { + Self { + slots_length: U64VarIntDeserializer::new( + Included(u64::MIN), + Included(max_deferred_calls_pool_changes), + ), + slot_changes_deserializer: DeferredRegistrySlotChangesDeserializer::new( + thread_count, + max_gas, + max_deferred_calls_pool_changes, + ), + slot_deserializer: SlotDeserializer::new( + (Bound::Included(0), Bound::Included(u64::MAX)), + (Bound::Included(0), Bound::Excluded(thread_count)), + ), + total_gas_deserializer: SetOrKeepDeserializer::new(U128VarIntDeserializer::new( + Included(u128::MIN), + Included(u128::MAX), + )), + } + } +} + +impl Deserializer for DeferredRegistryChangesDeserializer { + fn deserialize<'a, E: ParseError<&'a [u8]> + ContextError<&'a [u8]>>( + &self, + buffer: &'a [u8], + ) -> IResult<&'a [u8], DeferredRegistryChanges, E> { + unimplemented!("DeferredRegistryChangesDeserializer::deserialize") + // context( + // "Failed DeferredRegistryChanges deserialization", + // length_count( + // context("Failed length deserialization", |input| { + // self.slots_length.deserialize(input) + // }), + // |input| { + + // }, + // ), + // ) + } +} diff --git a/massa-deferred-calls/src/slot_changes.rs b/massa-deferred-calls/src/slot_changes.rs new file mode 100644 index 00000000000..cebccd18a13 --- /dev/null +++ b/massa-deferred-calls/src/slot_changes.rs @@ -0,0 +1,274 @@ +use std::collections::BTreeMap; + +use crate::{ + call::{DeferredCallDeserializer, DeferredCallSerializer}, + DeferredCall, DeferredRegistryBaseFeeChange, DeferredRegistryCallChange, + DeferredRegistryGasChange, +}; +use massa_ledger_exports::{ + SetOrDeleteDeserializer, SetOrDeleteSerializer, SetOrKeepDeserializer, SetOrKeepSerializer, +}; +use massa_models::{ + amount::{Amount, AmountDeserializer, AmountSerializer}, + deferred_call_id::{DeferredCallId, DeferredCallIdDeserializer, DeferredCallIdSerializer}, +}; +use massa_serialization::{ + Deserializer, SerializeError, Serializer, U64VarIntDeserializer, U64VarIntSerializer, +}; +use nom::{ + error::{ContextError, ParseError}, + IResult, +}; +use serde::{Deserialize, Serialize}; +use std::ops::Bound::Included; + +#[derive(Default, Debug, Clone, Serialize, Deserialize)] +pub struct DeferredRegistrySlotChanges { + pub(crate) calls: BTreeMap, + pub(crate) gas: DeferredRegistryGasChange, + pub(crate) base_fee: DeferredRegistryBaseFeeChange, +} + +impl DeferredRegistrySlotChanges { + pub fn merge(&mut self, other: DeferredRegistrySlotChanges) { + unimplemented!("DeferredRegistrySlotChanges::merge") + // for (id, change) in other.calls { + // match self.calls.entry(id) { + // std::collections::btree_map::Entry::Occupied(mut entry) => { + // entry.get_mut().merge(change); + // } + // std::collections::btree_map::Entry::Vacant(entry) => { + // entry.insert(change); + // } + // } + // } + // match other.gas { + // DeferredRegistryGasChange::Set(v) => self.gas = DeferredRegistryGasChange::Set(v), + // DeferredRegistryGasChange::Keep => {} + // } + // match other.base_fee { + // DeferredRegistryGasChange::Set(v) => self.base_fee = DeferredRegistryGasChange::Set(v), + // DeferredRegistryGasChange::Keep => {} + // } + } + + pub fn delete_call(&mut self, id: &DeferredCallId) { + unimplemented!("DeferredRegistrySlotChanges::delete_call") + // match self.calls.entry(id.clone()) { + // std::collections::btree_map::Entry::Occupied(mut v) => v.get_mut().delete_call(), + // std::collections::btree_map::Entry::Vacant(v) => { + // v.insert(DeferredRegistryCallChange::Delete); + // } + // } + } + + pub fn set_call(&mut self, id: DeferredCallId, call: DeferredCall) { + self.calls.insert(id, DeferredRegistryCallChange::Set(call)); + } + + pub fn get_call(&self, id: &DeferredCallId) -> Option<&DeferredCall> { + unimplemented!("DeferredRegistrySlotChanges::get_call") + // self.calls.get(id).and_then(|change| change.get_call()) + } + + pub fn set_gas(&mut self, gas: u64) { + self.gas = DeferredRegistryGasChange::Set(gas); + } + + pub fn get_gas(&self) -> Option { + match self.gas { + DeferredRegistryGasChange::Set(v) => Some(v), + DeferredRegistryGasChange::Keep => None, + } + } + + pub fn get_base_fee(&self) -> Option { + match self.base_fee { + DeferredRegistryGasChange::Set(v) => Some(v), + DeferredRegistryGasChange::Keep => None, + } + } + + pub fn set_base_fee(&mut self, base_fee: Amount) { + self.base_fee = DeferredRegistryGasChange::Set(base_fee); + } +} + +pub struct DeferredRegistrySlotChangesSerializer { + deferred_registry_slot_changes_length: U64VarIntSerializer, + call_id_serializer: DeferredCallIdSerializer, + calls_set_or_delete_serializer: SetOrDeleteSerializer, + gas_serializer: SetOrKeepSerializer, + base_fee_serializer: SetOrKeepSerializer, +} + +impl DeferredRegistrySlotChangesSerializer { + pub fn new() -> Self { + Self { + deferred_registry_slot_changes_length: U64VarIntSerializer::new(), + call_id_serializer: DeferredCallIdSerializer::new(), + calls_set_or_delete_serializer: SetOrDeleteSerializer::new( + DeferredCallSerializer::new(), + ), + gas_serializer: SetOrKeepSerializer::new(U64VarIntSerializer::new()), + base_fee_serializer: SetOrKeepSerializer::new(AmountSerializer::new()), + } + } +} + +impl Serializer for DeferredRegistrySlotChangesSerializer { + fn serialize( + &self, + value: &DeferredRegistrySlotChanges, + buffer: &mut Vec, + ) -> Result<(), massa_serialization::SerializeError> { + self.deferred_registry_slot_changes_length.serialize( + &(value.calls.len().try_into().map_err(|_| { + SerializeError::GeneralError("Fail to transform usize to u64".to_string()) + })?), + buffer, + )?; + for (id, call) in &value.calls { + self.call_id_serializer.serialize(id, buffer)?; + self.calls_set_or_delete_serializer + .serialize(call, buffer)?; + } + self.gas_serializer.serialize(&value.gas, buffer)?; + self.base_fee_serializer + .serialize(&value.base_fee, buffer)?; + + Ok(()) + } +} + +pub struct DeferredRegistrySlotChangesDeserializer { + deferred_registry_slot_changes_length: U64VarIntDeserializer, + call_id_deserializer: DeferredCallIdDeserializer, + calls_set_or_delete_deserializer: + SetOrDeleteDeserializer, + gas_deserializer: SetOrKeepDeserializer, + base_fee_deserializer: SetOrKeepDeserializer, +} + +impl DeferredRegistrySlotChangesDeserializer { + pub fn new(thread_count: u8, max_gas: u64, max_deferred_calls_pool_changes: u64) -> Self { + Self { + deferred_registry_slot_changes_length: U64VarIntDeserializer::new( + Included(u64::MIN), + Included(max_deferred_calls_pool_changes), + ), + call_id_deserializer: DeferredCallIdDeserializer::new(), + calls_set_or_delete_deserializer: SetOrDeleteDeserializer::new( + DeferredCallDeserializer::new(thread_count), + ), + gas_deserializer: SetOrKeepDeserializer::new(U64VarIntDeserializer::new( + Included(0), + Included(max_gas), + )), + base_fee_deserializer: SetOrKeepDeserializer::new(AmountDeserializer::new( + Included(Amount::MIN), + Included(Amount::MAX), + )), + } + } +} + +impl Deserializer for DeferredRegistrySlotChangesDeserializer { + fn deserialize<'a, E: ParseError<&'a [u8]> + ContextError<&'a [u8]>>( + &self, + buffer: &'a [u8], + ) -> IResult<&'a [u8], DeferredRegistrySlotChanges, E> { + unimplemented!("DeferredRegistrySlotChangesDeserializer::deserialize") + // context( + // "Failed DeferredRegistrySlotChanges deserialization", + // length_count( + // context("Failed length deserialization", |input| { + // self.async_pool_changes_length.deserialize(input) + // }), + // |input: &'a [u8]| { + // tuple(( + // context("Failed id deserialization", |input| { + // self.call_id_deserializer.deserialize(input) + // }), + // context( + // "Failed set_update_or_delete_message deserialization", + // |input| { + // self.set_update_or_delete_message_deserializer + // .deserialize(input) + // }, + // ), + // ))(input) + // }, + // ), + // ) + // .map(|vec| { + // DeferredRegistrySlotChanges(vec.into_iter().map(|data| (data.0, data.1)).collect()) + // }) + // .parse(buffer) + } +} + +#[cfg(test)] +mod tests { + use std::str::FromStr; + + use massa_models::{ + address::Address, amount::Amount, deferred_call_id::DeferredCallId, slot::Slot, + }; + use massa_serialization::{DeserializeError, Deserializer, Serializer}; + + use crate::{DeferredCall, DeferredRegistryBaseFeeChange}; + + use super::{ + DeferredRegistrySlotChanges, DeferredRegistrySlotChangesDeserializer, + DeferredRegistrySlotChangesSerializer, + }; + + #[test] + fn test_slot_changes_ser_deser() { + let mut registry_slot_changes = DeferredRegistrySlotChanges::default(); + registry_slot_changes.set_base_fee(Amount::from_str("100").unwrap()); + registry_slot_changes.set_gas(100_000); + let target_slot = Slot { + thread: 5, + period: 1, + }; + + let call = DeferredCall::new( + Address::from_str("AU12dG5xP1RDEB5ocdHkymNVvvSJmUL9BgHwCksDowqmGWxfpm93x").unwrap(), + target_slot.clone(), + Address::from_str("AS127QtY6Hzm6BnJc9wqCBfPNvEH9fKer3LiMNNQmcX3MzLwCL6G6").unwrap(), + "receive".to_string(), + vec![42, 42, 42, 42], + Amount::from_raw(100), + 3000000, + Amount::from_raw(1), + false, + ); + let id = DeferredCallId::new( + 0, + Slot { + thread: 5, + period: 1, + }, + 1, + &[], + ) + .unwrap(); + + registry_slot_changes.set_call(id, call); + + let mut buffer = Vec::new(); + let serializer = DeferredRegistrySlotChangesSerializer::new(); + serializer + .serialize(®istry_slot_changes, &mut buffer) + .unwrap(); + + let deserializer = DeferredRegistrySlotChangesDeserializer::new(32, 3000000, 100_000); + let (rest, changes_deser) = deserializer + .deserialize::(&buffer) + .unwrap(); + assert!(rest.is_empty()); + assert_eq!(changes_deser.calls, registry_slot_changes.calls); + } +} diff --git a/massa-execution-worker/src/speculative_deferred_calls.rs b/massa-execution-worker/src/speculative_deferred_calls.rs index 647982f4e3f..fceab4b7a25 100644 --- a/massa-execution-worker/src/speculative_deferred_calls.rs +++ b/massa-execution-worker/src/speculative_deferred_calls.rs @@ -1,7 +1,9 @@ //! Speculative async call registry. use crate::active_history::ActiveHistory; -use massa_deferred_calls::{DeferredCall, DeferredRegistryChanges, DeferredSlotCalls}; +use massa_deferred_calls::{ + registry_changes::DeferredRegistryChanges, DeferredCall, DeferredSlotCalls, +}; use massa_execution_exports::ExecutionError; use massa_final_state::FinalStateController; use massa_models::{ diff --git a/massa-execution-worker/src/tests/tests_active_history.rs b/massa-execution-worker/src/tests/tests_active_history.rs index 9d384b422fb..46334a7bf5c 100644 --- a/massa-execution-worker/src/tests/tests_active_history.rs +++ b/massa-execution-worker/src/tests/tests_active_history.rs @@ -43,6 +43,7 @@ fn test_active_history_deferred_credits() { state_changes: StateChanges { ledger_changes: Default::default(), async_pool_changes: Default::default(), + deferred_call_changes: Default::default(), pos_changes: PoSChanges { seed_bits: Default::default(), roll_changes: Default::default(), diff --git a/massa-final-state/src/state_changes.rs b/massa-final-state/src/state_changes.rs index ba6ab8d53d0..b9ab84b186d 100644 --- a/massa-final-state/src/state_changes.rs +++ b/massa-final-state/src/state_changes.rs @@ -5,8 +5,8 @@ use massa_async_pool::{ AsyncPoolChanges, AsyncPoolChangesDeserializer, AsyncPoolChangesSerializer, }; -use massa_deferred_calls::{ - DeferredRegistryChanges, DeferredRegistrySlotChanges, DeferredRegistrySlotChangesDeserializer, +use massa_deferred_calls::registry_changes::{ + DeferredRegistryChanges, DeferredRegistryChangesSerializer, }; use massa_executed_ops::{ ExecutedDenunciationsChanges, ExecutedDenunciationsChangesDeserializer, @@ -50,6 +50,7 @@ pub struct StateChanges { pub struct StateChangesSerializer { ledger_changes_serializer: LedgerChangesSerializer, async_pool_changes_serializer: AsyncPoolChangesSerializer, + deferred_call_changes_serializer: DeferredRegistryChangesSerializer, pos_changes_serializer: PoSChangesSerializer, ops_changes_serializer: ExecutedOpsChangesSerializer, de_changes_serializer: ExecutedDenunciationsChangesSerializer, @@ -68,6 +69,7 @@ impl StateChangesSerializer { Self { ledger_changes_serializer: LedgerChangesSerializer::new(), async_pool_changes_serializer: AsyncPoolChangesSerializer::new(), + deferred_call_changes_serializer: DeferredRegistryChangesSerializer::new(), pos_changes_serializer: PoSChangesSerializer::new(), ops_changes_serializer: ExecutedOpsChangesSerializer::new(), de_changes_serializer: ExecutedDenunciationsChangesSerializer::new(), @@ -82,6 +84,8 @@ impl Serializer for StateChangesSerializer { .serialize(&value.ledger_changes, buffer)?; self.async_pool_changes_serializer .serialize(&value.async_pool_changes, buffer)?; + self.deferred_call_changes_serializer + .serialize(&value.deferred_call_changes, buffer)?; self.pos_changes_serializer .serialize(&value.pos_changes, buffer)?; self.ops_changes_serializer @@ -98,7 +102,7 @@ impl Serializer for StateChangesSerializer { pub struct StateChangesDeserializer { ledger_changes_deserializer: LedgerChangesDeserializer, async_pool_changes_deserializer: AsyncPoolChangesDeserializer, - deferred_call_changes_deserializer: DeferredRegistrySlotChangesDeserializer, + // todo deferred_call_changes_deserializer: DeferredRegistrySlotChangesDeserializer, pos_changes_deserializer: PoSChangesDeserializer, ops_changes_deserializer: ExecutedOpsChangesDeserializer, de_changes_deserializer: ExecutedDenunciationsChangesDeserializer, @@ -140,11 +144,11 @@ impl StateChangesDeserializer { max_datastore_key_length as u32, ), // todo pass max gas && max deferred call changes - deferred_call_changes_deserializer: DeferredRegistrySlotChangesDeserializer::new( - thread_count, - u64::MAX, - 100_000, - ), + // deferred_call_changes_deserializer: DeferredRegistrySlotChangesDeserializer::new( + // thread_count, + // u64::MAX, + // 100_000, + // ), pos_changes_deserializer: PoSChangesDeserializer::new( thread_count, max_rolls_length, diff --git a/massa-final-state/src/test_exports/config.rs b/massa-final-state/src/test_exports/config.rs index 5321441ef96..fdcaa96a795 100644 --- a/massa-final-state/src/test_exports/config.rs +++ b/massa-final-state/src/test_exports/config.rs @@ -9,6 +9,7 @@ use num::rational::Ratio; use crate::{FinalState, FinalStateConfig}; use massa_async_pool::{AsyncPool, AsyncPoolConfig}; use massa_db_exports::ShareableMassaDBController; +use massa_deferred_calls::DeferredCallRegistry; use massa_executed_ops::{ ExecutedDenunciations, ExecutedDenunciationsConfig, ExecutedOps, ExecutedOpsConfig, }; @@ -34,6 +35,7 @@ impl FinalState { FinalState { ledger: Box::new(FinalLedger::new(config.ledger_config.clone(), db.clone())), async_pool: AsyncPool::new(config.async_pool_config.clone(), db.clone()), + deferred_call_registry: DeferredCallRegistry::new(db.clone()), pos_state, executed_ops: ExecutedOps::new(config.executed_ops_config.clone(), db.clone()), executed_denunciations: ExecutedDenunciations::new( diff --git a/massa-final-state/src/test_exports/mock.rs b/massa-final-state/src/test_exports/mock.rs index 741a2f27589..5c9d2d55852 100644 --- a/massa-final-state/src/test_exports/mock.rs +++ b/massa-final-state/src/test_exports/mock.rs @@ -9,10 +9,12 @@ use std::{ sync::Arc, }; +use crate::{controller_trait::FinalStateController, FinalState, FinalStateConfig}; use massa_async_pool::AsyncPool; use massa_db_exports::{ DBBatch, MassaIteratorMode, ShareableMassaDBController, METADATA_CF, STATE_CF, STATE_HASH_KEY, }; +use massa_deferred_calls::DeferredCallRegistry; use massa_executed_ops::{ExecutedDenunciations, ExecutedOps}; use massa_ledger_exports::{LedgerConfig, LedgerController, LedgerEntry, LedgerError}; use massa_ledger_worker::FinalLedger; @@ -27,14 +29,13 @@ use massa_versioning::versioning::MipStore; use parking_lot::RwLock; use tempfile::NamedTempFile; -use crate::{controller_trait::FinalStateController, FinalState, FinalStateConfig}; - #[allow(clippy::too_many_arguments)] /// Create a `FinalState` from pre-set values pub fn create_final_state( config: FinalStateConfig, ledger: Box, async_pool: AsyncPool, + deferred_call_registry: DeferredCallRegistry, pos_state: PoSFinalState, executed_ops: ExecutedOps, executed_denunciations: ExecutedDenunciations, @@ -45,6 +46,7 @@ pub fn create_final_state( config, ledger, async_pool, + deferred_call_registry, pos_state, executed_ops, executed_denunciations, diff --git a/massa-serialization/src/lib.rs b/massa-serialization/src/lib.rs index 79d75060879..9382241d85f 100644 --- a/massa-serialization/src/lib.rs +++ b/massa-serialization/src/lib.rs @@ -252,7 +252,8 @@ macro_rules! gen_varint { gen_varint! { u16, U16VarIntSerializer, u16_buffer, U16VarIntDeserializer, "`u16`"; u32, U32VarIntSerializer, u32_buffer, U32VarIntDeserializer, "`u32`"; -u64, U64VarIntSerializer, u64_buffer, U64VarIntDeserializer, "`u64`" +u64, U64VarIntSerializer, u64_buffer, U64VarIntDeserializer, "`u64`"; +u128, U128VarIntSerializer, u128_buffer, U128VarIntDeserializer, "`u128`" } #[derive(Clone)] From 7d7e8500f1113fdfc41984487184913c0b417e74 Mon Sep 17 00:00:00 2001 From: modship Date: Wed, 10 Jul 2024 14:33:34 +0200 Subject: [PATCH 014/100] Test(DeferredRegistrySlotChanges) : Ser/deser --- massa-deferred-calls/src/slot_changes.rs | 74 ++++++++++++++---------- 1 file changed, 44 insertions(+), 30 deletions(-) diff --git a/massa-deferred-calls/src/slot_changes.rs b/massa-deferred-calls/src/slot_changes.rs index cebccd18a13..704819998c6 100644 --- a/massa-deferred-calls/src/slot_changes.rs +++ b/massa-deferred-calls/src/slot_changes.rs @@ -16,8 +16,10 @@ use massa_serialization::{ Deserializer, SerializeError, Serializer, U64VarIntDeserializer, U64VarIntSerializer, }; use nom::{ - error::{ContextError, ParseError}, - IResult, + error::{context, ContextError, ParseError}, + multi::length_count, + sequence::tuple, + IResult, Parser, }; use serde::{Deserialize, Serialize}; use std::ops::Bound::Included; @@ -178,33 +180,45 @@ impl Deserializer for DeferredRegistrySlotChangesDe &self, buffer: &'a [u8], ) -> IResult<&'a [u8], DeferredRegistrySlotChanges, E> { - unimplemented!("DeferredRegistrySlotChangesDeserializer::deserialize") - // context( - // "Failed DeferredRegistrySlotChanges deserialization", - // length_count( - // context("Failed length deserialization", |input| { - // self.async_pool_changes_length.deserialize(input) - // }), - // |input: &'a [u8]| { - // tuple(( - // context("Failed id deserialization", |input| { - // self.call_id_deserializer.deserialize(input) - // }), - // context( - // "Failed set_update_or_delete_message deserialization", - // |input| { - // self.set_update_or_delete_message_deserializer - // .deserialize(input) - // }, - // ), - // ))(input) - // }, - // ), - // ) - // .map(|vec| { - // DeferredRegistrySlotChanges(vec.into_iter().map(|data| (data.0, data.1)).collect()) - // }) - // .parse(buffer) + // unimplemented!("DeferredRegistrySlotChangesDeserializer::deserialize") + context( + "Failed DeferredRegistrySlotChanges deserialization", + tuple(( + length_count( + context("Failed length deserialization", |input| { + self.deferred_registry_slot_changes_length + .deserialize(input) + }), + |input: &'a [u8]| { + tuple(( + context("Failed id deserialization", |input| { + self.call_id_deserializer.deserialize(input) + }), + context( + "Failed set_update_or_delete_message deserialization", + |input| self.calls_set_or_delete_deserializer.deserialize(input), + ), + ))(input) + }, + ), + context("Failed gas deserialization", |input| { + self.gas_deserializer.deserialize(input) + }), + context("Failed base fee deserialize", |input| { + self.base_fee_deserializer.deserialize(input) + }), + )), + ) + .map(|(vec, gas, base_fee)| { + let calls = vec.into_iter().collect::>(); + + DeferredRegistrySlotChanges { + calls, + gas, + base_fee, + } + }) + .parse(buffer) } } @@ -217,7 +231,7 @@ mod tests { }; use massa_serialization::{DeserializeError, Deserializer, Serializer}; - use crate::{DeferredCall, DeferredRegistryBaseFeeChange}; + use crate::DeferredCall; use super::{ DeferredRegistrySlotChanges, DeferredRegistrySlotChangesDeserializer, From f9453862b75d3ce9dee610687727799ad338c66d Mon Sep 17 00:00:00 2001 From: modship Date: Wed, 10 Jul 2024 15:18:21 +0200 Subject: [PATCH 015/100] Test(DeferredRegistryChanges) : Ser/Deser --- massa-deferred-calls/src/registry_changes.rs | 125 +++++++++++++++++-- massa-deferred-calls/src/slot_changes.rs | 1 - 2 files changed, 112 insertions(+), 14 deletions(-) diff --git a/massa-deferred-calls/src/registry_changes.rs b/massa-deferred-calls/src/registry_changes.rs index bd97b1af0b2..2f0e3011231 100644 --- a/massa-deferred-calls/src/registry_changes.rs +++ b/massa-deferred-calls/src/registry_changes.rs @@ -13,7 +13,8 @@ use massa_serialization::{ use nom::{ error::{context, ContextError, ParseError}, multi::length_count, - IResult, + sequence::tuple, + IResult, Parser, }; use serde::{Deserialize, Serialize}; @@ -183,17 +184,115 @@ impl Deserializer for DeferredRegistryChangesDeserializ &self, buffer: &'a [u8], ) -> IResult<&'a [u8], DeferredRegistryChanges, E> { - unimplemented!("DeferredRegistryChangesDeserializer::deserialize") - // context( - // "Failed DeferredRegistryChanges deserialization", - // length_count( - // context("Failed length deserialization", |input| { - // self.slots_length.deserialize(input) - // }), - // |input| { - - // }, - // ), - // ) + context( + "Failed DeferredRegistryChanges deserialization", + tuple(( + length_count( + context("Failed length deserialization", |input| { + self.slots_length.deserialize(input) + }), + |input| { + tuple(( + context("Failed slot deserialization", |input| { + self.slot_deserializer.deserialize(input) + }), + context( + "Failed set_update_or_delete_message deserialization", + |input| self.slot_changes_deserializer.deserialize(input), + ), + ))(input) + }, + ), + context("Failed total_gas deserialization", |input| { + self.total_gas_deserializer.deserialize(input) + }), + )), + ) + .map(|(changes, total_gas)| DeferredRegistryChanges { + slots: changes.into_iter().collect::>(), + total_gas, + }) + .parse(buffer) + } +} + +#[cfg(test)] +mod tests { + use std::str::FromStr; + + use massa_models::{address::Address, amount::Amount, deferred_call_id::DeferredCallId}; + use massa_serialization::DeserializeError; + + use crate::{ + registry_changes::{ + DeferredRegistryChangesDeserializer, DeferredRegistryChangesSerializer, + }, + slot_changes::DeferredRegistrySlotChanges, + DeferredCall, + }; + + #[test] + fn test_deferred_registry_ser_deser() { + use crate::DeferredRegistryChanges; + use massa_models::slot::Slot; + use massa_serialization::{Deserializer, Serializer}; + use std::collections::BTreeMap; + + let mut changes = DeferredRegistryChanges { + slots: BTreeMap::new(), + total_gas: Default::default(), + }; + + let mut registry_slot_changes = DeferredRegistrySlotChanges::default(); + registry_slot_changes.set_base_fee(Amount::from_str("100").unwrap()); + registry_slot_changes.set_gas(100_000); + let target_slot = Slot { + thread: 5, + period: 1, + }; + + let call = DeferredCall::new( + Address::from_str("AU12dG5xP1RDEB5ocdHkymNVvvSJmUL9BgHwCksDowqmGWxfpm93x").unwrap(), + target_slot.clone(), + Address::from_str("AS127QtY6Hzm6BnJc9wqCBfPNvEH9fKer3LiMNNQmcX3MzLwCL6G6").unwrap(), + "receive".to_string(), + vec![42, 42, 42, 42], + Amount::from_raw(100), + 3000000, + Amount::from_raw(1), + false, + ); + let id = DeferredCallId::new( + 0, + Slot { + thread: 5, + period: 1, + }, + 1, + &[], + ) + .unwrap(); + registry_slot_changes.set_call(id, call); + + changes + .slots + .insert(target_slot.clone(), registry_slot_changes); + + changes.set_total_gas(100_000); + + let mut buffer = Vec::new(); + let serializer = DeferredRegistryChangesSerializer::new(); + serializer.serialize(&changes, &mut buffer).unwrap(); + + let deserializer = DeferredRegistryChangesDeserializer::new(32, 300_000, 10_000); + let (rest, deserialized) = deserializer + .deserialize::(&buffer) + .unwrap(); + + assert_eq!(rest.len(), 0); + let base = changes.slots.get(&target_slot).unwrap(); + let slot_changes_deser = deserialized.slots.get(&target_slot).unwrap(); + assert_eq!(base.calls, slot_changes_deser.calls); + assert_eq!(changes.total_gas, deserialized.total_gas); } } diff --git a/massa-deferred-calls/src/slot_changes.rs b/massa-deferred-calls/src/slot_changes.rs index 704819998c6..e8430422ffa 100644 --- a/massa-deferred-calls/src/slot_changes.rs +++ b/massa-deferred-calls/src/slot_changes.rs @@ -180,7 +180,6 @@ impl Deserializer for DeferredRegistrySlotChangesDe &self, buffer: &'a [u8], ) -> IResult<&'a [u8], DeferredRegistrySlotChanges, E> { - // unimplemented!("DeferredRegistrySlotChangesDeserializer::deserialize") context( "Failed DeferredRegistrySlotChanges deserialization", tuple(( From 98145378e28cb9712cb0f63c9056d92fe551472b Mon Sep 17 00:00:00 2001 From: modship Date: Wed, 10 Jul 2024 16:35:53 +0200 Subject: [PATCH 016/100] update StateChanges Deserializer --- massa-deferred-calls/src/lib.rs | 2 +- massa-deferred-calls/src/registry_changes.rs | 42 +++++++++++--------- massa-final-state/src/state_changes.rs | 23 ++++++----- massa-models/src/config/constants.rs | 3 ++ 4 files changed, 39 insertions(+), 31 deletions(-) diff --git a/massa-deferred-calls/src/lib.rs b/massa-deferred-calls/src/lib.rs index 78144bf3805..f5886f2163a 100644 --- a/massa-deferred-calls/src/lib.rs +++ b/massa-deferred-calls/src/lib.rs @@ -132,7 +132,7 @@ impl DeferredSlotCalls { } pub fn apply_changes(&mut self, changes: &DeferredRegistryChanges) { - let Some(slot_changes) = changes.slots.get(&self.slot) else { + let Some(slot_changes) = changes.slots_change.get(&self.slot) else { return; }; for (id, change) in &slot_changes.calls { diff --git a/massa-deferred-calls/src/registry_changes.rs b/massa-deferred-calls/src/registry_changes.rs index 2f0e3011231..034f0c9267d 100644 --- a/massa-deferred-calls/src/registry_changes.rs +++ b/massa-deferred-calls/src/registry_changes.rs @@ -29,14 +29,14 @@ use std::ops::Bound::Included; #[derive(Default, Debug, Clone, Serialize, Deserialize)] pub struct DeferredRegistryChanges { - pub slots: BTreeMap, + pub slots_change: BTreeMap, pub total_gas: DeferredRegistryGasChange, } impl DeferredRegistryChanges { pub fn merge(&mut self, other: DeferredRegistryChanges) { - for (slot, changes) in other.slots { - match self.slots.entry(slot) { + for (slot, changes) in other.slots_change { + match self.slots_change.entry(slot) { std::collections::btree_map::Entry::Occupied(mut entry) => { entry.get_mut().merge(changes); } @@ -52,41 +52,47 @@ impl DeferredRegistryChanges { } pub fn delete_call(&mut self, target_slot: Slot, id: &DeferredCallId) { - self.slots.entry(target_slot).or_default().delete_call(id) + self.slots_change + .entry(target_slot) + .or_default() + .delete_call(id) } pub fn set_call(&mut self, id: DeferredCallId, call: DeferredCall) { - self.slots + self.slots_change .entry(call.target_slot.clone()) .or_default() .set_call(id, call); } pub fn get_call(&self, target_slot: &Slot, id: &DeferredCallId) -> Option<&DeferredCall> { - self.slots + self.slots_change .get(target_slot) .and_then(|slot_changes| slot_changes.get_call(id)) } pub fn get_slot_gas(&self, target_slot: &Slot) -> Option { - self.slots + self.slots_change .get(target_slot) .and_then(|slot_changes| slot_changes.get_gas()) } pub fn set_slot_gas(&mut self, target_slot: Slot, gas: u64) { - self.slots.entry(target_slot).or_default().set_gas(gas); + self.slots_change + .entry(target_slot) + .or_default() + .set_gas(gas); } pub fn set_slot_base_fee(&mut self, target_slot: Slot, base_fee: Amount) { - self.slots + self.slots_change .entry(target_slot) .or_default() .set_base_fee(base_fee); } pub fn get_slot_base_fee(&self, target_slot: &Slot) -> Option { - self.slots + self.slots_change .get(target_slot) .and_then(|slot_changes| slot_changes.get_base_fee()) } @@ -128,13 +134,13 @@ impl Serializer for DeferredRegistryChangesSerializer { buffer: &mut Vec, ) -> Result<(), SerializeError> { self.slots_length.serialize( - &(value.slots.len().try_into().map_err(|_| { + &(value.slots_change.len().try_into().map_err(|_| { SerializeError::GeneralError("Fail to transform usize to u64".to_string()) })?), buffer, )?; - for (slot, changes) in &value.slots { + for (slot, changes) in &value.slots_change { self.slot_serializer.serialize(slot, buffer)?; self.slot_changes_serializer.serialize(changes, buffer)?; } @@ -146,8 +152,6 @@ impl Serializer for DeferredRegistryChangesSerializer { } } -// todo deserialize - pub struct DeferredRegistryChangesDeserializer { slots_length: U64VarIntDeserializer, slot_changes_deserializer: DeferredRegistrySlotChangesDeserializer, @@ -209,7 +213,7 @@ impl Deserializer for DeferredRegistryChangesDeserializ )), ) .map(|(changes, total_gas)| DeferredRegistryChanges { - slots: changes.into_iter().collect::>(), + slots_change: changes.into_iter().collect::>(), total_gas, }) .parse(buffer) @@ -239,7 +243,7 @@ mod tests { use std::collections::BTreeMap; let mut changes = DeferredRegistryChanges { - slots: BTreeMap::new(), + slots_change: BTreeMap::new(), total_gas: Default::default(), }; @@ -275,7 +279,7 @@ mod tests { registry_slot_changes.set_call(id, call); changes - .slots + .slots_change .insert(target_slot.clone(), registry_slot_changes); changes.set_total_gas(100_000); @@ -290,8 +294,8 @@ mod tests { .unwrap(); assert_eq!(rest.len(), 0); - let base = changes.slots.get(&target_slot).unwrap(); - let slot_changes_deser = deserialized.slots.get(&target_slot).unwrap(); + let base = changes.slots_change.get(&target_slot).unwrap(); + let slot_changes_deser = deserialized.slots_change.get(&target_slot).unwrap(); assert_eq!(base.calls, slot_changes_deser.calls); assert_eq!(changes.total_gas, deserialized.total_gas); } diff --git a/massa-final-state/src/state_changes.rs b/massa-final-state/src/state_changes.rs index b9ab84b186d..abeacf5fee3 100644 --- a/massa-final-state/src/state_changes.rs +++ b/massa-final-state/src/state_changes.rs @@ -6,7 +6,7 @@ use massa_async_pool::{ AsyncPoolChanges, AsyncPoolChangesDeserializer, AsyncPoolChangesSerializer, }; use massa_deferred_calls::registry_changes::{ - DeferredRegistryChanges, DeferredRegistryChangesSerializer, + DeferredRegistryChanges, DeferredRegistryChangesDeserializer, DeferredRegistryChangesSerializer, }; use massa_executed_ops::{ ExecutedDenunciationsChanges, ExecutedDenunciationsChangesDeserializer, @@ -102,7 +102,7 @@ impl Serializer for StateChangesSerializer { pub struct StateChangesDeserializer { ledger_changes_deserializer: LedgerChangesDeserializer, async_pool_changes_deserializer: AsyncPoolChangesDeserializer, - // todo deferred_call_changes_deserializer: DeferredRegistrySlotChangesDeserializer, + deferred_call_changes_deserializer: DeferredRegistryChangesDeserializer, pos_changes_deserializer: PoSChangesDeserializer, ops_changes_deserializer: ExecutedOpsChangesDeserializer, de_changes_deserializer: ExecutedDenunciationsChangesDeserializer, @@ -128,6 +128,7 @@ impl StateChangesDeserializer { max_ops_changes_length: u64, endorsement_count: u32, max_de_changes_length: u64, + max_deferred_call_pool_changes: u64, ) -> Self { Self { ledger_changes_deserializer: LedgerChangesDeserializer::new( @@ -143,12 +144,12 @@ impl StateChangesDeserializer { max_function_params_length, max_datastore_key_length as u32, ), - // todo pass max gas && max deferred call changes - // deferred_call_changes_deserializer: DeferredRegistrySlotChangesDeserializer::new( - // thread_count, - // u64::MAX, - // 100_000, - // ), + // todo max gas + deferred_call_changes_deserializer: DeferredRegistryChangesDeserializer::new( + thread_count, + u64::MAX, + max_deferred_call_pool_changes, + ), pos_changes_deserializer: PoSChangesDeserializer::new( thread_count, max_rolls_length, @@ -186,8 +187,7 @@ impl Deserializer for StateChangesDeserializer { self.async_pool_changes_deserializer.deserialize(input) }), context("Failed deferred_call_changes deserialization", |input| { - todo!("Deferred call changes deserialization not implemented") - // self.def.deserialize(input) + self.deferred_call_changes_deserializer.deserialize(input) }), context("Failed roll_state_changes deserialization", |input| { self.pos_changes_deserializer.deserialize(input) @@ -251,10 +251,10 @@ mod test { use massa_async_pool::AsyncMessage; use massa_ledger_exports::{LedgerEntryUpdate, SetUpdateOrDelete}; - use massa_models::address::Address; use massa_models::amount::Amount; use massa_models::bytecode::Bytecode; use massa_models::slot::Slot; + use massa_models::{address::Address, config::MAX_DEFERRED_CALL_POOL_CHANGES}; use massa_serialization::DeserializeError; use massa_models::config::{ @@ -339,6 +339,7 @@ mod test { MAX_EXECUTED_OPS_CHANGES_LENGTH, ENDORSEMENT_COUNT, MAX_DENUNCIATION_CHANGES_LENGTH, + MAX_DEFERRED_CALL_POOL_CHANGES, ) .deserialize::(&serialized) .unwrap(); diff --git a/massa-models/src/config/constants.rs b/massa-models/src/config/constants.rs index 9ca91559eb3..81329b4ae77 100644 --- a/massa-models/src/config/constants.rs +++ b/massa-models/src/config/constants.rs @@ -338,6 +338,9 @@ pub const MAX_DENUNCIATIONS_PER_BLOCK_HEADER: u32 = 128; pub const ROLL_COUNT_TO_SLASH_ON_DENUNCIATION: u64 = 1; /// Maximum size of executed denunciations pub const MAX_DENUNCIATION_CHANGES_LENGTH: u64 = 1_000; +/// Maximum size of deferred call pool changes +// todo define this value +pub const MAX_DEFERRED_CALL_POOL_CHANGES: u64 = 100_000; // Some checks at compile time that should not be ignored! #[allow(clippy::assertions_on_constants)] From 90202d3bc825c032910b457cfea4789cc0b75203 Mon Sep 17 00:00:00 2001 From: modship Date: Fri, 12 Jul 2024 16:01:59 +0200 Subject: [PATCH 017/100] create macros, put_entry , delete_entry on DB --- massa-db-exports/src/constants.rs | 1 + massa-deferred-calls/Cargo.toml | 5 + massa-deferred-calls/src/call.rs | 16 +- massa-deferred-calls/src/lib.rs | 319 ++++++++++++++++++++++++++- massa-deferred-calls/src/macros.rs | 161 ++++++++++++++ massa-final-state/src/final_state.rs | 3 + 6 files changed, 486 insertions(+), 19 deletions(-) create mode 100644 massa-deferred-calls/src/macros.rs diff --git a/massa-db-exports/src/constants.rs b/massa-db-exports/src/constants.rs index 5716f078d63..b92f53811d2 100644 --- a/massa-db-exports/src/constants.rs +++ b/massa-db-exports/src/constants.rs @@ -29,6 +29,7 @@ pub const LEDGER_PREFIX: &str = "ledger/"; pub const MIP_STORE_PREFIX: &str = "versioning/"; pub const MIP_STORE_STATS_PREFIX: &str = "versioning_stats/"; pub const EXECUTION_TRAIL_HASH_PREFIX: &str = "execution_trail_hash/"; +pub const DEFERRED_CALLS_PREFIX: &str = "deferred_calls/"; // Async Pool pub const MESSAGE_DESER_ERROR: &str = "critical: message deserialization failed"; diff --git a/massa-deferred-calls/Cargo.toml b/massa-deferred-calls/Cargo.toml index 1ef255172c5..10a8fe70fc6 100644 --- a/massa-deferred-calls/Cargo.toml +++ b/massa-deferred-calls/Cargo.toml @@ -15,3 +15,8 @@ massa_db_exports = { workspace = true } massa_ledger_exports = { workspace = true } massa_models = { workspace = true } massa_serialization = { workspace = true } + +[dev-dependencies] +tempfile = { workspace = true } +massa_db_worker = { workspace = true } +parking_lot = { workspace = true } diff --git a/massa-deferred-calls/src/call.rs b/massa-deferred-calls/src/call.rs index a76364cd8de..f19c4b985e3 100644 --- a/massa-deferred-calls/src/call.rs +++ b/massa-deferred-calls/src/call.rs @@ -68,13 +68,13 @@ impl DeferredCall { /// Serializer for `AsyncCall` #[derive(Clone)] pub struct DeferredCallSerializer { - slot_serializer: SlotSerializer, - address_serializer: AddressSerializer, - string_serializer: StringSerializer, - vec_u8_serializer: VecU8Serializer, - amount_serializer: AmountSerializer, - u64_var_int_serializer: U64VarIntSerializer, - bool_serializer: BoolSerializer, + pub(crate) slot_serializer: SlotSerializer, + pub(crate) address_serializer: AddressSerializer, + pub(crate) string_serializer: StringSerializer, + pub(crate) vec_u8_serializer: VecU8Serializer, + pub(crate) amount_serializer: AmountSerializer, + pub(crate) u64_var_int_serializer: U64VarIntSerializer, + pub(crate) bool_serializer: BoolSerializer, } impl DeferredCallSerializer { @@ -120,7 +120,7 @@ pub struct DeferredCallDeserializer { string_deserializer: StringDeserializer, vec_u8_deserializer: VecU8Deserializer, amount_deserializer: AmountDeserializer, - u64_var_int_deserializer: U64VarIntDeserializer, + pub(crate) u64_var_int_deserializer: U64VarIntDeserializer, bool_deserializer: BoolDeserializer, } diff --git a/massa-deferred-calls/src/lib.rs b/massa-deferred-calls/src/lib.rs index f5886f2163a..5bcbc027b76 100644 --- a/massa-deferred-calls/src/lib.rs +++ b/massa-deferred-calls/src/lib.rs @@ -1,4 +1,9 @@ -use massa_db_exports::ShareableMassaDBController; +use call::{DeferredCallDeserializer, DeferredCallSerializer}; +use massa_db_exports::{ + DBBatch, ShareableMassaDBController, DEFERRED_CALLS_PREFIX, KEY_SER_ERROR, MESSAGE_DESER_ERROR, + MESSAGE_SER_ERROR, STATE_CF, +}; +use massa_serialization::{DeserializeError, Deserializer, Serializer}; use registry_changes::DeferredRegistryChanges; /// This module implements a new version of the Autonomous Smart Contracts. (ASC) @@ -7,18 +12,25 @@ mod call; pub mod registry_changes; pub mod slot_changes; +#[macro_use] +mod macros; + pub use call::DeferredCall; use massa_ledger_exports::{SetOrDelete, SetOrKeep}; use massa_models::{ amount::Amount, + config::THREAD_COUNT, deferred_call_id::{DeferredCallId, DeferredCallIdDeserializer, DeferredCallIdSerializer}, - slot::{Slot, SlotSerializer}, + slot::Slot, }; use std::collections::BTreeMap; -#[derive(Debug)] +// #[derive(Debug)] pub struct DeferredCallRegistry { db: ShareableMassaDBController, + deferred_call_serializer: DeferredCallSerializer, + deferred_call_id_serializer: DeferredCallIdSerializer, + deferred_call_deserializer: DeferredCallDeserializer, } impl DeferredCallRegistry { @@ -30,27 +42,72 @@ impl DeferredCallRegistry { */ pub fn new(db: ShareableMassaDBController) -> Self { - Self { db } + Self { + db, + deferred_call_serializer: DeferredCallSerializer::new(), + deferred_call_id_serializer: DeferredCallIdSerializer::new(), + deferred_call_deserializer: DeferredCallDeserializer::new(THREAD_COUNT), + } } pub fn get_slot_calls(&self, slot: Slot) -> DeferredSlotCalls { todo!() } + /// Returns the DeferredCall for a given slot and id pub fn get_call(&self, slot: &Slot, id: &DeferredCallId) -> Option { - todo!() + let mut buf_id = Vec::new(); + self.deferred_call_id_serializer + .serialize(id, &mut buf_id) + .expect(MESSAGE_SER_ERROR); + let key = deferred_call_prefix_key!(buf_id, slot.to_bytes_key()); + + let mut serialized_call: Vec = Vec::new(); + for (serialized_key, serialized_value) in self.db.read().prefix_iterator_cf(STATE_CF, &key) + { + if !serialized_key.starts_with(&key) { + break; + } + + serialized_call.extend(serialized_value.iter()); + } + + match self + .deferred_call_deserializer + .deserialize::(&serialized_call) + { + Ok((_rest, call)) => Some(call), + Err(_) => None, + } } /// Returns the total amount of gas booked for a slot - pub fn get_slot_gas(slot: Slot) -> u64 { + pub fn get_slot_gas(&self, slot: Slot) -> u64 { // By default, if it is absent, it is 0 - todo!() + let key = deferred_call_slot_total_gas_key!(slot.to_bytes_key()); + match self.db.read().get_cf(STATE_CF, key) { + Ok(Some(v)) => { + let result = self + .deferred_call_deserializer + .u64_var_int_deserializer + .deserialize::(&v) + .expect(MESSAGE_DESER_ERROR) + .1; + result + } + _ => 0, + } } /// Returns the base fee for a slot pub fn get_slot_base_fee(&self, slot: &Slot) -> Amount { - // By default, if it is absent, it is 0 - todo!() + unimplemented!("get_slot_base_fee"); + // self.db.read().get_cf(handle_cf, key) + // // By default, if it is absent, it is 0 + // self.db.read().get + // .get(ASYNC_CAL_SLOT_PREFIX, slot, BASE_FEE_TAG) + // .map(|v| Amount::from_bytes(v).unwrap()) + // .unwrap_or(Amount::zero()) } /// Returns the total amount of gas booked @@ -58,10 +115,177 @@ impl DeferredCallRegistry { todo!() } - pub fn apply_changes(changes: DeferredRegistryChanges) { + pub fn put_entry( + &self, + slot: &Slot, + call_id: &DeferredCallId, + call: &DeferredCall, + batch: &mut DBBatch, + ) { + let mut buffer_id = Vec::new(); + self.deferred_call_id_serializer + .serialize(call_id, &mut buffer_id) + .expect(MESSAGE_SER_ERROR); + + let slot_bytes = slot.to_bytes_key(); + + let db = self.db.read(); + + // sender address + let mut temp_buffer = Vec::new(); + self.deferred_call_serializer + .address_serializer + .serialize(&call.sender_address, &mut temp_buffer) + .expect(MESSAGE_SER_ERROR); + db.put_or_update_entry_value( + batch, + sender_address_key!(buffer_id, slot_bytes), + &temp_buffer, + ); + temp_buffer.clear(); + + // target slot + self.deferred_call_serializer + .slot_serializer + .serialize(&call.target_slot, &mut temp_buffer) + .expect(MESSAGE_SER_ERROR); + db.put_or_update_entry_value(batch, target_slot_key!(buffer_id, slot_bytes), &temp_buffer); + temp_buffer.clear(); + + // target address + self.deferred_call_serializer + .address_serializer + .serialize(&call.target_address, &mut temp_buffer) + .expect(MESSAGE_SER_ERROR); + db.put_or_update_entry_value( + batch, + target_address_key!(buffer_id, slot_bytes), + &temp_buffer, + ); + temp_buffer.clear(); + + // target function + self.deferred_call_serializer + .string_serializer + .serialize(&call.target_function, &mut temp_buffer) + .expect(MESSAGE_SER_ERROR); + db.put_or_update_entry_value( + batch, + target_function_key!(buffer_id, slot_bytes), + &temp_buffer, + ); + temp_buffer.clear(); + + // parameters + self.deferred_call_serializer + .vec_u8_serializer + .serialize(&call.parameters, &mut temp_buffer) + .expect(MESSAGE_SER_ERROR); + db.put_or_update_entry_value(batch, parameters_key!(buffer_id, slot_bytes), &temp_buffer); + temp_buffer.clear(); + + // coins + self.deferred_call_serializer + .amount_serializer + .serialize(&call.coins, &mut temp_buffer) + .expect(MESSAGE_SER_ERROR); + db.put_or_update_entry_value(batch, coins_key!(buffer_id, slot_bytes), &temp_buffer); + temp_buffer.clear(); + + // max gas + self.deferred_call_serializer + .u64_var_int_serializer + .serialize(&call.max_gas, &mut temp_buffer) + .expect(MESSAGE_SER_ERROR); + db.put_or_update_entry_value(batch, max_gas_key!(buffer_id, slot_bytes), &temp_buffer); + temp_buffer.clear(); + + // fee + self.deferred_call_serializer + .amount_serializer + .serialize(&call.fee, &mut temp_buffer) + .expect(MESSAGE_SER_ERROR); + db.put_or_update_entry_value(batch, fee_key!(buffer_id, slot_bytes), &temp_buffer); + temp_buffer.clear(); + + // cancelled + self.deferred_call_serializer + .bool_serializer + .serialize(&call.cancelled, &mut temp_buffer) + .expect(MESSAGE_SER_ERROR); + db.put_or_update_entry_value(batch, cancelled_key!(buffer_id, slot_bytes), &temp_buffer); + } + + fn delete_entry(&self, id: &DeferredCallId, slot: &Slot, batch: &mut DBBatch) { + let mut buffer_id = Vec::new(); + self.deferred_call_id_serializer + .serialize(id, &mut buffer_id) + .expect(MESSAGE_SER_ERROR); + + let slot_bytes = slot.to_bytes_key(); + + let db = self.db.read(); + + db.delete_key(batch, sender_address_key!(buffer_id, slot_bytes)); + db.delete_key(batch, target_slot_key!(buffer_id, slot_bytes)); + db.delete_key(batch, target_address_key!(buffer_id, slot_bytes)); + db.delete_key(batch, target_function_key!(buffer_id, slot_bytes)); + db.delete_key(batch, parameters_key!(buffer_id, slot_bytes)); + db.delete_key(batch, coins_key!(buffer_id, slot_bytes)); + db.delete_key(batch, max_gas_key!(buffer_id, slot_bytes)); + db.delete_key(batch, fee_key!(buffer_id, slot_bytes)); + db.delete_key(batch, cancelled_key!(buffer_id, slot_bytes)); + } + + pub fn apply_changes_to_batch(&self, changes: DeferredRegistryChanges, batch: &mut DBBatch) { //Note: if a slot gas is zet to 0, delete the slot gas entry // same for base fee - todo!() + + for change in changes.slots_change.iter() { + let slot = change.0; + let slot_changes = change.1; + for (id, call_change) in slot_changes.calls.iter() { + match call_change { + DeferredRegistryCallChange::Set(call) => { + self.put_entry(slot, id, call, batch); + } + DeferredRegistryCallChange::Delete => { + self.delete_entry(id, slot, batch); + } + } + } + match slot_changes.gas { + DeferredRegistryGasChange::Set(v) => { + let key = deferred_call_slot_total_gas_key!(slot.to_bytes_key()); + //Note: if a slot gas is zet to 0, delete the slot gas entry + if v.eq(&0) { + self.db.read().delete_key(batch, key); + } else { + let mut value_ser = Vec::new(); + self.deferred_call_serializer + .u64_var_int_serializer + .serialize(&v, &mut value_ser) + .expect(MESSAGE_SER_ERROR); + self.db + .read() + .put_or_update_entry_value(batch, key, &value_ser); + } + } + DeferredRegistryGasChange::Keep => {} + } + // match slot_changes.base_fee { + // DeferredRegistryBaseFeeChange::Set(v) => { + // if v.eq(&0) { + // batch.delete_key(ASYNC_CAL_SLOT_PREFIX, slot, BASE_FEE_TAG); + // } else { + // let key = BASE_FEE_TAG; + // let value = v.to_bytes().to_vec(); + // batch.put_or_update_entry_value(ASYNC_CAL_SLOT_PREFIX, slot, key, value); + // } + // } + // DeferredRegistryBaseFeeChange::Keep => {} + // } + } } } @@ -159,3 +383,76 @@ impl DeferredSlotCalls { } } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::{DeferredCall, DeferredCallRegistry, DeferredRegistryChanges}; + use massa_db_exports::{ + DBBatch, Key, MassaDBConfig, MassaDBController, ShareableMassaDBController, + DEFERRED_CALLS_PREFIX, STATE_CF, + }; + use massa_db_worker::MassaDB; + use massa_models::{ + address::Address, + amount::Amount, + config::THREAD_COUNT, + deferred_call_id::{DeferredCallId, DeferredCallIdSerializer}, + slot::Slot, + }; + use parking_lot::RwLock; + use std::{str::FromStr, sync::Arc}; + use tempfile::tempdir; + + #[test] + fn apply_changes() { + let temp_dir = tempdir().expect("Unable to create a temp folder"); + let db_config = MassaDBConfig { + path: temp_dir.path().to_path_buf(), + max_history_length: 100, + max_final_state_elements_size: 100, + max_versioning_elements_size: 100, + thread_count: THREAD_COUNT, + max_ledger_backups: 100, + }; + let call_id_serializer = DeferredCallIdSerializer::new(); + let db: ShareableMassaDBController = Arc::new(RwLock::new( + Box::new(MassaDB::new(db_config)) as Box<(dyn MassaDBController + 'static)>, + )); + + let registry = DeferredCallRegistry::new(db); + + let mut changes = DeferredRegistryChanges::default(); + + let target_slot = Slot { + thread: 5, + period: 1, + }; + + let call = DeferredCall::new( + Address::from_str("AU12dG5xP1RDEB5ocdHkymNVvvSJmUL9BgHwCksDowqmGWxfpm93x").unwrap(), + target_slot.clone(), + Address::from_str("AS127QtY6Hzm6BnJc9wqCBfPNvEH9fKer3LiMNNQmcX3MzLwCL6G6").unwrap(), + "receive".to_string(), + vec![42, 42, 42, 42], + Amount::from_raw(100), + 3000000, + Amount::from_raw(1), + false, + ); + let id = DeferredCallId::new(0, target_slot.clone(), 1, &[]).unwrap(); + let mut buf_id = Vec::new(); + call_id_serializer.serialize(&id, &mut buf_id).unwrap(); + + changes.set_call(id.clone(), call.clone()); + + let mut batch = DBBatch::new(); + registry.apply_changes_to_batch(changes, &mut batch); + + registry.db.write().write_batch(batch, DBBatch::new(), None); + + let result = registry.get_call(&target_slot, &id).unwrap(); + assert!(result.target_function.eq(&call.target_function)); + assert_eq!(result.sender_address, call.sender_address); + } +} diff --git a/massa-deferred-calls/src/macros.rs b/massa-deferred-calls/src/macros.rs new file mode 100644 index 00000000000..ee36d3d3083 --- /dev/null +++ b/massa-deferred-calls/src/macros.rs @@ -0,0 +1,161 @@ +use massa_db_exports::DEFERRED_CALLS_PREFIX; + +pub(crate) const CALL_SENDER_ADDRESS: u8 = 1u8; +pub(crate) const CALL_TARGET_SLOT: u8 = 2u8; +pub(crate) const CALL_TARGET_ADDRESS: u8 = 3u8; +pub(crate) const CALL_TARGET_FUNCTION: u8 = 4u8; +pub(crate) const CALL_PARAMETERS: u8 = 5u8; +pub(crate) const CALL_COINS: u8 = 6u8; +pub(crate) const CALL_MAX_GAS: u8 = 7u8; +pub(crate) const CALL_FEE: u8 = 8u8; +pub(crate) const CALL_CANCELED: u8 = 9u8; + +pub(crate) const CALLS_TAG: u8 = 0u8; + +pub(crate) const TOTAL_GAS_TAG: u8 = 1u8; + +#[macro_export] +macro_rules! deferred_call_slot_total_gas_key { + ($slot:expr) => { + [ + DEFERRED_CALLS_PREFIX.as_bytes(), + &$slot[..], + &[$crate::macros::TOTAL_GAS_TAG], + ] + .concat() + }; +} + +#[macro_export] +macro_rules! deferred_call_prefix_key { + ($id:expr, $slot:expr) => { + [ + DEFERRED_CALLS_PREFIX.as_bytes(), + &$slot[..], + &[$crate::macros::CALLS_TAG], + &$id[..], + ] + .concat() + }; +} + +/// key formatting macro +#[macro_export] +macro_rules! deferred_call_field_key { + ($id:expr, $slot:expr, $field:expr) => { + [deferred_call_prefix_key!($id, $slot), vec![$field]].concat() + }; +} + +/// sender address key formatting macro +#[macro_export] +macro_rules! sender_address_key { + ($id:expr, $slot:expr) => { + deferred_call_field_key!($id, $slot, $crate::macros::CALL_SENDER_ADDRESS) + }; +} + +/// target slot key formatting macro +#[macro_export] +macro_rules! target_slot_key { + ($id:expr, $slot:expr) => { + deferred_call_field_key!($id, $slot, $crate::macros::CALL_TARGET_SLOT) + }; +} + +/// target address key formatting macro +#[macro_export] +macro_rules! target_address_key { + ($id:expr, $slot:expr) => { + deferred_call_field_key!($id, $slot, $crate::macros::CALL_TARGET_ADDRESS) + }; +} + +/// target function key formatting macro +#[macro_export] +macro_rules! target_function_key { + ($id:expr, $slot:expr) => { + deferred_call_field_key!($id, $slot, $crate::macros::CALL_TARGET_FUNCTION) + }; +} + +/// parameters key formatting macro +#[macro_export] +macro_rules! parameters_key { + ($id:expr, $slot:expr) => { + deferred_call_field_key!($id, $slot, $crate::macros::CALL_PARAMETERS) + }; +} + +/// coins key formatting macro +#[macro_export] +macro_rules! coins_key { + ($id:expr, $slot:expr) => { + deferred_call_field_key!($id, $slot, $crate::macros::CALL_COINS) + }; +} + +/// max gas key formatting macro +#[macro_export] +macro_rules! max_gas_key { + ($id:expr, $slot:expr) => { + deferred_call_field_key!($id, $slot, $crate::macros::CALL_MAX_GAS) + }; +} + +/// fee key formatting macro +#[macro_export] +macro_rules! fee_key { + ($id:expr, $slot:expr) => { + deferred_call_field_key!($id, $slot, $crate::macros::CALL_FEE) + }; +} + +/// cancelled key formatting macro +#[macro_export] +macro_rules! cancelled_key { + ($id:expr, $slot:expr) => { + deferred_call_field_key!($id, $slot, $crate::macros::CALL_CANCELED) + }; +} + +#[cfg(test)] +mod tests { + use massa_db_exports::DEFERRED_CALLS_PREFIX; + use massa_models::{ + deferred_call_id::{DeferredCallId, DeferredCallIdSerializer}, + slot::Slot, + }; + use massa_serialization::Serializer; + + #[test] + fn test_deferred_call_prefix_key() { + let slot_ser = Slot { + period: 1, + thread: 5, + } + .to_bytes_key(); + + let id = DeferredCallId::new( + 0, + Slot { + thread: 5, + period: 1, + }, + 1, + &[], + ) + .unwrap(); + + let mut id_ser = DeferredCallIdSerializer::new(); + let mut buf_id = Vec::new(); + id_ser.serialize(&id, &mut buf_id).unwrap(); + + let prefix = ["deferred_calls/".as_bytes(), &slot_ser, &[0u8], &buf_id].concat(); + + assert_eq!(deferred_call_prefix_key!(buf_id, slot_ser), prefix); + + let to_check = [prefix[..], &[1u8]].concat(); + assert_eq!(sender_address_key!(buf_id, slot_ser), to_check); + } +} diff --git a/massa-final-state/src/final_state.rs b/massa-final-state/src/final_state.rs index b7f7ddd7b27..d05ad396024 100644 --- a/massa-final-state/src/final_state.rs +++ b/massa-final-state/src/final_state.rs @@ -460,6 +460,9 @@ impl FinalState { self.executed_ops .apply_changes_to_batch(changes.executed_ops_changes, slot, &mut db_batch); + self.deferred_call_registry + .apply_changes_to_batch(changes.deferred_call_changes, &mut db_batch); + self.executed_denunciations.apply_changes_to_batch( changes.executed_denunciations_changes, slot, From 698a0337ffb7c603d90651927d01886e7662b1c4 Mon Sep 17 00:00:00 2001 From: modship Date: Fri, 12 Jul 2024 17:19:15 +0200 Subject: [PATCH 018/100] refactor + get_total_gas --- massa-db-exports/src/constants.rs | 2 +- massa-deferred-calls/src/lib.rs | 122 ++++++++++++------- massa-deferred-calls/src/macros.rs | 68 +++++++---- massa-deferred-calls/src/registry_changes.rs | 3 +- 4 files changed, 124 insertions(+), 71 deletions(-) diff --git a/massa-db-exports/src/constants.rs b/massa-db-exports/src/constants.rs index b92f53811d2..fd315b23897 100644 --- a/massa-db-exports/src/constants.rs +++ b/massa-db-exports/src/constants.rs @@ -29,7 +29,7 @@ pub const LEDGER_PREFIX: &str = "ledger/"; pub const MIP_STORE_PREFIX: &str = "versioning/"; pub const MIP_STORE_STATS_PREFIX: &str = "versioning_stats/"; pub const EXECUTION_TRAIL_HASH_PREFIX: &str = "execution_trail_hash/"; -pub const DEFERRED_CALLS_PREFIX: &str = "deferred_calls/"; +pub const DEFERRED_CALLS_SLOT_PREFIX: &str = "deferred_calls/"; // Async Pool pub const MESSAGE_DESER_ERROR: &str = "critical: message deserialization failed"; diff --git a/massa-deferred-calls/src/lib.rs b/massa-deferred-calls/src/lib.rs index 5bcbc027b76..b48222c714d 100644 --- a/massa-deferred-calls/src/lib.rs +++ b/massa-deferred-calls/src/lib.rs @@ -1,10 +1,11 @@ use call::{DeferredCallDeserializer, DeferredCallSerializer}; +use macros::DEFERRED_CALL_TOTAL_GAS; use massa_db_exports::{ - DBBatch, ShareableMassaDBController, DEFERRED_CALLS_PREFIX, KEY_SER_ERROR, MESSAGE_DESER_ERROR, - MESSAGE_SER_ERROR, STATE_CF, + DBBatch, ShareableMassaDBController, CRUD_ERROR, DEFERRED_CALLS_SLOT_PREFIX, KEY_SER_ERROR, + MESSAGE_DESER_ERROR, MESSAGE_SER_ERROR, STATE_CF, }; use massa_serialization::{DeserializeError, Deserializer, Serializer}; -use registry_changes::DeferredRegistryChanges; +use registry_changes::{DeferredRegistryChanges, DeferredRegistryChangesDeserializer}; /// This module implements a new version of the Autonomous Smart Contracts. (ASC) /// This new version allow asynchronous calls to be registered for a specific slot and ensure his execution. @@ -20,7 +21,7 @@ use massa_ledger_exports::{SetOrDelete, SetOrKeep}; use massa_models::{ amount::Amount, config::THREAD_COUNT, - deferred_call_id::{DeferredCallId, DeferredCallIdDeserializer, DeferredCallIdSerializer}, + deferred_call_id::{DeferredCallId, DeferredCallIdSerializer}, slot::Slot, }; use std::collections::BTreeMap; @@ -28,25 +29,34 @@ use std::collections::BTreeMap; // #[derive(Debug)] pub struct DeferredCallRegistry { db: ShareableMassaDBController, - deferred_call_serializer: DeferredCallSerializer, - deferred_call_id_serializer: DeferredCallIdSerializer, - deferred_call_deserializer: DeferredCallDeserializer, + call_serializer: DeferredCallSerializer, + call_id_serializer: DeferredCallIdSerializer, + call_deserializer: DeferredCallDeserializer, + registry_changes_deserializer: DeferredRegistryChangesDeserializer, } impl DeferredCallRegistry { /* DB layout: - [ASYNC_CALL_TOTAL_GAS_PREFIX] -> u64 // total currently booked gas - [ASYNC_CAL_SLOT_PREFIX][slot][TOTAL_GAS_TAG] -> u64 // total gas booked for a slot (optional, default 0, deleted when set to 0) - [ASYNC_CAL_SLOT_PREFIX][slot][CALLS_TAG][id][ASYNC_CALL_FIELD_X_TAG] -> AsyncCall.x // call data + [DEFERRED_CALL_TOTAL_GAS] -> u64 // total currently booked gas + [DEFERRED_CALLS_SLOT_PREFIX][slot][SLOT_TOTAL_GAS] -> u64 // total gas booked for a slot (optional, default 0, deleted when set to 0) + [DEFERRED_CALLS_SLOT_PREFIX][slot][SLOT_BASE_FEE] -> u64 // deleted when set to 0 + [DEFERRED_CALLS_SLOT_PREFIX][slot][CALLS_TAG][id][CALL_FIELD_X_TAG] -> AsyncCall.x // call data */ + // todo pass args pub fn new(db: ShareableMassaDBController) -> Self { Self { db, - deferred_call_serializer: DeferredCallSerializer::new(), - deferred_call_id_serializer: DeferredCallIdSerializer::new(), - deferred_call_deserializer: DeferredCallDeserializer::new(THREAD_COUNT), + call_serializer: DeferredCallSerializer::new(), + call_id_serializer: DeferredCallIdSerializer::new(), + call_deserializer: DeferredCallDeserializer::new(THREAD_COUNT), + // todo args + registry_changes_deserializer: DeferredRegistryChangesDeserializer::new( + THREAD_COUNT, + 100_000, + 100_000, + ), } } @@ -57,7 +67,7 @@ impl DeferredCallRegistry { /// Returns the DeferredCall for a given slot and id pub fn get_call(&self, slot: &Slot, id: &DeferredCallId) -> Option { let mut buf_id = Vec::new(); - self.deferred_call_id_serializer + self.call_id_serializer .serialize(id, &mut buf_id) .expect(MESSAGE_SER_ERROR); let key = deferred_call_prefix_key!(buf_id, slot.to_bytes_key()); @@ -73,7 +83,7 @@ impl DeferredCallRegistry { } match self - .deferred_call_deserializer + .call_deserializer .deserialize::(&serialized_call) { Ok((_rest, call)) => Some(call), @@ -88,7 +98,7 @@ impl DeferredCallRegistry { match self.db.read().get_cf(STATE_CF, key) { Ok(Some(v)) => { let result = self - .deferred_call_deserializer + .call_deserializer .u64_var_int_deserializer .deserialize::(&v) .expect(MESSAGE_DESER_ERROR) @@ -111,8 +121,27 @@ impl DeferredCallRegistry { } /// Returns the total amount of gas booked - pub fn get_total_gas() -> u128 { - todo!() + pub fn get_total_gas(&self) -> u128 { + match self + .db + .read() + .get_cf(STATE_CF, DEFERRED_CALL_TOTAL_GAS.as_bytes().to_vec()) + .expect(CRUD_ERROR) + { + Some(v) => { + let result = self + .registry_changes_deserializer + .total_gas_deserializer + .deserialize::(&v) + .expect(MESSAGE_DESER_ERROR) + .1; + match result { + SetOrKeep::Set(v) => v, + SetOrKeep::Keep => 0, + } + } + None => 0, + } } pub fn put_entry( @@ -123,7 +152,7 @@ impl DeferredCallRegistry { batch: &mut DBBatch, ) { let mut buffer_id = Vec::new(); - self.deferred_call_id_serializer + self.call_id_serializer .serialize(call_id, &mut buffer_id) .expect(MESSAGE_SER_ERROR); @@ -133,7 +162,7 @@ impl DeferredCallRegistry { // sender address let mut temp_buffer = Vec::new(); - self.deferred_call_serializer + self.call_serializer .address_serializer .serialize(&call.sender_address, &mut temp_buffer) .expect(MESSAGE_SER_ERROR); @@ -145,7 +174,7 @@ impl DeferredCallRegistry { temp_buffer.clear(); // target slot - self.deferred_call_serializer + self.call_serializer .slot_serializer .serialize(&call.target_slot, &mut temp_buffer) .expect(MESSAGE_SER_ERROR); @@ -153,7 +182,7 @@ impl DeferredCallRegistry { temp_buffer.clear(); // target address - self.deferred_call_serializer + self.call_serializer .address_serializer .serialize(&call.target_address, &mut temp_buffer) .expect(MESSAGE_SER_ERROR); @@ -165,7 +194,7 @@ impl DeferredCallRegistry { temp_buffer.clear(); // target function - self.deferred_call_serializer + self.call_serializer .string_serializer .serialize(&call.target_function, &mut temp_buffer) .expect(MESSAGE_SER_ERROR); @@ -177,7 +206,7 @@ impl DeferredCallRegistry { temp_buffer.clear(); // parameters - self.deferred_call_serializer + self.call_serializer .vec_u8_serializer .serialize(&call.parameters, &mut temp_buffer) .expect(MESSAGE_SER_ERROR); @@ -185,7 +214,7 @@ impl DeferredCallRegistry { temp_buffer.clear(); // coins - self.deferred_call_serializer + self.call_serializer .amount_serializer .serialize(&call.coins, &mut temp_buffer) .expect(MESSAGE_SER_ERROR); @@ -193,7 +222,7 @@ impl DeferredCallRegistry { temp_buffer.clear(); // max gas - self.deferred_call_serializer + self.call_serializer .u64_var_int_serializer .serialize(&call.max_gas, &mut temp_buffer) .expect(MESSAGE_SER_ERROR); @@ -201,7 +230,7 @@ impl DeferredCallRegistry { temp_buffer.clear(); // fee - self.deferred_call_serializer + self.call_serializer .amount_serializer .serialize(&call.fee, &mut temp_buffer) .expect(MESSAGE_SER_ERROR); @@ -209,7 +238,7 @@ impl DeferredCallRegistry { temp_buffer.clear(); // cancelled - self.deferred_call_serializer + self.call_serializer .bool_serializer .serialize(&call.cancelled, &mut temp_buffer) .expect(MESSAGE_SER_ERROR); @@ -218,7 +247,7 @@ impl DeferredCallRegistry { fn delete_entry(&self, id: &DeferredCallId, slot: &Slot, batch: &mut DBBatch) { let mut buffer_id = Vec::new(); - self.deferred_call_id_serializer + self.call_id_serializer .serialize(id, &mut buffer_id) .expect(MESSAGE_SER_ERROR); @@ -262,7 +291,7 @@ impl DeferredCallRegistry { self.db.read().delete_key(batch, key); } else { let mut value_ser = Vec::new(); - self.deferred_call_serializer + self.call_serializer .u64_var_int_serializer .serialize(&v, &mut value_ser) .expect(MESSAGE_SER_ERROR); @@ -273,18 +302,25 @@ impl DeferredCallRegistry { } DeferredRegistryGasChange::Keep => {} } - // match slot_changes.base_fee { - // DeferredRegistryBaseFeeChange::Set(v) => { - // if v.eq(&0) { - // batch.delete_key(ASYNC_CAL_SLOT_PREFIX, slot, BASE_FEE_TAG); - // } else { - // let key = BASE_FEE_TAG; - // let value = v.to_bytes().to_vec(); - // batch.put_or_update_entry_value(ASYNC_CAL_SLOT_PREFIX, slot, key, value); - // } - // } - // DeferredRegistryBaseFeeChange::Keep => {} - // } + match slot_changes.base_fee { + DeferredRegistryBaseFeeChange::Set(v) => { + let key = deferred_call_slot_base_fee_key!(slot.to_bytes_key()); + //Note: if a base fee is zet to 0, delete the base fee entry + if v.eq(&Amount::zero()) { + self.db.read().delete_key(batch, key); + } else { + let mut value_ser = Vec::new(); + self.call_serializer + .amount_serializer + .serialize(&v, &mut value_ser) + .expect(MESSAGE_SER_ERROR); + self.db + .read() + .put_or_update_entry_value(batch, key, &value_ser); + } + } + DeferredRegistryBaseFeeChange::Keep => {} + } } } } @@ -390,7 +426,7 @@ mod tests { use crate::{DeferredCall, DeferredCallRegistry, DeferredRegistryChanges}; use massa_db_exports::{ DBBatch, Key, MassaDBConfig, MassaDBController, ShareableMassaDBController, - DEFERRED_CALLS_PREFIX, STATE_CF, + DEFERRED_CALLS_SLOT_PREFIX, STATE_CF, }; use massa_db_worker::MassaDB; use massa_models::{ diff --git a/massa-deferred-calls/src/macros.rs b/massa-deferred-calls/src/macros.rs index ee36d3d3083..81bb0c789ff 100644 --- a/massa-deferred-calls/src/macros.rs +++ b/massa-deferred-calls/src/macros.rs @@ -1,26 +1,42 @@ -use massa_db_exports::DEFERRED_CALLS_PREFIX; - -pub(crate) const CALL_SENDER_ADDRESS: u8 = 1u8; -pub(crate) const CALL_TARGET_SLOT: u8 = 2u8; -pub(crate) const CALL_TARGET_ADDRESS: u8 = 3u8; -pub(crate) const CALL_TARGET_FUNCTION: u8 = 4u8; -pub(crate) const CALL_PARAMETERS: u8 = 5u8; -pub(crate) const CALL_COINS: u8 = 6u8; -pub(crate) const CALL_MAX_GAS: u8 = 7u8; -pub(crate) const CALL_FEE: u8 = 8u8; -pub(crate) const CALL_CANCELED: u8 = 9u8; +use massa_db_exports::DEFERRED_CALLS_SLOT_PREFIX; -pub(crate) const CALLS_TAG: u8 = 0u8; +pub(crate) const DEFERRED_CALL_TOTAL_GAS: &str = "deferred_call_total_gas"; -pub(crate) const TOTAL_GAS_TAG: u8 = 1u8; +pub(crate) const CALLS_TAG: u8 = 0u8; +// slot fields +pub(crate) const SLOT_TOTAL_GAS: u8 = 1u8; +pub(crate) const SLOT_BASE_FEE: u8 = 2u8; + +// call fields +pub(crate) const CALL_FIELD_SENDER_ADDRESS: u8 = 1u8; +pub(crate) const CALL_FIELD_TARGET_SLOT: u8 = 2u8; +pub(crate) const CALL_FIELD_TARGET_ADDRESS: u8 = 3u8; +pub(crate) const CALL_FIELD_TARGET_FUNCTION: u8 = 4u8; +pub(crate) const CALL_FIELD_PARAMETERS: u8 = 5u8; +pub(crate) const CALL_FIELD_COINS: u8 = 6u8; +pub(crate) const CALL_FIELD_MAX_GAS: u8 = 7u8; +pub(crate) const CALL_FIELD_FEE: u8 = 8u8; +pub(crate) const CALL_FIELD_CANCELED: u8 = 9u8; #[macro_export] macro_rules! deferred_call_slot_total_gas_key { ($slot:expr) => { [ - DEFERRED_CALLS_PREFIX.as_bytes(), + DEFERRED_CALLS_SLOT_PREFIX.as_bytes(), + &$slot[..], + &[$crate::macros::SLOT_TOTAL_GAS], + ] + .concat() + }; +} + +#[macro_export] +macro_rules! deferred_call_slot_base_fee_key { + ($slot:expr) => { + [ + DEFERRED_CALLS_SLOT_PREFIX.as_bytes(), &$slot[..], - &[$crate::macros::TOTAL_GAS_TAG], + &[$crate::macros::SLOT_BASE_FEE], ] .concat() }; @@ -30,7 +46,7 @@ macro_rules! deferred_call_slot_total_gas_key { macro_rules! deferred_call_prefix_key { ($id:expr, $slot:expr) => { [ - DEFERRED_CALLS_PREFIX.as_bytes(), + DEFERRED_CALLS_SLOT_PREFIX.as_bytes(), &$slot[..], &[$crate::macros::CALLS_TAG], &$id[..], @@ -51,7 +67,7 @@ macro_rules! deferred_call_field_key { #[macro_export] macro_rules! sender_address_key { ($id:expr, $slot:expr) => { - deferred_call_field_key!($id, $slot, $crate::macros::CALL_SENDER_ADDRESS) + deferred_call_field_key!($id, $slot, $crate::macros::CALL_FIELD_SENDER_ADDRESS) }; } @@ -59,7 +75,7 @@ macro_rules! sender_address_key { #[macro_export] macro_rules! target_slot_key { ($id:expr, $slot:expr) => { - deferred_call_field_key!($id, $slot, $crate::macros::CALL_TARGET_SLOT) + deferred_call_field_key!($id, $slot, $crate::macros::CALL_FIELD_TARGET_SLOT) }; } @@ -67,7 +83,7 @@ macro_rules! target_slot_key { #[macro_export] macro_rules! target_address_key { ($id:expr, $slot:expr) => { - deferred_call_field_key!($id, $slot, $crate::macros::CALL_TARGET_ADDRESS) + deferred_call_field_key!($id, $slot, $crate::macros::CALL_FIELD_TARGET_ADDRESS) }; } @@ -75,7 +91,7 @@ macro_rules! target_address_key { #[macro_export] macro_rules! target_function_key { ($id:expr, $slot:expr) => { - deferred_call_field_key!($id, $slot, $crate::macros::CALL_TARGET_FUNCTION) + deferred_call_field_key!($id, $slot, $crate::macros::CALL_FIELD_TARGET_FUNCTION) }; } @@ -83,7 +99,7 @@ macro_rules! target_function_key { #[macro_export] macro_rules! parameters_key { ($id:expr, $slot:expr) => { - deferred_call_field_key!($id, $slot, $crate::macros::CALL_PARAMETERS) + deferred_call_field_key!($id, $slot, $crate::macros::CALL_FIELD_PARAMETERS) }; } @@ -91,7 +107,7 @@ macro_rules! parameters_key { #[macro_export] macro_rules! coins_key { ($id:expr, $slot:expr) => { - deferred_call_field_key!($id, $slot, $crate::macros::CALL_COINS) + deferred_call_field_key!($id, $slot, $crate::macros::CALL_FIELD_COINS) }; } @@ -99,7 +115,7 @@ macro_rules! coins_key { #[macro_export] macro_rules! max_gas_key { ($id:expr, $slot:expr) => { - deferred_call_field_key!($id, $slot, $crate::macros::CALL_MAX_GAS) + deferred_call_field_key!($id, $slot, $crate::macros::CALL_FIELD_MAX_GAS) }; } @@ -107,7 +123,7 @@ macro_rules! max_gas_key { #[macro_export] macro_rules! fee_key { ($id:expr, $slot:expr) => { - deferred_call_field_key!($id, $slot, $crate::macros::CALL_FEE) + deferred_call_field_key!($id, $slot, $crate::macros::CALL_FIELD_FEE) }; } @@ -115,13 +131,13 @@ macro_rules! fee_key { #[macro_export] macro_rules! cancelled_key { ($id:expr, $slot:expr) => { - deferred_call_field_key!($id, $slot, $crate::macros::CALL_CANCELED) + deferred_call_field_key!($id, $slot, $crate::macros::CALL_FIELD_CANCELED) }; } #[cfg(test)] mod tests { - use massa_db_exports::DEFERRED_CALLS_PREFIX; + use massa_db_exports::DEFERRED_CALLS_SLOT_PREFIX; use massa_models::{ deferred_call_id::{DeferredCallId, DeferredCallIdSerializer}, slot::Slot, diff --git a/massa-deferred-calls/src/registry_changes.rs b/massa-deferred-calls/src/registry_changes.rs index 034f0c9267d..9782e55d112 100644 --- a/massa-deferred-calls/src/registry_changes.rs +++ b/massa-deferred-calls/src/registry_changes.rs @@ -156,7 +156,8 @@ pub struct DeferredRegistryChangesDeserializer { slots_length: U64VarIntDeserializer, slot_changes_deserializer: DeferredRegistrySlotChangesDeserializer, slot_deserializer: SlotDeserializer, - total_gas_deserializer: SetOrKeepDeserializer, + // total gas deserializer should be a u128 or SetOrKeep ? + pub(crate) total_gas_deserializer: SetOrKeepDeserializer, } impl DeferredRegistryChangesDeserializer { From cfe824a00bd55f0227b31ad5a3344284c07420a6 Mon Sep 17 00:00:00 2001 From: modship Date: Mon, 15 Jul 2024 10:51:03 +0200 Subject: [PATCH 019/100] get_slot_calls && get_slot_base_fee --- massa-deferred-calls/src/call.rs | 2 +- massa-deferred-calls/src/lib.rs | 155 +++++++++++++++++-- massa-deferred-calls/src/macros.rs | 16 +- massa-deferred-calls/src/registry_changes.rs | 2 +- 4 files changed, 151 insertions(+), 24 deletions(-) diff --git a/massa-deferred-calls/src/call.rs b/massa-deferred-calls/src/call.rs index f19c4b985e3..3c208bd025d 100644 --- a/massa-deferred-calls/src/call.rs +++ b/massa-deferred-calls/src/call.rs @@ -119,7 +119,7 @@ pub struct DeferredCallDeserializer { address_deserializer: AddressDeserializer, string_deserializer: StringDeserializer, vec_u8_deserializer: VecU8Deserializer, - amount_deserializer: AmountDeserializer, + pub(crate) amount_deserializer: AmountDeserializer, pub(crate) u64_var_int_deserializer: U64VarIntDeserializer, bool_deserializer: BoolDeserializer, } diff --git a/massa-deferred-calls/src/lib.rs b/massa-deferred-calls/src/lib.rs index b48222c714d..4ec7462467d 100644 --- a/massa-deferred-calls/src/lib.rs +++ b/massa-deferred-calls/src/lib.rs @@ -1,11 +1,13 @@ use call::{DeferredCallDeserializer, DeferredCallSerializer}; use macros::DEFERRED_CALL_TOTAL_GAS; use massa_db_exports::{ - DBBatch, ShareableMassaDBController, CRUD_ERROR, DEFERRED_CALLS_SLOT_PREFIX, KEY_SER_ERROR, - MESSAGE_DESER_ERROR, MESSAGE_SER_ERROR, STATE_CF, + DBBatch, ShareableMassaDBController, CRUD_ERROR, DEFERRED_CALLS_SLOT_PREFIX, KEY_DESER_ERROR, + KEY_SER_ERROR, MESSAGE_DESER_ERROR, MESSAGE_SER_ERROR, STATE_CF, }; use massa_serialization::{DeserializeError, Deserializer, Serializer}; -use registry_changes::{DeferredRegistryChanges, DeferredRegistryChangesDeserializer}; +use registry_changes::{ + DeferredRegistryChanges, DeferredRegistryChangesDeserializer, DeferredRegistryChangesSerializer, +}; /// This module implements a new version of the Autonomous Smart Contracts. (ASC) /// This new version allow asynchronous calls to be registered for a specific slot and ensure his execution. @@ -21,7 +23,7 @@ use massa_ledger_exports::{SetOrDelete, SetOrKeep}; use massa_models::{ amount::Amount, config::THREAD_COUNT, - deferred_call_id::{DeferredCallId, DeferredCallIdSerializer}, + deferred_call_id::{DeferredCallId, DeferredCallIdDeserializer, DeferredCallIdSerializer}, slot::Slot, }; use std::collections::BTreeMap; @@ -32,7 +34,9 @@ pub struct DeferredCallRegistry { call_serializer: DeferredCallSerializer, call_id_serializer: DeferredCallIdSerializer, call_deserializer: DeferredCallDeserializer, + call_id_deserializer: DeferredCallIdDeserializer, registry_changes_deserializer: DeferredRegistryChangesDeserializer, + registry_changes_serializer: DeferredRegistryChangesSerializer, } impl DeferredCallRegistry { @@ -51,17 +55,53 @@ impl DeferredCallRegistry { call_serializer: DeferredCallSerializer::new(), call_id_serializer: DeferredCallIdSerializer::new(), call_deserializer: DeferredCallDeserializer::new(THREAD_COUNT), + call_id_deserializer: DeferredCallIdDeserializer::new(), // todo args registry_changes_deserializer: DeferredRegistryChangesDeserializer::new( THREAD_COUNT, 100_000, 100_000, ), + registry_changes_serializer: DeferredRegistryChangesSerializer::new(), } } pub fn get_slot_calls(&self, slot: Slot) -> DeferredSlotCalls { - todo!() + let mut to_return = DeferredSlotCalls::new(slot); + let key = deferred_slot_call_prefix_key!(slot.to_bytes_key()); + + // cache the call ids to avoid duplicates iteration + let mut temp = Vec::new(); + + for (serialized_key, _serialized_value) in self.db.read().prefix_iterator_cf(STATE_CF, &key) + { + if !serialized_key.starts_with(&key) { + break; + } + + let rest_key = &serialized_key[key.len()..]; + + let (_rest, call_id) = self + .call_id_deserializer + .deserialize::(&rest_key) + .expect(KEY_DESER_ERROR); + + if temp.contains(&call_id) { + continue; + } + + temp.push(call_id.clone()); + + if let Some(call) = self.get_call(&slot, &call_id) { + to_return.slot_calls.insert(call_id, call); + } + } + + to_return.slot_base_fee = self.get_slot_base_fee(&slot); + to_return.slot_gas = self.get_slot_gas(slot); + to_return.total_gas = self.get_total_gas(); + + to_return } /// Returns the DeferredCall for a given slot and id @@ -111,13 +151,17 @@ impl DeferredCallRegistry { /// Returns the base fee for a slot pub fn get_slot_base_fee(&self, slot: &Slot) -> Amount { - unimplemented!("get_slot_base_fee"); - // self.db.read().get_cf(handle_cf, key) - // // By default, if it is absent, it is 0 - // self.db.read().get - // .get(ASYNC_CAL_SLOT_PREFIX, slot, BASE_FEE_TAG) - // .map(|v| Amount::from_bytes(v).unwrap()) - // .unwrap_or(Amount::zero()) + let key = deferred_call_slot_base_fee_key!(slot.to_bytes_key()); + match self.db.read().get_cf(STATE_CF, key) { + Ok(Some(v)) => { + self.call_deserializer + .amount_deserializer + .deserialize::(&v) + .expect(MESSAGE_DESER_ERROR) + .1 + } + _ => Amount::zero(), + } } /// Returns the total amount of gas booked @@ -322,6 +366,21 @@ impl DeferredCallRegistry { DeferredRegistryBaseFeeChange::Keep => {} } } + + match changes.total_gas { + DeferredRegistryGasChange::Set(v) => { + let key = DEFERRED_CALL_TOTAL_GAS.as_bytes().to_vec(); + let mut value_ser = Vec::new(); + self.registry_changes_serializer + .total_gas_serializer + .serialize(&DeferredRegistryGasChange::Set(v), &mut value_ser) + .expect(MESSAGE_SER_ERROR); + self.db + .read() + .put_or_update_entry_value(batch, key, &value_ser); + } + DeferredRegistryGasChange::Keep => {} + } } } @@ -424,10 +483,7 @@ impl DeferredSlotCalls { mod tests { use super::*; use crate::{DeferredCall, DeferredCallRegistry, DeferredRegistryChanges}; - use massa_db_exports::{ - DBBatch, Key, MassaDBConfig, MassaDBController, ShareableMassaDBController, - DEFERRED_CALLS_SLOT_PREFIX, STATE_CF, - }; + use massa_db_exports::{DBBatch, MassaDBConfig, MassaDBController, ShareableMassaDBController}; use massa_db_worker::MassaDB; use massa_models::{ address::Address, @@ -437,7 +493,7 @@ mod tests { slot::Slot, }; use parking_lot::RwLock; - use std::{str::FromStr, sync::Arc}; + use std::{result, str::FromStr, sync::Arc}; use tempfile::tempdir; #[test] @@ -491,4 +547,69 @@ mod tests { assert!(result.target_function.eq(&call.target_function)); assert_eq!(result.sender_address, call.sender_address); } + + #[test] + fn get_slot_calls() { + let temp_dir = tempdir().expect("Unable to create a temp folder"); + let db_config = MassaDBConfig { + path: temp_dir.path().to_path_buf(), + max_history_length: 100, + max_final_state_elements_size: 100, + max_versioning_elements_size: 100, + thread_count: THREAD_COUNT, + max_ledger_backups: 100, + }; + let call_id_serializer = DeferredCallIdSerializer::new(); + let db: ShareableMassaDBController = Arc::new(RwLock::new( + Box::new(MassaDB::new(db_config)) as Box<(dyn MassaDBController + 'static)>, + )); + + let registry = DeferredCallRegistry::new(db); + + let mut changes = DeferredRegistryChanges::default(); + + let target_slot = Slot { + thread: 5, + period: 1, + }; + + let call = DeferredCall::new( + Address::from_str("AU12dG5xP1RDEB5ocdHkymNVvvSJmUL9BgHwCksDowqmGWxfpm93x").unwrap(), + target_slot.clone(), + Address::from_str("AS127QtY6Hzm6BnJc9wqCBfPNvEH9fKer3LiMNNQmcX3MzLwCL6G6").unwrap(), + "receive".to_string(), + vec![42, 42, 42, 42], + Amount::from_raw(100), + 3000000, + Amount::from_raw(1), + false, + ); + let id = DeferredCallId::new(0, target_slot.clone(), 1, &[]).unwrap(); + + let id2 = DeferredCallId::new(0, target_slot.clone(), 1, &[123]).unwrap(); + + let mut buf_id = Vec::new(); + call_id_serializer.serialize(&id, &mut buf_id).unwrap(); + + changes.set_call(id.clone(), call.clone()); + changes.set_call(id2.clone(), call.clone()); + changes.set_total_gas(100); + changes.set_slot_gas(target_slot.clone(), 100_000); + + changes.set_slot_base_fee(target_slot.clone(), Amount::from_raw(10000000)); + + let mut batch = DBBatch::new(); + registry.apply_changes_to_batch(changes, &mut batch); + + registry.db.write().write_batch(batch, DBBatch::new(), None); + + let result = registry.get_slot_calls(target_slot.clone()); + + assert!(result.slot_calls.len() == 2); + assert!(result.slot_calls.contains_key(&id)); + assert!(result.slot_calls.contains_key(&id2)); + assert_eq!(result.total_gas, 100); + assert_eq!(result.slot_base_fee, Amount::from_raw(10000000)); + assert_eq!(result.slot_gas, 100_000); + } } diff --git a/massa-deferred-calls/src/macros.rs b/massa-deferred-calls/src/macros.rs index 81bb0c789ff..6c905e62ce1 100644 --- a/massa-deferred-calls/src/macros.rs +++ b/massa-deferred-calls/src/macros.rs @@ -43,18 +43,24 @@ macro_rules! deferred_call_slot_base_fee_key { } #[macro_export] -macro_rules! deferred_call_prefix_key { - ($id:expr, $slot:expr) => { +macro_rules! deferred_slot_call_prefix_key { + ($slot:expr) => { [ DEFERRED_CALLS_SLOT_PREFIX.as_bytes(), &$slot[..], &[$crate::macros::CALLS_TAG], - &$id[..], ] .concat() }; } +#[macro_export] +macro_rules! deferred_call_prefix_key { + ($id:expr, $slot:expr) => { + [&deferred_slot_call_prefix_key!($slot), &$id[..]].concat() + }; +} + /// key formatting macro #[macro_export] macro_rules! deferred_call_field_key { @@ -171,7 +177,7 @@ mod tests { assert_eq!(deferred_call_prefix_key!(buf_id, slot_ser), prefix); - let to_check = [prefix[..], &[1u8]].concat(); - assert_eq!(sender_address_key!(buf_id, slot_ser), to_check); + // let to_check = [prefix[..], &[1u8]].concat(); + // assert_eq!(sender_address_key!(buf_id, slot_ser), to_check); } } diff --git a/massa-deferred-calls/src/registry_changes.rs b/massa-deferred-calls/src/registry_changes.rs index 9782e55d112..fc31a21e9df 100644 --- a/massa-deferred-calls/src/registry_changes.rs +++ b/massa-deferred-calls/src/registry_changes.rs @@ -113,7 +113,7 @@ pub struct DeferredRegistryChangesSerializer { slots_length: U64VarIntSerializer, slot_changes_serializer: DeferredRegistrySlotChangesSerializer, slot_serializer: SlotSerializer, - total_gas_serializer: SetOrKeepSerializer, + pub(crate) total_gas_serializer: SetOrKeepSerializer, } impl DeferredRegistryChangesSerializer { From 1a86834b07adca441c74310359005a44fd19ef6f Mon Sep 17 00:00:00 2001 From: modship Date: Tue, 16 Jul 2024 10:42:00 +0200 Subject: [PATCH 020/100] add mod tests / deferred_call_quote --- massa-deferred-calls/src/lib.rs | 144 +----------------- massa-deferred-calls/src/tests/mod.rs | 132 ++++++++++++++++ massa-execution-exports/src/error.rs | 2 +- massa-execution-exports/src/settings.rs | 2 + .../src/test_exports/config.rs | 1 + massa-execution-worker/src/context.rs | 30 ++++ massa-execution-worker/src/execution.rs | 68 +++------ .../src/speculative_deferred_calls.rs | 126 +++++++-------- massa-models/src/config/constants.rs | 2 + massa-node/src/main.rs | 21 +-- 10 files changed, 263 insertions(+), 265 deletions(-) create mode 100644 massa-deferred-calls/src/tests/mod.rs diff --git a/massa-deferred-calls/src/lib.rs b/massa-deferred-calls/src/lib.rs index 4ec7462467d..d395e2eb0dc 100644 --- a/massa-deferred-calls/src/lib.rs +++ b/massa-deferred-calls/src/lib.rs @@ -2,7 +2,7 @@ use call::{DeferredCallDeserializer, DeferredCallSerializer}; use macros::DEFERRED_CALL_TOTAL_GAS; use massa_db_exports::{ DBBatch, ShareableMassaDBController, CRUD_ERROR, DEFERRED_CALLS_SLOT_PREFIX, KEY_DESER_ERROR, - KEY_SER_ERROR, MESSAGE_DESER_ERROR, MESSAGE_SER_ERROR, STATE_CF, + MESSAGE_DESER_ERROR, MESSAGE_SER_ERROR, STATE_CF, }; use massa_serialization::{DeserializeError, Deserializer, Serializer}; use registry_changes::{ @@ -15,6 +15,9 @@ mod call; pub mod registry_changes; pub mod slot_changes; +#[cfg(test)] +mod tests; + #[macro_use] mod macros; @@ -98,7 +101,7 @@ impl DeferredCallRegistry { } to_return.slot_base_fee = self.get_slot_base_fee(&slot); - to_return.slot_gas = self.get_slot_gas(slot); + to_return.slot_gas = self.get_slot_gas(&slot); to_return.total_gas = self.get_total_gas(); to_return @@ -132,7 +135,7 @@ impl DeferredCallRegistry { } /// Returns the total amount of gas booked for a slot - pub fn get_slot_gas(&self, slot: Slot) -> u64 { + pub fn get_slot_gas(&self, slot: &Slot) -> u64 { // By default, if it is absent, it is 0 let key = deferred_call_slot_total_gas_key!(slot.to_bytes_key()); match self.db.read().get_cf(STATE_CF, key) { @@ -478,138 +481,3 @@ impl DeferredSlotCalls { } } } - -#[cfg(test)] -mod tests { - use super::*; - use crate::{DeferredCall, DeferredCallRegistry, DeferredRegistryChanges}; - use massa_db_exports::{DBBatch, MassaDBConfig, MassaDBController, ShareableMassaDBController}; - use massa_db_worker::MassaDB; - use massa_models::{ - address::Address, - amount::Amount, - config::THREAD_COUNT, - deferred_call_id::{DeferredCallId, DeferredCallIdSerializer}, - slot::Slot, - }; - use parking_lot::RwLock; - use std::{result, str::FromStr, sync::Arc}; - use tempfile::tempdir; - - #[test] - fn apply_changes() { - let temp_dir = tempdir().expect("Unable to create a temp folder"); - let db_config = MassaDBConfig { - path: temp_dir.path().to_path_buf(), - max_history_length: 100, - max_final_state_elements_size: 100, - max_versioning_elements_size: 100, - thread_count: THREAD_COUNT, - max_ledger_backups: 100, - }; - let call_id_serializer = DeferredCallIdSerializer::new(); - let db: ShareableMassaDBController = Arc::new(RwLock::new( - Box::new(MassaDB::new(db_config)) as Box<(dyn MassaDBController + 'static)>, - )); - - let registry = DeferredCallRegistry::new(db); - - let mut changes = DeferredRegistryChanges::default(); - - let target_slot = Slot { - thread: 5, - period: 1, - }; - - let call = DeferredCall::new( - Address::from_str("AU12dG5xP1RDEB5ocdHkymNVvvSJmUL9BgHwCksDowqmGWxfpm93x").unwrap(), - target_slot.clone(), - Address::from_str("AS127QtY6Hzm6BnJc9wqCBfPNvEH9fKer3LiMNNQmcX3MzLwCL6G6").unwrap(), - "receive".to_string(), - vec![42, 42, 42, 42], - Amount::from_raw(100), - 3000000, - Amount::from_raw(1), - false, - ); - let id = DeferredCallId::new(0, target_slot.clone(), 1, &[]).unwrap(); - let mut buf_id = Vec::new(); - call_id_serializer.serialize(&id, &mut buf_id).unwrap(); - - changes.set_call(id.clone(), call.clone()); - - let mut batch = DBBatch::new(); - registry.apply_changes_to_batch(changes, &mut batch); - - registry.db.write().write_batch(batch, DBBatch::new(), None); - - let result = registry.get_call(&target_slot, &id).unwrap(); - assert!(result.target_function.eq(&call.target_function)); - assert_eq!(result.sender_address, call.sender_address); - } - - #[test] - fn get_slot_calls() { - let temp_dir = tempdir().expect("Unable to create a temp folder"); - let db_config = MassaDBConfig { - path: temp_dir.path().to_path_buf(), - max_history_length: 100, - max_final_state_elements_size: 100, - max_versioning_elements_size: 100, - thread_count: THREAD_COUNT, - max_ledger_backups: 100, - }; - let call_id_serializer = DeferredCallIdSerializer::new(); - let db: ShareableMassaDBController = Arc::new(RwLock::new( - Box::new(MassaDB::new(db_config)) as Box<(dyn MassaDBController + 'static)>, - )); - - let registry = DeferredCallRegistry::new(db); - - let mut changes = DeferredRegistryChanges::default(); - - let target_slot = Slot { - thread: 5, - period: 1, - }; - - let call = DeferredCall::new( - Address::from_str("AU12dG5xP1RDEB5ocdHkymNVvvSJmUL9BgHwCksDowqmGWxfpm93x").unwrap(), - target_slot.clone(), - Address::from_str("AS127QtY6Hzm6BnJc9wqCBfPNvEH9fKer3LiMNNQmcX3MzLwCL6G6").unwrap(), - "receive".to_string(), - vec![42, 42, 42, 42], - Amount::from_raw(100), - 3000000, - Amount::from_raw(1), - false, - ); - let id = DeferredCallId::new(0, target_slot.clone(), 1, &[]).unwrap(); - - let id2 = DeferredCallId::new(0, target_slot.clone(), 1, &[123]).unwrap(); - - let mut buf_id = Vec::new(); - call_id_serializer.serialize(&id, &mut buf_id).unwrap(); - - changes.set_call(id.clone(), call.clone()); - changes.set_call(id2.clone(), call.clone()); - changes.set_total_gas(100); - changes.set_slot_gas(target_slot.clone(), 100_000); - - changes.set_slot_base_fee(target_slot.clone(), Amount::from_raw(10000000)); - - let mut batch = DBBatch::new(); - registry.apply_changes_to_batch(changes, &mut batch); - - registry.db.write().write_batch(batch, DBBatch::new(), None); - - let result = registry.get_slot_calls(target_slot.clone()); - - assert!(result.slot_calls.len() == 2); - assert!(result.slot_calls.contains_key(&id)); - assert!(result.slot_calls.contains_key(&id2)); - assert_eq!(result.total_gas, 100); - assert_eq!(result.slot_base_fee, Amount::from_raw(10000000)); - assert_eq!(result.slot_gas, 100_000); - } -} diff --git a/massa-deferred-calls/src/tests/mod.rs b/massa-deferred-calls/src/tests/mod.rs new file mode 100644 index 00000000000..a622fd2969a --- /dev/null +++ b/massa-deferred-calls/src/tests/mod.rs @@ -0,0 +1,132 @@ +use super::*; +use crate::{DeferredCall, DeferredCallRegistry, DeferredRegistryChanges}; +use massa_db_exports::{DBBatch, MassaDBConfig, MassaDBController, ShareableMassaDBController}; +use massa_db_worker::MassaDB; +use massa_models::{ + address::Address, + amount::Amount, + config::THREAD_COUNT, + deferred_call_id::{DeferredCallId, DeferredCallIdSerializer}, + slot::Slot, +}; +use parking_lot::RwLock; +use std::{str::FromStr, sync::Arc}; +use tempfile::tempdir; + +#[test] +fn call_registry_apply_changes() { + let temp_dir = tempdir().expect("Unable to create a temp folder"); + let db_config = MassaDBConfig { + path: temp_dir.path().to_path_buf(), + max_history_length: 100, + max_final_state_elements_size: 100, + max_versioning_elements_size: 100, + thread_count: THREAD_COUNT, + max_ledger_backups: 100, + }; + let call_id_serializer = DeferredCallIdSerializer::new(); + let db: ShareableMassaDBController = Arc::new(RwLock::new( + Box::new(MassaDB::new(db_config)) as Box<(dyn MassaDBController + 'static)> + )); + + let registry = DeferredCallRegistry::new(db); + + let mut changes = DeferredRegistryChanges::default(); + + let target_slot = Slot { + thread: 5, + period: 1, + }; + + let call = DeferredCall::new( + Address::from_str("AU12dG5xP1RDEB5ocdHkymNVvvSJmUL9BgHwCksDowqmGWxfpm93x").unwrap(), + target_slot.clone(), + Address::from_str("AS127QtY6Hzm6BnJc9wqCBfPNvEH9fKer3LiMNNQmcX3MzLwCL6G6").unwrap(), + "receive".to_string(), + vec![42, 42, 42, 42], + Amount::from_raw(100), + 3000000, + Amount::from_raw(1), + false, + ); + let id = DeferredCallId::new(0, target_slot.clone(), 1, &[]).unwrap(); + let mut buf_id = Vec::new(); + call_id_serializer.serialize(&id, &mut buf_id).unwrap(); + + changes.set_call(id.clone(), call.clone()); + + let mut batch = DBBatch::new(); + registry.apply_changes_to_batch(changes, &mut batch); + + registry.db.write().write_batch(batch, DBBatch::new(), None); + + let result = registry.get_call(&target_slot, &id).unwrap(); + assert!(result.target_function.eq(&call.target_function)); + assert_eq!(result.sender_address, call.sender_address); +} + +#[test] +fn call_registry_get_slot_calls() { + let temp_dir = tempdir().expect("Unable to create a temp folder"); + let db_config = MassaDBConfig { + path: temp_dir.path().to_path_buf(), + max_history_length: 100, + max_final_state_elements_size: 100, + max_versioning_elements_size: 100, + thread_count: THREAD_COUNT, + max_ledger_backups: 100, + }; + let call_id_serializer = DeferredCallIdSerializer::new(); + let db: ShareableMassaDBController = Arc::new(RwLock::new( + Box::new(MassaDB::new(db_config)) as Box<(dyn MassaDBController + 'static)> + )); + + let registry = DeferredCallRegistry::new(db); + + let mut changes = DeferredRegistryChanges::default(); + + let target_slot = Slot { + thread: 5, + period: 1, + }; + + let call = DeferredCall::new( + Address::from_str("AU12dG5xP1RDEB5ocdHkymNVvvSJmUL9BgHwCksDowqmGWxfpm93x").unwrap(), + target_slot.clone(), + Address::from_str("AS127QtY6Hzm6BnJc9wqCBfPNvEH9fKer3LiMNNQmcX3MzLwCL6G6").unwrap(), + "receive".to_string(), + vec![42, 42, 42, 42], + Amount::from_raw(100), + 3000000, + Amount::from_raw(1), + false, + ); + let id = DeferredCallId::new(0, target_slot.clone(), 1, &[]).unwrap(); + + let id2 = DeferredCallId::new(0, target_slot.clone(), 1, &[123]).unwrap(); + + let mut buf_id = Vec::new(); + call_id_serializer.serialize(&id, &mut buf_id).unwrap(); + + changes.set_call(id.clone(), call.clone()); + changes.set_call(id2.clone(), call.clone()); + changes.set_total_gas(100); + changes.set_slot_gas(target_slot.clone(), 100_000); + + changes.set_slot_base_fee(target_slot.clone(), Amount::from_raw(10000000)); + + let mut batch = DBBatch::new(); + // 2 calls + registry.apply_changes_to_batch(changes, &mut batch); + + registry.db.write().write_batch(batch, DBBatch::new(), None); + + let result = registry.get_slot_calls(target_slot.clone()); + + assert!(result.slot_calls.len() == 2); + assert!(result.slot_calls.contains_key(&id)); + assert!(result.slot_calls.contains_key(&id2)); + assert_eq!(result.total_gas, 100); + assert_eq!(result.slot_base_fee, Amount::from_raw(10000000)); + assert_eq!(result.slot_gas, 100_000); +} diff --git a/massa-execution-exports/src/error.rs b/massa-execution-exports/src/error.rs index 4220fcfe59c..1f92cc75a44 100644 --- a/massa-execution-exports/src/error.rs +++ b/massa-execution-exports/src/error.rs @@ -69,7 +69,7 @@ pub enum ExecutionError { FactoryError(#[from] FactoryError), /// Autonomous smart contract call error: {0} - AscError(String), + DeferredCallsError(String), } /// Execution query errors diff --git a/massa-execution-exports/src/settings.rs b/massa-execution-exports/src/settings.rs index 49ae83b4559..a9be4b66868 100644 --- a/massa-execution-exports/src/settings.rs +++ b/massa-execution-exports/src/settings.rs @@ -102,4 +102,6 @@ pub struct ExecutionConfig { pub max_execution_traces_slot_limit: usize, /// Where to dump blocks pub block_dump_folder_path: PathBuf, + /// Max deferred call future slot + pub max_deferred_call_future_slots: u64, } diff --git a/massa-execution-exports/src/test_exports/config.rs b/massa-execution-exports/src/test_exports/config.rs index f42f9bd53d2..97fe7f37e3e 100644 --- a/massa-execution-exports/src/test_exports/config.rs +++ b/massa-execution-exports/src/test_exports/config.rs @@ -81,6 +81,7 @@ impl Default for ExecutionConfig { broadcast_slot_execution_traces_channel_capacity: 5000, max_execution_traces_slot_limit: 320, block_dump_folder_path, + max_deferred_call_future_slots: MAX_DEFERRED_CALL_FUTURE_SLOTS, } } } diff --git a/massa-execution-worker/src/context.rs b/massa-execution-worker/src/context.rs index 8b3cc4f1530..4496579d8ad 100644 --- a/massa-execution-worker/src/context.rs +++ b/massa-execution-worker/src/context.rs @@ -1125,6 +1125,36 @@ impl ExecutionContext { ))), } } + + pub fn deferred_calls_get_slot_booked_gas(&self, slot: &Slot) -> u64 { + self.speculative_deferred_calls.get_slot_gas(slot) + } + + /// Get the price it would cost to reserve "gas" at target slot "slot". + pub fn deferred_calls_compute_call_fee( + &self, + target_slot: Slot, + max_gas: u64, + thread_count: u8, + async_call_max_booking_slots: u64, + max_async_gas: u64, + async_gas_target: u64, + global_overbooking_penalty: Amount, + slot_overbooking_penalty: Amount, + current_slot: Slot, + ) -> Result { + self.speculative_deferred_calls.compute_call_fee( + target_slot, + max_gas, + thread_count, + async_call_max_booking_slots, + max_async_gas, + async_gas_target, + global_overbooking_penalty, + slot_overbooking_penalty, + current_slot, + ) + } } /// Generate the execution trail hash diff --git a/massa-execution-worker/src/execution.rs b/massa-execution-worker/src/execution.rs index b1f10f3f623..f16e976ddc3 100644 --- a/massa-execution-worker/src/execution.rs +++ b/massa-execution-worker/src/execution.rs @@ -2272,49 +2272,27 @@ impl ExecutionState { ); } - // // Get the price it would cost to reserve "gas" at target slot "slot". - // pub fn deferred_call_quote(&self, slot: Slot, gas: u64) -> Result { - // let current_slot = self.active_cursor; - - // // check if the slot is valid - // if (slot <= current_slot || slot > current_slot + deferred_call_max_future_slots) { - - // return Err(ExecutionError::("Invalid target slot")); - // } - - // // check if there is enough gas available at the target slot - // if (gas > max_async_gas - slot.async_gas_booked) { - // return Err("No enough gas available at target slot"); - // } - - // // 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. - - // // Constant part of the fee: directly depends on the base async gas cost for the target slot. - // // This is the "Integral" part of the Proportional-Integral controller. - // // When a new slot `S` is made available for booking, the `S.base_async_gas_cost` is increased or decreased compared to `(S-1).base_async_gas_cost` depending on the average gas usage over the `deferred_call_max_future_slots` slots before `S`. - // let integral_fee = slot.base_deferred_call_gas_cost * gas; - - // // The integral fee is not enough to respond to quick demand surges within the long booking period `deferred_call_max_future_slots`. Proportional regulation is also necessary. - - // // A fee that linearly depends on the total load over `deferred_call_max_future_slots` slots but only when the average load is above `target_async_gas` to not penalize normal use. Booking all the gas from all slots within the booking period requires using the whole initial coin supply. - // let proportional_fee = compute_overbooking_fee( - // deferred_call_max_future_slots * max_async_gas, // total available async gas during the booking period - // deferred_call_max_future_slots * max_async_gas / 2, // target a 50% async gas usage over the booking period - // get_current_total_booked_async_gas(), // total amount of async gas currently booked in the booking period - // gas, // amount of gas to book - // total_initial_coin_supply, // fully booking all slots of the booking period requires spending the whole initial supply of coins - // ); - - // // Finally, a per-slot proportional fee is also added to prevent attackers from denying significant ranges of consecutive slots within the long booking period. - // let proportional_slot_fee = compute_overbooking_fee( - // max_async_gas, // total available async gas during the target slot - // max_async_gas / 2, // target a 50% async gas usage during the target slot - // slot.async_gas_booked, // total amount of async gas currently booked in the target slot - // gas, // amount of gas to book in the target slot - // total_initial_coin_supply / 10000, // fully booking 10000 consecutive slots (~1h40 of slots) requires spending the whole initial supply of coins - // ); - - // return Ok(integral_fee + proportional_fee + proportional_slot_fee); - // } + // Get the price it would cost to reserve "gas" at target slot "slot". + pub fn deferred_call_quote(&self, slot: Slot, gas: u64) -> Result { + let current_slot = self.active_cursor; + + let gas_booked_slot = self + .execution_context + .lock() + .deferred_calls_get_slot_booked_gas(&slot); + + self.execution_context + .lock() + .deferred_calls_compute_call_fee( + slot, + gas, + self.config.thread_count, + self.config.max_deferred_call_future_slots, + self.config.max_async_gas, + gas_booked_slot, + Amount::from_raw(1_000_000_000), + Amount::from_raw(1_000_000_000 / 10_000), + current_slot, + ) + } } diff --git a/massa-execution-worker/src/speculative_deferred_calls.rs b/massa-execution-worker/src/speculative_deferred_calls.rs index fceab4b7a25..238dc4fbefb 100644 --- a/massa-execution-worker/src/speculative_deferred_calls.rs +++ b/massa-execution-worker/src/speculative_deferred_calls.rs @@ -50,33 +50,31 @@ impl SpeculativeDeferredCallRegistry { } pub fn get_slot_gas(&self, slot: &Slot) -> u64 { - unimplemented!("get_slot_gas"); - - // // get slot gas from current changes - // if let Some(v) = self.current_changes.get_slot_gas(slot) { - // return v; - // } - - // // check in history backwards - // { - // let history = self.active_history.read(); - // for history_item in history.0.iter().rev() { - // if let Some(v) = history_item - // .state_changes - // .async_call_registry_changes - // .get_slot_gas(slot) - // { - // return v; - // } - // } - // } - - // // check in final state - // return self - // .final_state - // .read() - // .get_asc_registry() - // .get_slot_gas(slot); + // get slot gas from current changes + if let Some(v) = self.deferred_calls_changes.get_slot_gas(slot) { + return v; + } + + // check in history backwards + { + let history = self.active_history.read(); + for history_item in history.0.iter().rev() { + if let Some(v) = history_item + .state_changes + .deferred_call_changes + .get_slot_gas(slot) + { + return v; + } + } + } + + // check in final state + return self + .final_state + .read() + .get_deferred_call_registry() + .get_slot_gas(slot); } pub fn get_slot_base_fee(&self, slot: &Slot) -> Amount { @@ -131,7 +129,7 @@ impl SpeculativeDeferredCallRegistry { let mut new_slot = current_slot .skip(async_call_max_booking_slots, thread_count) .expect("could not skip enough slots"); - todo!(); + self.deferred_calls_changes .set_slot_base_fee(new_slot, todo!()); @@ -143,7 +141,7 @@ impl SpeculativeDeferredCallRegistry { ); // delete the current slot - for (id, call) in &slot_calls.slot_calls { + for (id, _call) in &slot_calls.slot_calls { self.deferred_calls_changes.delete_call(current_slot, id); } self.deferred_calls_changes.set_slot_gas(current_slot, 0); @@ -197,12 +195,14 @@ impl SpeculativeDeferredCallRegistry { ) -> Result<(Address, Amount), ExecutionError> { // get call, fail if it does not exist let Some(mut call) = self.get_call(id) else { - return Err(ExecutionError::AscError("Call ID does not exist.".into())); + return Err(ExecutionError::DeferredCallsError( + "Call ID does not exist.".into(), + )); }; // check if the call is already cancelled if call.cancelled { - return Err(ExecutionError::AscError( + return Err(ExecutionError::DeferredCallsError( "Call ID is already cancelled.".into(), )); } @@ -256,34 +256,6 @@ impl SpeculativeDeferredCallRegistry { Amount::from_raw(std::cmp::min(raw_fee, u64::MAX as u128) as u64) } - // pub fn get_slot_base_fee(&self, slot: &Slot) -> Amount { - // // get slot base fee from current changes - // if let Some(v) = self.current_changes.get_slot_base_fee(slot) { - // return v; - // } - - // // check in history backwards - // { - // let history = self.active_history.read(); - // for history_item in history.0.iter().rev() { - // if let Some(v) = history_item - // .state_changes - // .async_call_registry_changes - // .get_slot_base_fee(slot) - // { - // return v; - // } - // } - // } - - // // check in final state - // return self - // .final_state - // .read() - // .get_asc_registry() - // .get_slot_base_fee(slot); - // } - /// Compute call fee pub fn compute_call_fee( &self, @@ -299,7 +271,7 @@ impl SpeculativeDeferredCallRegistry { ) -> Result { // Check that the slot is not in the past if target_slot <= current_slot { - return Err(ExecutionError::AscError( + return Err(ExecutionError::DeferredCallsError( "Target slot is in the past.".into(), )); } @@ -311,7 +283,7 @@ impl SpeculativeDeferredCallRegistry { > async_call_max_booking_slots { // note: the current slot is not counted - return Err(ExecutionError::AscError( + return Err(ExecutionError::DeferredCallsError( "Target slot is too far in the future.".into(), )); } @@ -319,24 +291,26 @@ impl SpeculativeDeferredCallRegistry { // Check that the gas is not too high for the target slot let slot_occupancy = self.get_slot_gas(&target_slot); if slot_occupancy.saturating_add(max_gas) > max_async_gas { - return Err(ExecutionError::AscError( + return Err(ExecutionError::DeferredCallsError( "Not enough gas available in the target slot.".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. + + // Constant part of the fee: directly depends on the base async gas cost for the target slot. + // This is the "Integral" part of the Proportional-Integral controller. + // When a new slot `S` is made available for booking, the `S.base_async_gas_cost` is increased or decreased compared to `(S-1).base_async_gas_cost` depending on the average gas usage over the `deferred_call_max_future_slots` slots before `S`. + // Integral fee let integral_fee = self .get_slot_base_fee(&target_slot) .saturating_mul_u64(max_gas); - // Slot overbooking fee - let slot_overbooking_fee = Self::overbooking_fee( - max_async_gas as u128, - async_gas_target as u128, - slot_occupancy as u128, - max_gas as u128, - slot_overbooking_penalty, - ); + // The integral fee is not enough to respond to quick demand surges within the long booking period `deferred_call_max_future_slots`. Proportional regulation is also necessary. + + // A fee that linearly depends on the total load over `deferred_call_max_future_slots` slots but only when the average load is above `target_async_gas` to not penalize normal use. Booking all the gas from all slots within the booking period requires using the whole initial coin supply. // Global overbooking fee // todo check if this is correct @@ -349,7 +323,17 @@ impl SpeculativeDeferredCallRegistry { (async_gas_target as u128).saturating_mul(async_call_max_booking_slots as u128), global_occupancy, max_gas as u128, - global_overbooking_penalty, + global_overbooking_penalty, // total_supply + ); + + // Finally, a per-slot proportional fee is also added to prevent attackers from denying significant ranges of consecutive slots within the long booking period. + // Slot overbooking fee + let slot_overbooking_fee = Self::overbooking_fee( + max_async_gas as u128, + async_gas_target as u128, + slot_occupancy as u128, + max_gas as u128, + slot_overbooking_penalty, // total_initial_coin_supply/10000 ); // return the fee diff --git a/massa-models/src/config/constants.rs b/massa-models/src/config/constants.rs index 81329b4ae77..7ecb382a45b 100644 --- a/massa-models/src/config/constants.rs +++ b/massa-models/src/config/constants.rs @@ -341,6 +341,8 @@ pub const MAX_DENUNCIATION_CHANGES_LENGTH: u64 = 1_000; /// Maximum size of deferred call pool changes // todo define this value pub const MAX_DEFERRED_CALL_POOL_CHANGES: u64 = 100_000; +/// Maximum size of deferred call future slots (1 week) +pub const MAX_DEFERRED_CALL_FUTURE_SLOTS: u64 = 1209600; // Some checks at compile time that should not be ignored! #[allow(clippy::assertions_on_constants)] diff --git a/massa-node/src/main.rs b/massa-node/src/main.rs index 1709fd5c684..b48269b465d 100644 --- a/massa-node/src/main.rs +++ b/massa-node/src/main.rs @@ -63,16 +63,16 @@ use massa_models::config::constants::{ LEDGER_ENTRY_BASE_COST, LEDGER_ENTRY_DATASTORE_BASE_SIZE, MAX_ADVERTISE_LENGTH, MAX_ASYNC_GAS, MAX_ASYNC_POOL_LENGTH, MAX_BLOCK_SIZE, MAX_BOOTSTRAP_BLOCKS, MAX_BOOTSTRAP_ERROR_LENGTH, MAX_BYTECODE_LENGTH, MAX_CONSENSUS_BLOCKS_IDS, MAX_DATASTORE_ENTRY_COUNT, - MAX_DATASTORE_KEY_LENGTH, MAX_DATASTORE_VALUE_LENGTH, MAX_DEFERRED_CREDITS_LENGTH, - MAX_DENUNCIATIONS_PER_BLOCK_HEADER, MAX_DENUNCIATION_CHANGES_LENGTH, - MAX_ENDORSEMENTS_PER_MESSAGE, MAX_EXECUTED_OPS_CHANGES_LENGTH, MAX_EXECUTED_OPS_LENGTH, - MAX_FUNCTION_NAME_LENGTH, MAX_GAS_PER_BLOCK, MAX_LEDGER_CHANGES_COUNT, MAX_LISTENERS_PER_PEER, - MAX_OPERATIONS_PER_BLOCK, MAX_OPERATIONS_PER_MESSAGE, MAX_OPERATION_DATASTORE_ENTRY_COUNT, - MAX_OPERATION_DATASTORE_KEY_LENGTH, MAX_OPERATION_DATASTORE_VALUE_LENGTH, - MAX_OPERATION_STORAGE_TIME, MAX_PARAMETERS_SIZE, MAX_PEERS_IN_ANNOUNCEMENT_LIST, - MAX_PRODUCTION_STATS_LENGTH, MAX_ROLLS_COUNT_LENGTH, MAX_SIZE_CHANNEL_COMMANDS_CONNECTIVITY, - MAX_SIZE_CHANNEL_COMMANDS_PEERS, MAX_SIZE_CHANNEL_COMMANDS_PEER_TESTERS, - MAX_SIZE_CHANNEL_COMMANDS_PROPAGATION_BLOCKS, + MAX_DATASTORE_KEY_LENGTH, MAX_DATASTORE_VALUE_LENGTH, MAX_DEFERRED_CALL_FUTURE_SLOTS, + MAX_DEFERRED_CREDITS_LENGTH, MAX_DENUNCIATIONS_PER_BLOCK_HEADER, + MAX_DENUNCIATION_CHANGES_LENGTH, MAX_ENDORSEMENTS_PER_MESSAGE, MAX_EXECUTED_OPS_CHANGES_LENGTH, + MAX_EXECUTED_OPS_LENGTH, MAX_FUNCTION_NAME_LENGTH, MAX_GAS_PER_BLOCK, MAX_LEDGER_CHANGES_COUNT, + MAX_LISTENERS_PER_PEER, MAX_OPERATIONS_PER_BLOCK, MAX_OPERATIONS_PER_MESSAGE, + MAX_OPERATION_DATASTORE_ENTRY_COUNT, MAX_OPERATION_DATASTORE_KEY_LENGTH, + MAX_OPERATION_DATASTORE_VALUE_LENGTH, MAX_OPERATION_STORAGE_TIME, MAX_PARAMETERS_SIZE, + MAX_PEERS_IN_ANNOUNCEMENT_LIST, MAX_PRODUCTION_STATS_LENGTH, MAX_ROLLS_COUNT_LENGTH, + MAX_SIZE_CHANNEL_COMMANDS_CONNECTIVITY, MAX_SIZE_CHANNEL_COMMANDS_PEERS, + MAX_SIZE_CHANNEL_COMMANDS_PEER_TESTERS, MAX_SIZE_CHANNEL_COMMANDS_PROPAGATION_BLOCKS, MAX_SIZE_CHANNEL_COMMANDS_PROPAGATION_ENDORSEMENTS, MAX_SIZE_CHANNEL_COMMANDS_PROPAGATION_OPERATIONS, MAX_SIZE_CHANNEL_COMMANDS_RETRIEVAL_BLOCKS, MAX_SIZE_CHANNEL_COMMANDS_RETRIEVAL_ENDORSEMENTS, @@ -518,6 +518,7 @@ async fn launch( .broadcast_slot_execution_traces_channel_capacity, max_execution_traces_slot_limit: SETTINGS.execution.execution_traces_limit, block_dump_folder_path, + max_deferred_call_future_slots: MAX_DEFERRED_CALL_FUTURE_SLOTS, }; let execution_channels = ExecutionChannels { From 9d744235b597cbd28fd0b4f28a8238a790a6deb4 Mon Sep 17 00:00:00 2001 From: modship Date: Tue, 16 Jul 2024 15:24:10 +0200 Subject: [PATCH 021/100] get_deferred_call_quote (interface_impl) --- massa-execution-worker/src/execution.rs | 24 -------------------- massa-execution-worker/src/interface_impl.rs | 21 +++++++++++++++-- 2 files changed, 19 insertions(+), 26 deletions(-) diff --git a/massa-execution-worker/src/execution.rs b/massa-execution-worker/src/execution.rs index f16e976ddc3..297538ff8e9 100644 --- a/massa-execution-worker/src/execution.rs +++ b/massa-execution-worker/src/execution.rs @@ -2271,28 +2271,4 @@ impl ExecutionState { .map(|i| (i.current_version, i.announced_version)), ); } - - // Get the price it would cost to reserve "gas" at target slot "slot". - pub fn deferred_call_quote(&self, slot: Slot, gas: u64) -> Result { - let current_slot = self.active_cursor; - - let gas_booked_slot = self - .execution_context - .lock() - .deferred_calls_get_slot_booked_gas(&slot); - - self.execution_context - .lock() - .deferred_calls_compute_call_fee( - slot, - gas, - self.config.thread_count, - self.config.max_deferred_call_future_slots, - self.config.max_async_gas, - gas_booked_slot, - Amount::from_raw(1_000_000_000), - Amount::from_raw(1_000_000_000 / 10_000), - current_slot, - ) - } } diff --git a/massa-execution-worker/src/interface_impl.rs b/massa-execution-worker/src/interface_impl.rs index ba7d8451f09..8a3cc18b4a1 100644 --- a/massa-execution-worker/src/interface_impl.rs +++ b/massa-execution-worker/src/interface_impl.rs @@ -1347,9 +1347,26 @@ impl Interface for InterfaceImpl { // write-lock context let mut context = context_guard!(self); - //TODO: interrogate the context to check for target slot availability and fees + let current_slot = context.slot; - todo!() + let target_slot = Slot::new(target_slot.0, target_slot.1); + + let gas_booked_slot = context.deferred_calls_get_slot_booked_gas(&target_slot); + + match context.deferred_calls_compute_call_fee( + target_slot, + gas_limit, + self.config.thread_count, + self.config.max_deferred_call_future_slots, + self.config.max_async_gas, + gas_booked_slot, + Amount::from_raw(1_000_000_000), + Amount::from_raw(1_000_000_000 / 10_000), + current_slot, + ) { + Ok(fee) => Ok((true, fee.to_raw())), + Err(_) => Ok((false, 0)), + } } /// Register deferred call From e1f2eca6d76100f259c3e77e1b0bb74847a890ec Mon Sep 17 00:00:00 2001 From: modship Date: Wed, 17 Jul 2024 11:01:31 +0200 Subject: [PATCH 022/100] register call --- massa-deferred-calls/src/slot_changes.rs | 4 ++ massa-execution-worker/src/context.rs | 10 +++++ massa-execution-worker/src/interface_impl.rs | 11 ++---- .../src/speculative_deferred_calls.rs | 37 +++++++++++++++++++ 4 files changed, 55 insertions(+), 7 deletions(-) diff --git a/massa-deferred-calls/src/slot_changes.rs b/massa-deferred-calls/src/slot_changes.rs index e8430422ffa..75807f29ceb 100644 --- a/massa-deferred-calls/src/slot_changes.rs +++ b/massa-deferred-calls/src/slot_changes.rs @@ -32,6 +32,10 @@ pub struct DeferredRegistrySlotChanges { } impl DeferredRegistrySlotChanges { + pub fn calls_len(&self) -> usize { + self.calls.len() + } + pub fn merge(&mut self, other: DeferredRegistrySlotChanges) { unimplemented!("DeferredRegistrySlotChanges::merge") // for (id, change) in other.calls { diff --git a/massa-execution-worker/src/context.rs b/massa-execution-worker/src/context.rs index 4496579d8ad..46463db4cbd 100644 --- a/massa-execution-worker/src/context.rs +++ b/massa-execution-worker/src/context.rs @@ -16,6 +16,7 @@ use crate::speculative_ledger::SpeculativeLedger; use crate::{active_history::ActiveHistory, speculative_roll_state::SpeculativeRollState}; use massa_async_pool::{AsyncMessage, AsyncPoolChanges}; use massa_async_pool::{AsyncMessageId, AsyncMessageInfo}; +use massa_deferred_calls::DeferredCall; use massa_executed_ops::{ExecutedDenunciationsChanges, ExecutedOpsChanges}; use massa_execution_exports::{ EventStore, ExecutedBlockInfo, ExecutionConfig, ExecutionError, ExecutionOutput, @@ -27,6 +28,7 @@ use massa_ledger_exports::{LedgerChanges, SetOrKeep}; use massa_models::address::ExecutionAddressCycleInfo; use massa_models::block_id::BlockIdSerializer; use massa_models::bytecode::Bytecode; +use massa_models::deferred_call_id::DeferredCallId; use massa_models::denunciation::DenunciationIndex; use massa_models::timeslots::get_block_slot_timestamp; use massa_models::{ @@ -1155,6 +1157,14 @@ impl ExecutionContext { current_slot, ) } + + pub fn deferred_call_register( + &mut self, + call: DeferredCall, + ) -> Result { + self.speculative_deferred_calls + .register_call(call, self.execution_trail_hash) + } } /// Generate the execution trail hash diff --git a/massa-execution-worker/src/interface_impl.rs b/massa-execution-worker/src/interface_impl.rs index 8a3cc18b4a1..46773f440f7 100644 --- a/massa-execution-worker/src/interface_impl.rs +++ b/massa-execution-worker/src/interface_impl.rs @@ -1345,7 +1345,8 @@ impl Interface for InterfaceImpl { gas_limit: u64, ) -> Result<(bool, u64)> { // write-lock context - let mut context = context_guard!(self); + + let context = context_guard!(self); let current_slot = context.slot; @@ -1434,13 +1435,9 @@ impl Interface for InterfaceImpl { false, ); - /* - TODO: - * ask the context to register the call - * return the id of the call - */ + let call_id = context.deferred_call_register(call)?; - todo!() + Ok(call_id.as_bytes().to_vec()) } /// Check if an deferred call exists diff --git a/massa-execution-worker/src/speculative_deferred_calls.rs b/massa-execution-worker/src/speculative_deferred_calls.rs index 238dc4fbefb..bcd94414baf 100644 --- a/massa-execution-worker/src/speculative_deferred_calls.rs +++ b/massa-execution-worker/src/speculative_deferred_calls.rs @@ -9,6 +9,7 @@ use massa_final_state::FinalStateController; use massa_models::{ address::Address, amount::Amount, deferred_call_id::DeferredCallId, slot::Slot, }; +use num::Zero; use parking_lot::RwLock; use std::sync::Arc; @@ -342,6 +343,42 @@ impl SpeculativeDeferredCallRegistry { .saturating_add(slot_overbooking_fee)) } + pub fn register_call( + &mut self, + call: DeferredCall, + trail_hash: massa_hash::Hash, + ) -> Result { + let mut index = 0; + + if let Some(val) = self + .deferred_calls_changes + .slots_change + .get(&call.target_slot) + { + index += val.calls_len(); + } + + { + // final state + let slots_call = self + .final_state + .read() + .get_deferred_call_registry() + .get_slot_calls(call.target_slot); + index += slots_call.slot_calls.len(); + } + + if !index.is_zero() { + index += 1; + } + + let id = DeferredCallId::new(0, call.target_slot, index as u64, trail_hash.to_bytes())?; + + self.deferred_calls_changes.set_call(id.clone(), call); + + Ok(id) + } + /// Take the deferred registry slot changes pub(crate) fn take(&mut self) -> DeferredRegistryChanges { std::mem::take(&mut self.deferred_calls_changes) From 1bcc0269133c385128ded219bbea49f5282f89b8 Mon Sep 17 00:00:00 2001 From: modship Date: Wed, 17 Jul 2024 11:45:18 +0200 Subject: [PATCH 023/100] register set gas --- massa-execution-worker/src/interface_impl.rs | 35 ++++++++++++++--- .../src/speculative_deferred_calls.rs | 39 ++++++++++++++++++- 2 files changed, 67 insertions(+), 7 deletions(-) diff --git a/massa-execution-worker/src/interface_impl.rs b/massa-execution-worker/src/interface_impl.rs index 46773f440f7..92d2072d6ac 100644 --- a/massa-execution-worker/src/interface_impl.rs +++ b/massa-execution-worker/src/interface_impl.rs @@ -1339,11 +1339,7 @@ impl Interface for InterfaceImpl { /// /// # Returns /// A tuple containing a boolean indicating if the call is possible and the amount of fees needed - fn get_deferred_call_quote( - &self, - target_slot: (u64, u8), - gas_limit: u64, - ) -> Result<(bool, u64)> { + fn deferred_call_quote(&self, target_slot: (u64, u8), gas_limit: u64) -> Result<(bool, u64)> { // write-lock context let context = context_guard!(self); @@ -1391,6 +1387,24 @@ impl Interface for InterfaceImpl { coins: u64, max_gas: u64, ) -> Result> { + // This function spends coins + deferred_call_quote(target_slot, max_gas).unwrap() from the caller, fails if the balance is insufficient or if the quote would return None. + + // let total_booked_gas = get_current_total_booked_async_gas(); + + // const CONST_ASYNC_GAS: u64 = XXXXX; // TODO calibrate: const_gas is the gas used even when gas=0 in order to process the item + // let effective_gas = CONST_ASYNC_GAS + max_gas; + // let fee = get_price(target_slot, effective_gas)?; + + // // TODO: make sender pay `coins + fee` + + // let call = /* ... */; + // let id = /* ... */ ; + + // target_slot.booked_calls.push(callID, call); + // target_slot.async_gas_booked += effective_gas; + + // set_current_total_booked_async_gas(total_booked_gas + effective_gas) + let target_addr = Address::from_str(target_addr)?; // check that the target address is an SC address @@ -1407,7 +1421,7 @@ 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.deferred_call_quote(target_slot, max_gas)?; if !available { bail!("The ASC 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."); } @@ -1423,6 +1437,15 @@ impl Interface for InterfaceImpl { _ => bail!("failed to read call stack sender address"), }; + // transfer coins from caller to target address + // coins + cost for booking the deferred call + context.transfer_coins( + Some(sender_address), + Some(target_addr), + coins.saturating_add(fee), + true, + )?; + let call = DeferredCall::new( sender_address, Slot::new(target_slot.0, target_slot.1), diff --git a/massa-execution-worker/src/speculative_deferred_calls.rs b/massa-execution-worker/src/speculative_deferred_calls.rs index bcd94414baf..fb084144528 100644 --- a/massa-execution-worker/src/speculative_deferred_calls.rs +++ b/massa-execution-worker/src/speculative_deferred_calls.rs @@ -50,6 +50,34 @@ impl SpeculativeDeferredCallRegistry { self.deferred_calls_changes.set_call(id, call); } + pub fn get_total_gas(&self) -> u128 { + // get total gas from current changes + if let Some(v) = self.deferred_calls_changes.get_total_gas() { + return v; + } + + // check in history backwards + { + let history = self.active_history.read(); + for history_item in history.0.iter().rev() { + if let Some(v) = history_item + .state_changes + .deferred_call_changes + .get_total_gas() + { + return v; + } + } + } + + // check in final state + return self + .final_state + .read() + .get_deferred_call_registry() + .get_total_gas(); + } + pub fn get_slot_gas(&self, slot: &Slot) -> u64 { // get slot gas from current changes if let Some(v) = self.deferred_calls_changes.get_slot_gas(slot) { @@ -374,7 +402,16 @@ impl SpeculativeDeferredCallRegistry { let id = DeferredCallId::new(0, call.target_slot, index as u64, trail_hash.to_bytes())?; - self.deferred_calls_changes.set_call(id.clone(), call); + self.deferred_calls_changes + .set_call(id.clone(), call.clone()); + + let current_gas = self.get_slot_gas(&call.target_slot); + + self.deferred_calls_changes + .set_slot_gas(call.target_slot, current_gas + call.max_gas); + + self.deferred_calls_changes + .set_total_gas(self.get_total_gas().saturating_add(call.max_gas as u128)); Ok(id) } From 14ca8d54bfe623cd6c6db7b989f8957b41d1f943 Mon Sep 17 00:00:00 2001 From: modship Date: Wed, 17 Jul 2024 16:28:47 +0200 Subject: [PATCH 024/100] deferred_call_cancel --- massa-deferred-calls/src/macros.rs | 2 +- massa-execution-worker/src/context.rs | 39 +++++++++++++++++++ massa-execution-worker/src/interface_impl.rs | 35 +++++++++-------- .../src/speculative_deferred_calls.rs | 15 ++++++- massa-models/src/deferred_call_id.rs | 4 +- 5 files changed, 75 insertions(+), 20 deletions(-) diff --git a/massa-deferred-calls/src/macros.rs b/massa-deferred-calls/src/macros.rs index 6c905e62ce1..28f50e20081 100644 --- a/massa-deferred-calls/src/macros.rs +++ b/massa-deferred-calls/src/macros.rs @@ -169,7 +169,7 @@ mod tests { ) .unwrap(); - let mut id_ser = DeferredCallIdSerializer::new(); + let id_ser = DeferredCallIdSerializer::new(); let mut buf_id = Vec::new(); id_ser.serialize(&id, &mut buf_id).unwrap(); diff --git a/massa-execution-worker/src/context.rs b/massa-execution-worker/src/context.rs index 46463db4cbd..3b2042fca71 100644 --- a/massa-execution-worker/src/context.rs +++ b/massa-execution-worker/src/context.rs @@ -1165,6 +1165,45 @@ impl ExecutionContext { self.speculative_deferred_calls .register_call(call, self.execution_trail_hash) } + + pub fn deferred_call_exist(&self, call_id: &DeferredCallId) -> bool { + self.speculative_deferred_calls.get_call(call_id).is_some() + } + + pub fn deferred_call_cancel( + &mut self, + call_id: &DeferredCallId, + caller_address: Address, + ) -> Result<(), ExecutionError> { + match self.speculative_deferred_calls.get_call(call_id) { + Some(call) => { + // check that the caller is the one who registered the deferred call + if call.sender_address != caller_address { + return Err(ExecutionError::DeferredCallsError(format!( + "only the caller {} can cancel the deferred call", + call.sender_address + ))); + } + + let (address, amount) = self.speculative_deferred_calls.cancel_call(call_id)?; + + // refund the coins to the caller + let transfer_result = self.transfer_coins(None, Some(address), amount, false); + if let Err(e) = transfer_result.as_ref() { + debug!( + "deferred call cancel: reimbursement of {} failed: {}", + address, e + ); + } + + Ok(()) + } + _ => Err(ExecutionError::DeferredCallsError(format!( + "deferred call {} does not exist", + call_id + )))?, + } + } } /// Generate the execution trail hash diff --git a/massa-execution-worker/src/interface_impl.rs b/massa-execution-worker/src/interface_impl.rs index 92d2072d6ac..44839a35f2b 100644 --- a/massa-execution-worker/src/interface_impl.rs +++ b/massa-execution-worker/src/interface_impl.rs @@ -13,6 +13,7 @@ use massa_execution_exports::ExecutionConfig; use massa_execution_exports::ExecutionStackElement; use massa_models::bytecode::Bytecode; use massa_models::datastore::get_prefix_bounds; +use massa_models::deferred_call_id::DeferredCallId; use massa_models::{ address::{Address, SCAddress, UserAddress}, amount::Amount, @@ -1405,6 +1406,10 @@ impl Interface for InterfaceImpl { // set_current_total_booked_async_gas(total_booked_gas + effective_gas) + const CONST_DEFERRED_CALL_GAS: u64 = 0; // TODO calibrate: const_gas is the gas used even when gas=0 in order to process the item + + let max_gas = CONST_DEFERRED_CALL_GAS + max_gas; + let target_addr = Address::from_str(target_addr)?; // check that the target address is an SC address @@ -1437,14 +1442,9 @@ impl Interface for InterfaceImpl { _ => bail!("failed to read call stack sender address"), }; - // transfer coins from caller to target address + // make sender pay coins + fee // coins + cost for booking the deferred call - context.transfer_coins( - Some(sender_address), - Some(target_addr), - coins.saturating_add(fee), - true, - )?; + context.transfer_coins(Some(sender_address), None, coins.saturating_add(fee), true)?; let call = DeferredCall::new( sender_address, @@ -1472,24 +1472,27 @@ impl Interface for InterfaceImpl { /// true if the call exists, false otherwise fn deferred_call_exists(&self, id: &[u8]) -> Result { // write-lock context - let mut context = context_guard!(self); - - //TODO: ask the context if the call exists - - todo!() + let call_id = DeferredCallId::from_bytes(id)?; + let context = context_guard!(self); + Ok(context.deferred_call_exist(&call_id)) } - /// Cancel an asynchronous call + /// Cancel a deferred call /// /// # Arguments /// * id: the id of the call fn deferred_call_cancel(&self, id: &[u8]) -> Result<()> { - // write-lock context + // Reimburses coins to the sender but not the deferred call fee to avoid spam. Cancelled items are not removed from storage to avoid manipulation, just ignored when it is their turn to be executed. + let mut context = context_guard!(self); - //TODO: ask the context to cancel the call + // Can only be called by the creator of the deferred call. + let caller = context.get_current_address()?; + + let call_id = DeferredCallId::from_bytes(id)?; - todo!() + context.deferred_call_cancel(&call_id, caller)?; + Ok(()) } #[allow(unused_variables)] diff --git a/massa-execution-worker/src/speculative_deferred_calls.rs b/massa-execution-worker/src/speculative_deferred_calls.rs index fb084144528..90951acd6ff 100644 --- a/massa-execution-worker/src/speculative_deferred_calls.rs +++ b/massa-execution-worker/src/speculative_deferred_calls.rs @@ -243,7 +243,18 @@ impl SpeculativeDeferredCallRegistry { let res = (call.sender_address, call.coins); // Add a cancellation to the current changes - self.deferred_calls_changes.set_call(id.clone(), call); + self.deferred_calls_changes + .set_call(id.clone(), call.clone()); + + let current_gas = self.get_slot_gas(&call.target_slot); + + // set slot gas + self.deferred_calls_changes + .set_slot_gas(call.target_slot, current_gas - call.max_gas); + + // set total gas + self.deferred_calls_changes + .set_total_gas(self.get_total_gas().saturating_sub(call.max_gas as u128)); Ok(res) } @@ -407,9 +418,11 @@ impl SpeculativeDeferredCallRegistry { let current_gas = self.get_slot_gas(&call.target_slot); + // set slot gas self.deferred_calls_changes .set_slot_gas(call.target_slot, current_gas + call.max_gas); + // set total gas self.deferred_calls_changes .set_total_gas(self.get_total_gas().saturating_add(call.max_gas as u128)); diff --git a/massa-models/src/deferred_call_id.rs b/massa-models/src/deferred_call_id.rs index 111ac7a3450..3839fb4eab2 100644 --- a/massa-models/src/deferred_call_id.rs +++ b/massa-models/src/deferred_call_id.rs @@ -4,7 +4,7 @@ use massa_serialization::{ Deserializer, SerializeError, Serializer, U64VarIntDeserializer, U64VarIntSerializer, }; use nom::{ - error::{ContextError, ErrorKind, ParseError}, + error::{ContextError, ParseError}, IResult, }; use transition::Versioned; @@ -195,7 +195,7 @@ impl DeferredCallId { index: u64, trail_hash: &[u8], ) -> Result { - let mut id = Vec::new(); + let mut id: Vec = Vec::new(); match version { 0 => { let version_serializer = U64VarIntSerializer::new(); From 4a0c7db0ab4276276df9e6384b0a76acf3fd2d71 Mon Sep 17 00:00:00 2001 From: modship Date: Wed, 24 Jul 2024 09:59:40 +0200 Subject: [PATCH 025/100] execute deferred call, advance_slot, snapshot --- massa-deferred-calls/src/slot_changes.rs | 9 +- .../src/test_exports/config.rs | 2 +- massa-execution-worker/src/context.rs | 26 +++- massa-execution-worker/src/execution.rs | 142 +++++++++++++++++- massa-execution-worker/src/execution_info.rs | 23 +++ .../src/speculative_deferred_calls.rs | 81 ++++++++-- massa-final-state/src/state_changes.rs | 4 +- massa-models/src/config/constants.rs | 10 +- massa-models/src/deferred_call_id.rs | 8 +- massa-node/src/main.rs | 16 +- 10 files changed, 291 insertions(+), 30 deletions(-) diff --git a/massa-deferred-calls/src/slot_changes.rs b/massa-deferred-calls/src/slot_changes.rs index 75807f29ceb..f56f011062c 100644 --- a/massa-deferred-calls/src/slot_changes.rs +++ b/massa-deferred-calls/src/slot_changes.rs @@ -6,7 +6,8 @@ use crate::{ DeferredRegistryGasChange, }; use massa_ledger_exports::{ - SetOrDeleteDeserializer, SetOrDeleteSerializer, SetOrKeepDeserializer, SetOrKeepSerializer, + SetOrDelete, SetOrDeleteDeserializer, SetOrDeleteSerializer, SetOrKeepDeserializer, + SetOrKeepSerializer, }; use massa_models::{ amount::{Amount, AmountDeserializer, AmountSerializer}, @@ -73,8 +74,10 @@ impl DeferredRegistrySlotChanges { } pub fn get_call(&self, id: &DeferredCallId) -> Option<&DeferredCall> { - unimplemented!("DeferredRegistrySlotChanges::get_call") - // self.calls.get(id).and_then(|change| change.get_call()) + match self.calls.get(id) { + Some(SetOrDelete::Set(call)) => Some(call), + _ => None, + } } pub fn set_gas(&mut self, gas: u64) { diff --git a/massa-execution-exports/src/test_exports/config.rs b/massa-execution-exports/src/test_exports/config.rs index 97fe7f37e3e..c6f8f749893 100644 --- a/massa-execution-exports/src/test_exports/config.rs +++ b/massa-execution-exports/src/test_exports/config.rs @@ -81,7 +81,7 @@ impl Default for ExecutionConfig { broadcast_slot_execution_traces_channel_capacity: 5000, max_execution_traces_slot_limit: 320, block_dump_folder_path, - max_deferred_call_future_slots: MAX_DEFERRED_CALL_FUTURE_SLOTS, + max_deferred_call_future_slots: DEFERRED_CALL_MAX_FUTURE_SLOTS, } } } diff --git a/massa-execution-worker/src/context.rs b/massa-execution-worker/src/context.rs index 3b2042fca71..13836da8145 100644 --- a/massa-execution-worker/src/context.rs +++ b/massa-execution-worker/src/context.rs @@ -16,7 +16,8 @@ use crate::speculative_ledger::SpeculativeLedger; use crate::{active_history::ActiveHistory, speculative_roll_state::SpeculativeRollState}; use massa_async_pool::{AsyncMessage, AsyncPoolChanges}; use massa_async_pool::{AsyncMessageId, AsyncMessageInfo}; -use massa_deferred_calls::DeferredCall; +use massa_deferred_calls::registry_changes::DeferredRegistryChanges; +use massa_deferred_calls::{DeferredCall, DeferredSlotCalls}; use massa_executed_ops::{ExecutedDenunciationsChanges, ExecutedOpsChanges}; use massa_execution_exports::{ EventStore, ExecutedBlockInfo, ExecutionConfig, ExecutionError, ExecutionOutput, @@ -61,6 +62,9 @@ pub struct ExecutionContextSnapshot { /// speculative asynchronous pool messages emitted so far in the context pub async_pool_changes: AsyncPoolChanges, + /// speculative deferred calls changes + pub deferred_calls_changes: DeferredRegistryChanges, + /// the associated message infos for the speculative async pool pub message_infos: BTreeMap, @@ -263,6 +267,7 @@ impl ExecutionContext { ExecutionContextSnapshot { ledger_changes: self.speculative_ledger.get_snapshot(), async_pool_changes, + deferred_calls_changes: self.speculative_deferred_calls.get_snapshot(), message_infos, pos_changes: self.speculative_roll_state.get_snapshot(), executed_ops: self.speculative_executed_ops.get_snapshot(), @@ -290,6 +295,8 @@ impl ExecutionContext { .reset_to_snapshot(snapshot.ledger_changes); self.speculative_async_pool .reset_to_snapshot((snapshot.async_pool_changes, snapshot.message_infos)); + self.speculative_deferred_calls + .reset_to_snapshot(snapshot.deferred_calls_changes); self.speculative_roll_state .reset_to_snapshot(snapshot.pos_changes); self.speculative_executed_ops @@ -1132,6 +1139,23 @@ impl ExecutionContext { self.speculative_deferred_calls.get_slot_gas(slot) } + pub fn deferred_calls_get_slot_base_fee(&mut self, slot: &Slot) -> Amount { + self.speculative_deferred_calls.get_slot_base_fee(slot) + } + + pub fn deferred_calls_advance_slot( + &mut self, + current_slot: Slot, + async_call_max_booking_slots: u64, + thread_count: u8, + ) -> DeferredSlotCalls { + self.speculative_deferred_calls.advance_slot( + current_slot, + async_call_max_booking_slots, + thread_count, + ) + } + /// Get the price it would cost to reserve "gas" at target slot "slot". pub fn deferred_calls_compute_call_fee( &self, diff --git a/massa-execution-worker/src/execution.rs b/massa-execution-worker/src/execution.rs index 297538ff8e9..de61ae42f9b 100644 --- a/massa-execution-worker/src/execution.rs +++ b/massa-execution-worker/src/execution.rs @@ -15,6 +15,7 @@ use crate::stats::ExecutionStatsCounter; #[cfg(feature = "dump-block")] use crate::storage_backend::StorageBackend; use massa_async_pool::AsyncMessage; +use massa_deferred_calls::DeferredCall; use massa_execution_exports::{ EventStore, ExecutedBlockInfo, ExecutionBlockMetadata, ExecutionChannels, ExecutionConfig, ExecutionError, ExecutionOutput, ExecutionQueryCycleInfos, ExecutionQueryStakerInfo, @@ -27,6 +28,7 @@ use massa_metrics::MassaMetrics; use massa_models::address::ExecutionAddressCycleInfo; use massa_models::bytecode::Bytecode; +use massa_models::config::DEFERRED_CALL_MAX_FUTURE_SLOTS; use massa_models::datastore::get_prefix_bounds; use massa_models::denunciation::{Denunciation, DenunciationIndex}; use massa_models::execution::EventFilter; @@ -51,7 +53,9 @@ use std::collections::{BTreeMap, BTreeSet}; use std::sync::Arc; use tracing::{debug, info, trace, warn}; -use crate::execution_info::{AsyncMessageExecutionResult, DenunciationResult}; +use crate::execution_info::{ + AsyncMessageExecutionResult, DeferredCallExecutionResult, DenunciationResult, +}; #[cfg(feature = "execution-info")] use crate::execution_info::{ExecutionInfo, ExecutionInfoForSlot, OperationInfo}; #[cfg(feature = "execution-trace")] @@ -1221,6 +1225,123 @@ impl ExecutionState { } } + fn execute_deferred_call( + &self, + call: DeferredCall, + ) -> Result { + let mut result = DeferredCallExecutionResult::new(&call); + + let mut context = context_guard!(self); + + let snapshot = context.get_snapshot(); + + // todo call the function + + // prepare the current slot context for executing the operation + let bytecode; + { + // acquire write access to the context + // let mut context = context_guard!(self); + + // Set the call stack + // This needs to be defined before anything can fail, so that the emitted event contains the right stack + context.stack = vec![ + ExecutionStackElement { + address: call.sender_address, + coins: call.coins, + owned_addresses: vec![call.sender_address], + operation_datastore: None, + }, + ExecutionStackElement { + address: call.target_address, + coins: call.coins, + owned_addresses: vec![call.target_address], + operation_datastore: None, + }, + ]; + + // Ensure that the target address is an SC address + // Ensure that the target address exists + context.check_target_sc_address(call.target_address)?; + + // credit coins to the target address + if let Err(err) = + context.transfer_coins(None, Some(call.target_address), call.coins, false) + { + // coin crediting failed: reset context to snapshot and reimburse sender + let err = ExecutionError::RuntimeError(format!( + "could not credit coins to target of deferred call execution: {}", + err + )); + + context.reset_to_snapshot(snapshot, err.clone()); + // todo cancel the deferred call + // context.cancel_async_message(&message); + return Err(err); + } + + // quit if there is no function to be called + if call.target_function.is_empty() { + return Err(ExecutionError::RuntimeError( + "no function to call in the deferred call".to_string(), + )); + } + + // Load bytecode. Assume empty bytecode if not found. + bytecode = context + .get_bytecode(&call.target_address) + .unwrap_or_default() + .0; + } + + let module = self + .module_cache + .write() + .load_module(&bytecode, call.max_gas)?; + let response = massa_sc_runtime::run_function( + &*self.execution_interface, + module, + &call.target_function, + &call.parameters, + call.max_gas, + self.config.gas_costs.clone(), + ); + + match response { + Ok(res) => { + self.module_cache + .write() + .set_init_cost(&bytecode, res.init_gas_cost); + #[cfg(feature = "execution-trace")] + { + result.traces = Some((res.trace.into_iter().map(|t| t.into()).collect(), true)); + } + // #[cfg(feature = "execution-info")] + // { + // result.success = true; + // } + result.success = true; + Ok(result) + } + Err(error) => { + if let VMError::ExecutionError { init_gas_cost, .. } = error { + self.module_cache + .write() + .set_init_cost(&bytecode, init_gas_cost); + } + // execution failed: reset context to snapshot and reimburse sender + let err = ExecutionError::VMError { + context: "Deferred Call".to_string(), + error, + }; + let mut context = context_guard!(self); + context.reset_to_snapshot(snapshot, err.clone()); + // todo cancel the deferred call + // context.cancel_async_message(&message); + Err(err) + } + } + } /// Executes a full slot (with or without a block inside) without causing any changes to the state, /// just yielding the execution output. /// @@ -1260,6 +1381,25 @@ impl ExecutionState { self.mip_store.clone(), ); + // Deferred calls + let calls = execution_context.deferred_calls_advance_slot( + slot.clone(), + DEFERRED_CALL_MAX_FUTURE_SLOTS, + self.config.thread_count, + ); + + for (id, call) in calls.slot_calls { + match self.execute_deferred_call(call) { + Ok(exec) => { + info!("executed deferred call: {:?}", id); + } + Err(err) => { + let msg = format!("failed executing deferred call: {}", err); + debug!(msg); + } + } + } + // Get asynchronous messages to execute let messages = execution_context.take_async_batch( self.config.max_async_gas, diff --git a/massa-execution-worker/src/execution_info.rs b/massa-execution-worker/src/execution_info.rs index aaac0da631d..f881cedf901 100644 --- a/massa-execution-worker/src/execution_info.rs +++ b/massa-execution-worker/src/execution_info.rs @@ -2,6 +2,7 @@ use std::collections::HashMap; +use massa_deferred_calls::DeferredCall; use schnellru::{ByLength, LruMap}; // use massa_execution_exports::Transfer; @@ -94,3 +95,25 @@ impl AsyncMessageExecutionResult { } } } + +pub struct DeferredCallExecutionResult { + pub(crate) success: bool, + pub(crate) sender: Address, + pub(crate) target_address: Address, + pub(crate) target_function: String, + pub(crate) coins: Amount, + pub(crate) traces: Option, +} + +impl DeferredCallExecutionResult { + pub fn new(call: &DeferredCall) -> Self { + Self { + success: false, + sender: call.sender_address, + target_address: call.target_address, + target_function: call.target_function.clone(), + coins: call.coins, + traces: None, + } + } +} diff --git a/massa-execution-worker/src/speculative_deferred_calls.rs b/massa-execution-worker/src/speculative_deferred_calls.rs index 90951acd6ff..a8ef42ca0f5 100644 --- a/massa-execution-worker/src/speculative_deferred_calls.rs +++ b/massa-execution-worker/src/speculative_deferred_calls.rs @@ -7,11 +7,19 @@ use massa_deferred_calls::{ use massa_execution_exports::ExecutionError; use massa_final_state::FinalStateController; use massa_models::{ - address::Address, amount::Amount, deferred_call_id::DeferredCallId, slot::Slot, + address::Address, + amount::Amount, + config::{ + DEFERRED_CALL_BASE_FEE_MAX_CHANGE_DENOMINATOR, DEFERRED_CALL_MAX_FUTURE_SLOTS, + DEFERRED_CALL_MIN_GAS_COST, DEFERRED_CALL_MIN_GAS_INCREMENT, MAX_ASYNC_GAS, + }, + deferred_call_id::DeferredCallId, + slot::Slot, }; -use num::Zero; use parking_lot::RwLock; -use std::sync::Arc; +use std::{cmp::max, sync::Arc}; + +const TARGET_BOOKING: u128 = (MAX_ASYNC_GAS / 2) as u128; pub(crate) struct SpeculativeDeferredCallRegistry { final_state: Arc>, @@ -154,13 +162,71 @@ impl SpeculativeDeferredCallRegistry { } slot_calls.apply_changes(&self.deferred_calls_changes); + // const BASE_FEE_MAX_CHANGE_DENOMINATOR = 8; + // const MIN_GAS_INCREMENT = 1 nano-massa; + // const MIN_GAS_COST = 10 nano-massa + + // let TARGET_BOOKING = MAX_ASYNC_GAS/2; + // let total_booked_gas = get_current_total_booked_async_gas(); + // let avg_booked_gas = total_booked_gas/ASYNC_BOOKING_SLOT_COUNT; + + // if (avg_booked_gas == TARGET_BOOKING) { + // S.base_fee_per_gas = (S-1).base_async_gas_cost; + // } else if (avg_booked_gas > TARGET_BOOKING) { + // gas_used_delta = avg_booked_gas - TARGET_BOOKING; + // S.base_fee_per_gas = (S-1).base_async_gas_cost + ((S-1).base_async_gas_cost * gas_used_delta / TARGET_BOOKING / BASE_FEE_MAX_CHANGE_DENOMINATOR, MIN_GAS_INCREMENT) + // } else { + // gas_used_delta = TARGET_BOOKING - total_booked_gas + // S.base_fee_per_gas = max((S-1).base_async_gas_cost - (S-1).base_async_gas_cost * gas_used_delta / TARGET_BOOKING / BASE_FEE_MAX_CHANGE_DENOMINATOR, MIN_GAS_COST) + // } + + let total_booked_gas = self.get_total_gas(); + let avg_booked_gas = + total_booked_gas.saturating_div(DEFERRED_CALL_MAX_FUTURE_SLOTS as u128); + // select the slot that is newly made available and set its base fee - let mut new_slot = current_slot + let new_slot = current_slot .skip(async_call_max_booking_slots, thread_count) .expect("could not skip enough slots"); + let prev_slot = new_slot + .get_prev_slot(thread_count) + .expect("cannot get prev slot"); + + let prev_slot_base_fee = self.get_slot_base_fee(&prev_slot); + + let new_slot_base_fee = match avg_booked_gas.cmp(&TARGET_BOOKING) { + std::cmp::Ordering::Equal => prev_slot_base_fee, + std::cmp::Ordering::Greater => { + let gas_used_delta = avg_booked_gas.saturating_sub(TARGET_BOOKING); + + let factor = gas_used_delta as u64 + / TARGET_BOOKING as u64 + / DEFERRED_CALL_BASE_FEE_MAX_CHANGE_DENOMINATOR as u64; + + max( + prev_slot_base_fee + .saturating_add(prev_slot_base_fee.saturating_mul_u64(factor)), + Amount::from_raw(DEFERRED_CALL_MIN_GAS_INCREMENT), + ) + } + std::cmp::Ordering::Less => { + let gas_used_delta = TARGET_BOOKING.saturating_sub(total_booked_gas); + + let factor = gas_used_delta as u64 + / TARGET_BOOKING as u64 + / DEFERRED_CALL_BASE_FEE_MAX_CHANGE_DENOMINATOR as u64; + + max( + prev_slot_base_fee + .saturating_sub(prev_slot_base_fee.saturating_mul_u64(factor)), + Amount::from_raw(DEFERRED_CALL_MIN_GAS_COST), + ) + } + }; + self.deferred_calls_changes - .set_slot_base_fee(new_slot, todo!()); + .set_slot_base_fee(new_slot, new_slot_base_fee); // subtract the current slot gas from the total gas self.deferred_calls_changes.set_total_gas( @@ -168,7 +234,6 @@ impl SpeculativeDeferredCallRegistry { .total_gas .saturating_sub(slot_calls.slot_gas.into()), ); - // delete the current slot for (id, _call) in &slot_calls.slot_calls { self.deferred_calls_changes.delete_call(current_slot, id); @@ -407,10 +472,6 @@ impl SpeculativeDeferredCallRegistry { index += slots_call.slot_calls.len(); } - if !index.is_zero() { - index += 1; - } - let id = DeferredCallId::new(0, call.target_slot, index as u64, trail_hash.to_bytes())?; self.deferred_calls_changes diff --git a/massa-final-state/src/state_changes.rs b/massa-final-state/src/state_changes.rs index abeacf5fee3..1511f6de547 100644 --- a/massa-final-state/src/state_changes.rs +++ b/massa-final-state/src/state_changes.rs @@ -254,7 +254,7 @@ mod test { use massa_models::amount::Amount; use massa_models::bytecode::Bytecode; use massa_models::slot::Slot; - use massa_models::{address::Address, config::MAX_DEFERRED_CALL_POOL_CHANGES}; + use massa_models::{address::Address, config::DEFERRED_CALL_MAX_POOL_CHANGES}; use massa_serialization::DeserializeError; use massa_models::config::{ @@ -339,7 +339,7 @@ mod test { MAX_EXECUTED_OPS_CHANGES_LENGTH, ENDORSEMENT_COUNT, MAX_DENUNCIATION_CHANGES_LENGTH, - MAX_DEFERRED_CALL_POOL_CHANGES, + DEFERRED_CALL_MAX_POOL_CHANGES, ) .deserialize::(&serialized) .unwrap(); diff --git a/massa-models/src/config/constants.rs b/massa-models/src/config/constants.rs index 7ecb382a45b..828c6268120 100644 --- a/massa-models/src/config/constants.rs +++ b/massa-models/src/config/constants.rs @@ -340,9 +340,15 @@ pub const ROLL_COUNT_TO_SLASH_ON_DENUNCIATION: u64 = 1; pub const MAX_DENUNCIATION_CHANGES_LENGTH: u64 = 1_000; /// Maximum size of deferred call pool changes // todo define this value -pub const MAX_DEFERRED_CALL_POOL_CHANGES: u64 = 100_000; +pub const DEFERRED_CALL_MAX_POOL_CHANGES: u64 = 100_000; /// Maximum size of deferred call future slots (1 week) -pub const MAX_DEFERRED_CALL_FUTURE_SLOTS: u64 = 1209600; +pub const DEFERRED_CALL_MAX_FUTURE_SLOTS: u64 = 1209600; +/// max change denominator +pub const DEFERRED_CALL_BASE_FEE_MAX_CHANGE_DENOMINATOR: usize = 8; +/// deferred call min gas increment (1 nanomassa) +pub const DEFERRED_CALL_MIN_GAS_INCREMENT: u64 = 1; +/// deferred call max gas cost (10 nanomassa) +pub const DEFERRED_CALL_MIN_GAS_COST: u64 = 10; // Some checks at compile time that should not be ignored! #[allow(clippy::assertions_on_constants)] diff --git a/massa-models/src/deferred_call_id.rs b/massa-models/src/deferred_call_id.rs index 3839fb4eab2..efacbf2ce1c 100644 --- a/massa-models/src/deferred_call_id.rs +++ b/massa-models/src/deferred_call_id.rs @@ -12,7 +12,7 @@ use transition::Versioned; use crate::{ error::ModelsError, serialization::{VecU8Deserializer, VecU8Serializer}, - slot::{Slot, SlotSerializer}, + slot::{Slot, SlotDeserializer, SlotSerializer}, }; const DEFERRED_CALL_ID_PREFIX: &str = "D"; @@ -185,7 +185,11 @@ impl<'de> ::serde::Deserialize<'de> for DeferredCallId { impl DeferredCallId { pub fn get_slot(&self) -> Slot { - todo!(); + // retrieve the slot from the id + todo!() + // let slot_serializer = SlotDeserializer::new(); + // let (_, slot) = slot_serializer.deserialize(self.as_bytes()).unwrap(); + // slot } /// Create a new `DeferredCallId` diff --git a/massa-node/src/main.rs b/massa-node/src/main.rs index b48269b465d..31d66a1753f 100644 --- a/massa-node/src/main.rs +++ b/massa-node/src/main.rs @@ -58,13 +58,13 @@ use massa_models::address::Address; use massa_models::amount::Amount; use massa_models::config::constants::{ ASYNC_MSG_CST_GAS_COST, BLOCK_REWARD, BOOTSTRAP_RANDOMNESS_SIZE_BYTES, CHANNEL_SIZE, - CONSENSUS_BOOTSTRAP_PART_SIZE, DELTA_F0, DENUNCIATION_EXPIRE_PERIODS, ENDORSEMENT_COUNT, - END_TIMESTAMP, GENESIS_KEY, GENESIS_TIMESTAMP, INITIAL_DRAW_SEED, LEDGER_COST_PER_BYTE, - LEDGER_ENTRY_BASE_COST, LEDGER_ENTRY_DATASTORE_BASE_SIZE, MAX_ADVERTISE_LENGTH, MAX_ASYNC_GAS, - MAX_ASYNC_POOL_LENGTH, MAX_BLOCK_SIZE, MAX_BOOTSTRAP_BLOCKS, MAX_BOOTSTRAP_ERROR_LENGTH, - MAX_BYTECODE_LENGTH, MAX_CONSENSUS_BLOCKS_IDS, MAX_DATASTORE_ENTRY_COUNT, - MAX_DATASTORE_KEY_LENGTH, MAX_DATASTORE_VALUE_LENGTH, MAX_DEFERRED_CALL_FUTURE_SLOTS, - MAX_DEFERRED_CREDITS_LENGTH, MAX_DENUNCIATIONS_PER_BLOCK_HEADER, + CONSENSUS_BOOTSTRAP_PART_SIZE, DEFERRED_CALL_MAX_FUTURE_SLOTS, DELTA_F0, + DENUNCIATION_EXPIRE_PERIODS, ENDORSEMENT_COUNT, END_TIMESTAMP, GENESIS_KEY, GENESIS_TIMESTAMP, + INITIAL_DRAW_SEED, LEDGER_COST_PER_BYTE, LEDGER_ENTRY_BASE_COST, + LEDGER_ENTRY_DATASTORE_BASE_SIZE, MAX_ADVERTISE_LENGTH, MAX_ASYNC_GAS, MAX_ASYNC_POOL_LENGTH, + MAX_BLOCK_SIZE, MAX_BOOTSTRAP_BLOCKS, MAX_BOOTSTRAP_ERROR_LENGTH, MAX_BYTECODE_LENGTH, + MAX_CONSENSUS_BLOCKS_IDS, MAX_DATASTORE_ENTRY_COUNT, MAX_DATASTORE_KEY_LENGTH, + MAX_DATASTORE_VALUE_LENGTH, MAX_DEFERRED_CREDITS_LENGTH, MAX_DENUNCIATIONS_PER_BLOCK_HEADER, MAX_DENUNCIATION_CHANGES_LENGTH, MAX_ENDORSEMENTS_PER_MESSAGE, MAX_EXECUTED_OPS_CHANGES_LENGTH, MAX_EXECUTED_OPS_LENGTH, MAX_FUNCTION_NAME_LENGTH, MAX_GAS_PER_BLOCK, MAX_LEDGER_CHANGES_COUNT, MAX_LISTENERS_PER_PEER, MAX_OPERATIONS_PER_BLOCK, MAX_OPERATIONS_PER_MESSAGE, @@ -518,7 +518,7 @@ async fn launch( .broadcast_slot_execution_traces_channel_capacity, max_execution_traces_slot_limit: SETTINGS.execution.execution_traces_limit, block_dump_folder_path, - max_deferred_call_future_slots: MAX_DEFERRED_CALL_FUTURE_SLOTS, + max_deferred_call_future_slots: DEFERRED_CALL_MAX_FUTURE_SLOTS, }; let execution_channels = ExecutionChannels { From ee901f1ee5ee98541747ba15418cda76245c7673 Mon Sep 17 00:00:00 2001 From: modship Date: Wed, 24 Jul 2024 16:00:30 +0200 Subject: [PATCH 026/100] execution trace && execution info --- massa-deferred-calls/src/lib.rs | 6 +-- .../src/types_trace_info.rs | 2 + massa-execution-worker/src/execution.rs | 43 +++++++++++++------ massa-execution-worker/src/execution_info.rs | 2 + .../src/speculative_deferred_calls.rs | 4 +- massa-models/src/config/constants.rs | 2 +- massa-models/src/deferred_call_id.rs | 1 + 7 files changed, 42 insertions(+), 18 deletions(-) diff --git a/massa-deferred-calls/src/lib.rs b/massa-deferred-calls/src/lib.rs index d395e2eb0dc..effd128f5c1 100644 --- a/massa-deferred-calls/src/lib.rs +++ b/massa-deferred-calls/src/lib.rs @@ -51,7 +51,7 @@ impl DeferredCallRegistry { [DEFERRED_CALLS_SLOT_PREFIX][slot][CALLS_TAG][id][CALL_FIELD_X_TAG] -> AsyncCall.x // call data */ - // todo pass args + // TODO pass args pub fn new(db: ShareableMassaDBController) -> Self { Self { db, @@ -59,7 +59,7 @@ impl DeferredCallRegistry { call_id_serializer: DeferredCallIdSerializer::new(), call_deserializer: DeferredCallDeserializer::new(THREAD_COUNT), call_id_deserializer: DeferredCallIdDeserializer::new(), - // todo args + // TODO args registry_changes_deserializer: DeferredRegistryChangesDeserializer::new( THREAD_COUNT, 100_000, @@ -393,7 +393,7 @@ impl DeferredCallRegistry { // Delete, // } -// todo put SetOrDelete dans models +// TODO put SetOrDelete dans models pub type DeferredRegistryCallChange = SetOrDelete; pub type DeferredRegistryGasChange = SetOrKeep; pub type DeferredRegistryBaseFeeChange = SetOrKeep; diff --git a/massa-execution-exports/src/types_trace_info.rs b/massa-execution-exports/src/types_trace_info.rs index 9655e473513..6510db98dc7 100644 --- a/massa-execution-exports/src/types_trace_info.rs +++ b/massa-execution-exports/src/types_trace_info.rs @@ -23,6 +23,8 @@ pub struct SlotAbiCallStack { pub slot: Slot, /// asc call stacks pub asc_call_stacks: Vec>, + /// deferred call stacks + pub deferred_call_stacks: Vec>, /// operation call stacks pub operation_call_stacks: PreHashMap>, } diff --git a/massa-execution-worker/src/execution.rs b/massa-execution-worker/src/execution.rs index de61ae42f9b..7fb20fc38da 100644 --- a/massa-execution-worker/src/execution.rs +++ b/massa-execution-worker/src/execution.rs @@ -1235,8 +1235,6 @@ impl ExecutionState { let snapshot = context.get_snapshot(); - // todo call the function - // prepare the current slot context for executing the operation let bytecode; { @@ -1275,7 +1273,7 @@ impl ExecutionState { )); context.reset_to_snapshot(snapshot, err.clone()); - // todo cancel the deferred call + // TODO cancel the deferred call // context.cancel_async_message(&message); return Err(err); } @@ -1336,7 +1334,7 @@ impl ExecutionState { }; let mut context = context_guard!(self); context.reset_to_snapshot(snapshot, err.clone()); - // todo cancel the deferred call + // TODO cancel the deferred call // context.cancel_async_message(&message); Err(err) } @@ -1363,6 +1361,7 @@ impl ExecutionState { slot: *slot, operation_call_stacks: PreHashMap::default(), asc_call_stacks: vec![], + deferred_call_stacks: vec![], }; #[cfg(feature = "execution-trace")] let mut transfers = vec![]; @@ -1388,26 +1387,46 @@ impl ExecutionState { self.config.thread_count, ); + // Get asynchronous messages to execute + let messages = execution_context.take_async_batch( + self.config.max_async_gas, + self.config.async_msg_cst_gas_cost, + ); + + // Apply the created execution context for slot execution + *context_guard!(self) = execution_context; + for (id, call) in calls.slot_calls { + if call.cancelled { + // Skip cancelled calls + continue; + } match self.execute_deferred_call(call) { - Ok(exec) => { + Ok(_exec) => { info!("executed deferred call: {:?}", id); + cfg_if::cfg_if! { + if #[cfg(feature = "execution-trace")] { + // Safe to unwrap + slot_trace.deferred_call_stacks.push(_exec.traces.unwrap().0); + } else if #[cfg(feature = "execution-info")] { + slot_trace.deferred_call_stacks.push(_exec.traces.clone().unwrap().0); + exec_info.deferred_calls_messages.push(Ok(_exec)); + } + } } Err(err) => { let msg = format!("failed executing deferred call: {}", err); + #[cfg(feature = "execution-info")] + exec_info.deferred_calls_messages.push(Err(msg.clone())); debug!(msg); } } + // TODO remove D from the db } - // Get asynchronous messages to execute - let messages = execution_context.take_async_batch( - self.config.max_async_gas, - self.config.async_msg_cst_gas_cost, - ); + // TODO execute async messages as long as there is remaining gas in the slot (counting both unused max_async_gas and max_block_gas, and the latter can be used in full in case of block miss) - // Apply the created execution context for slot execution - *context_guard!(self) = execution_context; + // max_async_gas - calls.slot_gas is the remaining gas for the slot // Try executing asynchronous messages. // Effects are cancelled on failure and the sender is reimbursed. diff --git a/massa-execution-worker/src/execution_info.rs b/massa-execution-worker/src/execution_info.rs index f881cedf901..35994b25a68 100644 --- a/massa-execution-worker/src/execution_info.rs +++ b/massa-execution-worker/src/execution_info.rs @@ -41,6 +41,7 @@ pub struct ExecutionInfoForSlot { pub(crate) denunciations: Vec>, pub(crate) operations: Vec, pub(crate) async_messages: Vec>, + pub(crate) deferred_calls_messages: Vec>, /// Deferred credits execution (empty if execution-info feature is NOT enabled) pub deferred_credits_execution: Vec<(Address, Result)>, /// Cancel async message execution (empty if execution-info feature is NOT enabled) @@ -58,6 +59,7 @@ impl ExecutionInfoForSlot { denunciations: Default::default(), operations: Default::default(), async_messages: Default::default(), + deferred_calls_messages: Default::default(), deferred_credits_execution: vec![], cancel_async_message_execution: vec![], auto_sell_execution: vec![], diff --git a/massa-execution-worker/src/speculative_deferred_calls.rs b/massa-execution-worker/src/speculative_deferred_calls.rs index a8ef42ca0f5..57a9d95295b 100644 --- a/massa-execution-worker/src/speculative_deferred_calls.rs +++ b/massa-execution-worker/src/speculative_deferred_calls.rs @@ -135,7 +135,7 @@ impl SpeculativeDeferredCallRegistry { } // check in final state - // todo check if that is correct + // TODO check if that is correct return self .final_state .read() @@ -418,7 +418,7 @@ impl SpeculativeDeferredCallRegistry { // A fee that linearly depends on the total load over `deferred_call_max_future_slots` slots but only when the average load is above `target_async_gas` to not penalize normal use. Booking all the gas from all slots within the booking period requires using the whole initial coin supply. // Global overbooking fee - // todo check if this is correct + // TODO check if this is correct let global_occupancy = self .deferred_calls_changes .get_total_gas() diff --git a/massa-models/src/config/constants.rs b/massa-models/src/config/constants.rs index 828c6268120..66401fedafd 100644 --- a/massa-models/src/config/constants.rs +++ b/massa-models/src/config/constants.rs @@ -339,7 +339,7 @@ pub const ROLL_COUNT_TO_SLASH_ON_DENUNCIATION: u64 = 1; /// Maximum size of executed denunciations pub const MAX_DENUNCIATION_CHANGES_LENGTH: u64 = 1_000; /// Maximum size of deferred call pool changes -// todo define this value +// TODO define this value pub const DEFERRED_CALL_MAX_POOL_CHANGES: u64 = 100_000; /// Maximum size of deferred call future slots (1 week) pub const DEFERRED_CALL_MAX_FUTURE_SLOTS: u64 = 1209600; diff --git a/massa-models/src/deferred_call_id.rs b/massa-models/src/deferred_call_id.rs index efacbf2ce1c..fd90871de72 100644 --- a/massa-models/src/deferred_call_id.rs +++ b/massa-models/src/deferred_call_id.rs @@ -186,6 +186,7 @@ impl<'de> ::serde::Deserialize<'de> for DeferredCallId { impl DeferredCallId { pub fn get_slot(&self) -> Slot { // retrieve the slot from the id + // TODO implement this todo!() // let slot_serializer = SlotDeserializer::new(); // let (_, slot) = slot_serializer.deserialize(self.as_bytes()).unwrap(); From 693cf0eb9bf5cda8fcd4f611f7307c6339f2c817 Mon Sep 17 00:00:00 2001 From: modship Date: Wed, 24 Jul 2024 17:14:52 +0200 Subject: [PATCH 027/100] delete call from DB --- massa-deferred-calls/src/slot_changes.rs | 16 +++++++++------- massa-execution-worker/src/context.rs | 4 ++++ massa-execution-worker/src/execution.rs | 4 +++- .../src/speculative_deferred_calls.rs | 4 ++++ 4 files changed, 20 insertions(+), 8 deletions(-) diff --git a/massa-deferred-calls/src/slot_changes.rs b/massa-deferred-calls/src/slot_changes.rs index f56f011062c..9f551360ab6 100644 --- a/massa-deferred-calls/src/slot_changes.rs +++ b/massa-deferred-calls/src/slot_changes.rs @@ -59,14 +59,16 @@ impl DeferredRegistrySlotChanges { // } } + /// add Delete changes will delete the call from the db registry when the slot is finalized pub fn delete_call(&mut self, id: &DeferredCallId) { - unimplemented!("DeferredRegistrySlotChanges::delete_call") - // match self.calls.entry(id.clone()) { - // std::collections::btree_map::Entry::Occupied(mut v) => v.get_mut().delete_call(), - // std::collections::btree_map::Entry::Vacant(v) => { - // v.insert(DeferredRegistryCallChange::Delete); - // } - // } + match self.calls.entry(id.clone()) { + std::collections::btree_map::Entry::Occupied(mut v) => { + *v.get_mut() = DeferredRegistryCallChange::Delete; + } + std::collections::btree_map::Entry::Vacant(v) => { + v.insert(DeferredRegistryCallChange::Delete); + } + } } pub fn set_call(&mut self, id: DeferredCallId, call: DeferredCall) { diff --git a/massa-execution-worker/src/context.rs b/massa-execution-worker/src/context.rs index 13836da8145..63add9c1e0a 100644 --- a/massa-execution-worker/src/context.rs +++ b/massa-execution-worker/src/context.rs @@ -1194,6 +1194,10 @@ impl ExecutionContext { self.speculative_deferred_calls.get_call(call_id).is_some() } + pub fn deferred_call_delete(&mut self, call_id: &DeferredCallId, slot: Slot) { + self.speculative_deferred_calls.delete_call(call_id, slot); + } + pub fn deferred_call_cancel( &mut self, call_id: &DeferredCallId, diff --git a/massa-execution-worker/src/execution.rs b/massa-execution-worker/src/execution.rs index 7fb20fc38da..9c5dfda5f1a 100644 --- a/massa-execution-worker/src/execution.rs +++ b/massa-execution-worker/src/execution.rs @@ -1421,7 +1421,9 @@ impl ExecutionState { debug!(msg); } } - // TODO remove D from the db + // remove call from the db : (added Delete to changes) + let mut context = context_guard!(self); + context.deferred_call_delete(&id, slot.clone()); } // TODO execute async messages as long as there is remaining gas in the slot (counting both unused max_async_gas and max_block_gas, and the latter can be used in full in case of block miss) diff --git a/massa-execution-worker/src/speculative_deferred_calls.rs b/massa-execution-worker/src/speculative_deferred_calls.rs index 57a9d95295b..cf5133b7403 100644 --- a/massa-execution-worker/src/speculative_deferred_calls.rs +++ b/massa-execution-worker/src/speculative_deferred_calls.rs @@ -281,6 +281,10 @@ impl SpeculativeDeferredCallRegistry { None } + pub fn delete_call(&mut self, id: &DeferredCallId, slot: Slot) { + self.deferred_calls_changes.delete_call(slot, id) + } + /// Cancel a call /// Returns the sender address and the amount of coins to reimburse them pub fn cancel_call( From 43923d1392d3cb179d8e30a687c369b91fd8b699 Mon Sep 17 00:00:00 2001 From: modship Date: Thu, 25 Jul 2024 10:37:45 +0200 Subject: [PATCH 028/100] slot remaining gas for async msg --- massa-deferred-calls/src/lib.rs | 6 +++--- massa-execution-worker/src/context.rs | 4 ---- massa-execution-worker/src/execution.rs | 17 +++++++++++++++-- massa-execution-worker/src/interface_impl.rs | 2 +- 4 files changed, 19 insertions(+), 10 deletions(-) diff --git a/massa-deferred-calls/src/lib.rs b/massa-deferred-calls/src/lib.rs index effd128f5c1..99cfddb1d5b 100644 --- a/massa-deferred-calls/src/lib.rs +++ b/massa-deferred-calls/src/lib.rs @@ -25,7 +25,7 @@ pub use call::DeferredCall; use massa_ledger_exports::{SetOrDelete, SetOrKeep}; use massa_models::{ amount::Amount, - config::THREAD_COUNT, + config::{DEFERRED_CALL_MAX_POOL_CHANGES, MAX_ASYNC_GAS, THREAD_COUNT}, deferred_call_id::{DeferredCallId, DeferredCallIdDeserializer, DeferredCallIdSerializer}, slot::Slot, }; @@ -62,8 +62,8 @@ impl DeferredCallRegistry { // TODO args registry_changes_deserializer: DeferredRegistryChangesDeserializer::new( THREAD_COUNT, - 100_000, - 100_000, + MAX_ASYNC_GAS, + DEFERRED_CALL_MAX_POOL_CHANGES, ), registry_changes_serializer: DeferredRegistryChangesSerializer::new(), } diff --git a/massa-execution-worker/src/context.rs b/massa-execution-worker/src/context.rs index 63add9c1e0a..e09fa74f3c2 100644 --- a/massa-execution-worker/src/context.rs +++ b/massa-execution-worker/src/context.rs @@ -1139,10 +1139,6 @@ impl ExecutionContext { self.speculative_deferred_calls.get_slot_gas(slot) } - pub fn deferred_calls_get_slot_base_fee(&mut self, slot: &Slot) -> Amount { - self.speculative_deferred_calls.get_slot_base_fee(slot) - } - pub fn deferred_calls_advance_slot( &mut self, current_slot: Slot, diff --git a/massa-execution-worker/src/execution.rs b/massa-execution-worker/src/execution.rs index 9c5dfda5f1a..1ab57bceb6e 100644 --- a/massa-execution-worker/src/execution.rs +++ b/massa-execution-worker/src/execution.rs @@ -1426,13 +1426,26 @@ impl ExecutionState { context.deferred_call_delete(&id, slot.clone()); } - // TODO execute async messages as long as there is remaining gas in the slot (counting both unused max_async_gas and max_block_gas, and the latter can be used in full in case of block miss) + // execute async messages as long as there is remaining gas in the slot (counting both unused max_async_gas and max_block_gas, and the latter can be used in full in case of block miss) - // max_async_gas - calls.slot_gas is the remaining gas for the slot + let mut remaining_async_slot_gas = self.config.max_async_gas.saturating_sub(calls.slot_gas); + let mut remaining_block_gas = self.config.max_gas_per_block.saturating_sub(calls.slot_gas); // Try executing asynchronous messages. // Effects are cancelled on failure and the sender is reimbursed. for (opt_bytecode, message) in messages { + // TODO verify here + if remaining_async_slot_gas == 0 || remaining_block_gas == 0 { + // break if there is no gas left + break; + } + if message.max_gas > remaining_async_slot_gas || message.max_gas > remaining_block_gas { + // Skip message if there is not enough gas left for it + continue; + } + + remaining_async_slot_gas = remaining_async_slot_gas.saturating_sub(message.max_gas); + remaining_block_gas = remaining_block_gas.saturating_sub(message.max_gas); match self.execute_async_message(message, opt_bytecode) { Ok(_message_return) => { cfg_if::cfg_if! { diff --git a/massa-execution-worker/src/interface_impl.rs b/massa-execution-worker/src/interface_impl.rs index 44839a35f2b..5a865ce090d 100644 --- a/massa-execution-worker/src/interface_impl.rs +++ b/massa-execution-worker/src/interface_impl.rs @@ -1396,7 +1396,7 @@ impl Interface for InterfaceImpl { // let effective_gas = CONST_ASYNC_GAS + max_gas; // let fee = get_price(target_slot, effective_gas)?; - // // TODO: make sender pay `coins + fee` + // // make sender pay `coins + fee` // let call = /* ... */; // let id = /* ... */ ; From e94c57f71fbf46b3250182c8aebde7cad3f8cba6 Mon Sep 17 00:00:00 2001 From: modship Date: Thu, 25 Jul 2024 11:21:48 +0200 Subject: [PATCH 029/100] in case of fail, refound sender --- massa-execution-worker/src/context.rs | 27 +++++++++++++++++++++++++ massa-execution-worker/src/execution.rs | 6 ++---- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/massa-execution-worker/src/context.rs b/massa-execution-worker/src/context.rs index e09fa74f3c2..51a9a404f64 100644 --- a/massa-execution-worker/src/context.rs +++ b/massa-execution-worker/src/context.rs @@ -1190,6 +1190,33 @@ impl ExecutionContext { self.speculative_deferred_calls.get_call(call_id).is_some() } + /// when a deferred call execution fail we need to refund the coins to the caller + pub fn deferred_call_fail_exec( + &mut self, + call: &DeferredCall, + ) -> Option<(Address, Result)> { + #[allow(unused_assignments, unused_mut)] + let mut result = None; + + let transfer_result = + self.transfer_coins(None, Some(call.sender_address), call.coins, false); + if let Err(e) = transfer_result.as_ref() { + debug!( + "deferred call cancel: reimbursement of {} failed: {}", + call.sender_address, e + ); + } + + #[cfg(feature = "execution-info")] + if let Err(e) = transfer_result { + result = Some((call.sender_address, Err(e.to_string()))) + } else { + result = Some((call.sender_address, Ok(call.coins))); + } + + result + } + pub fn deferred_call_delete(&mut self, call_id: &DeferredCallId, slot: Slot) { self.speculative_deferred_calls.delete_call(call_id, slot); } diff --git a/massa-execution-worker/src/execution.rs b/massa-execution-worker/src/execution.rs index 1ab57bceb6e..548f33b9f7c 100644 --- a/massa-execution-worker/src/execution.rs +++ b/massa-execution-worker/src/execution.rs @@ -1273,8 +1273,7 @@ impl ExecutionState { )); context.reset_to_snapshot(snapshot, err.clone()); - // TODO cancel the deferred call - // context.cancel_async_message(&message); + context.deferred_call_fail_exec(&call); return Err(err); } @@ -1334,8 +1333,7 @@ impl ExecutionState { }; let mut context = context_guard!(self); context.reset_to_snapshot(snapshot, err.clone()); - // TODO cancel the deferred call - // context.cancel_async_message(&message); + context.deferred_call_fail_exec(&call); Err(err) } } From 6297693acca00a1ea9f1129c9f6a91f8f7a9acd8 Mon Sep 17 00:00:00 2001 From: modship Date: Thu, 25 Jul 2024 14:21:50 +0200 Subject: [PATCH 030/100] get_slot from DeferredCallId --- massa-deferred-calls/src/lib.rs | 1 - .../src/speculative_deferred_calls.rs | 5 ++- massa-models/src/deferred_call_id.rs | 43 +++++++++++++++---- massa-models/src/error.rs | 2 + 4 files changed, 40 insertions(+), 11 deletions(-) diff --git a/massa-deferred-calls/src/lib.rs b/massa-deferred-calls/src/lib.rs index 99cfddb1d5b..156200c0c84 100644 --- a/massa-deferred-calls/src/lib.rs +++ b/massa-deferred-calls/src/lib.rs @@ -59,7 +59,6 @@ impl DeferredCallRegistry { call_id_serializer: DeferredCallIdSerializer::new(), call_deserializer: DeferredCallDeserializer::new(THREAD_COUNT), call_id_deserializer: DeferredCallIdDeserializer::new(), - // TODO args registry_changes_deserializer: DeferredRegistryChangesDeserializer::new( THREAD_COUNT, MAX_ASYNC_GAS, diff --git a/massa-execution-worker/src/speculative_deferred_calls.rs b/massa-execution-worker/src/speculative_deferred_calls.rs index cf5133b7403..45eecc7f250 100644 --- a/massa-execution-worker/src/speculative_deferred_calls.rs +++ b/massa-execution-worker/src/speculative_deferred_calls.rs @@ -246,7 +246,10 @@ impl SpeculativeDeferredCallRegistry { } pub fn get_call(&self, id: &DeferredCallId) -> Option { - let slot: Slot = id.get_slot(); + let slot = match id.get_slot() { + Ok(slot) => slot, + Err(_) => return None, + }; // check from latest to earliest changes diff --git a/massa-models/src/deferred_call_id.rs b/massa-models/src/deferred_call_id.rs index fd90871de72..43b19fd149e 100644 --- a/massa-models/src/deferred_call_id.rs +++ b/massa-models/src/deferred_call_id.rs @@ -1,7 +1,8 @@ -use std::str::FromStr; +use std::{ops::Bound, str::FromStr}; use massa_serialization::{ - Deserializer, SerializeError, Serializer, U64VarIntDeserializer, U64VarIntSerializer, + DeserializeError, Deserializer, SerializeError, Serializer, U64VarIntDeserializer, + U64VarIntSerializer, }; use nom::{ error::{ContextError, ParseError}, @@ -9,7 +10,10 @@ use nom::{ }; use transition::Versioned; +// use std::collections::Bound; + use crate::{ + config::THREAD_COUNT, error::ModelsError, serialization::{VecU8Deserializer, VecU8Serializer}, slot::{Slot, SlotDeserializer, SlotSerializer}, @@ -184,13 +188,25 @@ impl<'de> ::serde::Deserialize<'de> for DeferredCallId { } impl DeferredCallId { - pub fn get_slot(&self) -> Slot { - // retrieve the slot from the id - // TODO implement this - todo!() - // let slot_serializer = SlotDeserializer::new(); - // let (_, slot) = slot_serializer.deserialize(self.as_bytes()).unwrap(); - // slot + /// Return the slot of the `DeferredCallId` + pub fn get_slot(&self) -> Result { + let version_deserializer = U64VarIntDeserializer::new( + std::ops::Bound::Included(0), + std::ops::Bound::Included(u64::MAX), + ); + + let slot_deser = SlotDeserializer::new( + (Bound::Included(0), Bound::Included(u64::MAX)), + (Bound::Included(0), Bound::Excluded(THREAD_COUNT)), + ); + + let (rest, version) = version_deserializer + .deserialize::(self.as_bytes()) + .map_err(|_e| ModelsError::DeferredCallIdParseError)?; + let (_rest, slot) = slot_deser + .deserialize::(rest) + .map_err(|_e| ModelsError::DeferredCallIdParseError)?; + Ok(slot) } /// Create a new `DeferredCallId` @@ -297,4 +313,13 @@ mod tests { let deserialized_id = DeferredCallId::from_str(&id_str).unwrap(); assert_eq!(deserialized_id, id); } + + #[test] + fn test_get_slot() { + let slot = Slot::new(1, 2); + let index = 3; + let trail_hash = [4, 5, 6]; + let id = DeferredCallId::new(0, slot, index, &trail_hash).unwrap(); + assert_eq!(id.get_slot().unwrap(), slot); + } } diff --git a/massa-models/src/error.rs b/massa-models/src/error.rs index ba4a6b8b069..213672c9ba5 100644 --- a/massa-models/src/error.rs +++ b/massa-models/src/error.rs @@ -62,6 +62,8 @@ pub enum ModelsError { OutdatedBootstrapCursor, /// Error raised {0} ErrorRaised(String), + /// deferred call id parsing error + DeferredCallIdParseError, } impl From>> for ModelsError { From 8bbb687c5a66d129580956dfeb97847be603a226 Mon Sep 17 00:00:00 2001 From: modship Date: Fri, 26 Jul 2024 10:02:13 +0200 Subject: [PATCH 031/100] Fix(ser/deser): error and update test --- massa-deferred-calls/src/call.rs | 18 +++++++++--------- massa-deferred-calls/src/slot_changes.rs | 6 +++--- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/massa-deferred-calls/src/call.rs b/massa-deferred-calls/src/call.rs index 3c208bd025d..7080ea055f1 100644 --- a/massa-deferred-calls/src/call.rs +++ b/massa-deferred-calls/src/call.rs @@ -51,7 +51,7 @@ impl DeferredCall { fee: Amount, cancelled: bool, ) -> Self { - Self { + DeferredCall { sender_address, target_slot, target_address, @@ -104,9 +104,9 @@ impl Serializer for DeferredCallSerializer { self.vec_u8_serializer .serialize(&value.parameters, buffer)?; self.amount_serializer.serialize(&value.coins, buffer)?; - self.amount_serializer.serialize(&value.fee, buffer)?; self.u64_var_int_serializer .serialize(&value.max_gas, buffer)?; + self.amount_serializer.serialize(&value.fee, buffer)?; self.bool_serializer.serialize(&value.cancelled, buffer)?; Ok(()) } @@ -180,12 +180,12 @@ impl Deserializer for DeferredCallDeserializer { context("Failed coins deserialization", |input| { self.amount_deserializer.deserialize(input) }), - context("Failed fee deserialization", |input| { - self.amount_deserializer.deserialize(input) - }), context("Failed max_gas deserialization", |input| { self.u64_var_int_deserializer.deserialize(input) }), + context("Failed fee deserialization", |input| { + self.amount_deserializer.deserialize(input) + }), context("Failed cancelled deserialization", |input| { self.bool_deserializer.deserialize(input) }), @@ -199,8 +199,8 @@ impl Deserializer for DeferredCallDeserializer { target_function, parameters, coins, - fee, max_gas, + fee, cancelled, )| { DeferredCall::new( @@ -236,9 +236,9 @@ mod tests { Address::from_str("AU12dG5xP1RDEB5ocdHkymNVvvSJmUL9BgHwCksDowqmGWxfpm93x").unwrap(), "function".to_string(), vec![0, 1, 2, 3], - Amount::from_raw(42), - 42, - Amount::from_raw(42), + Amount::from_raw(100), + 500000, + Amount::from_raw(25), false, ); let serializer = DeferredCallSerializer::new(); diff --git a/massa-deferred-calls/src/slot_changes.rs b/massa-deferred-calls/src/slot_changes.rs index 9f551360ab6..57774651494 100644 --- a/massa-deferred-calls/src/slot_changes.rs +++ b/massa-deferred-calls/src/slot_changes.rs @@ -27,9 +27,9 @@ use std::ops::Bound::Included; #[derive(Default, Debug, Clone, Serialize, Deserialize)] pub struct DeferredRegistrySlotChanges { - pub(crate) calls: BTreeMap, - pub(crate) gas: DeferredRegistryGasChange, - pub(crate) base_fee: DeferredRegistryBaseFeeChange, + pub calls: BTreeMap, + pub gas: DeferredRegistryGasChange, + pub base_fee: DeferredRegistryBaseFeeChange, } impl DeferredRegistrySlotChanges { From 801e65cc4f442c0a839f56d6ee477c23a1959d44 Mon Sep 17 00:00:00 2001 From: modship Date: Fri, 26 Jul 2024 11:29:50 +0200 Subject: [PATCH 032/100] Fix(exec_deferred_call) : Fix lock --- massa-execution-worker/src/execution.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/massa-execution-worker/src/execution.rs b/massa-execution-worker/src/execution.rs index 548f33b9f7c..73626929842 100644 --- a/massa-execution-worker/src/execution.rs +++ b/massa-execution-worker/src/execution.rs @@ -1231,13 +1231,12 @@ impl ExecutionState { ) -> Result { let mut result = DeferredCallExecutionResult::new(&call); - let mut context = context_guard!(self); - - let snapshot = context.get_snapshot(); - + let snapshot; // prepare the current slot context for executing the operation let bytecode; { + let mut context = context_guard!(self); + snapshot = context.get_snapshot(); // acquire write access to the context // let mut context = context_guard!(self); @@ -1385,6 +1384,8 @@ impl ExecutionState { self.config.thread_count, ); + dbg!(&calls); + // Get asynchronous messages to execute let messages = execution_context.take_async_batch( self.config.max_async_gas, From d59a5565fb3a064778b3bf93bb974108288bc1b4 Mon Sep 17 00:00:00 2001 From: modship Date: Fri, 26 Jul 2024 11:30:28 +0200 Subject: [PATCH 033/100] Test(deferred_call) : first execution test --- .../src/tests/scenarios_mandatories.rs | 239 +++++++++++++++++- 1 file changed, 238 insertions(+), 1 deletion(-) diff --git a/massa-execution-worker/src/tests/scenarios_mandatories.rs b/massa-execution-worker/src/tests/scenarios_mandatories.rs index b80355791cd..3f375e310d1 100644 --- a/massa-execution-worker/src/tests/scenarios_mandatories.rs +++ b/massa-execution-worker/src/tests/scenarios_mandatories.rs @@ -2,6 +2,9 @@ use massa_async_pool::{AsyncMessage, AsyncPool, AsyncPoolChanges, AsyncPoolConfig}; use massa_db_exports::{DBBatch, ShareableMassaDBController}; +use massa_deferred_calls::registry_changes::DeferredRegistryChanges; +use massa_deferred_calls::slot_changes::DeferredRegistrySlotChanges; +use massa_deferred_calls::{DeferredCall, DeferredCallRegistry, DeferredRegistryCallChange}; use massa_executed_ops::{ExecutedDenunciations, ExecutedDenunciationsConfig}; use massa_execution_exports::{ ExecutionConfig, ExecutionQueryRequest, ExecutionQueryRequestItem, ExecutionStackElement, @@ -11,12 +14,13 @@ use massa_final_state::test_exports::get_initials; use massa_final_state::MockFinalStateController; use massa_hash::Hash; use massa_ledger_exports::{ - LedgerEntryUpdate, MockLedgerControllerWrapper, SetOrKeep, SetUpdateOrDelete, + LedgerEntryUpdate, MockLedgerControllerWrapper, SetOrDelete, SetOrKeep, SetUpdateOrDelete, }; use massa_models::bytecode::Bytecode; use massa_models::config::{ CHAINID, ENDORSEMENT_COUNT, LEDGER_ENTRY_DATASTORE_BASE_SIZE, THREAD_COUNT, }; +use massa_models::deferred_call_id::DeferredCallId; use massa_models::prehash::PreHashMap; use massa_models::test_exports::gen_endorsements_for_denunciation; use massa_models::{address::Address, amount::Amount, slot::Slot}; @@ -67,6 +71,7 @@ fn final_state_boilerplate( saved_bytecode: Option>>>, custom_async_pool: Option, custom_pos_state: Option, + custom_deferred_call_registry: Option, ) { mock_final_state .write() @@ -140,6 +145,14 @@ fn final_state_boilerplate( }, db.clone(), )); + + let deferred_call_registry = + custom_deferred_call_registry.unwrap_or_else(|| DeferredCallRegistry::new(db.clone())); + + mock_final_state + .write() + .expect_get_deferred_call_registry() + .return_const(deferred_call_registry); } fn expect_finalize_deploy_and_call_blocks( @@ -207,6 +220,7 @@ fn test_execution_shutdown() { None, None, None, + None, ); ExecutionTestUniverse::new(foreign_controllers, ExecutionConfig::default()); } @@ -223,6 +237,7 @@ fn test_sending_command() { None, None, None, + None, ); let universe = ExecutionTestUniverse::new(foreign_controllers, ExecutionConfig::default()); universe.module_controller.update_blockclique_status( @@ -268,6 +283,7 @@ fn test_readonly_execution() { None, None, None, + None, ); let universe = ExecutionTestUniverse::new(foreign_controllers, exec_cfg); @@ -396,6 +412,7 @@ fn test_nested_call_gas_usage() { Some(saved_bytecode), None, None, + None, ); let mut universe = ExecutionTestUniverse::new(foreign_controllers, exec_cfg); @@ -492,6 +509,7 @@ fn test_get_call_coins() { Some(saved_bytecode), None, None, + None, ); foreign_controllers .final_state @@ -727,6 +745,7 @@ fn send_and_receive_async_message() { Some(saved_bytecode), Some(async_pool), None, + None, ); let mut universe = ExecutionTestUniverse::new(foreign_controllers, exec_cfg.clone()); @@ -775,6 +794,7 @@ fn cancel_async_message() { )) }); }); + let saved_bytecode = Arc::new(RwLock::new(None)); let saved_bytecode_edit = saved_bytecode.clone(); let finalized_waitpoint_trigger_handle = finalized_waitpoint.get_trigger_handle(); @@ -887,6 +907,7 @@ fn cancel_async_message() { Some(saved_bytecode), Some(async_pool), None, + None, ); let mut universe = ExecutionTestUniverse::new(foreign_controllers, exec_cfg.clone()); @@ -919,6 +940,203 @@ fn cancel_async_message() { assert!(events[0].data.contains(" is not a smart contract address")); } +#[test] +fn deferred_calls() { + let exec_cfg = ExecutionConfig::default(); + let finalized_waitpoint = WaitPoint::new(); + let mut foreign_controllers = ExecutionForeignControllers::new_with_mocks(); + selector_boilerplate(&mut foreign_controllers.selector_controller); + // TODO: add some context for this override + foreign_controllers + .selector_controller + .set_expectations(|selector_controller| { + selector_controller + .expect_get_producer() + .returning(move |_| { + Ok(Address::from_public_key( + &KeyPair::from_str(TEST_SK_2).unwrap().get_public_key(), + )) + }); + }); + + foreign_controllers + .ledger_controller + .set_expectations(|ledger_controller| { + ledger_controller + .expect_get_balance() + .returning(move |_| Some(Amount::from_str("100").unwrap())); + + ledger_controller + .expect_entry_exists() + .times(2) + .returning(move |_| false); + + ledger_controller + .expect_entry_exists() + .returning(move |_| true); + }); + let saved_bytecode = Arc::new(RwLock::new(None)); + let saved_bytecode_edit = saved_bytecode.clone(); + let finalized_waitpoint_trigger_handle = finalized_waitpoint.get_trigger_handle(); + + let destination = match *CHAINID { + 77 => Address::from_str("AS12jc7fTsSKwQ9hSk97C3iMNgNT1XrrD6MjSJRJZ4NE53YgQ4kFV").unwrap(), + 77658366 => { + Address::from_str("AS12DSPbsNvvdP1ScCivmKpbQfcJJ3tCQFkNb8ewkRuNjsgoL2AeQ").unwrap() + } + 77658377 => { + Address::from_str("AS127QtY6Hzm6BnJc9wqCBfPNvEH9fKer3LiMNNQmcX3MzLwCL6G6").unwrap() + } + _ => panic!("CHAINID not supported"), + }; + + let target_slot = Slot { + period: 1, + thread: 1, + }; + + let call = DeferredCall { + sender_address: Address::from_str("AU1TyzwHarZMQSVJgxku8co7xjrRLnH74nFbNpoqNd98YhJkWgi") + .unwrap(), + target_slot: target_slot.clone(), + target_address: destination, + target_function: "receive".to_string(), + parameters: vec![42, 42, 42, 42], + coins: Amount::from_raw(100), + max_gas: 300000000, + fee: Amount::from_raw(1), + cancelled: false, + }; + + let call_id = DeferredCallId::new( + 0, + target_slot.clone(), + 0, + "trail_hash".to_string().as_bytes(), + ) + .unwrap(); + + let call_cloned = call.clone(); + foreign_controllers + .final_state + .write() + .expect_finalize() + .times(1) + .with(predicate::eq(Slot::new(1, 0)), predicate::always()) + .returning(move |_, changes| { + { + let mut saved_bytecode = saved_bytecode_edit.write(); + *saved_bytecode = Some(changes.ledger_changes.get_bytecode_updates()[0].clone()); + } + + println!("changes: {:?}", changes.deferred_call_changes.slots_change); + assert_eq!(changes.deferred_call_changes.slots_change.len(), 2); + finalized_waitpoint_trigger_handle.trigger(); + }); + + let finalized_waitpoint_trigger_handle2 = finalized_waitpoint.get_trigger_handle(); + foreign_controllers + .final_state + .write() + .expect_finalize() + .times(1) + .with(predicate::eq(Slot::new(1, 1)), predicate::always()) + .returning(move |_, changes| { + // match changes.ledger_changes.0.get(&destination).unwrap() { + // // sc has received the coins (0.0000001) + // SetUpdateOrDelete::Update(change_sc_update) => { + // assert_eq!( + // change_sc_update.balance, + // SetOrKeep::Set(Amount::from_str("100.0000001").unwrap()) + // ); + // } + // _ => panic!("wrong change type"), + // } + + dbg!(&changes.ledger_changes); + + assert_eq!(changes.deferred_call_changes.slots_change.len(), 2); + + let (_slot, slot_change) = changes + .deferred_call_changes + .slots_change + .first_key_value() + .unwrap(); + + let (_id, set_delete) = slot_change.calls.first_key_value().unwrap(); + assert_eq!(set_delete, &SetOrDelete::Delete); + + finalized_waitpoint_trigger_handle2.trigger(); + }); + + let registry = DeferredCallRegistry::new(foreign_controllers.db.clone()); + + let mut defer_reg_slot_changes = DeferredRegistrySlotChanges { + calls: BTreeMap::new(), + gas: massa_deferred_calls::DeferredRegistryGasChange::Keep, + base_fee: massa_deferred_calls::DeferredRegistryBaseFeeChange::Keep, + }; + + defer_reg_slot_changes.set_call(call_id.clone(), call.clone()); + + let mut slot_changes = BTreeMap::default(); + slot_changes.insert(target_slot.clone(), defer_reg_slot_changes); + + let mut db_batch = DBBatch::default(); + + registry.apply_changes_to_batch( + DeferredRegistryChanges { + slots_change: slot_changes, + total_gas: SetOrKeep::Keep, + }, + &mut db_batch, + ); + + foreign_controllers + .db + .write() + .write_batch(db_batch, DBBatch::default(), Some(Slot::new(1, 0))); + final_state_boilerplate( + &mut foreign_controllers.final_state, + foreign_controllers.db.clone(), + &foreign_controllers.selector_controller, + &mut foreign_controllers.ledger_controller, + Some(saved_bytecode), + None, + None, + Some(registry), + ); + let mut universe = ExecutionTestUniverse::new(foreign_controllers, exec_cfg.clone()); + + // load bytecodes + universe.deploy_bytecode_block( + &KeyPair::from_str(TEST_SK_1).unwrap(), + Slot::new(1, 0), + include_bytes!("./wasm/send_message.wasm"), + include_bytes!("./wasm/receive_message.wasm"), + ); + finalized_waitpoint.wait(); + + let keypair = KeyPair::from_str(TEST_SK_2).unwrap(); + let block = + ExecutionTestUniverse::create_block(&keypair, Slot::new(1, 1), vec![], vec![], vec![]); + + universe.send_and_finalize(&keypair, block); + finalized_waitpoint.wait(); + // retrieve events emitted by smart contracts + let events = universe + .module_controller + .get_filtered_sc_output_event(EventFilter { + start: Some(Slot::new(1, 1)), + end: Some(Slot::new(20, 1)), + ..Default::default() + }); + + // match the events + assert!(events.len() == 1, "One event was expected"); + assert_eq!(events[0].data, "message correctly received: 42,42,42,42"); +} + /// Context /// /// Functional test for local smart-contract execution @@ -957,6 +1175,7 @@ fn local_execution() { None, None, None, + None, ); let mut universe = ExecutionTestUniverse::new(foreign_controllers, exec_cfg); // load bytecodes @@ -1036,6 +1255,7 @@ fn sc_deployment() { Some(saved_bytecode), None, None, + None, ); let mut universe = ExecutionTestUniverse::new(foreign_controllers, exec_cfg); // load bytecodes @@ -1120,6 +1340,7 @@ fn send_and_receive_async_message_with_trigger() { None, None, None, + None, ); let mut universe = ExecutionTestUniverse::new(foreign_controllers, exec_cfg.clone()); // load bytecode @@ -1234,6 +1455,7 @@ fn send_and_receive_transaction() { None, None, None, + None, ); foreign_controllers .final_state @@ -1313,6 +1535,7 @@ fn roll_buy() { None, None, None, + None, ); foreign_controllers .final_state @@ -1413,6 +1636,7 @@ fn roll_sell() { None, None, Some(pos_final_state), + None, ); foreign_controllers .final_state @@ -1572,6 +1796,7 @@ fn auto_sell_on_missed_blocks() { None, None, Some(pos_final_state.clone()), + None, ); foreign_controllers @@ -1689,6 +1914,7 @@ fn roll_slash() { None, None, None, + None, ); let mut universe = ExecutionTestUniverse::new(foreign_controllers, exec_cfg.clone()); @@ -1807,6 +2033,7 @@ fn roll_slash_2() { None, None, None, + None, ); let mut universe = ExecutionTestUniverse::new(foreign_controllers, exec_cfg.clone()); @@ -1870,6 +2097,7 @@ fn sc_execution_error() { None, None, None, + None, ); let mut universe = ExecutionTestUniverse::new(foreign_controllers, exec_cfg); // load bytecode @@ -1928,6 +2156,7 @@ fn sc_datastore() { Some(saved_bytecode), None, None, + None, ); let mut universe = ExecutionTestUniverse::new(foreign_controllers, exec_cfg); // load bytecode @@ -1982,6 +2211,7 @@ fn set_bytecode_error() { Some(saved_bytecode), None, None, + None, ); let mut universe = ExecutionTestUniverse::new(foreign_controllers, exec_cfg); // load bytecodes @@ -2061,6 +2291,7 @@ fn datastore_manipulations() { None, None, None, + None, ); foreign_controllers .final_state @@ -2240,6 +2471,7 @@ fn events_from_switching_blockclique() { None, None, None, + None, ); let mut universe = ExecutionTestUniverse::new(foreign_controllers, exec_cfg); @@ -2291,6 +2523,7 @@ fn not_enough_instance_gas() { None, None, None, + None, ); let mut universe = ExecutionTestUniverse::new(foreign_controllers, exec_cfg); @@ -2357,6 +2590,7 @@ fn sc_builtins() { None, None, None, + None, ); let mut universe = ExecutionTestUniverse::new(foreign_controllers, exec_cfg); universe.deploy_bytecode_block( @@ -2404,6 +2638,7 @@ fn validate_address() { None, None, None, + None, ); let mut universe = ExecutionTestUniverse::new(foreign_controllers, exec_cfg); universe.deploy_bytecode_block( @@ -2455,6 +2690,7 @@ fn test_rewards() { None, None, None, + None, ); foreign_controllers .final_state @@ -2610,6 +2846,7 @@ fn chain_id() { None, None, None, + None, ); let mut universe = ExecutionTestUniverse::new(foreign_controllers, exec_cfg); universe.deploy_bytecode_block( From cd44aa1adba3d39caea1caa5f796389a66acd967 Mon Sep 17 00:00:00 2001 From: modship Date: Fri, 26 Jul 2024 11:56:02 +0200 Subject: [PATCH 034/100] fix(deferred_call) : remove double delete_call --- massa-execution-worker/src/execution.rs | 5 ---- .../src/speculative_deferred_calls.rs | 6 ++--- .../src/tests/scenarios_mandatories.rs | 26 +++++++++---------- 3 files changed, 15 insertions(+), 22 deletions(-) diff --git a/massa-execution-worker/src/execution.rs b/massa-execution-worker/src/execution.rs index 73626929842..ef129dd1bec 100644 --- a/massa-execution-worker/src/execution.rs +++ b/massa-execution-worker/src/execution.rs @@ -1384,8 +1384,6 @@ impl ExecutionState { self.config.thread_count, ); - dbg!(&calls); - // Get asynchronous messages to execute let messages = execution_context.take_async_batch( self.config.max_async_gas, @@ -1420,9 +1418,6 @@ impl ExecutionState { debug!(msg); } } - // remove call from the db : (added Delete to changes) - let mut context = context_guard!(self); - context.deferred_call_delete(&id, slot.clone()); } // execute async messages as long as there is remaining gas in the slot (counting both unused max_async_gas and max_block_gas, and the latter can be used in full in case of block miss) diff --git a/massa-execution-worker/src/speculative_deferred_calls.rs b/massa-execution-worker/src/speculative_deferred_calls.rs index 45eecc7f250..be994b641e1 100644 --- a/massa-execution-worker/src/speculative_deferred_calls.rs +++ b/massa-execution-worker/src/speculative_deferred_calls.rs @@ -238,9 +238,9 @@ impl SpeculativeDeferredCallRegistry { for (id, _call) in &slot_calls.slot_calls { self.deferred_calls_changes.delete_call(current_slot, id); } - self.deferred_calls_changes.set_slot_gas(current_slot, 0); - self.deferred_calls_changes - .set_slot_base_fee(current_slot, Amount::zero()); + // self.deferred_calls_changes.set_slot_gas(current_slot, 0); + // self.deferred_calls_changes + // .set_slot_base_fee(current_slot, Amount::zero()); slot_calls } diff --git a/massa-execution-worker/src/tests/scenarios_mandatories.rs b/massa-execution-worker/src/tests/scenarios_mandatories.rs index 3f375e310d1..c1933df5347 100644 --- a/massa-execution-worker/src/tests/scenarios_mandatories.rs +++ b/massa-execution-worker/src/tests/scenarios_mandatories.rs @@ -1030,7 +1030,7 @@ fn deferred_calls() { } println!("changes: {:?}", changes.deferred_call_changes.slots_change); - assert_eq!(changes.deferred_call_changes.slots_change.len(), 2); + assert_eq!(changes.deferred_call_changes.slots_change.len(), 1); finalized_waitpoint_trigger_handle.trigger(); }); @@ -1042,21 +1042,18 @@ fn deferred_calls() { .times(1) .with(predicate::eq(Slot::new(1, 1)), predicate::always()) .returning(move |_, changes| { - // match changes.ledger_changes.0.get(&destination).unwrap() { - // // sc has received the coins (0.0000001) - // SetUpdateOrDelete::Update(change_sc_update) => { - // assert_eq!( - // change_sc_update.balance, - // SetOrKeep::Set(Amount::from_str("100.0000001").unwrap()) - // ); - // } - // _ => panic!("wrong change type"), - // } - - dbg!(&changes.ledger_changes); + match changes.ledger_changes.0.get(&destination).unwrap() { + // sc has received the coins (0.0000001) + SetUpdateOrDelete::Update(change_sc_update) => { + assert_eq!( + change_sc_update.balance, + SetOrKeep::Set(Amount::from_str("100.0000001").unwrap()) + ); + } + _ => panic!("wrong change type"), + } assert_eq!(changes.deferred_call_changes.slots_change.len(), 2); - let (_slot, slot_change) = changes .deferred_call_changes .slots_change @@ -1064,6 +1061,7 @@ fn deferred_calls() { .unwrap(); let (_id, set_delete) = slot_change.calls.first_key_value().unwrap(); + // call was executed and then deleted assert_eq!(set_delete, &SetOrDelete::Delete); finalized_waitpoint_trigger_handle2.trigger(); From cc14cdc7092e6a2d757ab1426e5a73ecf5b9a194 Mon Sep 17 00:00:00 2001 From: modship Date: Mon, 29 Jul 2024 17:32:29 +0200 Subject: [PATCH 035/100] Test(abi) : First test for register deferred_call --- massa-execution-worker/src/interface_impl.rs | 7 +- .../src/tests/scenarios_mandatories.rs | 123 +++++++++++++++++- .../src/tests/wasm/deferred_call.wasm | Bin 0 -> 3645 bytes 3 files changed, 125 insertions(+), 5 deletions(-) create mode 100644 massa-execution-worker/src/tests/wasm/deferred_call.wasm diff --git a/massa-execution-worker/src/interface_impl.rs b/massa-execution-worker/src/interface_impl.rs index 5a865ce090d..ec849b230e0 100644 --- a/massa-execution-worker/src/interface_impl.rs +++ b/massa-execution-worker/src/interface_impl.rs @@ -1375,18 +1375,19 @@ impl Interface for InterfaceImpl { /// * target_func: string representation of the target function /// * params: byte array of the parameters /// * coins: the amount of coins to send + /// * fee: the amount of fee to send /// * max_gas: the gas limit for the call /// /// # Returns /// The id of the call fn deferred_call_register( &self, - target_slot: (u64, u8), target_addr: &str, target_func: &str, - params: &[u8], - coins: u64, + target_slot: (u64, u8), max_gas: u64, + coins: u64, + params: &[u8], ) -> Result> { // This function spends coins + deferred_call_quote(target_slot, max_gas).unwrap() from the caller, fails if the balance is insufficient or if the quote would return None. diff --git a/massa-execution-worker/src/tests/scenarios_mandatories.rs b/massa-execution-worker/src/tests/scenarios_mandatories.rs index c1933df5347..b6ee65e0ff5 100644 --- a/massa-execution-worker/src/tests/scenarios_mandatories.rs +++ b/massa-execution-worker/src/tests/scenarios_mandatories.rs @@ -3,7 +3,7 @@ use massa_async_pool::{AsyncMessage, AsyncPool, AsyncPoolChanges, AsyncPoolConfig}; use massa_db_exports::{DBBatch, ShareableMassaDBController}; use massa_deferred_calls::registry_changes::DeferredRegistryChanges; -use massa_deferred_calls::slot_changes::DeferredRegistrySlotChanges; +use massa_deferred_calls::slot_changes::{self, DeferredRegistrySlotChanges}; use massa_deferred_calls::{DeferredCall, DeferredCallRegistry, DeferredRegistryCallChange}; use massa_executed_ops::{ExecutedDenunciations, ExecutedDenunciationsConfig}; use massa_execution_exports::{ @@ -1016,7 +1016,6 @@ fn deferred_calls() { ) .unwrap(); - let call_cloned = call.clone(); foreign_controllers .final_state .write() @@ -1104,6 +1103,7 @@ fn deferred_calls() { None, Some(registry), ); + let mut universe = ExecutionTestUniverse::new(foreign_controllers, exec_cfg.clone()); // load bytecodes @@ -1135,6 +1135,125 @@ fn deferred_calls() { assert_eq!(events[0].data, "message correctly received: 42,42,42,42"); } +#[test] +fn deferred_call_register() { + // setup the period duration + let exec_cfg = ExecutionConfig::default(); + let finalized_waitpoint = WaitPoint::new(); + let mut foreign_controllers = ExecutionForeignControllers::new_with_mocks(); + let keypair = KeyPair::from_str(TEST_SK_1).unwrap(); + let saved_bytecode = Arc::new(RwLock::new(None)); + + let db_lock = foreign_controllers.db.clone(); + + selector_boilerplate(&mut foreign_controllers.selector_controller); + + foreign_controllers + .selector_controller + .set_expectations(|selector_controller| { + selector_controller + .expect_get_producer() + .returning(move |_| { + Ok(Address::from_public_key( + &KeyPair::from_str(TEST_SK_2).unwrap().get_public_key(), + )) + }); + }); + + foreign_controllers + .ledger_controller + .set_expectations(|ledger_controller| { + ledger_controller + .expect_get_balance() + .returning(move |_| Some(Amount::from_str("100").unwrap())); + }); + + let finalized_waitpoint_trigger_handle = finalized_waitpoint.get_trigger_handle(); + foreign_controllers + .final_state + .write() + .expect_finalize() + .times(1) + .with(predicate::eq(Slot::new(1, 0)), predicate::always()) + .returning(move |_, changes| { + { + // manually write the deferred call to the db + // then in the next slot (1,1) we will find and execute it + let reg = DeferredCallRegistry::new(db_lock.clone()); + let mut batch = DBBatch::default(); + reg.apply_changes_to_batch(changes.deferred_call_changes.clone(), &mut batch); + db_lock + .write() + .write_batch(batch, DBBatch::default(), Some(Slot::new(1, 0))); + } + let slot_changes = changes + .deferred_call_changes + .slots_change + .get(&Slot::new(1, 1)) + .unwrap(); + let _call = slot_changes.calls.first_key_value().unwrap().1; + + finalized_waitpoint_trigger_handle.trigger(); + }); + + let finalized_waitpoint_trigger_handle2 = finalized_waitpoint.get_trigger_handle(); + foreign_controllers + .final_state + .write() + .expect_finalize() + .times(1) + .with(predicate::eq(Slot::new(1, 1)), predicate::always()) + .returning(move |_, changes| { + assert_eq!(changes.deferred_call_changes.slots_change.len(), 2); + let (_slot, slot_change) = changes + .deferred_call_changes + .slots_change + .first_key_value() + .unwrap(); + + let (_id, set_delete) = slot_change.calls.first_key_value().unwrap(); + // call was executed and then deleted + assert_eq!(set_delete, &SetOrDelete::Delete); + finalized_waitpoint_trigger_handle2.trigger(); + }); + + final_state_boilerplate( + &mut foreign_controllers.final_state, + foreign_controllers.db.clone(), + &foreign_controllers.selector_controller, + &mut foreign_controllers.ledger_controller, + Some(saved_bytecode), + None, + None, + Some(DeferredCallRegistry::new(foreign_controllers.db.clone())), + ); + + let mut universe = ExecutionTestUniverse::new(foreign_controllers, exec_cfg); + + // abi call to register a deferred call + universe.deploy_bytecode_block( + &keypair, + Slot::new(1, 0), + include_bytes!("./wasm/deferred_call.wasm"), + //unused + include_bytes!("./wasm/use_builtins.wasm"), + ); + finalized_waitpoint.wait(); + let events = universe + .module_controller + .get_filtered_sc_output_event(EventFilter::default()); + + assert_eq!(events[0].data, "Deferred call registered"); + + let keypair = KeyPair::from_str(TEST_SK_2).unwrap(); + let block = + ExecutionTestUniverse::create_block(&keypair, Slot::new(1, 1), vec![], vec![], vec![]); + + universe.send_and_finalize(&keypair, block); + // match the events + finalized_waitpoint.wait(); +} + /// Context /// /// Functional test for local smart-contract execution diff --git a/massa-execution-worker/src/tests/wasm/deferred_call.wasm b/massa-execution-worker/src/tests/wasm/deferred_call.wasm new file mode 100644 index 0000000000000000000000000000000000000000..6f49d0ed2f354a30c8057b2302a2e3534d296e6e GIT binary patch literal 3645 zcma)9&u<&Y6@IfnNQy(tOxgg2=^9HW4xA>jmg4WWK|O9{_*X0>Zi1vJKvC36;Zmd| zawW$_V5)%8`rx8DSwa#G9(0_+Ryn zXc&z;Nz{(^qG2M+&CZDrVkzY~zN_$%b0*4&o{0IRpwmlfZ_w!tCGEG{!{{1lwA5GLkV&ptj(uWVCwGRB3Bya<- z?nvO!tZSt1c!3=BK0S~cy@IyfMslN55 z4lPeLeQQef50}FDX9}A>hYbMwSnZhX1?z755{|HJ)KS{SV$m@!h-8uLth3$xw6ui?0@-t4r{k7$@(dC=d`3a(r`tULV!w;21V< z)E>$y8wdU-dQ{0&yQq*kH}F{o3Y%hrkdhd5^M2sOMU>dnC9_{Z#i`^VD@aM;VOb-8 zDlWPsSG)z$ZT(Atp}00jI`CTo9|A5iXhgS#w{XMa0g2 z^VjFkJ_NBmOqx5nJn6`kT|Sj}w1-#iin4M^xf64@@X`~DsPF8d#fZY2x{>#sJpzSF`G996H0sX_k(=)R5jzMPZy;9c8j+|&96dY^}k5Z5lGhnOJ3 zkDvkG|G|J=+|Frr8PUt>2K7V8o6uT^aQBgoA7jD%1$JfwmKY~$aNRtB4OsjZ1M1`e z1NMLGi0;$k8iaYiihcwn^KeRDv9>x`?a4=Yp5}j72Cz7UW`L(%>m@*@BfPUu5V6Q= z1c)Y4L(8v%_?UwuHm|ql|6g8rf$d=j3qa5dt&N`K_3pgoe{WvTk?}MR_>k*AxgjDF zA`c<_g@|^DNQa1f2#+B$7D^M+vKnRd%yJoeW$2ZmSB730dS&R9p+_s!ShTHzz6z;9 z>W~Jc329kRv_g%FZB_KlcOBAzG$Ad^hMs7J8dckB=?@L z?3IBp178Nd415{*GVrrzbrJYQ;1_{k1bz|tMc`Rivt+vhdZk!<1HJ})4fq=HHQ;BhnmX`x;OoHGfv*E!2Y%LSY5?B= zz5#p#_y+L&p3YijP2iirH-T>g-vqu1{H)d20=@-&3-}iBE#OjQ z2Q$npG180{cTCpwOf=gXgg3)Fo_HEq(X2{V7OR69W|kOfMvFTpYkDS{jo*LX6+B5i z4XkKZB`b^7!3;A?j5MRg9g{UZ6V0}cHa&$rNjwd#XjUaFi`BslGfRv#qs1MQH9Zq; zZXeU?H@L-)>1BQs&O>;j`R(L)j^8AHKNvkSCu#%tZVz{AAGg8)x5Ace%MR{@>3ucsqvxCy=&^I1Wsc-uKjev%(=?T)(9Tb*tEh}wAf Woy$Kuz3|L$xzpG1qw(~hv;7?n=36rW literal 0 HcmV?d00001 From 1668f4d20350ed7af794970f6a7e9c3c49edb805 Mon Sep 17 00:00:00 2001 From: modship Date: Tue, 30 Jul 2024 14:36:19 +0200 Subject: [PATCH 036/100] Test(register) : more assert --- .../src/tests/scenarios_mandatories.rs | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/massa-execution-worker/src/tests/scenarios_mandatories.rs b/massa-execution-worker/src/tests/scenarios_mandatories.rs index b6ee65e0ff5..da11893f77a 100644 --- a/massa-execution-worker/src/tests/scenarios_mandatories.rs +++ b/massa-execution-worker/src/tests/scenarios_mandatories.rs @@ -1211,7 +1211,12 @@ fn deferred_call_register() { .first_key_value() .unwrap(); - let (_id, set_delete) = slot_change.calls.first_key_value().unwrap(); + let (id, set_delete) = slot_change.calls.first_key_value().unwrap(); + + assert_eq!( + id.to_string().as_str(), + "D17MpSPsmYL3eDjTq4jSLemHycnQs7yGqTLY4v481cmz8SZuF1MuPQr6hL95E1Zv" + ); // call was executed and then deleted assert_eq!(set_delete, &SetOrDelete::Delete); finalized_waitpoint_trigger_handle2.trigger(); @@ -1245,6 +1250,21 @@ fn deferred_call_register() { assert_eq!(events[0].data, "Deferred call registered"); + // call id in the register event + let vec: Vec = events[1] + .data + .split(',') + .map(|s| s.parse::().unwrap()) + .collect(); + + let call_id = DeferredCallId::from_bytes(&vec).unwrap(); + assert_eq!( + call_id, + DeferredCallId::from_str( + "D17MpSPsmYL3eDjTq4jSLemHycnQs7yGqTLY4v481cmz8SZuF1MuPQr6hL95E1Zv" + ) + .unwrap() + ); let keypair = KeyPair::from_str(TEST_SK_2).unwrap(); let block = ExecutionTestUniverse::create_block(&keypair, Slot::new(1, 1), vec![], vec![], vec![]); From 24e09fee0c76ad214d693518a85091576c88781d Mon Sep 17 00:00:00 2001 From: modship Date: Wed, 31 Jul 2024 10:38:12 +0200 Subject: [PATCH 037/100] Fix(set_total_gas) : fix set / keep --- .../src/speculative_deferred_calls.rs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/massa-execution-worker/src/speculative_deferred_calls.rs b/massa-execution-worker/src/speculative_deferred_calls.rs index be994b641e1..0ce65317d67 100644 --- a/massa-execution-worker/src/speculative_deferred_calls.rs +++ b/massa-execution-worker/src/speculative_deferred_calls.rs @@ -229,11 +229,14 @@ impl SpeculativeDeferredCallRegistry { .set_slot_base_fee(new_slot, new_slot_base_fee); // subtract the current slot gas from the total gas - self.deferred_calls_changes.set_total_gas( - slot_calls - .total_gas - .saturating_sub(slot_calls.slot_gas.into()), - ); + + let total_gas = slot_calls + .total_gas + .saturating_sub(slot_calls.slot_gas.into()); + if !total_gas.eq(&self.get_total_gas()) { + self.deferred_calls_changes.set_total_gas(total_gas); + } + // delete the current slot for (id, _call) in &slot_calls.slot_calls { self.deferred_calls_changes.delete_call(current_slot, id); @@ -400,6 +403,8 @@ impl SpeculativeDeferredCallRegistry { )); } + // TODO FIX async_gas_target = slot_occupancy ?? + // Check that the gas is not too high for the target slot let slot_occupancy = self.get_slot_gas(&target_slot); if slot_occupancy.saturating_add(max_gas) > max_async_gas { From 64f6c24ce9b94df7ff25e0c0a76e5bb2e18ef259 Mon Sep 17 00:00:00 2001 From: modship Date: Wed, 31 Jul 2024 10:44:04 +0200 Subject: [PATCH 038/100] Test(deferred_call) : Register call fail (total_gas) --- massa-execution-worker/src/interface_impl.rs | 2 + .../src/tests/scenarios_mandatories.rs | 171 ++++++++++++++++-- ..._call.wasm => deferred_call_register.wasm} | Bin 3645 -> 3654 bytes .../wasm/deferred_call_register_fail.wasm | Bin 0 -> 3663 bytes 4 files changed, 157 insertions(+), 16 deletions(-) rename massa-execution-worker/src/tests/wasm/{deferred_call.wasm => deferred_call_register.wasm} (96%) create mode 100644 massa-execution-worker/src/tests/wasm/deferred_call_register_fail.wasm diff --git a/massa-execution-worker/src/interface_impl.rs b/massa-execution-worker/src/interface_impl.rs index ec849b230e0..16bb696473e 100644 --- a/massa-execution-worker/src/interface_impl.rs +++ b/massa-execution-worker/src/interface_impl.rs @@ -1351,6 +1351,8 @@ impl Interface for InterfaceImpl { let gas_booked_slot = context.deferred_calls_get_slot_booked_gas(&target_slot); + // TODO fix gas_booked_slot = async_gas_target ?? + match context.deferred_calls_compute_call_fee( target_slot, gas_limit, diff --git a/massa-execution-worker/src/tests/scenarios_mandatories.rs b/massa-execution-worker/src/tests/scenarios_mandatories.rs index da11893f77a..ec24d50d5d7 100644 --- a/massa-execution-worker/src/tests/scenarios_mandatories.rs +++ b/massa-execution-worker/src/tests/scenarios_mandatories.rs @@ -3,8 +3,8 @@ use massa_async_pool::{AsyncMessage, AsyncPool, AsyncPoolChanges, AsyncPoolConfig}; use massa_db_exports::{DBBatch, ShareableMassaDBController}; use massa_deferred_calls::registry_changes::DeferredRegistryChanges; -use massa_deferred_calls::slot_changes::{self, DeferredRegistrySlotChanges}; -use massa_deferred_calls::{DeferredCall, DeferredCallRegistry, DeferredRegistryCallChange}; +use massa_deferred_calls::slot_changes::DeferredRegistrySlotChanges; +use massa_deferred_calls::{DeferredCall, DeferredCallRegistry}; use massa_executed_ops::{ExecutedDenunciations, ExecutedDenunciationsConfig}; use massa_execution_exports::{ ExecutionConfig, ExecutionQueryRequest, ExecutionQueryRequestItem, ExecutionStackElement, @@ -1211,14 +1211,13 @@ fn deferred_call_register() { .first_key_value() .unwrap(); - let (id, set_delete) = slot_change.calls.first_key_value().unwrap(); + let (_id, set_delete) = slot_change.calls.first_key_value().unwrap(); - assert_eq!( - id.to_string().as_str(), - "D17MpSPsmYL3eDjTq4jSLemHycnQs7yGqTLY4v481cmz8SZuF1MuPQr6hL95E1Zv" - ); // call was executed and then deleted assert_eq!(set_delete, &SetOrDelete::Delete); + + // assert total gas was set to 0 + assert_eq!(changes.deferred_call_changes.total_gas, SetOrKeep::Set(0)); finalized_waitpoint_trigger_handle2.trigger(); }); @@ -1239,7 +1238,7 @@ fn deferred_call_register() { universe.deploy_bytecode_block( &keypair, Slot::new(1, 0), - include_bytes!("./wasm/deferred_call.wasm"), + include_bytes!("./wasm/deferred_call_register.wasm"), //unused include_bytes!("./wasm/use_builtins.wasm"), ); @@ -1257,14 +1256,8 @@ fn deferred_call_register() { .map(|s| s.parse::().unwrap()) .collect(); - let call_id = DeferredCallId::from_bytes(&vec).unwrap(); - assert_eq!( - call_id, - DeferredCallId::from_str( - "D17MpSPsmYL3eDjTq4jSLemHycnQs7yGqTLY4v481cmz8SZuF1MuPQr6hL95E1Zv" - ) - .unwrap() - ); + let _call_id = DeferredCallId::from_bytes(&vec).unwrap(); + let keypair = KeyPair::from_str(TEST_SK_2).unwrap(); let block = ExecutionTestUniverse::create_block(&keypair, Slot::new(1, 1), vec![], vec![], vec![]); @@ -1274,6 +1267,152 @@ fn deferred_call_register() { finalized_waitpoint.wait(); } +#[test] +fn deferred_call_register_fail() { + // setup the period duration + let exec_cfg = ExecutionConfig::default(); + let finalized_waitpoint = WaitPoint::new(); + let mut foreign_controllers = ExecutionForeignControllers::new_with_mocks(); + let keypair = KeyPair::from_str(TEST_SK_1).unwrap(); + let saved_bytecode = Arc::new(RwLock::new(None)); + let target_slot = Slot { + period: 1, + thread: 10, + }; + + selector_boilerplate(&mut foreign_controllers.selector_controller); + + foreign_controllers + .selector_controller + .set_expectations(|selector_controller| { + selector_controller + .expect_get_producer() + .returning(move |_| { + Ok(Address::from_public_key( + &KeyPair::from_str(TEST_SK_2).unwrap().get_public_key(), + )) + }); + }); + + let finalized_waitpoint_trigger_handle = finalized_waitpoint.get_trigger_handle(); + foreign_controllers + .final_state + .write() + .expect_finalize() + .times(1) + .with(predicate::eq(Slot::new(1, 0)), predicate::always()) + .returning(move |_, changes| { + assert!(changes.deferred_call_changes.total_gas == SetOrKeep::Keep); + finalized_waitpoint_trigger_handle.trigger(); + }); + + let finalized_waitpoint_trigger_handle2 = finalized_waitpoint.get_trigger_handle(); + foreign_controllers + .final_state + .write() + .expect_finalize() + .times(1) + .with(predicate::eq(Slot::new(1, 1)), predicate::always()) + .returning(move |_, changes| { + assert_eq!(changes.deferred_call_changes.slots_change.len(), 1); + // deferred call was not register + assert!(changes.deferred_call_changes.total_gas == SetOrKeep::Keep); + + finalized_waitpoint_trigger_handle2.trigger(); + }); + + let call = DeferredCall { + sender_address: Address::from_str("AU1TyzwHarZMQSVJgxku8co7xjrRLnH74nFbNpoqNd98YhJkWgi") + .unwrap(), + target_slot: target_slot.clone(), + target_address: Address::from_str("AS12jc7fTsSKwQ9hSk97C3iMNgNT1XrrD6MjSJRJZ4NE53YgQ4kFV") + .unwrap(), + target_function: "toto".to_string(), + parameters: vec![42, 42, 42, 42], + coins: Amount::from_raw(100), + max_gas: 500, + fee: Amount::from_raw(1), + cancelled: false, + }; + + let call_id = DeferredCallId::new( + 0, + target_slot.clone(), + 0, + "trail_hash".to_string().as_bytes(), + ) + .unwrap(); + let registry = DeferredCallRegistry::new(foreign_controllers.db.clone()); + + let mut defer_reg_slot_changes = DeferredRegistrySlotChanges { + calls: BTreeMap::new(), + gas: massa_deferred_calls::DeferredRegistryGasChange::Set(500), + base_fee: massa_deferred_calls::DeferredRegistryBaseFeeChange::Keep, + }; + + defer_reg_slot_changes.set_call(call_id.clone(), call.clone()); + + let mut slot_changes = BTreeMap::default(); + slot_changes.insert(target_slot.clone(), defer_reg_slot_changes); + + let mut db_batch = DBBatch::default(); + + registry.apply_changes_to_batch( + DeferredRegistryChanges { + slots_change: slot_changes, + total_gas: SetOrKeep::Set(2000), + }, + &mut db_batch, + ); + + foreign_controllers + .db + .write() + .write_batch(db_batch, DBBatch::default(), Some(Slot::new(1, 0))); + + final_state_boilerplate( + &mut foreign_controllers.final_state, + foreign_controllers.db.clone(), + &foreign_controllers.selector_controller, + &mut foreign_controllers.ledger_controller, + Some(saved_bytecode), + None, + None, + Some(registry), + ); + + let mut universe = ExecutionTestUniverse::new(foreign_controllers, exec_cfg); + + let keypair = KeyPair::from_str(TEST_SK_2).unwrap(); + let block = + ExecutionTestUniverse::create_block(&keypair, Slot::new(1, 0), vec![], vec![], vec![]); + + universe.send_and_finalize(&keypair, block); + + finalized_waitpoint.wait(); + + // abi call to register a deferred call + // the call want to book max_async_gas 1_000_000_000 so it fail because we already have a call at this slot with 500 gas + universe.deploy_bytecode_block( + &keypair, + Slot::new(1, 1), + include_bytes!("./wasm/deferred_call_register_fail.wasm"), + //unused + include_bytes!("./wasm/use_builtins.wasm"), + ); + finalized_waitpoint.wait(); + let events = universe + .module_controller + .get_filtered_sc_output_event(EventFilter { + start: Some(Slot::new(1, 1)), + end: Some(Slot::new(20, 1)), + ..Default::default() + }); + + let ev = events[1].clone(); + assert!(ev.context.is_error); + assert!(ev.data.contains("The ASC 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")); +} /// Context /// /// Functional test for local smart-contract execution diff --git a/massa-execution-worker/src/tests/wasm/deferred_call.wasm b/massa-execution-worker/src/tests/wasm/deferred_call_register.wasm similarity index 96% rename from massa-execution-worker/src/tests/wasm/deferred_call.wasm rename to massa-execution-worker/src/tests/wasm/deferred_call_register.wasm index 6f49d0ed2f354a30c8057b2302a2e3534d296e6e..6630e133fde393f3ca96cceb1a7fff0dfa335a7e 100644 GIT binary patch delta 60 zcmdlhb4+G~5TA*$KyiL)QF5wpVnIP>UV3PdkD{J_N@`kaQBi72d~#w=PJB^ndS-D+ PYLQ-fVsWlsZejrdk>eI4 delta 51 zcmX>mvsY$=5TCY|KyiL)QF5wpVnIP>UV3PdkA$9nN@`kaQBi72d~#w=j$V0Uajsr& GVgUfs7!pJP diff --git a/massa-execution-worker/src/tests/wasm/deferred_call_register_fail.wasm b/massa-execution-worker/src/tests/wasm/deferred_call_register_fail.wasm new file mode 100644 index 0000000000000000000000000000000000000000..9d58cc40550246b2b6fcf650128b58507c136f60 GIT binary patch literal 3663 zcma)9yKh_98UN0GkQ5IsGkq+kYg{t1;i8RoDZZNq^>HJ^uUJUj7Hv_0qNpo{mlP$D zS8`kgrV0eD2N%tdp+g6cS@Iuf2s(KvicD<>4@Kc2Kr?jAAi(|o&Xwb)$Uq%@=lT7< z_qj)u-gH}ui27c3&6&;AY)#E%O=QiR;ZN4Gv)TRG{rfy{?S{hC>AP+;KJa_%JCj6Q zf4euG_RgV;w%14Zy3_t-u$y$ZqH#3oB~dpzh{lPilBbo;&0s5^?AbH- zrgzyq%9(%W%-_VED~f2G6yu6#j=y?bHs9gt%TjTT7gwCXGvAEO?w;|66|DUqNhM>7 zi8;;9N)~d1OyCFEp@Ejz93H;6XNm`vEOxUuN|(jRHLzq)CZe?t{8uD!1Fz{w;83h< zr0IBp9dbBPO{ahXn?*1bWBrLzYUW-Jl=uNJU5^7UvyxHSU%_>Ape5jYEvhYQ%>KC zQp1y@Fn&$J>8o%6&}VATvr-~($NZpWj21sjWPQyyBce59e(^TFXj5= z{nuAbCbpX&{`-l$YI5W}{PW+Jz^g0Jn;56)q9_m$807fo(?xw+o8vQZ-lzkVQ$7y- z5qeZf%3W5-oE!Ko0|lp;AfzOQxkW#4;xbC?#gREIq2g3>oEM}d@Nle=KNXi0Y!xduU^y^|i%@=W#jgR19Q82=D^GKUVg)69-D~F8d zm8Y<;=)gKjtt)1VN_$vpSCplj%AJ{`(kpPo3PXM8PlV-+XQi_oPfi_-a;zaBaCn1Y zoE>BoK`;+^T(WCazx}J$jAt7NBYu}Lo2iEK$E<}WGs zA31%V*mI!!I3LKmEP*FMKSjTf^(Bl`Xj{TY$hikQ-hhXjAj*xbWz@pR1a@Z&_R<1!n1@=c_u!Y-dz2G{jNFl`EMwl6 z79{-y+;`-r+?BVa1K;k*5MxVzEHy}aQ*OiO+u*9o&#lfkq>0@ad^hB6&@W-#ZCQ~9 z_3cf1%s^F`FuL`~@_$Y-O%eK|f*FgB@ltPY%ZB6toP#e?%ik{JG zT10J>)Bv%yKy47~jNa2TT1|_njgrX4)&_OZGeY#9p3!PrL~WErF18L@8bwBk-qSN$ zO^c|FlE`H~e@Q!MJuzRrq<@!Vrg-`0%~FVp36c8{wH%^yLR3MByTts?lf5eNRp6_@ zSAnkrUj=^NtS$q;4E!?i%fK%KzYILQymT98^AY!Zvfu_z5)EaRnr8%349ayCh$$*o50UoO)cPCz_);J0p9|i z-@5rfuFbfI>2{;?*QKcz5{#*cvclFgV|+<7-dF^-qK=fC9-GR zI(mNlH$V|+6B1dKtSnXsGt4Y8(u@{8rq$Hk1F`i%8=wfZi4`lFRmsX?buh!s5+luM z(PLUo%|x?pfcRD4#EiFr70s$-WwAP#VP=VuX0+%rt)^z8+4z$2RpU+KZD2*SDp^^q z4rZ8HVx$=@dQ7XSnP|36wDcD8Ch<0~qFI%!ELI0I%q%g|j21nn)znP1d3Z*vU*Wwx zqgVM&xMsiL{L1o+$gdZ_G>kuer`}Dxc<wR4oTi_@L`Nk4kCw~HTATR(mK)`d$; WU;jg`yV)CzF5Sh?$V=P3-Twmjw_;!b literal 0 HcmV?d00001 From 9a022ef8cf21cfe8271e18a86e81fd89294f7247 Mon Sep 17 00:00:00 2001 From: modship Date: Wed, 31 Jul 2024 12:25:01 +0200 Subject: [PATCH 039/100] Fix(execution) : cancel deferred on check target sc + test refound --- massa-execution-worker/src/execution.rs | 6 ++- .../src/tests/scenarios_mandatories.rs | 48 ++++++++++++++++++- 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/massa-execution-worker/src/execution.rs b/massa-execution-worker/src/execution.rs index ef129dd1bec..7b14e1e1b59 100644 --- a/massa-execution-worker/src/execution.rs +++ b/massa-execution-worker/src/execution.rs @@ -1259,7 +1259,11 @@ impl ExecutionState { // Ensure that the target address is an SC address // Ensure that the target address exists - context.check_target_sc_address(call.target_address)?; + if let Err(err) = context.check_target_sc_address(call.target_address) { + context.reset_to_snapshot(snapshot, err.clone()); + context.deferred_call_fail_exec(&call); + return Err(err); + } // credit coins to the target address if let Err(err) = diff --git a/massa-execution-worker/src/tests/scenarios_mandatories.rs b/massa-execution-worker/src/tests/scenarios_mandatories.rs index ec24d50d5d7..c25cee21183 100644 --- a/massa-execution-worker/src/tests/scenarios_mandatories.rs +++ b/massa-execution-worker/src/tests/scenarios_mandatories.rs @@ -14,7 +14,8 @@ use massa_final_state::test_exports::get_initials; use massa_final_state::MockFinalStateController; use massa_hash::Hash; use massa_ledger_exports::{ - LedgerEntryUpdate, MockLedgerControllerWrapper, SetOrDelete, SetOrKeep, SetUpdateOrDelete, + LedgerChanges, LedgerController, LedgerEntryUpdate, MockLedgerControllerWrapper, SetOrDelete, + SetOrKeep, SetUpdateOrDelete, }; use massa_models::bytecode::Bytecode; use massa_models::config::{ @@ -22,6 +23,7 @@ use massa_models::config::{ }; use massa_models::deferred_call_id::DeferredCallId; use massa_models::prehash::PreHashMap; +use massa_models::slot; use massa_models::test_exports::gen_endorsements_for_denunciation; use massa_models::{address::Address, amount::Amount, slot::Slot}; use massa_models::{ @@ -1146,6 +1148,11 @@ fn deferred_call_register() { let db_lock = foreign_controllers.db.clone(); + let sender_addr = + Address::from_str("AU1TyzwHarZMQSVJgxku8co7xjrRLnH74nFbNpoqNd98YhJkWgi").unwrap(); + + let sender_addr_clone = sender_addr.clone(); + selector_boilerplate(&mut foreign_controllers.selector_controller); foreign_controllers @@ -1176,6 +1183,17 @@ fn deferred_call_register() { .times(1) .with(predicate::eq(Slot::new(1, 0)), predicate::always()) .returning(move |_, changes| { + // assert sender was debited ( -10 coins) + match changes.ledger_changes.0.get(&sender_addr_clone).unwrap() { + SetUpdateOrDelete::Update(change_sc_update) => { + assert_eq!( + change_sc_update.balance, + SetOrKeep::Set(Amount::from_str("91.02").unwrap()) + ); + } + _ => panic!("wrong change type"), + }; + { // manually write the deferred call to the db // then in the next slot (1,1) we will find and execute it @@ -1186,12 +1204,20 @@ fn deferred_call_register() { .write() .write_batch(batch, DBBatch::default(), Some(Slot::new(1, 0))); } + let slot_changes = changes .deferred_call_changes .slots_change .get(&Slot::new(1, 1)) .unwrap(); let _call = slot_changes.calls.first_key_value().unwrap().1; + // assert total gas was set to 300000 + assert_eq!( + changes.deferred_call_changes.total_gas, + SetOrKeep::Set(300000) + ); + + assert_eq!(slot_changes.get_gas().unwrap(), 300000); finalized_waitpoint_trigger_handle.trigger(); }); @@ -1204,6 +1230,26 @@ fn deferred_call_register() { .times(1) .with(predicate::eq(Slot::new(1, 1)), predicate::always()) .returning(move |_, changes| { + // the deferred call was register and executed but the asc call will fail (sc doesn"t exist) + // so the user should be refunded + match changes + .ledger_changes + .0 + .get( + &Address::from_str("AU1TyzwHarZMQSVJgxku8co7xjrRLnH74nFbNpoqNd98YhJkWgi") + .unwrap(), + ) + .unwrap() + { + SetUpdateOrDelete::Update(change_sc_update) => { + assert_eq!( + change_sc_update.balance, + SetOrKeep::Set(Amount::from_str("110").unwrap()) + ); + } + _ => panic!("wrong change type"), + } + assert_eq!(changes.deferred_call_changes.slots_change.len(), 2); let (_slot, slot_change) = changes .deferred_call_changes From 08bbef28854ca9b88c6b2c56eabccdae744a4496 Mon Sep 17 00:00:00 2001 From: modship Date: Wed, 31 Jul 2024 16:41:42 +0200 Subject: [PATCH 040/100] update wasm file --- .../tests/wasm/deferred_call_register.wasm | Bin 3654 -> 3657 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/massa-execution-worker/src/tests/wasm/deferred_call_register.wasm b/massa-execution-worker/src/tests/wasm/deferred_call_register.wasm index 6630e133fde393f3ca96cceb1a7fff0dfa335a7e..ea7b2c73f232baab8d086b55fb00a381c79fd609 100644 GIT binary patch delta 31 ncmX>mb5dplJ0oMuW)8+|W=4m}B`k`p4JXzwP~AM8Wj!YVpVtaw delta 28 kcmX>pb4+FfJ0oM`W)8+|W=7k|B`k_ePZ&1OVp-1#0DcJwg#Z8m From 9fb3c0e88b5afe7bf620942cca808081765fe2ec Mon Sep 17 00:00:00 2001 From: modship Date: Thu, 1 Aug 2024 11:24:34 +0200 Subject: [PATCH 041/100] Fix(deferred_call) : fix compute call fee --- Cargo.lock | 5 +++++ Cargo.toml | 2 +- massa-deferred-calls/src/slot_changes.rs | 2 +- massa-execution-worker/src/context.rs | 2 -- massa-execution-worker/src/interface_impl.rs | 5 ----- massa-execution-worker/src/speculative_deferred_calls.rs | 7 ++----- massa-execution-worker/src/tests/scenarios_mandatories.rs | 1 - massa-models/src/deferred_call_id.rs | 2 +- 8 files changed, 10 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 42faa190fa7..dfcf7941d11 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2570,6 +2570,7 @@ dependencies = [ [[package]] name = "massa-sc-runtime" version = "0.10.0" +source = "git+https://github.com/massalabs/massa-sc-runtime?rev=116dd8a32819c8def8a5aa014f805ee2cab9f384#116dd8a32819c8def8a5aa014f805ee2cab9f384" dependencies = [ "anyhow", "as-ffi-bindings", @@ -2696,6 +2697,7 @@ dependencies = [ "massa_consensus_exports", "massa_db_exports", "massa_db_worker", + "massa_deferred_calls", "massa_executed_ops", "massa_final_state", "massa_hash", @@ -2836,11 +2838,14 @@ name = "massa_deferred_calls" version = "2.2.0" dependencies = [ "massa_db_exports", + "massa_db_worker", "massa_ledger_exports", "massa_models", "massa_serialization", "nom", + "parking_lot", "serde", + "tempfile", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 997715243d3..50ef2c50b5a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -108,7 +108,7 @@ massa_wallet = { path = "./massa-wallet" } # Massa projects dependencies massa-proto-rs = { git = "https://github.com/massalabs/massa-proto-rs", "rev" = "38950875a7aa406fedc4f0b8336864e5ff290f2c" } -massa-sc-runtime = { path = "/Users/urvoy/dev/massa-sc-runtime" } +massa-sc-runtime = { git = "https://github.com/massalabs/massa-sc-runtime", "rev" = "116dd8a32819c8def8a5aa014f805ee2cab9f384" } peernet = { git = "https://github.com/massalabs/PeerNet", "rev" = "04b05ddd320fbe76cc858115af7b5fc28bdb8310" } diff --git a/massa-deferred-calls/src/slot_changes.rs b/massa-deferred-calls/src/slot_changes.rs index 57774651494..6ca84bfa4c6 100644 --- a/massa-deferred-calls/src/slot_changes.rs +++ b/massa-deferred-calls/src/slot_changes.rs @@ -37,7 +37,7 @@ impl DeferredRegistrySlotChanges { self.calls.len() } - pub fn merge(&mut self, other: DeferredRegistrySlotChanges) { + pub fn merge(&mut self, _other: DeferredRegistrySlotChanges) { unimplemented!("DeferredRegistrySlotChanges::merge") // for (id, change) in other.calls { // match self.calls.entry(id) { diff --git a/massa-execution-worker/src/context.rs b/massa-execution-worker/src/context.rs index 51a9a404f64..2840c4caeb5 100644 --- a/massa-execution-worker/src/context.rs +++ b/massa-execution-worker/src/context.rs @@ -1160,7 +1160,6 @@ impl ExecutionContext { thread_count: u8, async_call_max_booking_slots: u64, max_async_gas: u64, - async_gas_target: u64, global_overbooking_penalty: Amount, slot_overbooking_penalty: Amount, current_slot: Slot, @@ -1171,7 +1170,6 @@ impl ExecutionContext { thread_count, async_call_max_booking_slots, max_async_gas, - async_gas_target, global_overbooking_penalty, slot_overbooking_penalty, current_slot, diff --git a/massa-execution-worker/src/interface_impl.rs b/massa-execution-worker/src/interface_impl.rs index 16bb696473e..5421de59bee 100644 --- a/massa-execution-worker/src/interface_impl.rs +++ b/massa-execution-worker/src/interface_impl.rs @@ -1349,17 +1349,12 @@ impl Interface for InterfaceImpl { let target_slot = Slot::new(target_slot.0, target_slot.1); - let gas_booked_slot = context.deferred_calls_get_slot_booked_gas(&target_slot); - - // TODO fix gas_booked_slot = async_gas_target ?? - match context.deferred_calls_compute_call_fee( target_slot, gas_limit, self.config.thread_count, self.config.max_deferred_call_future_slots, self.config.max_async_gas, - gas_booked_slot, Amount::from_raw(1_000_000_000), Amount::from_raw(1_000_000_000 / 10_000), current_slot, diff --git a/massa-execution-worker/src/speculative_deferred_calls.rs b/massa-execution-worker/src/speculative_deferred_calls.rs index 0ce65317d67..2aa07da2fae 100644 --- a/massa-execution-worker/src/speculative_deferred_calls.rs +++ b/massa-execution-worker/src/speculative_deferred_calls.rs @@ -379,7 +379,6 @@ impl SpeculativeDeferredCallRegistry { thread_count: u8, async_call_max_booking_slots: u64, max_async_gas: u64, - async_gas_target: u64, global_overbooking_penalty: Amount, slot_overbooking_penalty: Amount, current_slot: Slot, @@ -403,8 +402,6 @@ impl SpeculativeDeferredCallRegistry { )); } - // TODO FIX async_gas_target = slot_occupancy ?? - // Check that the gas is not too high for the target slot let slot_occupancy = self.get_slot_gas(&target_slot); if slot_occupancy.saturating_add(max_gas) > max_async_gas { @@ -437,7 +434,7 @@ impl SpeculativeDeferredCallRegistry { .unwrap_or_default(); let global_overbooking_fee = Self::overbooking_fee( (max_async_gas as u128).saturating_mul(async_call_max_booking_slots as u128), - (async_gas_target as u128).saturating_mul(async_call_max_booking_slots as u128), + async_call_max_booking_slots.saturating_mul(max_async_gas.saturating_div(2)) as u128, global_occupancy, max_gas as u128, global_overbooking_penalty, // total_supply @@ -447,7 +444,7 @@ impl SpeculativeDeferredCallRegistry { // Slot overbooking fee let slot_overbooking_fee = Self::overbooking_fee( max_async_gas as u128, - async_gas_target as u128, + max_async_gas.saturating_div(2) as u128, slot_occupancy as u128, max_gas as u128, slot_overbooking_penalty, // total_initial_coin_supply/10000 diff --git a/massa-execution-worker/src/tests/scenarios_mandatories.rs b/massa-execution-worker/src/tests/scenarios_mandatories.rs index c25cee21183..53fcb3c4591 100644 --- a/massa-execution-worker/src/tests/scenarios_mandatories.rs +++ b/massa-execution-worker/src/tests/scenarios_mandatories.rs @@ -1319,7 +1319,6 @@ fn deferred_call_register_fail() { let exec_cfg = ExecutionConfig::default(); let finalized_waitpoint = WaitPoint::new(); let mut foreign_controllers = ExecutionForeignControllers::new_with_mocks(); - let keypair = KeyPair::from_str(TEST_SK_1).unwrap(); let saved_bytecode = Arc::new(RwLock::new(None)); let target_slot = Slot { period: 1, diff --git a/massa-models/src/deferred_call_id.rs b/massa-models/src/deferred_call_id.rs index 43b19fd149e..ff5972443f5 100644 --- a/massa-models/src/deferred_call_id.rs +++ b/massa-models/src/deferred_call_id.rs @@ -200,7 +200,7 @@ impl DeferredCallId { (Bound::Included(0), Bound::Excluded(THREAD_COUNT)), ); - let (rest, version) = version_deserializer + let (rest, _version) = version_deserializer .deserialize::(self.as_bytes()) .map_err(|_e| ModelsError::DeferredCallIdParseError)?; let (_rest, slot) = slot_deser From 82938ec7e27ee973d5943173a5e4f1867fcc46ae Mon Sep 17 00:00:00 2001 From: modship Date: Thu, 1 Aug 2024 14:50:07 +0200 Subject: [PATCH 042/100] Fix(deferred_call) : some fix --- massa-execution-worker/src/context.rs | 8 +++++++- .../src/speculative_deferred_calls.rs | 11 ++++++++--- .../src/tests/scenarios_mandatories.rs | 4 +--- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/massa-execution-worker/src/context.rs b/massa-execution-worker/src/context.rs index 2840c4caeb5..77d1447d440 100644 --- a/massa-execution-worker/src/context.rs +++ b/massa-execution-worker/src/context.rs @@ -1184,8 +1184,14 @@ impl ExecutionContext { .register_call(call, self.execution_trail_hash) } + /// Check if a deferred call exists + /// If it exists, check if it has been cancelled + /// If it has been cancelled, return false pub fn deferred_call_exist(&self, call_id: &DeferredCallId) -> bool { - self.speculative_deferred_calls.get_call(call_id).is_some() + if let Some(call) = self.speculative_deferred_calls.get_call(call_id) { + return call.cancelled; + } + false } /// when a deferred call execution fail we need to refund the coins to the caller diff --git a/massa-execution-worker/src/speculative_deferred_calls.rs b/massa-execution-worker/src/speculative_deferred_calls.rs index 2aa07da2fae..ccfd9bfc512 100644 --- a/massa-execution-worker/src/speculative_deferred_calls.rs +++ b/massa-execution-worker/src/speculative_deferred_calls.rs @@ -434,7 +434,7 @@ impl SpeculativeDeferredCallRegistry { .unwrap_or_default(); let global_overbooking_fee = Self::overbooking_fee( (max_async_gas as u128).saturating_mul(async_call_max_booking_slots as u128), - async_call_max_booking_slots.saturating_mul(max_async_gas.saturating_div(2)) as u128, + (async_call_max_booking_slots as u128).saturating_mul(TARGET_BOOKING) as u128, global_occupancy, max_gas as u128, global_overbooking_penalty, // total_supply @@ -444,7 +444,7 @@ impl SpeculativeDeferredCallRegistry { // Slot overbooking fee let slot_overbooking_fee = Self::overbooking_fee( max_async_gas as u128, - max_async_gas.saturating_div(2) as u128, + TARGET_BOOKING, slot_occupancy as u128, max_gas as u128, slot_overbooking_penalty, // total_initial_coin_supply/10000 @@ -456,6 +456,11 @@ impl SpeculativeDeferredCallRegistry { .saturating_add(slot_overbooking_fee)) } + /// Register a new call + /// Returns the call id + /// # Arguments + /// * `call` - The call to register + /// * `trail_hash` - The hash of the execution trail hash pub fn register_call( &mut self, call: DeferredCall, @@ -490,7 +495,7 @@ impl SpeculativeDeferredCallRegistry { // set slot gas self.deferred_calls_changes - .set_slot_gas(call.target_slot, current_gas + call.max_gas); + .set_slot_gas(call.target_slot, current_gas.saturating_add(call.max_gas)); // set total gas self.deferred_calls_changes diff --git a/massa-execution-worker/src/tests/scenarios_mandatories.rs b/massa-execution-worker/src/tests/scenarios_mandatories.rs index 53fcb3c4591..aeb9dc05a97 100644 --- a/massa-execution-worker/src/tests/scenarios_mandatories.rs +++ b/massa-execution-worker/src/tests/scenarios_mandatories.rs @@ -14,8 +14,7 @@ use massa_final_state::test_exports::get_initials; use massa_final_state::MockFinalStateController; use massa_hash::Hash; use massa_ledger_exports::{ - LedgerChanges, LedgerController, LedgerEntryUpdate, MockLedgerControllerWrapper, SetOrDelete, - SetOrKeep, SetUpdateOrDelete, + LedgerEntryUpdate, MockLedgerControllerWrapper, SetOrDelete, SetOrKeep, SetUpdateOrDelete, }; use massa_models::bytecode::Bytecode; use massa_models::config::{ @@ -23,7 +22,6 @@ use massa_models::config::{ }; use massa_models::deferred_call_id::DeferredCallId; use massa_models::prehash::PreHashMap; -use massa_models::slot; use massa_models::test_exports::gen_endorsements_for_denunciation; use massa_models::{address::Address, amount::Amount, slot::Slot}; use massa_models::{ From 3ce418f2ac27097e88e8f77d338884397af57e0a Mon Sep 17 00:00:00 2001 From: modship Date: Thu, 1 Aug 2024 15:58:55 +0200 Subject: [PATCH 043/100] Test(deferred_call) : Add slot base fee --- .../src/tests/scenarios_mandatories.rs | 37 ++++++++++++++++++- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/massa-execution-worker/src/tests/scenarios_mandatories.rs b/massa-execution-worker/src/tests/scenarios_mandatories.rs index aeb9dc05a97..e583d0ae531 100644 --- a/massa-execution-worker/src/tests/scenarios_mandatories.rs +++ b/massa-execution-worker/src/tests/scenarios_mandatories.rs @@ -1181,12 +1181,12 @@ fn deferred_call_register() { .times(1) .with(predicate::eq(Slot::new(1, 0)), predicate::always()) .returning(move |_, changes| { - // assert sender was debited ( -10 coins) + // assert sender was debited ( -10 coins) and -1.50 for fees match changes.ledger_changes.0.get(&sender_addr_clone).unwrap() { SetUpdateOrDelete::Update(change_sc_update) => { assert_eq!( change_sc_update.balance, - SetOrKeep::Set(Amount::from_str("91.02").unwrap()) + SetOrKeep::Set(Amount::from_str("89.52").unwrap()) ); } _ => panic!("wrong change type"), @@ -1265,6 +1265,39 @@ fn deferred_call_register() { finalized_waitpoint_trigger_handle2.trigger(); }); + let registry = DeferredCallRegistry::new(foreign_controllers.db.clone()); + + let mut defer_reg_slot_changes = DeferredRegistrySlotChanges { + calls: BTreeMap::new(), + gas: massa_deferred_calls::DeferredRegistryGasChange::Keep, + base_fee: massa_deferred_calls::DeferredRegistryBaseFeeChange::Keep, + }; + + defer_reg_slot_changes.set_base_fee(Amount::from_str("0.000005").unwrap()); + + let mut slot_changes = BTreeMap::default(); + slot_changes.insert( + Slot { + period: 1, + thread: 1, + }, + defer_reg_slot_changes, + ); + + let mut db_batch = DBBatch::default(); + + registry.apply_changes_to_batch( + DeferredRegistryChanges { + slots_change: slot_changes, + total_gas: SetOrKeep::Keep, + }, + &mut db_batch, + ); + + foreign_controllers + .db + .write() + .write_batch(db_batch, DBBatch::default(), Some(Slot::new(1, 0))); final_state_boilerplate( &mut foreign_controllers.final_state, foreign_controllers.db.clone(), From baa1c3ae2ec87ed23904e31458cbdd75aa9f5554 Mon Sep 17 00:00:00 2001 From: modship Date: Wed, 14 Aug 2024 09:29:18 +0200 Subject: [PATCH 044/100] rename DEFERRED_CALLS_SLOT_PREFIX to DEFERRED_CALLS_PREFIX --- massa-db-exports/src/constants.rs | 2 +- massa-deferred-calls/src/lib.rs | 8 ++++---- massa-deferred-calls/src/macros.rs | 10 ++++------ 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/massa-db-exports/src/constants.rs b/massa-db-exports/src/constants.rs index fd315b23897..b92f53811d2 100644 --- a/massa-db-exports/src/constants.rs +++ b/massa-db-exports/src/constants.rs @@ -29,7 +29,7 @@ pub const LEDGER_PREFIX: &str = "ledger/"; pub const MIP_STORE_PREFIX: &str = "versioning/"; pub const MIP_STORE_STATS_PREFIX: &str = "versioning_stats/"; pub const EXECUTION_TRAIL_HASH_PREFIX: &str = "execution_trail_hash/"; -pub const DEFERRED_CALLS_SLOT_PREFIX: &str = "deferred_calls/"; +pub const DEFERRED_CALLS_PREFIX: &str = "deferred_calls/"; // Async Pool pub const MESSAGE_DESER_ERROR: &str = "critical: message deserialization failed"; diff --git a/massa-deferred-calls/src/lib.rs b/massa-deferred-calls/src/lib.rs index 156200c0c84..34e22f9839b 100644 --- a/massa-deferred-calls/src/lib.rs +++ b/massa-deferred-calls/src/lib.rs @@ -1,7 +1,7 @@ use call::{DeferredCallDeserializer, DeferredCallSerializer}; use macros::DEFERRED_CALL_TOTAL_GAS; use massa_db_exports::{ - DBBatch, ShareableMassaDBController, CRUD_ERROR, DEFERRED_CALLS_SLOT_PREFIX, KEY_DESER_ERROR, + DBBatch, ShareableMassaDBController, CRUD_ERROR, DEFERRED_CALLS_PREFIX, KEY_DESER_ERROR, MESSAGE_DESER_ERROR, MESSAGE_SER_ERROR, STATE_CF, }; use massa_serialization::{DeserializeError, Deserializer, Serializer}; @@ -46,9 +46,9 @@ impl DeferredCallRegistry { /* DB layout: [DEFERRED_CALL_TOTAL_GAS] -> u64 // total currently booked gas - [DEFERRED_CALLS_SLOT_PREFIX][slot][SLOT_TOTAL_GAS] -> u64 // total gas booked for a slot (optional, default 0, deleted when set to 0) - [DEFERRED_CALLS_SLOT_PREFIX][slot][SLOT_BASE_FEE] -> u64 // deleted when set to 0 - [DEFERRED_CALLS_SLOT_PREFIX][slot][CALLS_TAG][id][CALL_FIELD_X_TAG] -> AsyncCall.x // call data + [DEFERRED_CALLS_PREFIX][slot][SLOT_TOTAL_GAS] -> u64 // total gas booked for a slot (optional, default 0, deleted when set to 0) + [DEFERRED_CALLS_PREFIX][slot][SLOT_BASE_FEE] -> u64 // deleted when set to 0 + [DEFERRED_CALLS_PREFIX][slot][CALLS_TAG][id][CALL_FIELD_X_TAG] -> AsyncCall.x // call data */ // TODO pass args diff --git a/massa-deferred-calls/src/macros.rs b/massa-deferred-calls/src/macros.rs index 28f50e20081..9c45187d91f 100644 --- a/massa-deferred-calls/src/macros.rs +++ b/massa-deferred-calls/src/macros.rs @@ -1,5 +1,3 @@ -use massa_db_exports::DEFERRED_CALLS_SLOT_PREFIX; - pub(crate) const DEFERRED_CALL_TOTAL_GAS: &str = "deferred_call_total_gas"; pub(crate) const CALLS_TAG: u8 = 0u8; @@ -22,7 +20,7 @@ pub(crate) const CALL_FIELD_CANCELED: u8 = 9u8; macro_rules! deferred_call_slot_total_gas_key { ($slot:expr) => { [ - DEFERRED_CALLS_SLOT_PREFIX.as_bytes(), + DEFERRED_CALLS_PREFIX.as_bytes(), &$slot[..], &[$crate::macros::SLOT_TOTAL_GAS], ] @@ -34,7 +32,7 @@ macro_rules! deferred_call_slot_total_gas_key { macro_rules! deferred_call_slot_base_fee_key { ($slot:expr) => { [ - DEFERRED_CALLS_SLOT_PREFIX.as_bytes(), + DEFERRED_CALLS_PREFIX.as_bytes(), &$slot[..], &[$crate::macros::SLOT_BASE_FEE], ] @@ -46,7 +44,7 @@ macro_rules! deferred_call_slot_base_fee_key { macro_rules! deferred_slot_call_prefix_key { ($slot:expr) => { [ - DEFERRED_CALLS_SLOT_PREFIX.as_bytes(), + DEFERRED_CALLS_PREFIX.as_bytes(), &$slot[..], &[$crate::macros::CALLS_TAG], ] @@ -143,7 +141,7 @@ macro_rules! cancelled_key { #[cfg(test)] mod tests { - use massa_db_exports::DEFERRED_CALLS_SLOT_PREFIX; + use massa_db_exports::DEFERRED_CALLS_PREFIX; use massa_models::{ deferred_call_id::{DeferredCallId, DeferredCallIdSerializer}, slot::Slot, From 87bb3a2f7b760d3aa3d7b48e29b13bc965fe1f45 Mon Sep 17 00:00:00 2001 From: modship Date: Wed, 14 Aug 2024 15:55:38 +0200 Subject: [PATCH 045/100] deferred calls ser/deser error msg --- massa-db-exports/src/constants.rs | 4 ++ massa-deferred-calls/src/lib.rs | 40 ++++++++++---------- massa-execution-worker/src/interface_impl.rs | 5 +-- 3 files changed, 25 insertions(+), 24 deletions(-) diff --git a/massa-db-exports/src/constants.rs b/massa-db-exports/src/constants.rs index b92f53811d2..771807b4a2f 100644 --- a/massa-db-exports/src/constants.rs +++ b/massa-db-exports/src/constants.rs @@ -57,3 +57,7 @@ pub const EXECUTED_DENUNCIATIONS_INDEX_SER_ERROR: &str = pub const KEY_DESER_ERROR: &str = "critical: key deserialization failed"; pub const KEY_SER_ERROR: &str = "critical: key serialization failed"; pub const KEY_LEN_SER_ERROR: &str = "critical: key length serialization failed"; + +// deferred calls +pub const DEFERRED_CALL_DESER_ERROR: &str = "critical: message deserialization failed"; +pub const DEFERRED_CALL_SER_ERROR: &str = "critical: message serialization failed"; diff --git a/massa-deferred-calls/src/lib.rs b/massa-deferred-calls/src/lib.rs index 34e22f9839b..67d047765f3 100644 --- a/massa-deferred-calls/src/lib.rs +++ b/massa-deferred-calls/src/lib.rs @@ -1,8 +1,8 @@ use call::{DeferredCallDeserializer, DeferredCallSerializer}; use macros::DEFERRED_CALL_TOTAL_GAS; use massa_db_exports::{ - DBBatch, ShareableMassaDBController, CRUD_ERROR, DEFERRED_CALLS_PREFIX, KEY_DESER_ERROR, - MESSAGE_DESER_ERROR, MESSAGE_SER_ERROR, STATE_CF, + DBBatch, ShareableMassaDBController, CRUD_ERROR, DEFERRED_CALLS_PREFIX, + DEFERRED_CALL_DESER_ERROR, DEFERRED_CALL_SER_ERROR, KEY_DESER_ERROR, STATE_CF, }; use massa_serialization::{DeserializeError, Deserializer, Serializer}; use registry_changes::{ @@ -111,7 +111,7 @@ impl DeferredCallRegistry { let mut buf_id = Vec::new(); self.call_id_serializer .serialize(id, &mut buf_id) - .expect(MESSAGE_SER_ERROR); + .expect(DEFERRED_CALL_SER_ERROR); let key = deferred_call_prefix_key!(buf_id, slot.to_bytes_key()); let mut serialized_call: Vec = Vec::new(); @@ -143,7 +143,7 @@ impl DeferredCallRegistry { .call_deserializer .u64_var_int_deserializer .deserialize::(&v) - .expect(MESSAGE_DESER_ERROR) + .expect(DEFERRED_CALL_DESER_ERROR) .1; result } @@ -159,7 +159,7 @@ impl DeferredCallRegistry { self.call_deserializer .amount_deserializer .deserialize::(&v) - .expect(MESSAGE_DESER_ERROR) + .expect(DEFERRED_CALL_DESER_ERROR) .1 } _ => Amount::zero(), @@ -179,7 +179,7 @@ impl DeferredCallRegistry { .registry_changes_deserializer .total_gas_deserializer .deserialize::(&v) - .expect(MESSAGE_DESER_ERROR) + .expect(DEFERRED_CALL_DESER_ERROR) .1; match result { SetOrKeep::Set(v) => v, @@ -200,7 +200,7 @@ impl DeferredCallRegistry { let mut buffer_id = Vec::new(); self.call_id_serializer .serialize(call_id, &mut buffer_id) - .expect(MESSAGE_SER_ERROR); + .expect(DEFERRED_CALL_SER_ERROR); let slot_bytes = slot.to_bytes_key(); @@ -211,7 +211,7 @@ impl DeferredCallRegistry { self.call_serializer .address_serializer .serialize(&call.sender_address, &mut temp_buffer) - .expect(MESSAGE_SER_ERROR); + .expect(DEFERRED_CALL_SER_ERROR); db.put_or_update_entry_value( batch, sender_address_key!(buffer_id, slot_bytes), @@ -223,7 +223,7 @@ impl DeferredCallRegistry { self.call_serializer .slot_serializer .serialize(&call.target_slot, &mut temp_buffer) - .expect(MESSAGE_SER_ERROR); + .expect(DEFERRED_CALL_SER_ERROR); db.put_or_update_entry_value(batch, target_slot_key!(buffer_id, slot_bytes), &temp_buffer); temp_buffer.clear(); @@ -231,7 +231,7 @@ impl DeferredCallRegistry { self.call_serializer .address_serializer .serialize(&call.target_address, &mut temp_buffer) - .expect(MESSAGE_SER_ERROR); + .expect(DEFERRED_CALL_SER_ERROR); db.put_or_update_entry_value( batch, target_address_key!(buffer_id, slot_bytes), @@ -243,7 +243,7 @@ impl DeferredCallRegistry { self.call_serializer .string_serializer .serialize(&call.target_function, &mut temp_buffer) - .expect(MESSAGE_SER_ERROR); + .expect(DEFERRED_CALL_SER_ERROR); db.put_or_update_entry_value( batch, target_function_key!(buffer_id, slot_bytes), @@ -255,7 +255,7 @@ impl DeferredCallRegistry { self.call_serializer .vec_u8_serializer .serialize(&call.parameters, &mut temp_buffer) - .expect(MESSAGE_SER_ERROR); + .expect(DEFERRED_CALL_SER_ERROR); db.put_or_update_entry_value(batch, parameters_key!(buffer_id, slot_bytes), &temp_buffer); temp_buffer.clear(); @@ -263,7 +263,7 @@ impl DeferredCallRegistry { self.call_serializer .amount_serializer .serialize(&call.coins, &mut temp_buffer) - .expect(MESSAGE_SER_ERROR); + .expect(DEFERRED_CALL_SER_ERROR); db.put_or_update_entry_value(batch, coins_key!(buffer_id, slot_bytes), &temp_buffer); temp_buffer.clear(); @@ -271,7 +271,7 @@ impl DeferredCallRegistry { self.call_serializer .u64_var_int_serializer .serialize(&call.max_gas, &mut temp_buffer) - .expect(MESSAGE_SER_ERROR); + .expect(DEFERRED_CALL_SER_ERROR); db.put_or_update_entry_value(batch, max_gas_key!(buffer_id, slot_bytes), &temp_buffer); temp_buffer.clear(); @@ -279,7 +279,7 @@ impl DeferredCallRegistry { self.call_serializer .amount_serializer .serialize(&call.fee, &mut temp_buffer) - .expect(MESSAGE_SER_ERROR); + .expect(DEFERRED_CALL_SER_ERROR); db.put_or_update_entry_value(batch, fee_key!(buffer_id, slot_bytes), &temp_buffer); temp_buffer.clear(); @@ -287,7 +287,7 @@ impl DeferredCallRegistry { self.call_serializer .bool_serializer .serialize(&call.cancelled, &mut temp_buffer) - .expect(MESSAGE_SER_ERROR); + .expect(DEFERRED_CALL_SER_ERROR); db.put_or_update_entry_value(batch, cancelled_key!(buffer_id, slot_bytes), &temp_buffer); } @@ -295,7 +295,7 @@ impl DeferredCallRegistry { let mut buffer_id = Vec::new(); self.call_id_serializer .serialize(id, &mut buffer_id) - .expect(MESSAGE_SER_ERROR); + .expect(DEFERRED_CALL_SER_ERROR); let slot_bytes = slot.to_bytes_key(); @@ -340,7 +340,7 @@ impl DeferredCallRegistry { self.call_serializer .u64_var_int_serializer .serialize(&v, &mut value_ser) - .expect(MESSAGE_SER_ERROR); + .expect(DEFERRED_CALL_SER_ERROR); self.db .read() .put_or_update_entry_value(batch, key, &value_ser); @@ -359,7 +359,7 @@ impl DeferredCallRegistry { self.call_serializer .amount_serializer .serialize(&v, &mut value_ser) - .expect(MESSAGE_SER_ERROR); + .expect(DEFERRED_CALL_SER_ERROR); self.db .read() .put_or_update_entry_value(batch, key, &value_ser); @@ -376,7 +376,7 @@ impl DeferredCallRegistry { self.registry_changes_serializer .total_gas_serializer .serialize(&DeferredRegistryGasChange::Set(v), &mut value_ser) - .expect(MESSAGE_SER_ERROR); + .expect(DEFERRED_CALL_SER_ERROR); self.db .read() .put_or_update_entry_value(batch, key, &value_ser); diff --git a/massa-execution-worker/src/interface_impl.rs b/massa-execution-worker/src/interface_impl.rs index 5421de59bee..6f968fe76fd 100644 --- a/massa-execution-worker/src/interface_impl.rs +++ b/massa-execution-worker/src/interface_impl.rs @@ -1435,10 +1435,7 @@ impl Interface for InterfaceImpl { let mut context = context_guard!(self); // get caller address - let sender_address = match context.stack.last() { - Some(addr) => addr.address, - _ => bail!("failed to read call stack sender address"), - }; + let sender_address = context.get_current_address()?; // make sender pay coins + fee // coins + cost for booking the deferred call From 1dcab48066b5b8f486044219e73b0573add43d6c Mon Sep 17 00:00:00 2001 From: modship Date: Wed, 14 Aug 2024 16:33:14 +0200 Subject: [PATCH 046/100] deferred_call_id deserializer limit --- massa-models/src/deferred_call_id.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/massa-models/src/deferred_call_id.rs b/massa-models/src/deferred_call_id.rs index ff5972443f5..0d9cc4f5bb9 100644 --- a/massa-models/src/deferred_call_id.rs +++ b/massa-models/src/deferred_call_id.rs @@ -69,7 +69,7 @@ impl DeferredCallIdDeserializer { Self { bytes_deserializer: VecU8Deserializer::new( std::ops::Bound::Included(0), - std::ops::Bound::Included(u64::MAX), + std::ops::Bound::Included(128), ), } } From ac7ccde7138f527aa072184203b7eaac0967a43c Mon Sep 17 00:00:00 2001 From: modship Date: Wed, 14 Aug 2024 17:12:04 +0200 Subject: [PATCH 047/100] models error --- massa-execution-worker/src/context.rs | 1 + massa-execution-worker/src/speculative_deferred_calls.rs | 3 --- massa-models/src/slot.rs | 2 +- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/massa-execution-worker/src/context.rs b/massa-execution-worker/src/context.rs index 77d1447d440..00f4fcb37cc 100644 --- a/massa-execution-worker/src/context.rs +++ b/massa-execution-worker/src/context.rs @@ -1221,6 +1221,7 @@ impl ExecutionContext { result } + /// not used for now pub fn deferred_call_delete(&mut self, call_id: &DeferredCallId, slot: Slot) { self.speculative_deferred_calls.delete_call(call_id, slot); } diff --git a/massa-execution-worker/src/speculative_deferred_calls.rs b/massa-execution-worker/src/speculative_deferred_calls.rs index ccfd9bfc512..17f39c12c74 100644 --- a/massa-execution-worker/src/speculative_deferred_calls.rs +++ b/massa-execution-worker/src/speculative_deferred_calls.rs @@ -241,9 +241,6 @@ impl SpeculativeDeferredCallRegistry { for (id, _call) in &slot_calls.slot_calls { self.deferred_calls_changes.delete_call(current_slot, id); } - // self.deferred_calls_changes.set_slot_gas(current_slot, 0); - // self.deferred_calls_changes - // .set_slot_base_fee(current_slot, Amount::zero()); slot_calls } diff --git a/massa-models/src/slot.rs b/massa-models/src/slot.rs index a21a5af2a22..c5de3031d82 100644 --- a/massa-models/src/slot.rs +++ b/massa-models/src/slot.rs @@ -341,7 +341,7 @@ impl Slot { .ok_or(ModelsError::PeriodOverflowError)?; let mut res_thread = (self.thread as u64) .checked_add(n % (thread_count as u64)) - .ok_or(ModelsError::PeriodOverflowError)?; + .ok_or(ModelsError::ThreadOverflowError)?; if res_thread >= thread_count as u64 { res_period = res_period From ebe33e106bf106e91d62277ae05e64535e1d1ade Mon Sep 17 00:00:00 2001 From: modship Date: Fri, 16 Aug 2024 11:54:51 +0200 Subject: [PATCH 048/100] update max_async_gas for async msg --- massa-execution-worker/src/execution.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/massa-execution-worker/src/execution.rs b/massa-execution-worker/src/execution.rs index 7b14e1e1b59..d2b154af759 100644 --- a/massa-execution-worker/src/execution.rs +++ b/massa-execution-worker/src/execution.rs @@ -1390,7 +1390,7 @@ impl ExecutionState { // Get asynchronous messages to execute let messages = execution_context.take_async_batch( - self.config.max_async_gas, + self.config.max_async_gas.saturating_sub(calls.slot_gas), self.config.async_msg_cst_gas_cost, ); From 12971b5cbc8bc5f0c2aa6f5ab877e6acdac90903 Mon Sep 17 00:00:00 2001 From: modship Date: Fri, 16 Aug 2024 15:37:37 +0200 Subject: [PATCH 049/100] remove useless condition --- massa-execution-worker/src/execution.rs | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/massa-execution-worker/src/execution.rs b/massa-execution-worker/src/execution.rs index d2b154af759..cd8dd9f3517 100644 --- a/massa-execution-worker/src/execution.rs +++ b/massa-execution-worker/src/execution.rs @@ -1424,26 +1424,9 @@ impl ExecutionState { } } - // execute async messages as long as there is remaining gas in the slot (counting both unused max_async_gas and max_block_gas, and the latter can be used in full in case of block miss) - - let mut remaining_async_slot_gas = self.config.max_async_gas.saturating_sub(calls.slot_gas); - let mut remaining_block_gas = self.config.max_gas_per_block.saturating_sub(calls.slot_gas); - // Try executing asynchronous messages. // Effects are cancelled on failure and the sender is reimbursed. for (opt_bytecode, message) in messages { - // TODO verify here - if remaining_async_slot_gas == 0 || remaining_block_gas == 0 { - // break if there is no gas left - break; - } - if message.max_gas > remaining_async_slot_gas || message.max_gas > remaining_block_gas { - // Skip message if there is not enough gas left for it - continue; - } - - remaining_async_slot_gas = remaining_async_slot_gas.saturating_sub(message.max_gas); - remaining_block_gas = remaining_block_gas.saturating_sub(message.max_gas); match self.execute_async_message(message, opt_bytecode) { Ok(_message_return) => { cfg_if::cfg_if! { From 1d61d1479270fe20a5e25329a376af980f8fb1f8 Mon Sep 17 00:00:00 2001 From: modship Date: Fri, 16 Aug 2024 16:46:19 +0200 Subject: [PATCH 050/100] overbooking_fee return Result --- .../src/speculative_deferred_calls.rs | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/massa-execution-worker/src/speculative_deferred_calls.rs b/massa-execution-worker/src/speculative_deferred_calls.rs index 17f39c12c74..284314bbc98 100644 --- a/massa-execution-worker/src/speculative_deferred_calls.rs +++ b/massa-execution-worker/src/speculative_deferred_calls.rs @@ -341,7 +341,7 @@ impl SpeculativeDeferredCallRegistry { current_occupancy: u128, resource_request: u128, max_penalty: Amount, - ) -> Amount { + ) -> Result { // linear part of the occupancy before booking the requested amount let relu_occupancy_before = std::cmp::max(current_occupancy, target_occupancy) - target_occupancy; @@ -353,7 +353,18 @@ impl SpeculativeDeferredCallRegistry { ) - target_occupancy; // denominator for the linear fee - let denominator = resource_supply - target_occupancy; + let denominator = resource_supply.checked_sub(target_occupancy).ok_or( + ExecutionError::DeferredCallsError("Error with denominator on overbooking fee".into()), + )?; + + if denominator.eq(&0) { + // TODO : check if this is correct + return Err(ExecutionError::DeferredCallsError( + "Denominator is zero on overbooking fee".into(), + )); + // OR + // return Ok(Amount::from_raw(0)); + } // compute using the raw fee and u128 to avoid u64 overflows let raw_max_penalty = max_penalty.to_raw() as u128; @@ -365,7 +376,9 @@ impl SpeculativeDeferredCallRegistry { / denominator, ); - Amount::from_raw(std::cmp::min(raw_fee, u64::MAX as u128) as u64) + Ok(Amount::from_raw( + std::cmp::min(raw_fee, u64::MAX as u128) as u64 + )) } /// Compute call fee @@ -435,7 +448,7 @@ impl SpeculativeDeferredCallRegistry { global_occupancy, max_gas as u128, global_overbooking_penalty, // total_supply - ); + )?; // Finally, a per-slot proportional fee is also added to prevent attackers from denying significant ranges of consecutive slots within the long booking period. // Slot overbooking fee @@ -445,7 +458,7 @@ impl SpeculativeDeferredCallRegistry { slot_occupancy as u128, max_gas as u128, slot_overbooking_penalty, // total_initial_coin_supply/10000 - ); + )?; // return the fee Ok(integral_fee From 8f82d3e36a58217b6e8e9536c7e4723f1a1304fa Mon Sep 17 00:00:00 2001 From: modship Date: Fri, 16 Aug 2024 17:22:36 +0200 Subject: [PATCH 051/100] fix operator --- massa-execution-worker/src/context.rs | 4 ---- massa-execution-worker/src/speculative_deferred_calls.rs | 9 +++++---- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/massa-execution-worker/src/context.rs b/massa-execution-worker/src/context.rs index 00f4fcb37cc..12f696644ab 100644 --- a/massa-execution-worker/src/context.rs +++ b/massa-execution-worker/src/context.rs @@ -1135,10 +1135,6 @@ impl ExecutionContext { } } - pub fn deferred_calls_get_slot_booked_gas(&self, slot: &Slot) -> u64 { - self.speculative_deferred_calls.get_slot_gas(slot) - } - pub fn deferred_calls_advance_slot( &mut self, current_slot: Slot, diff --git a/massa-execution-worker/src/speculative_deferred_calls.rs b/massa-execution-worker/src/speculative_deferred_calls.rs index 284314bbc98..7baeda5bb24 100644 --- a/massa-execution-worker/src/speculative_deferred_calls.rs +++ b/massa-execution-worker/src/speculative_deferred_calls.rs @@ -312,7 +312,7 @@ impl SpeculativeDeferredCallRegistry { call.cancelled = true; // we need to reimburse coins to the sender - let res = (call.sender_address, call.coins); + let res: (Address, Amount) = (call.sender_address, call.coins); // Add a cancellation to the current changes self.deferred_calls_changes @@ -322,7 +322,7 @@ impl SpeculativeDeferredCallRegistry { // set slot gas self.deferred_calls_changes - .set_slot_gas(call.target_slot, current_gas - call.max_gas); + .set_slot_gas(call.target_slot, current_gas.saturating_sub(call.max_gas)); // set total gas self.deferred_calls_changes @@ -344,13 +344,14 @@ impl SpeculativeDeferredCallRegistry { ) -> Result { // linear part of the occupancy before booking the requested amount let relu_occupancy_before = - std::cmp::max(current_occupancy, target_occupancy) - target_occupancy; + std::cmp::max(current_occupancy, target_occupancy).saturating_sub(target_occupancy); // linear part of the occupancy after booking the requested amount let relu_occupancy_after = std::cmp::max( current_occupancy.saturating_add(resource_request), target_occupancy, - ) - target_occupancy; + ) + .saturating_sub(target_occupancy); // denominator for the linear fee let denominator = resource_supply.checked_sub(target_occupancy).ok_or( From 6c1caec81681c06620c0460231b3a918876ed477 Mon Sep 17 00:00:00 2001 From: modship Date: Fri, 16 Aug 2024 17:34:02 +0200 Subject: [PATCH 052/100] add penalty constant --- massa-execution-worker/src/interface_impl.rs | 7 +++++-- massa-models/src/config/constants.rs | 4 ++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/massa-execution-worker/src/interface_impl.rs b/massa-execution-worker/src/interface_impl.rs index 6f968fe76fd..bfc1a947f3f 100644 --- a/massa-execution-worker/src/interface_impl.rs +++ b/massa-execution-worker/src/interface_impl.rs @@ -12,6 +12,9 @@ use massa_deferred_calls::DeferredCall; use massa_execution_exports::ExecutionConfig; use massa_execution_exports::ExecutionStackElement; use massa_models::bytecode::Bytecode; +use massa_models::config::{ + DEFERRED_CALL_GLOBAL_OVERBOOKING_PENALTY, DEFERRED_CALL_SLOT_OVERBOOKING_PENALTY, +}; use massa_models::datastore::get_prefix_bounds; use massa_models::deferred_call_id::DeferredCallId; use massa_models::{ @@ -1355,8 +1358,8 @@ impl Interface for InterfaceImpl { self.config.thread_count, self.config.max_deferred_call_future_slots, self.config.max_async_gas, - Amount::from_raw(1_000_000_000), - Amount::from_raw(1_000_000_000 / 10_000), + DEFERRED_CALL_GLOBAL_OVERBOOKING_PENALTY, + DEFERRED_CALL_SLOT_OVERBOOKING_PENALTY, current_slot, ) { Ok(fee) => Ok((true, fee.to_raw())), diff --git a/massa-models/src/config/constants.rs b/massa-models/src/config/constants.rs index 66401fedafd..0bd147194cd 100644 --- a/massa-models/src/config/constants.rs +++ b/massa-models/src/config/constants.rs @@ -349,6 +349,10 @@ pub const DEFERRED_CALL_BASE_FEE_MAX_CHANGE_DENOMINATOR: usize = 8; pub const DEFERRED_CALL_MIN_GAS_INCREMENT: u64 = 1; /// deferred call max gas cost (10 nanomassa) pub const DEFERRED_CALL_MIN_GAS_COST: u64 = 10; +/// deferred call global overbooking penalty +pub const DEFERRED_CALL_GLOBAL_OVERBOOKING_PENALTY: Amount = Amount::from_raw(1_000_000_000); +/// deferred call slot overbooking penalty +pub const DEFERRED_CALL_SLOT_OVERBOOKING_PENALTY: Amount = Amount::from_raw(1_000_000_000 / 10_000); // Some checks at compile time that should not be ignored! #[allow(clippy::assertions_on_constants)] From f3331b56b324ac3b59289e89ab593804e9710e31 Mon Sep 17 00:00:00 2001 From: modship Date: Mon, 26 Aug 2024 11:53:42 +0200 Subject: [PATCH 053/100] pr comment # 1 --- massa-deferred-calls/src/lib.rs | 21 ++++---- massa-deferred-calls/src/registry_changes.rs | 35 ++++--------- massa-deferred-calls/src/slot_changes.rs | 22 -------- massa-deferred-calls/src/tests/mod.rs | 6 +-- massa-execution-worker/src/context.rs | 4 +- .../src/speculative_deferred_calls.rs | 10 ++-- .../src/tests/scenarios_mandatories.rs | 50 +++++++++++++++++-- massa-final-state/src/state_changes.rs | 5 +- massa-models/src/deferred_call_id.rs | 2 +- 9 files changed, 81 insertions(+), 74 deletions(-) diff --git a/massa-deferred-calls/src/lib.rs b/massa-deferred-calls/src/lib.rs index 67d047765f3..6165e89a48f 100644 --- a/massa-deferred-calls/src/lib.rs +++ b/massa-deferred-calls/src/lib.rs @@ -6,7 +6,8 @@ use massa_db_exports::{ }; use massa_serialization::{DeserializeError, Deserializer, Serializer}; use registry_changes::{ - DeferredRegistryChanges, DeferredRegistryChangesDeserializer, DeferredRegistryChangesSerializer, + DeferredCallRegistryChanges, DeferredRegistryChangesDeserializer, + DeferredRegistryChangesSerializer, }; /// This module implements a new version of the Autonomous Smart Contracts. (ASC) @@ -29,7 +30,7 @@ use massa_models::{ deferred_call_id::{DeferredCallId, DeferredCallIdDeserializer, DeferredCallIdSerializer}, slot::Slot, }; -use std::collections::BTreeMap; +use std::collections::{BTreeMap, HashSet}; // #[derive(Debug)] pub struct DeferredCallRegistry { @@ -68,12 +69,12 @@ impl DeferredCallRegistry { } } + /// Returns the DeferredSlotCalls for a given slot pub fn get_slot_calls(&self, slot: Slot) -> DeferredSlotCalls { let mut to_return = DeferredSlotCalls::new(slot); let key = deferred_slot_call_prefix_key!(slot.to_bytes_key()); - // cache the call ids to avoid duplicates iteration - let mut temp = Vec::new(); + let mut temp = HashSet::new(); for (serialized_key, _serialized_value) in self.db.read().prefix_iterator_cf(STATE_CF, &key) { @@ -88,12 +89,10 @@ impl DeferredCallRegistry { .deserialize::(&rest_key) .expect(KEY_DESER_ERROR); - if temp.contains(&call_id) { + if !temp.insert(call_id.clone()) { continue; } - temp.push(call_id.clone()); - if let Some(call) = self.get_call(&slot, &call_id) { to_return.slot_calls.insert(call_id, call); } @@ -312,7 +311,11 @@ impl DeferredCallRegistry { db.delete_key(batch, cancelled_key!(buffer_id, slot_bytes)); } - pub fn apply_changes_to_batch(&self, changes: DeferredRegistryChanges, batch: &mut DBBatch) { + pub fn apply_changes_to_batch( + &self, + changes: DeferredCallRegistryChanges, + batch: &mut DBBatch, + ) { //Note: if a slot gas is zet to 0, delete the slot gas entry // same for base fee @@ -452,7 +455,7 @@ impl DeferredSlotCalls { } } - pub fn apply_changes(&mut self, changes: &DeferredRegistryChanges) { + pub fn apply_changes(&mut self, changes: &DeferredCallRegistryChanges) { let Some(slot_changes) = changes.slots_change.get(&self.slot) else { return; }; diff --git a/massa-deferred-calls/src/registry_changes.rs b/massa-deferred-calls/src/registry_changes.rs index fc31a21e9df..b18b35f79e0 100644 --- a/massa-deferred-calls/src/registry_changes.rs +++ b/massa-deferred-calls/src/registry_changes.rs @@ -28,29 +28,12 @@ use crate::{ use std::ops::Bound::Included; #[derive(Default, Debug, Clone, Serialize, Deserialize)] -pub struct DeferredRegistryChanges { +pub struct DeferredCallRegistryChanges { pub slots_change: BTreeMap, pub total_gas: DeferredRegistryGasChange, } -impl DeferredRegistryChanges { - pub fn merge(&mut self, other: DeferredRegistryChanges) { - for (slot, changes) in other.slots_change { - match self.slots_change.entry(slot) { - std::collections::btree_map::Entry::Occupied(mut entry) => { - entry.get_mut().merge(changes); - } - std::collections::btree_map::Entry::Vacant(entry) => { - entry.insert(changes); - } - } - } - match other.total_gas { - DeferredRegistryGasChange::Set(v) => self.total_gas = DeferredRegistryGasChange::Set(v), - DeferredRegistryGasChange::Keep => {} - } - } - +impl DeferredCallRegistryChanges { pub fn delete_call(&mut self, target_slot: Slot, id: &DeferredCallId) { self.slots_change .entry(target_slot) @@ -127,10 +110,10 @@ impl DeferredRegistryChangesSerializer { } } -impl Serializer for DeferredRegistryChangesSerializer { +impl Serializer for DeferredRegistryChangesSerializer { fn serialize( &self, - value: &DeferredRegistryChanges, + value: &DeferredCallRegistryChanges, buffer: &mut Vec, ) -> Result<(), SerializeError> { self.slots_length.serialize( @@ -184,11 +167,11 @@ impl DeferredRegistryChangesDeserializer { } } -impl Deserializer for DeferredRegistryChangesDeserializer { +impl Deserializer for DeferredRegistryChangesDeserializer { fn deserialize<'a, E: ParseError<&'a [u8]> + ContextError<&'a [u8]>>( &self, buffer: &'a [u8], - ) -> IResult<&'a [u8], DeferredRegistryChanges, E> { + ) -> IResult<&'a [u8], DeferredCallRegistryChanges, E> { context( "Failed DeferredRegistryChanges deserialization", tuple(( @@ -213,7 +196,7 @@ impl Deserializer for DeferredRegistryChangesDeserializ }), )), ) - .map(|(changes, total_gas)| DeferredRegistryChanges { + .map(|(changes, total_gas)| DeferredCallRegistryChanges { slots_change: changes.into_iter().collect::>(), total_gas, }) @@ -238,12 +221,12 @@ mod tests { #[test] fn test_deferred_registry_ser_deser() { - use crate::DeferredRegistryChanges; + use crate::DeferredCallRegistryChanges; use massa_models::slot::Slot; use massa_serialization::{Deserializer, Serializer}; use std::collections::BTreeMap; - let mut changes = DeferredRegistryChanges { + let mut changes = DeferredCallRegistryChanges { slots_change: BTreeMap::new(), total_gas: Default::default(), }; diff --git a/massa-deferred-calls/src/slot_changes.rs b/massa-deferred-calls/src/slot_changes.rs index 6ca84bfa4c6..c2ac6d40f58 100644 --- a/massa-deferred-calls/src/slot_changes.rs +++ b/massa-deferred-calls/src/slot_changes.rs @@ -37,28 +37,6 @@ impl DeferredRegistrySlotChanges { self.calls.len() } - pub fn merge(&mut self, _other: DeferredRegistrySlotChanges) { - unimplemented!("DeferredRegistrySlotChanges::merge") - // for (id, change) in other.calls { - // match self.calls.entry(id) { - // std::collections::btree_map::Entry::Occupied(mut entry) => { - // entry.get_mut().merge(change); - // } - // std::collections::btree_map::Entry::Vacant(entry) => { - // entry.insert(change); - // } - // } - // } - // match other.gas { - // DeferredRegistryGasChange::Set(v) => self.gas = DeferredRegistryGasChange::Set(v), - // DeferredRegistryGasChange::Keep => {} - // } - // match other.base_fee { - // DeferredRegistryGasChange::Set(v) => self.base_fee = DeferredRegistryGasChange::Set(v), - // DeferredRegistryGasChange::Keep => {} - // } - } - /// add Delete changes will delete the call from the db registry when the slot is finalized pub fn delete_call(&mut self, id: &DeferredCallId) { match self.calls.entry(id.clone()) { diff --git a/massa-deferred-calls/src/tests/mod.rs b/massa-deferred-calls/src/tests/mod.rs index a622fd2969a..9cc414d2951 100644 --- a/massa-deferred-calls/src/tests/mod.rs +++ b/massa-deferred-calls/src/tests/mod.rs @@ -1,5 +1,5 @@ use super::*; -use crate::{DeferredCall, DeferredCallRegistry, DeferredRegistryChanges}; +use crate::{DeferredCall, DeferredCallRegistry, DeferredCallRegistryChanges}; use massa_db_exports::{DBBatch, MassaDBConfig, MassaDBController, ShareableMassaDBController}; use massa_db_worker::MassaDB; use massa_models::{ @@ -31,7 +31,7 @@ fn call_registry_apply_changes() { let registry = DeferredCallRegistry::new(db); - let mut changes = DeferredRegistryChanges::default(); + let mut changes = DeferredCallRegistryChanges::default(); let target_slot = Slot { thread: 5, @@ -83,7 +83,7 @@ fn call_registry_get_slot_calls() { let registry = DeferredCallRegistry::new(db); - let mut changes = DeferredRegistryChanges::default(); + let mut changes = DeferredCallRegistryChanges::default(); let target_slot = Slot { thread: 5, diff --git a/massa-execution-worker/src/context.rs b/massa-execution-worker/src/context.rs index 12f696644ab..9250e698056 100644 --- a/massa-execution-worker/src/context.rs +++ b/massa-execution-worker/src/context.rs @@ -16,7 +16,7 @@ use crate::speculative_ledger::SpeculativeLedger; use crate::{active_history::ActiveHistory, speculative_roll_state::SpeculativeRollState}; use massa_async_pool::{AsyncMessage, AsyncPoolChanges}; use massa_async_pool::{AsyncMessageId, AsyncMessageInfo}; -use massa_deferred_calls::registry_changes::DeferredRegistryChanges; +use massa_deferred_calls::registry_changes::DeferredCallRegistryChanges; use massa_deferred_calls::{DeferredCall, DeferredSlotCalls}; use massa_executed_ops::{ExecutedDenunciationsChanges, ExecutedOpsChanges}; use massa_execution_exports::{ @@ -63,7 +63,7 @@ pub struct ExecutionContextSnapshot { pub async_pool_changes: AsyncPoolChanges, /// speculative deferred calls changes - pub deferred_calls_changes: DeferredRegistryChanges, + pub deferred_calls_changes: DeferredCallRegistryChanges, /// the associated message infos for the speculative async pool pub message_infos: BTreeMap, diff --git a/massa-execution-worker/src/speculative_deferred_calls.rs b/massa-execution-worker/src/speculative_deferred_calls.rs index 7baeda5bb24..b058cfe5319 100644 --- a/massa-execution-worker/src/speculative_deferred_calls.rs +++ b/massa-execution-worker/src/speculative_deferred_calls.rs @@ -2,7 +2,7 @@ use crate::active_history::ActiveHistory; use massa_deferred_calls::{ - registry_changes::DeferredRegistryChanges, DeferredCall, DeferredSlotCalls, + registry_changes::DeferredCallRegistryChanges, DeferredCall, DeferredSlotCalls, }; use massa_execution_exports::ExecutionError; use massa_final_state::FinalStateController; @@ -25,7 +25,7 @@ pub(crate) struct SpeculativeDeferredCallRegistry { final_state: Arc>, active_history: Arc>, // current speculative registry changes - deferred_calls_changes: DeferredRegistryChanges, + deferred_calls_changes: DeferredCallRegistryChanges, } impl SpeculativeDeferredCallRegistry { @@ -44,12 +44,12 @@ impl SpeculativeDeferredCallRegistry { } /// Takes a snapshot (clone) of the message states - pub fn get_snapshot(&self) -> DeferredRegistryChanges { + pub fn get_snapshot(&self) -> DeferredCallRegistryChanges { self.deferred_calls_changes.clone() } /// Resets the `SpeculativeDeferredCallRegistry` to a snapshot (see `get_snapshot` method) - pub fn reset_to_snapshot(&mut self, snapshot: DeferredRegistryChanges) { + pub fn reset_to_snapshot(&mut self, snapshot: DeferredCallRegistryChanges) { self.deferred_calls_changes = snapshot; } @@ -516,7 +516,7 @@ impl SpeculativeDeferredCallRegistry { } /// Take the deferred registry slot changes - pub(crate) fn take(&mut self) -> DeferredRegistryChanges { + pub(crate) fn take(&mut self) -> DeferredCallRegistryChanges { std::mem::take(&mut self.deferred_calls_changes) } } diff --git a/massa-execution-worker/src/tests/scenarios_mandatories.rs b/massa-execution-worker/src/tests/scenarios_mandatories.rs index e583d0ae531..f081f8fcc7b 100644 --- a/massa-execution-worker/src/tests/scenarios_mandatories.rs +++ b/massa-execution-worker/src/tests/scenarios_mandatories.rs @@ -2,7 +2,7 @@ use massa_async_pool::{AsyncMessage, AsyncPool, AsyncPoolChanges, AsyncPoolConfig}; use massa_db_exports::{DBBatch, ShareableMassaDBController}; -use massa_deferred_calls::registry_changes::DeferredRegistryChanges; +use massa_deferred_calls::registry_changes::DeferredCallRegistryChanges; use massa_deferred_calls::slot_changes::DeferredRegistrySlotChanges; use massa_deferred_calls::{DeferredCall, DeferredCallRegistry}; use massa_executed_ops::{ExecutedDenunciations, ExecutedDenunciationsConfig}; @@ -1082,7 +1082,7 @@ fn deferred_calls() { let mut db_batch = DBBatch::default(); registry.apply_changes_to_batch( - DeferredRegistryChanges { + DeferredCallRegistryChanges { slots_change: slot_changes, total_gas: SetOrKeep::Keep, }, @@ -1181,6 +1181,7 @@ fn deferred_call_register() { .times(1) .with(predicate::eq(Slot::new(1, 0)), predicate::always()) .returning(move |_, changes| { + dbg!(&changes.deferred_call_changes); // assert sender was debited ( -10 coins) and -1.50 for fees match changes.ledger_changes.0.get(&sender_addr_clone).unwrap() { SetUpdateOrDelete::Update(change_sc_update) => { @@ -1287,7 +1288,7 @@ fn deferred_call_register() { let mut db_batch = DBBatch::default(); registry.apply_changes_to_batch( - DeferredRegistryChanges { + DeferredCallRegistryChanges { slots_change: slot_changes, total_gas: SetOrKeep::Keep, }, @@ -1434,7 +1435,7 @@ fn deferred_call_register_fail() { let mut db_batch = DBBatch::default(); registry.apply_changes_to_batch( - DeferredRegistryChanges { + DeferredCallRegistryChanges { slots_change: slot_changes, total_gas: SetOrKeep::Set(2000), }, @@ -1488,6 +1489,47 @@ fn deferred_call_register_fail() { let ev = events[1].clone(); assert!(ev.context.is_error); assert!(ev.data.contains("The ASC 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")); + + // // update base fee at slot 1,10 + // defer_reg_slot_changes.set_base_fee(Amount::from_str("0.0005").unwrap()); + + // slot_changes.insert(target_slot.clone(), defer_reg_slot_changes); + + // let mut db_batch = DBBatch::default(); + + // // reset total slot gas + // registry.apply_changes_to_batch( + // DeferredRegistryChanges { + // slots_change: slot_changes, + // total_gas: SetOrKeep::Set(0), + // }, + // &mut db_batch, + // ); + + // foreign_controllers + // .db + // .write() + // .write_batch(db_batch, DBBatch::default(), Some(Slot::new(1, 1))); + + // universe.deploy_bytecode_block( + // &keypair, + // Slot::new(1, 2), + // include_bytes!("./wasm/deferred_call_register_fail.wasm"), + // //unused + // include_bytes!("./wasm/use_builtins.wasm"), + // ); + + // let events = universe + // .module_controller + // .get_filtered_sc_output_event(EventFilter { + // start: Some(Slot::new(1, 1)), + // end: Some(Slot::new(20, 1)), + // ..Default::default() + // }); + + // dbg!(&events); + + // let ev = events[1].clone(); } /// Context /// diff --git a/massa-final-state/src/state_changes.rs b/massa-final-state/src/state_changes.rs index 1511f6de547..9de90ab9cf8 100644 --- a/massa-final-state/src/state_changes.rs +++ b/massa-final-state/src/state_changes.rs @@ -6,7 +6,8 @@ use massa_async_pool::{ AsyncPoolChanges, AsyncPoolChangesDeserializer, AsyncPoolChangesSerializer, }; use massa_deferred_calls::registry_changes::{ - DeferredRegistryChanges, DeferredRegistryChangesDeserializer, DeferredRegistryChangesSerializer, + DeferredCallRegistryChanges, DeferredRegistryChangesDeserializer, + DeferredRegistryChangesSerializer, }; use massa_executed_ops::{ ExecutedDenunciationsChanges, ExecutedDenunciationsChangesDeserializer, @@ -35,7 +36,7 @@ pub struct StateChanges { /// asynchronous pool changes pub async_pool_changes: AsyncPoolChanges, /// deferred call changes - pub deferred_call_changes: DeferredRegistryChanges, + pub deferred_call_changes: DeferredCallRegistryChanges, /// roll state changes pub pos_changes: PoSChanges, /// executed operations changes diff --git a/massa-models/src/deferred_call_id.rs b/massa-models/src/deferred_call_id.rs index 0d9cc4f5bb9..f1b98535c2f 100644 --- a/massa-models/src/deferred_call_id.rs +++ b/massa-models/src/deferred_call_id.rs @@ -24,7 +24,7 @@ const DEFERRED_CALL_ID_PREFIX: &str = "D"; /// block id #[allow(missing_docs)] #[transition::versioned(versions("0"))] -#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] +#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] pub struct DeferredCallId(Vec); /// Serializer for `DeferredCallId` From 9664ca7c883a54b028c31bb849ad75778e989eb2 Mon Sep 17 00:00:00 2001 From: Modship Date: Mon, 26 Aug 2024 12:04:27 +0200 Subject: [PATCH 054/100] Update massa-execution-worker/src/context.rs Co-authored-by: Damir Vodenicarevic --- massa-execution-worker/src/context.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/massa-execution-worker/src/context.rs b/massa-execution-worker/src/context.rs index 9250e698056..18da3cecf48 100644 --- a/massa-execution-worker/src/context.rs +++ b/massa-execution-worker/src/context.rs @@ -1190,7 +1190,7 @@ impl ExecutionContext { false } - /// when a deferred call execution fail we need to refund the coins to the caller + /// when a deferred call execution fails we need to refund the coins to the caller pub fn deferred_call_fail_exec( &mut self, call: &DeferredCall, From a08664e0da0a811ecc423baeeafeca84c88626a2 Mon Sep 17 00:00:00 2001 From: modship Date: Mon, 26 Aug 2024 16:03:32 +0200 Subject: [PATCH 055/100] pr comment # 2 --- massa-deferred-calls/src/call.rs | 2 +- massa-deferred-calls/src/lib.rs | 207 ++++++++---------- massa-deferred-calls/src/macros.rs | 2 +- massa-deferred-calls/src/registry_changes.rs | 4 +- massa-deferred-calls/src/slot_changes.rs | 4 +- massa-deferred-calls/src/tests/mod.rs | 2 +- massa-execution-worker/src/context.rs | 14 +- massa-execution-worker/src/execution.rs | 76 +++---- massa-execution-worker/src/interface_impl.rs | 4 +- .../src/speculative_deferred_calls.rs | 2 +- .../src/tests/scenarios_mandatories.rs | 2 +- ...{deferred_call_id.rs => deferred_calls.rs} | 0 massa-models/src/lib.rs | 2 +- 13 files changed, 150 insertions(+), 171 deletions(-) rename massa-models/src/{deferred_call_id.rs => deferred_calls.rs} (100%) diff --git a/massa-deferred-calls/src/call.rs b/massa-deferred-calls/src/call.rs index 7080ea055f1..4feeef85fe1 100644 --- a/massa-deferred-calls/src/call.rs +++ b/massa-deferred-calls/src/call.rs @@ -78,7 +78,7 @@ pub struct DeferredCallSerializer { } impl DeferredCallSerializer { - /// Serializes an `AsyncCall` into a `Vec` + /// Serializes an `DeferredCall` into a `Vec` pub fn new() -> Self { Self { slot_serializer: SlotSerializer::new(), diff --git a/massa-deferred-calls/src/lib.rs b/massa-deferred-calls/src/lib.rs index 6165e89a48f..b259ef1a807 100644 --- a/massa-deferred-calls/src/lib.rs +++ b/massa-deferred-calls/src/lib.rs @@ -27,7 +27,7 @@ use massa_ledger_exports::{SetOrDelete, SetOrKeep}; use massa_models::{ amount::Amount, config::{DEFERRED_CALL_MAX_POOL_CHANGES, MAX_ASYNC_GAS, THREAD_COUNT}, - deferred_call_id::{DeferredCallId, DeferredCallIdDeserializer, DeferredCallIdSerializer}, + deferred_calls::{DeferredCallId, DeferredCallIdDeserializer, DeferredCallIdSerializer}, slot::Slot, }; use std::collections::{BTreeMap, HashSet}; @@ -49,7 +49,7 @@ impl DeferredCallRegistry { [DEFERRED_CALL_TOTAL_GAS] -> u64 // total currently booked gas [DEFERRED_CALLS_PREFIX][slot][SLOT_TOTAL_GAS] -> u64 // total gas booked for a slot (optional, default 0, deleted when set to 0) [DEFERRED_CALLS_PREFIX][slot][SLOT_BASE_FEE] -> u64 // deleted when set to 0 - [DEFERRED_CALLS_PREFIX][slot][CALLS_TAG][id][CALL_FIELD_X_TAG] -> AsyncCall.x // call data + [DEFERRED_CALLS_PREFIX][slot][CALLS_TAG][id][CALL_FIELD_X_TAG] -> DeferredCalls.x // call data */ // TODO pass args @@ -205,89 +205,105 @@ impl DeferredCallRegistry { let db = self.db.read(); - // sender address - let mut temp_buffer = Vec::new(); - self.call_serializer - .address_serializer - .serialize(&call.sender_address, &mut temp_buffer) - .expect(DEFERRED_CALL_SER_ERROR); - db.put_or_update_entry_value( - batch, - sender_address_key!(buffer_id, slot_bytes), - &temp_buffer, - ); - temp_buffer.clear(); - - // target slot - self.call_serializer - .slot_serializer - .serialize(&call.target_slot, &mut temp_buffer) - .expect(DEFERRED_CALL_SER_ERROR); - db.put_or_update_entry_value(batch, target_slot_key!(buffer_id, slot_bytes), &temp_buffer); - temp_buffer.clear(); + { + // sender address + let mut buffer = Vec::new(); + self.call_serializer + .address_serializer + .serialize(&call.sender_address, &mut buffer) + .expect(DEFERRED_CALL_SER_ERROR); + db.put_or_update_entry_value( + batch, + sender_address_key!(buffer_id, slot_bytes), + &buffer, + ); + } - // target address - self.call_serializer - .address_serializer - .serialize(&call.target_address, &mut temp_buffer) - .expect(DEFERRED_CALL_SER_ERROR); - db.put_or_update_entry_value( - batch, - target_address_key!(buffer_id, slot_bytes), - &temp_buffer, - ); - temp_buffer.clear(); - - // target function - self.call_serializer - .string_serializer - .serialize(&call.target_function, &mut temp_buffer) - .expect(DEFERRED_CALL_SER_ERROR); - db.put_or_update_entry_value( - batch, - target_function_key!(buffer_id, slot_bytes), - &temp_buffer, - ); - temp_buffer.clear(); - - // parameters - self.call_serializer - .vec_u8_serializer - .serialize(&call.parameters, &mut temp_buffer) - .expect(DEFERRED_CALL_SER_ERROR); - db.put_or_update_entry_value(batch, parameters_key!(buffer_id, slot_bytes), &temp_buffer); - temp_buffer.clear(); + { + // target slot + let mut buffer = Vec::new(); + self.call_serializer + .slot_serializer + .serialize(&call.target_slot, &mut buffer) + .expect(DEFERRED_CALL_SER_ERROR); + db.put_or_update_entry_value(batch, target_slot_key!(buffer_id, slot_bytes), &buffer); + } - // coins - self.call_serializer - .amount_serializer - .serialize(&call.coins, &mut temp_buffer) - .expect(DEFERRED_CALL_SER_ERROR); - db.put_or_update_entry_value(batch, coins_key!(buffer_id, slot_bytes), &temp_buffer); - temp_buffer.clear(); + { + // target address + let mut buffer = Vec::new(); + self.call_serializer + .address_serializer + .serialize(&call.target_address, &mut buffer) + .expect(DEFERRED_CALL_SER_ERROR); + db.put_or_update_entry_value( + batch, + target_address_key!(buffer_id, slot_bytes), + &buffer, + ); + } - // max gas - self.call_serializer - .u64_var_int_serializer - .serialize(&call.max_gas, &mut temp_buffer) - .expect(DEFERRED_CALL_SER_ERROR); - db.put_or_update_entry_value(batch, max_gas_key!(buffer_id, slot_bytes), &temp_buffer); - temp_buffer.clear(); + { + // target function + let mut buffer = Vec::new(); + self.call_serializer + .string_serializer + .serialize(&call.target_function, &mut buffer) + .expect(DEFERRED_CALL_SER_ERROR); + db.put_or_update_entry_value( + batch, + target_function_key!(buffer_id, slot_bytes), + &buffer, + ); + } - // fee - self.call_serializer - .amount_serializer - .serialize(&call.fee, &mut temp_buffer) - .expect(DEFERRED_CALL_SER_ERROR); - db.put_or_update_entry_value(batch, fee_key!(buffer_id, slot_bytes), &temp_buffer); - temp_buffer.clear(); + { + // parameters + let mut buffer = Vec::new(); + self.call_serializer + .vec_u8_serializer + .serialize(&call.parameters, &mut buffer) + .expect(DEFERRED_CALL_SER_ERROR); + db.put_or_update_entry_value(batch, parameters_key!(buffer_id, slot_bytes), &buffer); + } + + { + // coins + let mut buffer = Vec::new(); + self.call_serializer + .amount_serializer + .serialize(&call.coins, &mut buffer) + .expect(DEFERRED_CALL_SER_ERROR); + db.put_or_update_entry_value(batch, coins_key!(buffer_id, slot_bytes), &buffer); + } + + { + // max gas + let mut buffer = Vec::new(); + self.call_serializer + .u64_var_int_serializer + .serialize(&call.max_gas, &mut buffer) + .expect(DEFERRED_CALL_SER_ERROR); + db.put_or_update_entry_value(batch, max_gas_key!(buffer_id, slot_bytes), &buffer); + } + + { + // fee + let mut buffer = Vec::new(); + self.call_serializer + .amount_serializer + .serialize(&call.fee, &mut buffer) + .expect(DEFERRED_CALL_SER_ERROR); + db.put_or_update_entry_value(batch, fee_key!(buffer_id, slot_bytes), &buffer); + } // cancelled + let mut buffer = Vec::new(); self.call_serializer .bool_serializer - .serialize(&call.cancelled, &mut temp_buffer) + .serialize(&call.cancelled, &mut buffer) .expect(DEFERRED_CALL_SER_ERROR); - db.put_or_update_entry_value(batch, cancelled_key!(buffer_id, slot_bytes), &temp_buffer); + db.put_or_update_entry_value(batch, cancelled_key!(buffer_id, slot_bytes), &buffer); } fn delete_entry(&self, id: &DeferredCallId, slot: &Slot, batch: &mut DBBatch) { @@ -389,50 +405,11 @@ impl DeferredCallRegistry { } } -// #[derive(Debug, Clone, Serialize, Deserialize)] -// pub enum DeferredRegistryCallChange { -// Set(DeferredCall), -// Delete, -// } - // TODO put SetOrDelete dans models pub type DeferredRegistryCallChange = SetOrDelete; pub type DeferredRegistryGasChange = SetOrKeep; pub type DeferredRegistryBaseFeeChange = SetOrKeep; -// impl DeferredRegistryCallChange { -// pub fn merge(&mut self, other: DeferredRegistryCallChange) { -// *self = other; -// } - -// pub fn delete_call(&mut self) { -// *self = DeferredRegistryCallChange::Delete; -// } - -// pub fn set_call(&mut self, call: DeferredCall) { -// *self = DeferredRegistryCallChange::Set(call); -// } - -// pub fn get_call(&self) -> Option<&DeferredCall> { -// match self { -// DeferredRegistryCallChange::Set(v) => Some(v), -// DeferredRegistryCallChange::Delete => None, -// } -// } -// } - -// #[derive(Debug, Clone, Serialize, Deserialize)] -// pub enum DeferredRegistryGasChange { -// Set(V), -// Keep, -// } - -// impl Default for DeferredRegistryGasChange { -// fn default() -> Self { -// DeferredRegistryGasChange::Keep -// } -// } - /// A structure that lists slot calls for a given slot, /// as well as global gas usage statistics. #[derive(Debug, Clone)] diff --git a/massa-deferred-calls/src/macros.rs b/massa-deferred-calls/src/macros.rs index 9c45187d91f..f881e758f4a 100644 --- a/massa-deferred-calls/src/macros.rs +++ b/massa-deferred-calls/src/macros.rs @@ -143,7 +143,7 @@ macro_rules! cancelled_key { mod tests { use massa_db_exports::DEFERRED_CALLS_PREFIX; use massa_models::{ - deferred_call_id::{DeferredCallId, DeferredCallIdSerializer}, + deferred_calls::{DeferredCallId, DeferredCallIdSerializer}, slot::Slot, }; use massa_serialization::Serializer; diff --git a/massa-deferred-calls/src/registry_changes.rs b/massa-deferred-calls/src/registry_changes.rs index b18b35f79e0..703811bff58 100644 --- a/massa-deferred-calls/src/registry_changes.rs +++ b/massa-deferred-calls/src/registry_changes.rs @@ -3,7 +3,7 @@ use std::{collections::BTreeMap, ops::Bound}; use massa_ledger_exports::{SetOrKeepDeserializer, SetOrKeepSerializer}; use massa_models::{ amount::Amount, - deferred_call_id::DeferredCallId, + deferred_calls::DeferredCallId, slot::{Slot, SlotDeserializer, SlotSerializer}, }; use massa_serialization::{ @@ -208,7 +208,7 @@ impl Deserializer for DeferredRegistryChangesDeseri mod tests { use std::str::FromStr; - use massa_models::{address::Address, amount::Amount, deferred_call_id::DeferredCallId}; + use massa_models::{address::Address, amount::Amount, deferred_calls::DeferredCallId}; use massa_serialization::DeserializeError; use crate::{ diff --git a/massa-deferred-calls/src/slot_changes.rs b/massa-deferred-calls/src/slot_changes.rs index c2ac6d40f58..294b0762f54 100644 --- a/massa-deferred-calls/src/slot_changes.rs +++ b/massa-deferred-calls/src/slot_changes.rs @@ -11,7 +11,7 @@ use massa_ledger_exports::{ }; use massa_models::{ amount::{Amount, AmountDeserializer, AmountSerializer}, - deferred_call_id::{DeferredCallId, DeferredCallIdDeserializer, DeferredCallIdSerializer}, + deferred_calls::{DeferredCallId, DeferredCallIdDeserializer, DeferredCallIdSerializer}, }; use massa_serialization::{ Deserializer, SerializeError, Serializer, U64VarIntDeserializer, U64VarIntSerializer, @@ -213,7 +213,7 @@ mod tests { use std::str::FromStr; use massa_models::{ - address::Address, amount::Amount, deferred_call_id::DeferredCallId, slot::Slot, + address::Address, amount::Amount, deferred_calls::DeferredCallId, slot::Slot, }; use massa_serialization::{DeserializeError, Deserializer, Serializer}; diff --git a/massa-deferred-calls/src/tests/mod.rs b/massa-deferred-calls/src/tests/mod.rs index 9cc414d2951..d89ee1054c7 100644 --- a/massa-deferred-calls/src/tests/mod.rs +++ b/massa-deferred-calls/src/tests/mod.rs @@ -6,7 +6,7 @@ use massa_models::{ address::Address, amount::Amount, config::THREAD_COUNT, - deferred_call_id::{DeferredCallId, DeferredCallIdSerializer}, + deferred_calls::{DeferredCallId, DeferredCallIdSerializer}, slot::Slot, }; use parking_lot::RwLock; diff --git a/massa-execution-worker/src/context.rs b/massa-execution-worker/src/context.rs index 18da3cecf48..34efa720299 100644 --- a/massa-execution-worker/src/context.rs +++ b/massa-execution-worker/src/context.rs @@ -29,7 +29,7 @@ use massa_ledger_exports::{LedgerChanges, SetOrKeep}; use massa_models::address::ExecutionAddressCycleInfo; use massa_models::block_id::BlockIdSerializer; use massa_models::bytecode::Bytecode; -use massa_models::deferred_call_id::DeferredCallId; +use massa_models::deferred_calls::DeferredCallId; use massa_models::denunciation::DenunciationIndex; use massa_models::timeslots::get_block_slot_timestamp; use massa_models::{ @@ -1183,7 +1183,7 @@ impl ExecutionContext { /// Check if a deferred call exists /// If it exists, check if it has been cancelled /// If it has been cancelled, return false - pub fn deferred_call_exist(&self, call_id: &DeferredCallId) -> bool { + pub fn deferred_call_exists(&self, call_id: &DeferredCallId) -> bool { if let Some(call) = self.speculative_deferred_calls.get_call(call_id) { return call.cancelled; } @@ -1193,6 +1193,7 @@ impl ExecutionContext { /// when a deferred call execution fails we need to refund the coins to the caller pub fn deferred_call_fail_exec( &mut self, + id: &DeferredCallId, call: &DeferredCall, ) -> Option<(Address, Result)> { #[allow(unused_assignments, unused_mut)] @@ -1207,6 +1208,9 @@ impl ExecutionContext { ); } + let event = self.event_create(format!("DeferredCall execution fail call_id:{}", id), true); + self.event_emit(event); + #[cfg(feature = "execution-info")] if let Err(e) = transfer_result { result = Some((call.sender_address, Err(e.to_string()))) @@ -1217,11 +1221,7 @@ impl ExecutionContext { result } - /// not used for now - pub fn deferred_call_delete(&mut self, call_id: &DeferredCallId, slot: Slot) { - self.speculative_deferred_calls.delete_call(call_id, slot); - } - + /// when a deferred call is cancelled we need to refund the coins to the caller pub fn deferred_call_cancel( &mut self, call_id: &DeferredCallId, diff --git a/massa-execution-worker/src/execution.rs b/massa-execution-worker/src/execution.rs index cd8dd9f3517..d23ef84c0b4 100644 --- a/massa-execution-worker/src/execution.rs +++ b/massa-execution-worker/src/execution.rs @@ -30,6 +30,7 @@ use massa_models::bytecode::Bytecode; use massa_models::config::DEFERRED_CALL_MAX_FUTURE_SLOTS; use massa_models::datastore::get_prefix_bounds; +use massa_models::deferred_calls::DeferredCallId; use massa_models::denunciation::{Denunciation, DenunciationIndex}; use massa_models::execution::EventFilter; use massa_models::output_event::SCOutputEvent; @@ -1227,6 +1228,7 @@ impl ExecutionState { fn execute_deferred_call( &self, + id: &DeferredCallId, call: DeferredCall, ) -> Result { let mut result = DeferredCallExecutionResult::new(&call); @@ -1261,7 +1263,7 @@ impl ExecutionState { // Ensure that the target address exists if let Err(err) = context.check_target_sc_address(call.target_address) { context.reset_to_snapshot(snapshot, err.clone()); - context.deferred_call_fail_exec(&call); + context.deferred_call_fail_exec(id, &call); return Err(err); } @@ -1276,7 +1278,7 @@ impl ExecutionState { )); context.reset_to_snapshot(snapshot, err.clone()); - context.deferred_call_fail_exec(&call); + context.deferred_call_fail_exec(id, &call); return Err(err); } @@ -1336,7 +1338,7 @@ impl ExecutionState { }; let mut context = context_guard!(self); context.reset_to_snapshot(snapshot, err.clone()); - context.deferred_call_fail_exec(&call); + context.deferred_call_fail_exec(id, &call); Err(err) } } @@ -1388,12 +1390,6 @@ impl ExecutionState { self.config.thread_count, ); - // Get asynchronous messages to execute - let messages = execution_context.take_async_batch( - self.config.max_async_gas.saturating_sub(calls.slot_gas), - self.config.async_msg_cst_gas_cost, - ); - // Apply the created execution context for slot execution *context_guard!(self) = execution_context; @@ -1402,7 +1398,7 @@ impl ExecutionState { // Skip cancelled calls continue; } - match self.execute_deferred_call(call) { + match self.execute_deferred_call(&id, call) { Ok(_exec) => { info!("executed deferred call: {:?}", id); cfg_if::cfg_if! { @@ -1424,31 +1420,9 @@ impl ExecutionState { } } - // Try executing asynchronous messages. - // Effects are cancelled on failure and the sender is reimbursed. - for (opt_bytecode, message) in messages { - match self.execute_async_message(message, opt_bytecode) { - Ok(_message_return) => { - cfg_if::cfg_if! { - if #[cfg(feature = "execution-trace")] { - // Safe to unwrap - slot_trace.asc_call_stacks.push(_message_return.traces.unwrap().0); - } else if #[cfg(feature = "execution-info")] { - slot_trace.asc_call_stacks.push(_message_return.traces.clone().unwrap().0); - exec_info.async_messages.push(Ok(_message_return)); - } - } - } - Err(err) => { - let msg = format!("failed executing async message: {}", err); - #[cfg(feature = "execution-info")] - exec_info.async_messages.push(Err(msg.clone())); - debug!(msg); - } - } - } - let mut block_info: Option = None; + // Set block gas (max_gas_per_block - gas used by deferred calls) + let mut remaining_block_gas = self.config.max_gas_per_block; // Check if there is a block at this slot if let Some((block_id, block_metadata)) = exec_target { @@ -1500,9 +1474,6 @@ impl ExecutionState { .same_thread_parent_creator .expect("same thread parent creator missing"); - // Set remaining block gas - let mut remaining_block_gas = self.config.max_gas_per_block; - // Set block credits let mut block_credits = self.config.block_reward; @@ -1704,6 +1675,37 @@ impl ExecutionState { context_guard!(self).update_production_stats(&producer_addr, *slot, None); } + // Get asynchronous messages to execute + // The gas available for async messages is the remaining block gas + async remaining gas (max_async - gas used by deferred calls) + let async_msg_gas_available = + self.config.max_async_gas.saturating_sub(calls.slot_gas) + remaining_block_gas; + let messages = context_guard!(self) + .take_async_batch(async_msg_gas_available, self.config.async_msg_cst_gas_cost); + + // Try executing asynchronous messages. + // Effects are cancelled on failure and the sender is reimbursed. + for (opt_bytecode, message) in messages { + match self.execute_async_message(message, opt_bytecode) { + Ok(_message_return) => { + cfg_if::cfg_if! { + if #[cfg(feature = "execution-trace")] { + // Safe to unwrap + slot_trace.asc_call_stacks.push(_message_return.traces.unwrap().0); + } else if #[cfg(feature = "execution-info")] { + slot_trace.asc_call_stacks.push(_message_return.traces.clone().unwrap().0); + exec_info.async_messages.push(Ok(_message_return)); + } + } + } + Err(err) => { + let msg = format!("failed executing async message: {}", err); + #[cfg(feature = "execution-info")] + exec_info.async_messages.push(Err(msg.clone())); + debug!(msg); + } + } + } + #[cfg(feature = "execution-trace")] self.trace_history .write() diff --git a/massa-execution-worker/src/interface_impl.rs b/massa-execution-worker/src/interface_impl.rs index bfc1a947f3f..1bf5791628f 100644 --- a/massa-execution-worker/src/interface_impl.rs +++ b/massa-execution-worker/src/interface_impl.rs @@ -16,7 +16,7 @@ use massa_models::config::{ DEFERRED_CALL_GLOBAL_OVERBOOKING_PENALTY, DEFERRED_CALL_SLOT_OVERBOOKING_PENALTY, }; use massa_models::datastore::get_prefix_bounds; -use massa_models::deferred_call_id::DeferredCallId; +use massa_models::deferred_calls::DeferredCallId; use massa_models::{ address::{Address, SCAddress, UserAddress}, amount::Amount, @@ -1472,7 +1472,7 @@ impl Interface for InterfaceImpl { // write-lock context let call_id = DeferredCallId::from_bytes(id)?; let context = context_guard!(self); - Ok(context.deferred_call_exist(&call_id)) + Ok(context.deferred_call_exists(&call_id)) } /// Cancel a deferred call diff --git a/massa-execution-worker/src/speculative_deferred_calls.rs b/massa-execution-worker/src/speculative_deferred_calls.rs index b058cfe5319..e299965e1d6 100644 --- a/massa-execution-worker/src/speculative_deferred_calls.rs +++ b/massa-execution-worker/src/speculative_deferred_calls.rs @@ -13,7 +13,7 @@ use massa_models::{ DEFERRED_CALL_BASE_FEE_MAX_CHANGE_DENOMINATOR, DEFERRED_CALL_MAX_FUTURE_SLOTS, DEFERRED_CALL_MIN_GAS_COST, DEFERRED_CALL_MIN_GAS_INCREMENT, MAX_ASYNC_GAS, }, - deferred_call_id::DeferredCallId, + deferred_calls::DeferredCallId, slot::Slot, }; use parking_lot::RwLock; diff --git a/massa-execution-worker/src/tests/scenarios_mandatories.rs b/massa-execution-worker/src/tests/scenarios_mandatories.rs index f081f8fcc7b..f078d96ad8f 100644 --- a/massa-execution-worker/src/tests/scenarios_mandatories.rs +++ b/massa-execution-worker/src/tests/scenarios_mandatories.rs @@ -20,7 +20,7 @@ use massa_models::bytecode::Bytecode; use massa_models::config::{ CHAINID, ENDORSEMENT_COUNT, LEDGER_ENTRY_DATASTORE_BASE_SIZE, THREAD_COUNT, }; -use massa_models::deferred_call_id::DeferredCallId; +use massa_models::deferred_calls::DeferredCallId; use massa_models::prehash::PreHashMap; use massa_models::test_exports::gen_endorsements_for_denunciation; use massa_models::{address::Address, amount::Amount, slot::Slot}; diff --git a/massa-models/src/deferred_call_id.rs b/massa-models/src/deferred_calls.rs similarity index 100% rename from massa-models/src/deferred_call_id.rs rename to massa-models/src/deferred_calls.rs diff --git a/massa-models/src/lib.rs b/massa-models/src/lib.rs index 4aede396e25..5b3026725bc 100644 --- a/massa-models/src/lib.rs +++ b/massa-models/src/lib.rs @@ -29,7 +29,7 @@ pub mod config; /// datastore serialization / deserialization pub mod datastore; /// deferred call id -pub mod deferred_call_id; +pub mod deferred_calls; /// denunciation pub mod denunciation; /// endorsements From b53c77f5a554ed9262a5ae3c58bfba20a269158c Mon Sep 17 00:00:00 2001 From: modship Date: Mon, 26 Aug 2024 17:05:06 +0200 Subject: [PATCH 056/100] create DeferredCallsConfig --- Cargo.lock | 1 + massa-deferred-calls/src/call.rs | 14 +++++---- massa-deferred-calls/src/config.rs | 30 ++++++++++++++++++++ massa-deferred-calls/src/lib.rs | 13 ++++----- massa-deferred-calls/src/registry_changes.rs | 16 +++++------ massa-deferred-calls/src/slot_changes.rs | 14 +++++---- massa-deferred-calls/src/tests/mod.rs | 4 +-- massa-final-state/src/config.rs | 3 ++ massa-final-state/src/final_state.rs | 6 +++- massa-final-state/src/state_changes.rs | 18 ++++++------ massa-node/Cargo.toml | 5 ++-- massa-node/src/main.rs | 10 +++++++ 12 files changed, 92 insertions(+), 42 deletions(-) create mode 100644 massa-deferred-calls/src/config.rs diff --git a/Cargo.lock b/Cargo.lock index dfcf7941d11..46c16e1104c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2522,6 +2522,7 @@ dependencies = [ "massa_consensus_worker", "massa_db_exports", "massa_db_worker", + "massa_deferred_calls", "massa_executed_ops", "massa_execution_exports", "massa_execution_worker", diff --git a/massa-deferred-calls/src/call.rs b/massa-deferred-calls/src/call.rs index 4feeef85fe1..92a55c79ced 100644 --- a/massa-deferred-calls/src/call.rs +++ b/massa-deferred-calls/src/call.rs @@ -16,6 +16,8 @@ use nom::{ use serde::{Deserialize, Serialize}; use std::ops::Bound; +use crate::config::DeferredCallsConfig; + /// Definition of a call in the future #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct DeferredCall { @@ -126,20 +128,20 @@ pub struct DeferredCallDeserializer { impl DeferredCallDeserializer { /// Deserializes a `Vec` into an `AsyncCall` - pub fn new(thread_count: u8) -> Self { + pub fn new(config: DeferredCallsConfig) -> Self { Self { slot_deserializer: SlotDeserializer::new( (Bound::Included(0), Bound::Included(u64::MAX)), - (Bound::Included(0), Bound::Excluded(thread_count)), + (Bound::Included(0), Bound::Excluded(config.thread_count)), ), address_deserializer: AddressDeserializer::new(), string_deserializer: StringDeserializer::new(U16VarIntDeserializer::new( Bound::Included(0), - Bound::Included(u16::MAX), + Bound::Included(config.max_function_name_length), )), vec_u8_deserializer: VecU8Deserializer::new( std::ops::Bound::Included(0), - std::ops::Bound::Included(u16::MAX as u64), + std::ops::Bound::Included(config.max_parameter_size as u64), ), amount_deserializer: AmountDeserializer::new( Bound::Included(Amount::MIN), @@ -224,6 +226,7 @@ impl Deserializer for DeferredCallDeserializer { mod tests { use std::str::FromStr; + use massa_models::config::{MAX_PARAMETERS_SIZE, THREAD_COUNT}; use massa_serialization::DeserializeError; use super::*; @@ -242,7 +245,8 @@ mod tests { false, ); let serializer = DeferredCallSerializer::new(); - let deserializer = DeferredCallDeserializer::new(1); + + let deserializer = DeferredCallDeserializer::new(DeferredCallsConfig::default()); let mut buffer = Vec::new(); serializer.serialize(&call, &mut buffer).unwrap(); let (rest, deserialized_call) = deserializer diff --git a/massa-deferred-calls/src/config.rs b/massa-deferred-calls/src/config.rs new file mode 100644 index 00000000000..9df57dbcea0 --- /dev/null +++ b/massa-deferred-calls/src/config.rs @@ -0,0 +1,30 @@ +use massa_models::config::{ + MAX_ASYNC_GAS, MAX_FUNCTION_NAME_LENGTH, MAX_PARAMETERS_SIZE, THREAD_COUNT, +}; + +#[derive(Debug, Clone)] +pub struct DeferredCallsConfig { + /// thread count + pub thread_count: u8, + /// max function name length + pub max_function_name_length: u16, + /// max parameter size + pub max_parameter_size: u32, + + pub max_deferred_calls_pool_changes: u64, + + pub max_gas: u64, +} + +impl Default for DeferredCallsConfig { + fn default() -> Self { + Self { + thread_count: THREAD_COUNT, + max_function_name_length: MAX_FUNCTION_NAME_LENGTH, + max_parameter_size: MAX_PARAMETERS_SIZE, + // TODO: set to a reasonable value + max_deferred_calls_pool_changes: 1000000, + max_gas: MAX_ASYNC_GAS, + } + } +} diff --git a/massa-deferred-calls/src/lib.rs b/massa-deferred-calls/src/lib.rs index b259ef1a807..72780caba8d 100644 --- a/massa-deferred-calls/src/lib.rs +++ b/massa-deferred-calls/src/lib.rs @@ -1,4 +1,5 @@ use call::{DeferredCallDeserializer, DeferredCallSerializer}; +use config::DeferredCallsConfig; use macros::DEFERRED_CALL_TOTAL_GAS; use massa_db_exports::{ DBBatch, ShareableMassaDBController, CRUD_ERROR, DEFERRED_CALLS_PREFIX, @@ -13,6 +14,7 @@ use registry_changes::{ /// This module implements a new version of the Autonomous Smart Contracts. (ASC) /// This new version allow asynchronous calls to be registered for a specific slot and ensure his execution. mod call; +pub mod config; pub mod registry_changes; pub mod slot_changes; @@ -26,7 +28,6 @@ pub use call::DeferredCall; use massa_ledger_exports::{SetOrDelete, SetOrKeep}; use massa_models::{ amount::Amount, - config::{DEFERRED_CALL_MAX_POOL_CHANGES, MAX_ASYNC_GAS, THREAD_COUNT}, deferred_calls::{DeferredCallId, DeferredCallIdDeserializer, DeferredCallIdSerializer}, slot::Slot, }; @@ -53,18 +54,14 @@ impl DeferredCallRegistry { */ // TODO pass args - pub fn new(db: ShareableMassaDBController) -> Self { + pub fn new(db: ShareableMassaDBController, config: DeferredCallsConfig) -> Self { Self { db, call_serializer: DeferredCallSerializer::new(), call_id_serializer: DeferredCallIdSerializer::new(), - call_deserializer: DeferredCallDeserializer::new(THREAD_COUNT), + call_deserializer: DeferredCallDeserializer::new(config.clone()), call_id_deserializer: DeferredCallIdDeserializer::new(), - registry_changes_deserializer: DeferredRegistryChangesDeserializer::new( - THREAD_COUNT, - MAX_ASYNC_GAS, - DEFERRED_CALL_MAX_POOL_CHANGES, - ), + registry_changes_deserializer: DeferredRegistryChangesDeserializer::new(config), registry_changes_serializer: DeferredRegistryChangesSerializer::new(), } } diff --git a/massa-deferred-calls/src/registry_changes.rs b/massa-deferred-calls/src/registry_changes.rs index 703811bff58..0998a599b35 100644 --- a/massa-deferred-calls/src/registry_changes.rs +++ b/massa-deferred-calls/src/registry_changes.rs @@ -19,6 +19,7 @@ use nom::{ use serde::{Deserialize, Serialize}; use crate::{ + config::DeferredCallsConfig, slot_changes::{ DeferredRegistrySlotChanges, DeferredRegistrySlotChangesDeserializer, DeferredRegistrySlotChangesSerializer, @@ -144,20 +145,16 @@ pub struct DeferredRegistryChangesDeserializer { } impl DeferredRegistryChangesDeserializer { - pub fn new(thread_count: u8, max_gas: u64, max_deferred_calls_pool_changes: u64) -> Self { + pub fn new(config: DeferredCallsConfig) -> Self { Self { slots_length: U64VarIntDeserializer::new( Included(u64::MIN), - Included(max_deferred_calls_pool_changes), - ), - slot_changes_deserializer: DeferredRegistrySlotChangesDeserializer::new( - thread_count, - max_gas, - max_deferred_calls_pool_changes, + Included(config.max_deferred_calls_pool_changes), ), + slot_changes_deserializer: DeferredRegistrySlotChangesDeserializer::new(config.clone()), slot_deserializer: SlotDeserializer::new( (Bound::Included(0), Bound::Included(u64::MAX)), - (Bound::Included(0), Bound::Excluded(thread_count)), + (Bound::Included(0), Bound::Excluded(config.thread_count)), ), total_gas_deserializer: SetOrKeepDeserializer::new(U128VarIntDeserializer::new( Included(u128::MIN), @@ -212,6 +209,7 @@ mod tests { use massa_serialization::DeserializeError; use crate::{ + config::DeferredCallsConfig, registry_changes::{ DeferredRegistryChangesDeserializer, DeferredRegistryChangesSerializer, }, @@ -272,7 +270,7 @@ mod tests { let serializer = DeferredRegistryChangesSerializer::new(); serializer.serialize(&changes, &mut buffer).unwrap(); - let deserializer = DeferredRegistryChangesDeserializer::new(32, 300_000, 10_000); + let deserializer = DeferredRegistryChangesDeserializer::new(DeferredCallsConfig::default()); let (rest, deserialized) = deserializer .deserialize::(&buffer) .unwrap(); diff --git a/massa-deferred-calls/src/slot_changes.rs b/massa-deferred-calls/src/slot_changes.rs index 294b0762f54..9b330471d7f 100644 --- a/massa-deferred-calls/src/slot_changes.rs +++ b/massa-deferred-calls/src/slot_changes.rs @@ -2,6 +2,7 @@ use std::collections::BTreeMap; use crate::{ call::{DeferredCallDeserializer, DeferredCallSerializer}, + config::DeferredCallsConfig, DeferredCall, DeferredRegistryBaseFeeChange, DeferredRegistryCallChange, DeferredRegistryGasChange, }; @@ -140,19 +141,19 @@ pub struct DeferredRegistrySlotChangesDeserializer { } impl DeferredRegistrySlotChangesDeserializer { - pub fn new(thread_count: u8, max_gas: u64, max_deferred_calls_pool_changes: u64) -> Self { + pub fn new(config: DeferredCallsConfig) -> Self { Self { deferred_registry_slot_changes_length: U64VarIntDeserializer::new( Included(u64::MIN), - Included(max_deferred_calls_pool_changes), + Included(config.max_deferred_calls_pool_changes), ), call_id_deserializer: DeferredCallIdDeserializer::new(), calls_set_or_delete_deserializer: SetOrDeleteDeserializer::new( - DeferredCallDeserializer::new(thread_count), + DeferredCallDeserializer::new(config.clone()), ), gas_deserializer: SetOrKeepDeserializer::new(U64VarIntDeserializer::new( Included(0), - Included(max_gas), + Included(config.max_gas), )), base_fee_deserializer: SetOrKeepDeserializer::new(AmountDeserializer::new( Included(Amount::MIN), @@ -217,7 +218,7 @@ mod tests { }; use massa_serialization::{DeserializeError, Deserializer, Serializer}; - use crate::DeferredCall; + use crate::{config::DeferredCallsConfig, DeferredCall}; use super::{ DeferredRegistrySlotChanges, DeferredRegistrySlotChangesDeserializer, @@ -264,7 +265,8 @@ mod tests { .serialize(®istry_slot_changes, &mut buffer) .unwrap(); - let deserializer = DeferredRegistrySlotChangesDeserializer::new(32, 3000000, 100_000); + let deserializer = + DeferredRegistrySlotChangesDeserializer::new(DeferredCallsConfig::default()); let (rest, changes_deser) = deserializer .deserialize::(&buffer) .unwrap(); diff --git a/massa-deferred-calls/src/tests/mod.rs b/massa-deferred-calls/src/tests/mod.rs index d89ee1054c7..216aa29a7a8 100644 --- a/massa-deferred-calls/src/tests/mod.rs +++ b/massa-deferred-calls/src/tests/mod.rs @@ -29,7 +29,7 @@ fn call_registry_apply_changes() { Box::new(MassaDB::new(db_config)) as Box<(dyn MassaDBController + 'static)> )); - let registry = DeferredCallRegistry::new(db); + let registry = DeferredCallRegistry::new(db, DeferredCallsConfig::default()); let mut changes = DeferredCallRegistryChanges::default(); @@ -81,7 +81,7 @@ fn call_registry_get_slot_calls() { Box::new(MassaDB::new(db_config)) as Box<(dyn MassaDBController + 'static)> )); - let registry = DeferredCallRegistry::new(db); + let registry = DeferredCallRegistry::new(db, DeferredCallsConfig::default()); let mut changes = DeferredCallRegistryChanges::default(); diff --git a/massa-final-state/src/config.rs b/massa-final-state/src/config.rs index 49396734a91..0895734a439 100644 --- a/massa-final-state/src/config.rs +++ b/massa-final-state/src/config.rs @@ -3,6 +3,7 @@ //! This file defines a configuration structure containing all settings for final state management use massa_async_pool::AsyncPoolConfig; +use massa_deferred_calls::config::DeferredCallsConfig; use massa_executed_ops::{ExecutedDenunciationsConfig, ExecutedOpsConfig}; use massa_ledger_exports::LedgerConfig; use massa_pos_exports::PoSConfig; @@ -16,6 +17,8 @@ pub struct FinalStateConfig { pub ledger_config: LedgerConfig, /// asynchronous pool configuration pub async_pool_config: AsyncPoolConfig, + /// config for deferred calls + pub deferred_calls_config: DeferredCallsConfig, /// proof-of-stake configuration pub pos_config: PoSConfig, /// executed operations configuration diff --git a/massa-final-state/src/final_state.rs b/massa-final-state/src/final_state.rs index d05ad396024..ff37de7ac3e 100644 --- a/massa-final-state/src/final_state.rs +++ b/massa-final-state/src/final_state.rs @@ -109,7 +109,8 @@ impl FinalState { let executed_denunciations = ExecutedDenunciations::new(config.executed_denunciations_config.clone(), db.clone()); - let deferred_call_registry = DeferredCallRegistry::new(db.clone()); + let deferred_call_registry = + DeferredCallRegistry::new(db.clone(), config.deferred_calls_config.clone()); let mut final_state = FinalState { ledger, @@ -939,6 +940,7 @@ mod test { use std::str::FromStr; use std::sync::Arc; + use massa_deferred_calls::config::DeferredCallsConfig; use num::rational::Ratio; use parking_lot::RwLock; use tempfile::tempdir; @@ -1008,9 +1010,11 @@ mod test { keep_executed_history_extra_periods: KEEP_EXECUTED_HISTORY_EXTRA_PERIODS, }; + let deferred_calls_config = DeferredCallsConfig::default(); let final_state_config = FinalStateConfig { ledger_config: ledger_config.clone(), async_pool_config, + deferred_calls_config, pos_config, executed_ops_config, executed_denunciations_config, diff --git a/massa-final-state/src/state_changes.rs b/massa-final-state/src/state_changes.rs index 9de90ab9cf8..a755172b134 100644 --- a/massa-final-state/src/state_changes.rs +++ b/massa-final-state/src/state_changes.rs @@ -5,9 +5,12 @@ use massa_async_pool::{ AsyncPoolChanges, AsyncPoolChangesDeserializer, AsyncPoolChangesSerializer, }; -use massa_deferred_calls::registry_changes::{ - DeferredCallRegistryChanges, DeferredRegistryChangesDeserializer, - DeferredRegistryChangesSerializer, +use massa_deferred_calls::{ + config::DeferredCallsConfig, + registry_changes::{ + DeferredCallRegistryChanges, DeferredRegistryChangesDeserializer, + DeferredRegistryChangesSerializer, + }, }; use massa_executed_ops::{ ExecutedDenunciationsChanges, ExecutedDenunciationsChangesDeserializer, @@ -129,7 +132,7 @@ impl StateChangesDeserializer { max_ops_changes_length: u64, endorsement_count: u32, max_de_changes_length: u64, - max_deferred_call_pool_changes: u64, + deferred_calls_config: DeferredCallsConfig, ) -> Self { Self { ledger_changes_deserializer: LedgerChangesDeserializer::new( @@ -147,9 +150,7 @@ impl StateChangesDeserializer { ), // todo max gas deferred_call_changes_deserializer: DeferredRegistryChangesDeserializer::new( - thread_count, - u64::MAX, - max_deferred_call_pool_changes, + deferred_calls_config, ), pos_changes_deserializer: PoSChangesDeserializer::new( thread_count, @@ -251,6 +252,7 @@ mod test { use std::str::FromStr; use massa_async_pool::AsyncMessage; + use massa_deferred_calls::config::DeferredCallsConfig; use massa_ledger_exports::{LedgerEntryUpdate, SetUpdateOrDelete}; use massa_models::amount::Amount; use massa_models::bytecode::Bytecode; @@ -340,7 +342,7 @@ mod test { MAX_EXECUTED_OPS_CHANGES_LENGTH, ENDORSEMENT_COUNT, MAX_DENUNCIATION_CHANGES_LENGTH, - DEFERRED_CALL_MAX_POOL_CHANGES, + DeferredCallsConfig::default(), ) .deserialize::(&serialized) .unwrap(); diff --git a/massa-node/Cargo.toml b/massa-node/Cargo.toml index 82cbd2741e4..3d7a977f8b5 100644 --- a/massa-node/Cargo.toml +++ b/massa-node/Cargo.toml @@ -35,9 +35,7 @@ dump-block = [ ] db_storage_backend = [] file_storage_backend = [] -execution-info = [ - "execution-trace" -] +execution-info = ["execution-trace"] [dependencies] crossbeam-channel = { workspace = true } # BOM UPGRADE Revert to "0.5.6" if problem @@ -64,6 +62,7 @@ massa_bootstrap = { workspace = true } massa_channel = { workspace = true } massa_consensus_exports = { workspace = true } massa_consensus_worker = { workspace = true } +massa_deferred_calls = { workspace = true } massa_executed_ops = { workspace = true } massa_execution_exports = { workspace = true } massa_execution_worker = { workspace = true } diff --git a/massa-node/src/main.rs b/massa-node/src/main.rs index 31d66a1753f..6d0051a03fd 100644 --- a/massa-node/src/main.rs +++ b/massa-node/src/main.rs @@ -31,6 +31,7 @@ use massa_consensus_exports::{ use massa_consensus_worker::start_consensus_worker; use massa_db_exports::{MassaDBConfig, MassaDBController}; use massa_db_worker::MassaDB; +use massa_deferred_calls::config::DeferredCallsConfig; use massa_executed_ops::{ExecutedDenunciationsConfig, ExecutedOpsConfig}; use massa_execution_exports::{ ExecutionChannels, ExecutionConfig, ExecutionManager, GasCosts, StorageCostsConstants, @@ -190,9 +191,18 @@ async fn launch( endorsement_count: ENDORSEMENT_COUNT, keep_executed_history_extra_periods: KEEP_EXECUTED_HISTORY_EXTRA_PERIODS, }; + let deferred_calls_config = DeferredCallsConfig { + thread_count: THREAD_COUNT, + max_function_name_length: MAX_FUNCTION_NAME_LENGTH, + max_parameter_size: MAX_PARAMETERS_SIZE, + // TODO: set to a reasonable value + max_deferred_calls_pool_changes: 1000000, + max_gas: MAX_ASYNC_GAS, + }; let final_state_config = FinalStateConfig { ledger_config: ledger_config.clone(), async_pool_config, + deferred_calls_config, pos_config, executed_ops_config, executed_denunciations_config, From 91ac5e3ad43c8bffd8a56166a1fc3a64be6066db Mon Sep 17 00:00:00 2001 From: modship Date: Tue, 27 Aug 2024 11:40:29 +0200 Subject: [PATCH 057/100] use config struct --- Cargo.lock | 1 + massa-deferred-calls/src/call.rs | 1 - massa-deferred-calls/src/config.rs | 37 ++++++-- massa-deferred-calls/src/registry_changes.rs | 2 +- massa-deferred-calls/src/slot_changes.rs | 2 +- massa-execution-exports/Cargo.toml | 39 +++++---- massa-execution-exports/src/settings.rs | 5 +- .../src/test_exports/config.rs | 3 +- massa-execution-worker/src/context.rs | 33 ++----- massa-execution-worker/src/execution.rs | 7 +- massa-execution-worker/src/interface_impl.rs | 14 +-- .../src/speculative_deferred_calls.rs | 85 ++++++------------- massa-final-state/src/state_changes.rs | 2 +- massa-final-state/src/test_exports/config.rs | 7 +- massa-models/src/config/constants.rs | 3 + massa-models/src/deferred_calls.rs | 3 +- massa-node/src/main.rs | 20 +++-- 17 files changed, 119 insertions(+), 145 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 46c16e1104c..eaf070eed2a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2870,6 +2870,7 @@ dependencies = [ "displaydoc", "massa-proto-rs", "massa-sc-runtime", + "massa_deferred_calls", "massa_final_state", "massa_hash", "massa_models", diff --git a/massa-deferred-calls/src/call.rs b/massa-deferred-calls/src/call.rs index 92a55c79ced..b22a79ab2d7 100644 --- a/massa-deferred-calls/src/call.rs +++ b/massa-deferred-calls/src/call.rs @@ -226,7 +226,6 @@ impl Deserializer for DeferredCallDeserializer { mod tests { use std::str::FromStr; - use massa_models::config::{MAX_PARAMETERS_SIZE, THREAD_COUNT}; use massa_serialization::DeserializeError; use super::*; diff --git a/massa-deferred-calls/src/config.rs b/massa-deferred-calls/src/config.rs index 9df57dbcea0..3eb3a1d5df9 100644 --- a/massa-deferred-calls/src/config.rs +++ b/massa-deferred-calls/src/config.rs @@ -1,5 +1,12 @@ -use massa_models::config::{ - MAX_ASYNC_GAS, MAX_FUNCTION_NAME_LENGTH, MAX_PARAMETERS_SIZE, THREAD_COUNT, +use massa_models::{ + amount::Amount, + config::{ + DEFERRED_CALL_BASE_FEE_MAX_CHANGE_DENOMINATOR, 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, + }, }; #[derive(Debug, Clone)] @@ -8,10 +15,23 @@ pub struct DeferredCallsConfig { pub thread_count: u8, /// max function name length pub max_function_name_length: u16, + /// Maximum size of deferred call future slots (1 week) + pub max_future_slots: u64, + /// base fee max max change denominator + pub base_fee_max_max_change_denominator: usize, + /// min gas increment (1 nanomassa) + pub min_gas_increment: u64, + /// min gas cost (10 nanomassa) + pub min_gas_cost: u64, + /// global overbooking penalty + pub global_overbooking_penalty: Amount, + /// slot overbooking penalty + pub slot_overbooking_penalty: Amount, + /// max parameter size pub max_parameter_size: u32, - pub max_deferred_calls_pool_changes: u64, + pub max_pool_changes: u64, pub max_gas: u64, } @@ -21,10 +41,15 @@ impl Default for DeferredCallsConfig { Self { thread_count: THREAD_COUNT, max_function_name_length: MAX_FUNCTION_NAME_LENGTH, + max_future_slots: DEFERRED_CALL_MAX_FUTURE_SLOTS, max_parameter_size: MAX_PARAMETERS_SIZE, - // TODO: set to a reasonable value - max_deferred_calls_pool_changes: 1000000, - max_gas: MAX_ASYNC_GAS, + max_pool_changes: DEFERRED_CALL_MAX_POOL_CHANGES, + max_gas: DEFERRED_CALL_MAX_ASYNC_GAS, + base_fee_max_max_change_denominator: DEFERRED_CALL_BASE_FEE_MAX_CHANGE_DENOMINATOR, + min_gas_increment: DEFERRED_CALL_MIN_GAS_INCREMENT, + min_gas_cost: DEFERRED_CALL_MIN_GAS_COST, + global_overbooking_penalty: DEFERRED_CALL_GLOBAL_OVERBOOKING_PENALTY, + slot_overbooking_penalty: DEFERRED_CALL_SLOT_OVERBOOKING_PENALTY, } } } diff --git a/massa-deferred-calls/src/registry_changes.rs b/massa-deferred-calls/src/registry_changes.rs index 0998a599b35..e16a7f8ab98 100644 --- a/massa-deferred-calls/src/registry_changes.rs +++ b/massa-deferred-calls/src/registry_changes.rs @@ -149,7 +149,7 @@ impl DeferredRegistryChangesDeserializer { Self { slots_length: U64VarIntDeserializer::new( Included(u64::MIN), - Included(config.max_deferred_calls_pool_changes), + Included(config.max_pool_changes), ), slot_changes_deserializer: DeferredRegistrySlotChangesDeserializer::new(config.clone()), slot_deserializer: SlotDeserializer::new( diff --git a/massa-deferred-calls/src/slot_changes.rs b/massa-deferred-calls/src/slot_changes.rs index 9b330471d7f..ff5f8925dd4 100644 --- a/massa-deferred-calls/src/slot_changes.rs +++ b/massa-deferred-calls/src/slot_changes.rs @@ -145,7 +145,7 @@ impl DeferredRegistrySlotChangesDeserializer { Self { deferred_registry_slot_changes_length: U64VarIntDeserializer::new( Included(u64::MIN), - Included(config.max_deferred_calls_pool_changes), + Included(config.max_pool_changes), ), call_id_deserializer: DeferredCallIdDeserializer::new(), calls_set_or_delete_deserializer: SetOrDeleteDeserializer::new( diff --git a/massa-execution-exports/Cargo.toml b/massa-execution-exports/Cargo.toml index f4c9184245a..f9a70616c10 100644 --- a/massa-execution-exports/Cargo.toml +++ b/massa-execution-exports/Cargo.toml @@ -12,23 +12,26 @@ dump-block = [] execution-info = ["execution-trace"] [dependencies] -displaydoc = {workspace = true} -thiserror = {workspace = true} -num = {workspace = true, "features" = ["serde"]} # BOM UPGRADE Revert to {"version": "0.4", "features": ["serde"]} if problem -tempfile = {workspace = true, "optional" = true} # BOM UPGRADE Revert to {"version": "3.3", "optional": true} if problem -tokio = {workspace = true, "features" = ["sync"]} -mockall = {workspace = true, "optional" = true} # BOM UPGRADE Revert to {"version": "0.11.4", "optional": true} if problem -massa-proto-rs = {workspace = true, "features" = ["tonic"]} -massa_hash = {workspace = true} -massa_models = {workspace = true} -massa_time = {workspace = true} -massa_storage = {workspace = true} -massa_final_state = {workspace = true} -massa_pos_exports = {workspace = true} -massa_module_cache = {workspace = true} -massa_versioning = {workspace = true} -massa-sc-runtime = {workspace = true} -serde = {workspace = true, "features" = ["derive"]} +displaydoc = { workspace = true } +thiserror = { workspace = true } +num = { workspace = true, "features" = [ + "serde", +] } # BOM UPGRADE Revert to {"version": "0.4", "features": ["serde"]} if problem +tempfile = { workspace = true, "optional" = true } # BOM UPGRADE Revert to {"version": "3.3", "optional": true} if problem +tokio = { workspace = true, "features" = ["sync"] } +mockall = { workspace = true, "optional" = true } # BOM UPGRADE Revert to {"version": "0.11.4", "optional": true} if problem +massa_deferred_calls = { workspace = true } +massa-proto-rs = { workspace = true, "features" = ["tonic"] } +massa_hash = { workspace = true } +massa_models = { workspace = true } +massa_time = { workspace = true } +massa_storage = { workspace = true } +massa_final_state = { workspace = true } +massa_pos_exports = { workspace = true } +massa_module_cache = { workspace = true } +massa_versioning = { workspace = true } +massa-sc-runtime = { workspace = true } +serde = { workspace = true, "features" = ["derive"] } [dev-dependencies] -mockall = {workspace = true} +mockall = { workspace = true } diff --git a/massa-execution-exports/src/settings.rs b/massa-execution-exports/src/settings.rs index a9be4b66868..994cc8acc8b 100644 --- a/massa-execution-exports/src/settings.rs +++ b/massa-execution-exports/src/settings.rs @@ -2,6 +2,7 @@ //! This module provides the structures used to provide configuration parameters to the Execution system +use massa_deferred_calls::config::DeferredCallsConfig; use massa_models::amount::Amount; use massa_sc_runtime::GasCosts; use massa_time::MassaTime; @@ -102,6 +103,6 @@ pub struct ExecutionConfig { pub max_execution_traces_slot_limit: usize, /// Where to dump blocks pub block_dump_folder_path: PathBuf, - /// Max deferred call future slot - pub max_deferred_call_future_slots: u64, + /// deferred calls config + pub deferred_calls_config: DeferredCallsConfig, } diff --git a/massa-execution-exports/src/test_exports/config.rs b/massa-execution-exports/src/test_exports/config.rs index c6f8f749893..e5a3e91ce7e 100644 --- a/massa-execution-exports/src/test_exports/config.rs +++ b/massa-execution-exports/src/test_exports/config.rs @@ -3,6 +3,7 @@ //! This file defines testing tools related to the configuration use crate::{ExecutionConfig, StorageCostsConstants}; +use massa_deferred_calls::config::DeferredCallsConfig; use massa_models::config::*; use massa_sc_runtime::GasCosts; use massa_time::MassaTime; @@ -81,7 +82,7 @@ impl Default for ExecutionConfig { broadcast_slot_execution_traces_channel_capacity: 5000, max_execution_traces_slot_limit: 320, block_dump_folder_path, - max_deferred_call_future_slots: DEFERRED_CALL_MAX_FUTURE_SLOTS, + deferred_calls_config: DeferredCallsConfig::default(), } } } diff --git a/massa-execution-worker/src/context.rs b/massa-execution-worker/src/context.rs index 34efa720299..cd964b59783 100644 --- a/massa-execution-worker/src/context.rs +++ b/massa-execution-worker/src/context.rs @@ -227,6 +227,7 @@ impl ExecutionContext { speculative_deferred_calls: SpeculativeDeferredCallRegistry::new( final_state.clone(), active_history.clone(), + config.deferred_calls_config.clone(), ), speculative_roll_state: SpeculativeRollState::new( final_state.clone(), @@ -1135,41 +1136,19 @@ impl ExecutionContext { } } - pub fn deferred_calls_advance_slot( - &mut self, - current_slot: Slot, - async_call_max_booking_slots: u64, - thread_count: u8, - ) -> DeferredSlotCalls { - self.speculative_deferred_calls.advance_slot( - current_slot, - async_call_max_booking_slots, - thread_count, - ) + pub fn deferred_calls_advance_slot(&mut self, current_slot: Slot) -> DeferredSlotCalls { + self.speculative_deferred_calls.advance_slot(current_slot) } /// Get the price it would cost to reserve "gas" at target slot "slot". pub fn deferred_calls_compute_call_fee( &self, target_slot: Slot, - max_gas: u64, - thread_count: u8, - async_call_max_booking_slots: u64, - max_async_gas: u64, - global_overbooking_penalty: Amount, - slot_overbooking_penalty: Amount, + max_gas_request: u64, current_slot: Slot, ) -> Result { - self.speculative_deferred_calls.compute_call_fee( - target_slot, - max_gas, - thread_count, - async_call_max_booking_slots, - max_async_gas, - global_overbooking_penalty, - slot_overbooking_penalty, - current_slot, - ) + self.speculative_deferred_calls + .compute_call_fee(target_slot, max_gas_request, current_slot) } pub fn deferred_call_register( diff --git a/massa-execution-worker/src/execution.rs b/massa-execution-worker/src/execution.rs index d23ef84c0b4..d8ab4ec151b 100644 --- a/massa-execution-worker/src/execution.rs +++ b/massa-execution-worker/src/execution.rs @@ -28,7 +28,6 @@ use massa_metrics::MassaMetrics; use massa_models::address::ExecutionAddressCycleInfo; use massa_models::bytecode::Bytecode; -use massa_models::config::DEFERRED_CALL_MAX_FUTURE_SLOTS; use massa_models::datastore::get_prefix_bounds; use massa_models::deferred_calls::DeferredCallId; use massa_models::denunciation::{Denunciation, DenunciationIndex}; @@ -1384,11 +1383,7 @@ impl ExecutionState { ); // Deferred calls - let calls = execution_context.deferred_calls_advance_slot( - slot.clone(), - DEFERRED_CALL_MAX_FUTURE_SLOTS, - self.config.thread_count, - ); + let calls = execution_context.deferred_calls_advance_slot(slot.clone()); // Apply the created execution context for slot execution *context_guard!(self) = execution_context; diff --git a/massa-execution-worker/src/interface_impl.rs b/massa-execution-worker/src/interface_impl.rs index 1bf5791628f..ac4ac9e1393 100644 --- a/massa-execution-worker/src/interface_impl.rs +++ b/massa-execution-worker/src/interface_impl.rs @@ -12,9 +12,6 @@ use massa_deferred_calls::DeferredCall; use massa_execution_exports::ExecutionConfig; use massa_execution_exports::ExecutionStackElement; use massa_models::bytecode::Bytecode; -use massa_models::config::{ - DEFERRED_CALL_GLOBAL_OVERBOOKING_PENALTY, DEFERRED_CALL_SLOT_OVERBOOKING_PENALTY, -}; use massa_models::datastore::get_prefix_bounds; use massa_models::deferred_calls::DeferredCallId; use massa_models::{ @@ -1352,16 +1349,7 @@ impl Interface for InterfaceImpl { let target_slot = Slot::new(target_slot.0, target_slot.1); - match context.deferred_calls_compute_call_fee( - target_slot, - gas_limit, - self.config.thread_count, - self.config.max_deferred_call_future_slots, - self.config.max_async_gas, - DEFERRED_CALL_GLOBAL_OVERBOOKING_PENALTY, - DEFERRED_CALL_SLOT_OVERBOOKING_PENALTY, - current_slot, - ) { + match context.deferred_calls_compute_call_fee(target_slot, gas_limit, current_slot) { Ok(fee) => Ok((true, fee.to_raw())), Err(_) => Ok((false, 0)), } diff --git a/massa-execution-worker/src/speculative_deferred_calls.rs b/massa-execution-worker/src/speculative_deferred_calls.rs index e299965e1d6..4bc5254c1a8 100644 --- a/massa-execution-worker/src/speculative_deferred_calls.rs +++ b/massa-execution-worker/src/speculative_deferred_calls.rs @@ -2,18 +2,13 @@ use crate::active_history::ActiveHistory; use massa_deferred_calls::{ - registry_changes::DeferredCallRegistryChanges, DeferredCall, DeferredSlotCalls, + config::DeferredCallsConfig, registry_changes::DeferredCallRegistryChanges, DeferredCall, + DeferredSlotCalls, }; use massa_execution_exports::ExecutionError; use massa_final_state::FinalStateController; use massa_models::{ - address::Address, - amount::Amount, - config::{ - DEFERRED_CALL_BASE_FEE_MAX_CHANGE_DENOMINATOR, DEFERRED_CALL_MAX_FUTURE_SLOTS, - DEFERRED_CALL_MIN_GAS_COST, DEFERRED_CALL_MIN_GAS_INCREMENT, MAX_ASYNC_GAS, - }, - deferred_calls::DeferredCallId, + address::Address, amount::Amount, config::MAX_ASYNC_GAS, deferred_calls::DeferredCallId, slot::Slot, }; use parking_lot::RwLock; @@ -26,6 +21,7 @@ pub(crate) struct SpeculativeDeferredCallRegistry { active_history: Arc>, // current speculative registry changes deferred_calls_changes: DeferredCallRegistryChanges, + config: DeferredCallsConfig, } impl SpeculativeDeferredCallRegistry { @@ -35,11 +31,13 @@ impl SpeculativeDeferredCallRegistry { pub fn new( final_state: Arc>, active_history: Arc>, + config: DeferredCallsConfig, ) -> Self { SpeculativeDeferredCallRegistry { final_state, active_history, deferred_calls_changes: Default::default(), + config, } } @@ -135,7 +133,6 @@ impl SpeculativeDeferredCallRegistry { } // check in final state - // TODO check if that is correct return self .final_state .read() @@ -145,12 +142,7 @@ impl SpeculativeDeferredCallRegistry { /// Consumes and deletes the current slot, prepares a new slot in the future /// and returns the calls that need to be executed in the current slot - pub fn advance_slot( - &mut self, - current_slot: Slot, - async_call_max_booking_slots: u64, - thread_count: u8, - ) -> DeferredSlotCalls { + pub fn advance_slot(&mut self, current_slot: Slot) -> DeferredSlotCalls { // get the state of the current slot let mut slot_calls: DeferredSlotCalls = self .final_state @@ -162,35 +154,15 @@ impl SpeculativeDeferredCallRegistry { } slot_calls.apply_changes(&self.deferred_calls_changes); - // const BASE_FEE_MAX_CHANGE_DENOMINATOR = 8; - // const MIN_GAS_INCREMENT = 1 nano-massa; - // const MIN_GAS_COST = 10 nano-massa - - // let TARGET_BOOKING = MAX_ASYNC_GAS/2; - // let total_booked_gas = get_current_total_booked_async_gas(); - // let avg_booked_gas = total_booked_gas/ASYNC_BOOKING_SLOT_COUNT; - - // if (avg_booked_gas == TARGET_BOOKING) { - // S.base_fee_per_gas = (S-1).base_async_gas_cost; - // } else if (avg_booked_gas > TARGET_BOOKING) { - // gas_used_delta = avg_booked_gas - TARGET_BOOKING; - // S.base_fee_per_gas = (S-1).base_async_gas_cost + ((S-1).base_async_gas_cost * gas_used_delta / TARGET_BOOKING / BASE_FEE_MAX_CHANGE_DENOMINATOR, MIN_GAS_INCREMENT) - // } else { - // gas_used_delta = TARGET_BOOKING - total_booked_gas - // S.base_fee_per_gas = max((S-1).base_async_gas_cost - (S-1).base_async_gas_cost * gas_used_delta / TARGET_BOOKING / BASE_FEE_MAX_CHANGE_DENOMINATOR, MIN_GAS_COST) - // } - let total_booked_gas = self.get_total_gas(); - let avg_booked_gas = - total_booked_gas.saturating_div(DEFERRED_CALL_MAX_FUTURE_SLOTS as u128); - + let avg_booked_gas = total_booked_gas.saturating_div(self.config.max_future_slots as u128); // select the slot that is newly made available and set its base fee let new_slot = current_slot - .skip(async_call_max_booking_slots, thread_count) + .skip(self.config.max_future_slots, self.config.thread_count) .expect("could not skip enough slots"); let prev_slot = new_slot - .get_prev_slot(thread_count) + .get_prev_slot(self.config.thread_count) .expect("cannot get prev slot"); let prev_slot_base_fee = self.get_slot_base_fee(&prev_slot); @@ -202,12 +174,12 @@ impl SpeculativeDeferredCallRegistry { let factor = gas_used_delta as u64 / TARGET_BOOKING as u64 - / DEFERRED_CALL_BASE_FEE_MAX_CHANGE_DENOMINATOR as u64; + / self.config.base_fee_max_max_change_denominator as u64; max( prev_slot_base_fee .saturating_add(prev_slot_base_fee.saturating_mul_u64(factor)), - Amount::from_raw(DEFERRED_CALL_MIN_GAS_INCREMENT), + Amount::from_raw(self.config.min_gas_increment), ) } std::cmp::Ordering::Less => { @@ -215,12 +187,12 @@ impl SpeculativeDeferredCallRegistry { let factor = gas_used_delta as u64 / TARGET_BOOKING as u64 - / DEFERRED_CALL_BASE_FEE_MAX_CHANGE_DENOMINATOR as u64; + / self.config.base_fee_max_max_change_denominator as u64; max( prev_slot_base_fee .saturating_sub(prev_slot_base_fee.saturating_mul_u64(factor)), - Amount::from_raw(DEFERRED_CALL_MIN_GAS_COST), + Amount::from_raw(self.config.min_gas_cost), ) } }; @@ -386,12 +358,7 @@ impl SpeculativeDeferredCallRegistry { pub fn compute_call_fee( &self, target_slot: Slot, - max_gas: u64, - thread_count: u8, - async_call_max_booking_slots: u64, - max_async_gas: u64, - global_overbooking_penalty: Amount, - slot_overbooking_penalty: Amount, + max_gas_request: u64, current_slot: Slot, ) -> Result { // Check that the slot is not in the past @@ -403,9 +370,9 @@ impl SpeculativeDeferredCallRegistry { // Check that the slot is not in the future if target_slot - .slots_since(¤t_slot, thread_count) + .slots_since(¤t_slot, self.config.thread_count) .unwrap_or(u64::MAX) - > async_call_max_booking_slots + > self.config.max_future_slots { // note: the current slot is not counted return Err(ExecutionError::DeferredCallsError( @@ -415,7 +382,7 @@ impl SpeculativeDeferredCallRegistry { // Check that the gas is not too high for the target slot let slot_occupancy = self.get_slot_gas(&target_slot); - if slot_occupancy.saturating_add(max_gas) > max_async_gas { + if slot_occupancy.saturating_add(max_gas_request) > self.config.max_gas { return Err(ExecutionError::DeferredCallsError( "Not enough gas available in the target slot.".into(), )); @@ -431,7 +398,7 @@ impl SpeculativeDeferredCallRegistry { // Integral fee let integral_fee = self .get_slot_base_fee(&target_slot) - .saturating_mul_u64(max_gas); + .saturating_mul_u64(max_gas_request); // The integral fee is not enough to respond to quick demand surges within the long booking period `deferred_call_max_future_slots`. Proportional regulation is also necessary. @@ -444,21 +411,21 @@ impl SpeculativeDeferredCallRegistry { .get_total_gas() .unwrap_or_default(); let global_overbooking_fee = Self::overbooking_fee( - (max_async_gas as u128).saturating_mul(async_call_max_booking_slots as u128), - (async_call_max_booking_slots as u128).saturating_mul(TARGET_BOOKING) as u128, + (self.config.max_gas as u128).saturating_mul(self.config.max_future_slots as u128), + (self.config.max_future_slots as u128).saturating_mul(TARGET_BOOKING), global_occupancy, - max_gas as u128, - global_overbooking_penalty, // total_supply + max_gas_request as u128, + self.config.global_overbooking_penalty, // total_supply )?; // Finally, a per-slot proportional fee is also added to prevent attackers from denying significant ranges of consecutive slots within the long booking period. // Slot overbooking fee let slot_overbooking_fee = Self::overbooking_fee( - max_async_gas as u128, + self.config.max_gas as u128, TARGET_BOOKING, slot_occupancy as u128, - max_gas as u128, - slot_overbooking_penalty, // total_initial_coin_supply/10000 + max_gas_request as u128, + self.config.slot_overbooking_penalty, // total_initial_coin_supply/10000 )?; // return the fee diff --git a/massa-final-state/src/state_changes.rs b/massa-final-state/src/state_changes.rs index a755172b134..07b66b248d6 100644 --- a/massa-final-state/src/state_changes.rs +++ b/massa-final-state/src/state_changes.rs @@ -254,10 +254,10 @@ mod test { use massa_async_pool::AsyncMessage; use massa_deferred_calls::config::DeferredCallsConfig; use massa_ledger_exports::{LedgerEntryUpdate, SetUpdateOrDelete}; + use massa_models::address::Address; use massa_models::amount::Amount; use massa_models::bytecode::Bytecode; use massa_models::slot::Slot; - use massa_models::{address::Address, config::DEFERRED_CALL_MAX_POOL_CHANGES}; use massa_serialization::DeserializeError; use massa_models::config::{ diff --git a/massa-final-state/src/test_exports/config.rs b/massa-final-state/src/test_exports/config.rs index fdcaa96a795..068db07a3ad 100644 --- a/massa-final-state/src/test_exports/config.rs +++ b/massa-final-state/src/test_exports/config.rs @@ -4,6 +4,7 @@ use std::path::PathBuf; +use massa_deferred_calls::config::DeferredCallsConfig; use num::rational::Ratio; use crate::{FinalState, FinalStateConfig}; @@ -35,7 +36,10 @@ impl FinalState { FinalState { ledger: Box::new(FinalLedger::new(config.ledger_config.clone(), db.clone())), async_pool: AsyncPool::new(config.async_pool_config.clone(), db.clone()), - deferred_call_registry: DeferredCallRegistry::new(db.clone()), + deferred_call_registry: DeferredCallRegistry::new( + db.clone(), + config.deferred_calls_config, + ), pos_state, executed_ops: ExecutedOps::new(config.executed_ops_config.clone(), db.clone()), executed_denunciations: ExecutedDenunciations::new( @@ -64,6 +68,7 @@ impl Default for FinalStateConfig { FinalStateConfig { ledger_config: LedgerConfig::default(), async_pool_config: AsyncPoolConfig::default(), + deferred_calls_config: DeferredCallsConfig::default(), executed_ops_config: ExecutedOpsConfig { thread_count: THREAD_COUNT, keep_executed_history_extra_periods: KEEP_EXECUTED_HISTORY_EXTRA_PERIODS, diff --git a/massa-models/src/config/constants.rs b/massa-models/src/config/constants.rs index 0bd147194cd..799074759fd 100644 --- a/massa-models/src/config/constants.rs +++ b/massa-models/src/config/constants.rs @@ -340,9 +340,12 @@ pub const ROLL_COUNT_TO_SLASH_ON_DENUNCIATION: u64 = 1; pub const MAX_DENUNCIATION_CHANGES_LENGTH: u64 = 1_000; /// Maximum size of deferred call pool changes // TODO define this value +// TODO: set to a reasonable value max pool changes pub const DEFERRED_CALL_MAX_POOL_CHANGES: u64 = 100_000; /// Maximum size of deferred call future slots (1 week) pub const DEFERRED_CALL_MAX_FUTURE_SLOTS: u64 = 1209600; +/// maximum gas for deferred call +pub const DEFERRED_CALL_MAX_ASYNC_GAS: u64 = MAX_ASYNC_GAS; /// max change denominator pub const DEFERRED_CALL_BASE_FEE_MAX_CHANGE_DENOMINATOR: usize = 8; /// deferred call min gas increment (1 nanomassa) diff --git a/massa-models/src/deferred_calls.rs b/massa-models/src/deferred_calls.rs index f1b98535c2f..5157128a44f 100644 --- a/massa-models/src/deferred_calls.rs +++ b/massa-models/src/deferred_calls.rs @@ -10,8 +10,6 @@ use nom::{ }; use transition::Versioned; -// use std::collections::Bound; - use crate::{ config::THREAD_COUNT, error::ModelsError, @@ -25,6 +23,7 @@ const DEFERRED_CALL_ID_PREFIX: &str = "D"; #[allow(missing_docs)] #[transition::versioned(versions("0"))] #[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] +#[allow(unused_macros)] pub struct DeferredCallId(Vec); /// Serializer for `DeferredCallId` diff --git a/massa-node/src/main.rs b/massa-node/src/main.rs index 6d0051a03fd..90634427316 100644 --- a/massa-node/src/main.rs +++ b/massa-node/src/main.rs @@ -86,7 +86,10 @@ use massa_models::config::constants::{ VERSION, }; use massa_models::config::{ - BASE_OPERATION_GAS_COST, CHAINID, KEEP_EXECUTED_HISTORY_EXTRA_PERIODS, + BASE_OPERATION_GAS_COST, CHAINID, DEFERRED_CALL_BASE_FEE_MAX_CHANGE_DENOMINATOR, + DEFERRED_CALL_GLOBAL_OVERBOOKING_PENALTY, DEFERRED_CALL_MAX_ASYNC_GAS, + DEFERRED_CALL_MAX_POOL_CHANGES, DEFERRED_CALL_MIN_GAS_COST, DEFERRED_CALL_MIN_GAS_INCREMENT, + DEFERRED_CALL_SLOT_OVERBOOKING_PENALTY, KEEP_EXECUTED_HISTORY_EXTRA_PERIODS, MAX_BOOTSTRAP_FINAL_STATE_PARTS_SIZE, MAX_BOOTSTRAP_VERSIONING_ELEMENTS_SIZE, MAX_EVENT_DATA_SIZE, MAX_MESSAGE_SIZE, POOL_CONTROLLER_DENUNCIATIONS_CHANNEL_SIZE, POOL_CONTROLLER_ENDORSEMENTS_CHANNEL_SIZE, POOL_CONTROLLER_OPERATIONS_CHANNEL_SIZE, @@ -195,14 +198,19 @@ async fn launch( thread_count: THREAD_COUNT, max_function_name_length: MAX_FUNCTION_NAME_LENGTH, max_parameter_size: MAX_PARAMETERS_SIZE, - // TODO: set to a reasonable value - max_deferred_calls_pool_changes: 1000000, - max_gas: MAX_ASYNC_GAS, + max_pool_changes: DEFERRED_CALL_MAX_POOL_CHANGES, + max_gas: DEFERRED_CALL_MAX_ASYNC_GAS, + max_future_slots: DEFERRED_CALL_MAX_FUTURE_SLOTS, + base_fee_max_max_change_denominator: DEFERRED_CALL_BASE_FEE_MAX_CHANGE_DENOMINATOR, + min_gas_increment: DEFERRED_CALL_MIN_GAS_INCREMENT, + min_gas_cost: DEFERRED_CALL_MIN_GAS_COST, + global_overbooking_penalty: DEFERRED_CALL_GLOBAL_OVERBOOKING_PENALTY, + slot_overbooking_penalty: DEFERRED_CALL_SLOT_OVERBOOKING_PENALTY, }; let final_state_config = FinalStateConfig { ledger_config: ledger_config.clone(), async_pool_config, - deferred_calls_config, + deferred_calls_config: deferred_calls_config.clone(), pos_config, executed_ops_config, executed_denunciations_config, @@ -528,7 +536,7 @@ async fn launch( .broadcast_slot_execution_traces_channel_capacity, max_execution_traces_slot_limit: SETTINGS.execution.execution_traces_limit, block_dump_folder_path, - max_deferred_call_future_slots: DEFERRED_CALL_MAX_FUTURE_SLOTS, + deferred_calls_config: deferred_calls_config.clone(), }; let execution_channels = ExecutionChannels { From fe347bbe887a50475cf524037316a568f7d9e6aa Mon Sep 17 00:00:00 2001 From: modship Date: Tue, 27 Aug 2024 16:05:12 +0200 Subject: [PATCH 058/100] clippy --- massa-bootstrap/src/tests/tools.rs | 4 +- massa-deferred-calls/src/call.rs | 1 + massa-deferred-calls/src/config.rs | 2 +- massa-deferred-calls/src/lib.rs | 5 +- massa-deferred-calls/src/registry_changes.rs | 14 +++-- massa-deferred-calls/src/slot_changes.rs | 10 +++- massa-deferred-calls/src/tests/mod.rs | 16 ++--- massa-execution-worker/src/context.rs | 2 +- massa-execution-worker/src/execution.rs | 2 +- .../src/speculative_deferred_calls.rs | 7 +-- .../src/tests/scenarios_mandatories.rs | 59 ++++++++++--------- massa-final-state/src/final_state.rs | 2 +- massa-final-state/src/test_exports/mock.rs | 3 +- massa-final-state/src/tests/scenarios.rs | 2 + massa-models/src/deferred_calls.rs | 19 +++--- massa-node/src/main.rs | 4 +- 16 files changed, 88 insertions(+), 64 deletions(-) diff --git a/massa-bootstrap/src/tests/tools.rs b/massa-bootstrap/src/tests/tools.rs index 01af04d4c1e..584d9759f57 100644 --- a/massa-bootstrap/src/tests/tools.rs +++ b/massa-bootstrap/src/tests/tools.rs @@ -9,6 +9,7 @@ use massa_consensus_exports::{ bootstrapable_graph::BootstrapableGraph, export_active_block::ExportActiveBlock, }; use massa_db_exports::{DBBatch, ShareableMassaDBController, StreamBatch}; +use massa_deferred_calls::config::DeferredCallsConfig; use massa_deferred_calls::DeferredCallRegistry; use massa_executed_ops::{ ExecutedDenunciations, ExecutedDenunciationsChanges, ExecutedDenunciationsConfig, ExecutedOps, @@ -276,7 +277,8 @@ pub fn get_random_final_state_bootstrap( .write() .write_batch(batch, versioning_batch, None); - let deferred_call_registry = DeferredCallRegistry::new(db.clone()); + let deferred_call_registry = + DeferredCallRegistry::new(db.clone(), DeferredCallsConfig::default()); let executed_ops = get_random_executed_ops( r_limit, diff --git a/massa-deferred-calls/src/call.rs b/massa-deferred-calls/src/call.rs index b22a79ab2d7..703053873a6 100644 --- a/massa-deferred-calls/src/call.rs +++ b/massa-deferred-calls/src/call.rs @@ -42,6 +42,7 @@ pub struct DeferredCall { } impl DeferredCall { + #[allow(clippy::too_many_arguments)] pub fn new( sender_address: Address, target_slot: Slot, diff --git a/massa-deferred-calls/src/config.rs b/massa-deferred-calls/src/config.rs index 3eb3a1d5df9..79464db0e4a 100644 --- a/massa-deferred-calls/src/config.rs +++ b/massa-deferred-calls/src/config.rs @@ -9,7 +9,7 @@ use massa_models::{ }, }; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Copy)] pub struct DeferredCallsConfig { /// thread count pub thread_count: u8, diff --git a/massa-deferred-calls/src/lib.rs b/massa-deferred-calls/src/lib.rs index 72780caba8d..c9257f057db 100644 --- a/massa-deferred-calls/src/lib.rs +++ b/massa-deferred-calls/src/lib.rs @@ -53,13 +53,12 @@ impl DeferredCallRegistry { [DEFERRED_CALLS_PREFIX][slot][CALLS_TAG][id][CALL_FIELD_X_TAG] -> DeferredCalls.x // call data */ - // TODO pass args pub fn new(db: ShareableMassaDBController, config: DeferredCallsConfig) -> Self { Self { db, call_serializer: DeferredCallSerializer::new(), call_id_serializer: DeferredCallIdSerializer::new(), - call_deserializer: DeferredCallDeserializer::new(config.clone()), + call_deserializer: DeferredCallDeserializer::new(config), call_id_deserializer: DeferredCallIdDeserializer::new(), registry_changes_deserializer: DeferredRegistryChangesDeserializer::new(config), registry_changes_serializer: DeferredRegistryChangesSerializer::new(), @@ -83,7 +82,7 @@ impl DeferredCallRegistry { let (_rest, call_id) = self .call_id_deserializer - .deserialize::(&rest_key) + .deserialize::(rest_key) .expect(KEY_DESER_ERROR); if !temp.insert(call_id.clone()) { diff --git a/massa-deferred-calls/src/registry_changes.rs b/massa-deferred-calls/src/registry_changes.rs index e16a7f8ab98..9e9a974412f 100644 --- a/massa-deferred-calls/src/registry_changes.rs +++ b/massa-deferred-calls/src/registry_changes.rs @@ -44,7 +44,7 @@ impl DeferredCallRegistryChanges { pub fn set_call(&mut self, id: DeferredCallId, call: DeferredCall) { self.slots_change - .entry(call.target_slot.clone()) + .entry(call.target_slot) .or_default() .set_call(id, call); } @@ -111,6 +111,12 @@ impl DeferredRegistryChangesSerializer { } } +impl Default for DeferredRegistryChangesSerializer { + fn default() -> Self { + Self::new() + } +} + impl Serializer for DeferredRegistryChangesSerializer { fn serialize( &self, @@ -151,7 +157,7 @@ impl DeferredRegistryChangesDeserializer { Included(u64::MIN), Included(config.max_pool_changes), ), - slot_changes_deserializer: DeferredRegistrySlotChangesDeserializer::new(config.clone()), + slot_changes_deserializer: DeferredRegistrySlotChangesDeserializer::new(config), slot_deserializer: SlotDeserializer::new( (Bound::Included(0), Bound::Included(u64::MAX)), (Bound::Included(0), Bound::Excluded(config.thread_count)), @@ -239,7 +245,7 @@ mod tests { let call = DeferredCall::new( Address::from_str("AU12dG5xP1RDEB5ocdHkymNVvvSJmUL9BgHwCksDowqmGWxfpm93x").unwrap(), - target_slot.clone(), + target_slot, Address::from_str("AS127QtY6Hzm6BnJc9wqCBfPNvEH9fKer3LiMNNQmcX3MzLwCL6G6").unwrap(), "receive".to_string(), vec![42, 42, 42, 42], @@ -262,7 +268,7 @@ mod tests { changes .slots_change - .insert(target_slot.clone(), registry_slot_changes); + .insert(target_slot, registry_slot_changes); changes.set_total_gas(100_000); diff --git a/massa-deferred-calls/src/slot_changes.rs b/massa-deferred-calls/src/slot_changes.rs index ff5f8925dd4..a784eeb1310 100644 --- a/massa-deferred-calls/src/slot_changes.rs +++ b/massa-deferred-calls/src/slot_changes.rs @@ -106,6 +106,12 @@ impl DeferredRegistrySlotChangesSerializer { } } +impl Default for DeferredRegistrySlotChangesSerializer { + fn default() -> Self { + Self::new() + } +} + impl Serializer for DeferredRegistrySlotChangesSerializer { fn serialize( &self, @@ -149,7 +155,7 @@ impl DeferredRegistrySlotChangesDeserializer { ), call_id_deserializer: DeferredCallIdDeserializer::new(), calls_set_or_delete_deserializer: SetOrDeleteDeserializer::new( - DeferredCallDeserializer::new(config.clone()), + DeferredCallDeserializer::new(config), ), gas_deserializer: SetOrKeepDeserializer::new(U64VarIntDeserializer::new( Included(0), @@ -237,7 +243,7 @@ mod tests { let call = DeferredCall::new( Address::from_str("AU12dG5xP1RDEB5ocdHkymNVvvSJmUL9BgHwCksDowqmGWxfpm93x").unwrap(), - target_slot.clone(), + target_slot, Address::from_str("AS127QtY6Hzm6BnJc9wqCBfPNvEH9fKer3LiMNNQmcX3MzLwCL6G6").unwrap(), "receive".to_string(), vec![42, 42, 42, 42], diff --git a/massa-deferred-calls/src/tests/mod.rs b/massa-deferred-calls/src/tests/mod.rs index 216aa29a7a8..a1063261df3 100644 --- a/massa-deferred-calls/src/tests/mod.rs +++ b/massa-deferred-calls/src/tests/mod.rs @@ -40,7 +40,7 @@ fn call_registry_apply_changes() { let call = DeferredCall::new( Address::from_str("AU12dG5xP1RDEB5ocdHkymNVvvSJmUL9BgHwCksDowqmGWxfpm93x").unwrap(), - target_slot.clone(), + target_slot, Address::from_str("AS127QtY6Hzm6BnJc9wqCBfPNvEH9fKer3LiMNNQmcX3MzLwCL6G6").unwrap(), "receive".to_string(), vec![42, 42, 42, 42], @@ -49,7 +49,7 @@ fn call_registry_apply_changes() { Amount::from_raw(1), false, ); - let id = DeferredCallId::new(0, target_slot.clone(), 1, &[]).unwrap(); + let id = DeferredCallId::new(0, target_slot, 1, &[]).unwrap(); let mut buf_id = Vec::new(); call_id_serializer.serialize(&id, &mut buf_id).unwrap(); @@ -92,7 +92,7 @@ fn call_registry_get_slot_calls() { let call = DeferredCall::new( Address::from_str("AU12dG5xP1RDEB5ocdHkymNVvvSJmUL9BgHwCksDowqmGWxfpm93x").unwrap(), - target_slot.clone(), + target_slot, Address::from_str("AS127QtY6Hzm6BnJc9wqCBfPNvEH9fKer3LiMNNQmcX3MzLwCL6G6").unwrap(), "receive".to_string(), vec![42, 42, 42, 42], @@ -101,9 +101,9 @@ fn call_registry_get_slot_calls() { Amount::from_raw(1), false, ); - let id = DeferredCallId::new(0, target_slot.clone(), 1, &[]).unwrap(); + let id = DeferredCallId::new(0, target_slot, 1, &[]).unwrap(); - let id2 = DeferredCallId::new(0, target_slot.clone(), 1, &[123]).unwrap(); + let id2 = DeferredCallId::new(0, target_slot, 1, &[123]).unwrap(); let mut buf_id = Vec::new(); call_id_serializer.serialize(&id, &mut buf_id).unwrap(); @@ -111,9 +111,9 @@ fn call_registry_get_slot_calls() { changes.set_call(id.clone(), call.clone()); changes.set_call(id2.clone(), call.clone()); changes.set_total_gas(100); - changes.set_slot_gas(target_slot.clone(), 100_000); + changes.set_slot_gas(target_slot, 100_000); - changes.set_slot_base_fee(target_slot.clone(), Amount::from_raw(10000000)); + changes.set_slot_base_fee(target_slot, Amount::from_raw(10000000)); let mut batch = DBBatch::new(); // 2 calls @@ -121,7 +121,7 @@ fn call_registry_get_slot_calls() { registry.db.write().write_batch(batch, DBBatch::new(), None); - let result = registry.get_slot_calls(target_slot.clone()); + let result = registry.get_slot_calls(target_slot); assert!(result.slot_calls.len() == 2); assert!(result.slot_calls.contains_key(&id)); diff --git a/massa-execution-worker/src/context.rs b/massa-execution-worker/src/context.rs index cd964b59783..e7e4897330d 100644 --- a/massa-execution-worker/src/context.rs +++ b/massa-execution-worker/src/context.rs @@ -227,7 +227,7 @@ impl ExecutionContext { speculative_deferred_calls: SpeculativeDeferredCallRegistry::new( final_state.clone(), active_history.clone(), - config.deferred_calls_config.clone(), + config.deferred_calls_config, ), speculative_roll_state: SpeculativeRollState::new( final_state.clone(), diff --git a/massa-execution-worker/src/execution.rs b/massa-execution-worker/src/execution.rs index d8ab4ec151b..ac484ce28d5 100644 --- a/massa-execution-worker/src/execution.rs +++ b/massa-execution-worker/src/execution.rs @@ -1383,7 +1383,7 @@ impl ExecutionState { ); // Deferred calls - let calls = execution_context.deferred_calls_advance_slot(slot.clone()); + let calls = execution_context.deferred_calls_advance_slot(*slot); // Apply the created execution context for slot execution *context_guard!(self) = execution_context; diff --git a/massa-execution-worker/src/speculative_deferred_calls.rs b/massa-execution-worker/src/speculative_deferred_calls.rs index 4bc5254c1a8..a295fb872dc 100644 --- a/massa-execution-worker/src/speculative_deferred_calls.rs +++ b/massa-execution-worker/src/speculative_deferred_calls.rs @@ -210,8 +210,8 @@ impl SpeculativeDeferredCallRegistry { } // delete the current slot - for (id, _call) in &slot_calls.slot_calls { - self.deferred_calls_changes.delete_call(current_slot, id); + for id in slot_calls.slot_calls.keys() { + self.delete_call(id, current_slot); } slot_calls @@ -466,8 +466,7 @@ impl SpeculativeDeferredCallRegistry { let id = DeferredCallId::new(0, call.target_slot, index as u64, trail_hash.to_bytes())?; - self.deferred_calls_changes - .set_call(id.clone(), call.clone()); + self.push_new_call(id.clone(), call.clone()); let current_gas = self.get_slot_gas(&call.target_slot); diff --git a/massa-execution-worker/src/tests/scenarios_mandatories.rs b/massa-execution-worker/src/tests/scenarios_mandatories.rs index f078d96ad8f..fda9de20896 100644 --- a/massa-execution-worker/src/tests/scenarios_mandatories.rs +++ b/massa-execution-worker/src/tests/scenarios_mandatories.rs @@ -2,6 +2,7 @@ use massa_async_pool::{AsyncMessage, AsyncPool, AsyncPoolChanges, AsyncPoolConfig}; use massa_db_exports::{DBBatch, ShareableMassaDBController}; +use massa_deferred_calls::config::DeferredCallsConfig; use massa_deferred_calls::registry_changes::DeferredCallRegistryChanges; use massa_deferred_calls::slot_changes::DeferredRegistrySlotChanges; use massa_deferred_calls::{DeferredCall, DeferredCallRegistry}; @@ -63,6 +64,7 @@ const TEST_SK_1: &str = "S18r2i8oJJyhF7Kprx98zwxAc3W4szf7RKuVMX6JydZz8zSxHeC"; const TEST_SK_2: &str = "S1FpYC4ugG9ivZZbLVrTwWtF9diSRiAwwrVX5Gx1ANSRLfouUjq"; const TEST_SK_3: &str = "S1LgXhWLEgAgCX3nm6y8PVPzpybmsYpi6yg6ZySwu5Z4ERnD7Bu"; +#[allow(clippy::too_many_arguments)] fn final_state_boilerplate( mock_final_state: &mut Arc>, db: ShareableMassaDBController, @@ -146,8 +148,8 @@ fn final_state_boilerplate( db.clone(), )); - let deferred_call_registry = - custom_deferred_call_registry.unwrap_or_else(|| DeferredCallRegistry::new(db.clone())); + let deferred_call_registry = custom_deferred_call_registry + .unwrap_or_else(|| DeferredCallRegistry::new(db.clone(), DeferredCallsConfig::default())); mock_final_state .write() @@ -998,7 +1000,7 @@ fn deferred_calls() { let call = DeferredCall { sender_address: Address::from_str("AU1TyzwHarZMQSVJgxku8co7xjrRLnH74nFbNpoqNd98YhJkWgi") .unwrap(), - target_slot: target_slot.clone(), + target_slot, target_address: destination, target_function: "receive".to_string(), parameters: vec![42, 42, 42, 42], @@ -1008,13 +1010,8 @@ fn deferred_calls() { cancelled: false, }; - let call_id = DeferredCallId::new( - 0, - target_slot.clone(), - 0, - "trail_hash".to_string().as_bytes(), - ) - .unwrap(); + let call_id = + DeferredCallId::new(0, target_slot, 0, "trail_hash".to_string().as_bytes()).unwrap(); foreign_controllers .final_state @@ -1066,7 +1063,10 @@ fn deferred_calls() { finalized_waitpoint_trigger_handle2.trigger(); }); - let registry = DeferredCallRegistry::new(foreign_controllers.db.clone()); + let registry = DeferredCallRegistry::new( + foreign_controllers.db.clone(), + DeferredCallsConfig::default(), + ); let mut defer_reg_slot_changes = DeferredRegistrySlotChanges { calls: BTreeMap::new(), @@ -1077,7 +1077,7 @@ fn deferred_calls() { defer_reg_slot_changes.set_call(call_id.clone(), call.clone()); let mut slot_changes = BTreeMap::default(); - slot_changes.insert(target_slot.clone(), defer_reg_slot_changes); + slot_changes.insert(target_slot, defer_reg_slot_changes); let mut db_batch = DBBatch::default(); @@ -1149,7 +1149,7 @@ fn deferred_call_register() { let sender_addr = Address::from_str("AU1TyzwHarZMQSVJgxku8co7xjrRLnH74nFbNpoqNd98YhJkWgi").unwrap(); - let sender_addr_clone = sender_addr.clone(); + let sender_addr_clone = sender_addr; selector_boilerplate(&mut foreign_controllers.selector_controller); @@ -1196,7 +1196,8 @@ fn deferred_call_register() { { // manually write the deferred call to the db // then in the next slot (1,1) we will find and execute it - let reg = DeferredCallRegistry::new(db_lock.clone()); + let reg = + DeferredCallRegistry::new(db_lock.clone(), DeferredCallsConfig::default()); let mut batch = DBBatch::default(); reg.apply_changes_to_batch(changes.deferred_call_changes.clone(), &mut batch); db_lock @@ -1266,7 +1267,10 @@ fn deferred_call_register() { finalized_waitpoint_trigger_handle2.trigger(); }); - let registry = DeferredCallRegistry::new(foreign_controllers.db.clone()); + let registry = DeferredCallRegistry::new( + foreign_controllers.db.clone(), + DeferredCallsConfig::default(), + ); let mut defer_reg_slot_changes = DeferredRegistrySlotChanges { calls: BTreeMap::new(), @@ -1307,7 +1311,10 @@ fn deferred_call_register() { Some(saved_bytecode), None, None, - Some(DeferredCallRegistry::new(foreign_controllers.db.clone())), + Some(DeferredCallRegistry::new( + foreign_controllers.db.clone(), + DeferredCallsConfig::default(), + )), ); let mut universe = ExecutionTestUniverse::new(foreign_controllers, exec_cfg); @@ -1401,7 +1408,7 @@ fn deferred_call_register_fail() { let call = DeferredCall { sender_address: Address::from_str("AU1TyzwHarZMQSVJgxku8co7xjrRLnH74nFbNpoqNd98YhJkWgi") .unwrap(), - target_slot: target_slot.clone(), + target_slot, target_address: Address::from_str("AS12jc7fTsSKwQ9hSk97C3iMNgNT1XrrD6MjSJRJZ4NE53YgQ4kFV") .unwrap(), target_function: "toto".to_string(), @@ -1412,14 +1419,12 @@ fn deferred_call_register_fail() { cancelled: false, }; - let call_id = DeferredCallId::new( - 0, - target_slot.clone(), - 0, - "trail_hash".to_string().as_bytes(), - ) - .unwrap(); - let registry = DeferredCallRegistry::new(foreign_controllers.db.clone()); + let call_id = + DeferredCallId::new(0, target_slot, 0, "trail_hash".to_string().as_bytes()).unwrap(); + let registry = DeferredCallRegistry::new( + foreign_controllers.db.clone(), + DeferredCallsConfig::default(), + ); let mut defer_reg_slot_changes = DeferredRegistrySlotChanges { calls: BTreeMap::new(), @@ -1430,7 +1435,7 @@ fn deferred_call_register_fail() { defer_reg_slot_changes.set_call(call_id.clone(), call.clone()); let mut slot_changes = BTreeMap::default(); - slot_changes.insert(target_slot.clone(), defer_reg_slot_changes); + slot_changes.insert(target_slot, defer_reg_slot_changes); let mut db_batch = DBBatch::default(); @@ -1493,7 +1498,7 @@ fn deferred_call_register_fail() { // // update base fee at slot 1,10 // defer_reg_slot_changes.set_base_fee(Amount::from_str("0.0005").unwrap()); - // slot_changes.insert(target_slot.clone(), defer_reg_slot_changes); + // slot_changes.insert(target_slot, defer_reg_slot_changes); // let mut db_batch = DBBatch::default(); diff --git a/massa-final-state/src/final_state.rs b/massa-final-state/src/final_state.rs index ff37de7ac3e..98b47fdf5f7 100644 --- a/massa-final-state/src/final_state.rs +++ b/massa-final-state/src/final_state.rs @@ -110,7 +110,7 @@ impl FinalState { ExecutedDenunciations::new(config.executed_denunciations_config.clone(), db.clone()); let deferred_call_registry = - DeferredCallRegistry::new(db.clone(), config.deferred_calls_config.clone()); + DeferredCallRegistry::new(db.clone(), config.deferred_calls_config); let mut final_state = FinalState { ledger, diff --git a/massa-final-state/src/test_exports/mock.rs b/massa-final-state/src/test_exports/mock.rs index 5c9d2d55852..349820152e8 100644 --- a/massa-final-state/src/test_exports/mock.rs +++ b/massa-final-state/src/test_exports/mock.rs @@ -14,7 +14,7 @@ use massa_async_pool::AsyncPool; use massa_db_exports::{ DBBatch, MassaIteratorMode, ShareableMassaDBController, METADATA_CF, STATE_CF, STATE_HASH_KEY, }; -use massa_deferred_calls::DeferredCallRegistry; +use massa_deferred_calls::{config::DeferredCallsConfig, DeferredCallRegistry}; use massa_executed_ops::{ExecutedDenunciations, ExecutedOps}; use massa_ledger_exports::{LedgerConfig, LedgerController, LedgerEntry, LedgerError}; use massa_ledger_worker::FinalLedger; @@ -204,6 +204,7 @@ pub fn get_sample_state( t0: T0, genesis_timestamp: *GENESIS_TIMESTAMP, ledger_backup_periods_interval: 10, + deferred_calls_config: DeferredCallsConfig::default(), }; let mut final_state = if last_start_period > 0 { diff --git a/massa-final-state/src/tests/scenarios.rs b/massa-final-state/src/tests/scenarios.rs index 0d862e30dd9..f280ffe2053 100644 --- a/massa-final-state/src/tests/scenarios.rs +++ b/massa-final-state/src/tests/scenarios.rs @@ -8,6 +8,7 @@ use crate::{ use massa_async_pool::{AsyncMessage, AsyncPoolChanges, AsyncPoolConfig}; use massa_db_exports::{DBBatch, MassaDBConfig, MassaDBController}; use massa_db_worker::MassaDB; +use massa_deferred_calls::config::DeferredCallsConfig; use massa_executed_ops::{ExecutedDenunciationsConfig, ExecutedOpsConfig}; use massa_ledger_exports::{ LedgerChanges, LedgerConfig, LedgerEntryUpdate, SetOrKeep, SetUpdateOrDelete, @@ -94,6 +95,7 @@ fn create_final_state(temp_dir: &TempDir, reset_final_state: bool) -> Arc); /// Serializer for `DeferredCallId` @@ -74,6 +73,12 @@ impl DeferredCallIdDeserializer { } } +impl Default for DeferredCallIdDeserializer { + fn default() -> Self { + Self::new() + } +} + impl Deserializer for DeferredCallIdDeserializer { fn deserialize<'a, E: ParseError<&'a [u8]> + ContextError<&'a [u8]>>( &self, @@ -127,7 +132,7 @@ impl ::serde::Serialize for DeferredCallId { if serializer.is_human_readable() { serializer.collect_str(&self.to_string()) } else { - serializer.serialize_bytes(&self.as_bytes()) + serializer.serialize_bytes(self.as_bytes()) } } } @@ -226,12 +231,10 @@ impl DeferredCallId { id.extend(trail_hash); Ok(DeferredCallId::DeferredCallIdV0(DeferredCallIdV0(id))) } - _ => { - return Err(ModelsError::InvalidVersionError(format!( - "Invalid version to create an DeferredCallId: {}", - version - ))) - } + _ => Err(ModelsError::InvalidVersionError(format!( + "Invalid version to create an DeferredCallId: {}", + version + ))), } } diff --git a/massa-node/src/main.rs b/massa-node/src/main.rs index 90634427316..6c008971fdf 100644 --- a/massa-node/src/main.rs +++ b/massa-node/src/main.rs @@ -210,7 +210,7 @@ async fn launch( let final_state_config = FinalStateConfig { ledger_config: ledger_config.clone(), async_pool_config, - deferred_calls_config: deferred_calls_config.clone(), + deferred_calls_config, pos_config, executed_ops_config, executed_denunciations_config, @@ -536,7 +536,7 @@ async fn launch( .broadcast_slot_execution_traces_channel_capacity, max_execution_traces_slot_limit: SETTINGS.execution.execution_traces_limit, block_dump_folder_path, - deferred_calls_config: deferred_calls_config.clone(), + deferred_calls_config, }; let execution_channels = ExecutionChannels { From 07863fc154d8337d50be9c2791bdfe67562bdce0 Mon Sep 17 00:00:00 2001 From: modship Date: Tue, 27 Aug 2024 16:55:34 +0200 Subject: [PATCH 059/100] allow unused_macros --- massa-models/src/deferred_calls.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/massa-models/src/deferred_calls.rs b/massa-models/src/deferred_calls.rs index 4b7b0473ea9..b2ae425345f 100644 --- a/massa-models/src/deferred_calls.rs +++ b/massa-models/src/deferred_calls.rs @@ -1,3 +1,5 @@ +#![allow(unused_macros)] + use std::{ops::Bound, str::FromStr}; use massa_serialization::{ @@ -19,7 +21,6 @@ use crate::{ const DEFERRED_CALL_ID_PREFIX: &str = "D"; -/// block id #[allow(missing_docs)] #[transition::versioned(versions("0"))] #[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] From 5f28f444bc1fa576c5cbf33bcd7f819d203655d9 Mon Sep 17 00:00:00 2001 From: modship Date: Tue, 27 Aug 2024 17:03:31 +0200 Subject: [PATCH 060/100] fix : massa-bootstrap import --- massa-bootstrap/Cargo.toml | 98 +++++++++++++++++++++----------------- 1 file changed, 54 insertions(+), 44 deletions(-) diff --git a/massa-bootstrap/Cargo.toml b/massa-bootstrap/Cargo.toml index e1a4eac00f3..b9ca8ae070c 100644 --- a/massa-bootstrap/Cargo.toml +++ b/massa-bootstrap/Cargo.toml @@ -5,54 +5,64 @@ authors = ["Massa Labs "] edition = "2021" [features] -test-exports = ["massa_final_state/test-exports", "massa_ledger_worker/test-exports", "massa_consensus_exports/test-exports", "massa_async_pool/test-exports"] -sandbox = ["massa_async_pool/sandbox", "massa_final_state/sandbox", "massa_models/sandbox"] +test-exports = [ + "massa_final_state/test-exports", + "massa_ledger_worker/test-exports", + "massa_consensus_exports/test-exports", + "massa_async_pool/test-exports", +] +sandbox = [ + "massa_async_pool/sandbox", + "massa_final_state/sandbox", + "massa_models/sandbox", +] heavy_testing = [] [dependencies] -displaydoc = {workspace = true} -num_enum = {workspace = true} -nom = {workspace = true} -rand = {workspace = true} -serde = {workspace = true, "features" = ["derive"]} -serde_json = {workspace = true} # BOM UPGRADE Revert to "1.0" if problem -humantime = {workspace = true} -thiserror = {workspace = true} -parking_lot = {workspace = true} -tracing = {workspace = true} -substruct = {workspace = true} -socket2 = {workspace = true} -crossbeam = {workspace = true} # BOM UPGRADE Revert to "0.8.2" if problem -mio = {workspace = true, "features" = ["net", "os-poll"]} +displaydoc = { workspace = true } +num_enum = { workspace = true } +nom = { workspace = true } +rand = { workspace = true } +serde = { workspace = true, "features" = ["derive"] } +serde_json = { workspace = true } # BOM UPGRADE Revert to "1.0" if problem +humantime = { workspace = true } +thiserror = { workspace = true } +parking_lot = { workspace = true } +tracing = { workspace = true } +substruct = { workspace = true } +socket2 = { workspace = true } +crossbeam = { workspace = true } # BOM UPGRADE Revert to "0.8.2" if problem +mio = { workspace = true, "features" = ["net", "os-poll"] } stream_limiter = { workspace = true } -massa_consensus_exports = {workspace = true} -massa_final_state = {workspace = true} -massa_hash = {workspace = true} -massa_logging = {workspace = true} -massa_models = {workspace = true} -massa_protocol_exports = {workspace = true} -massa_serialization = {workspace = true} -massa_signature = {workspace = true} -massa_pos_exports = {workspace = true} -massa_time = {workspace = true} -massa_db_exports = {workspace = true} -massa_versioning = {workspace = true} -massa_metrics = {workspace = true} +massa_consensus_exports = { workspace = true } +massa_final_state = { workspace = true } +massa_hash = { workspace = true } +massa_logging = { workspace = true } +massa_models = { workspace = true } +massa_protocol_exports = { workspace = true } +massa_serialization = { workspace = true } +massa_signature = { workspace = true } +massa_pos_exports = { workspace = true } +massa_time = { workspace = true } +massa_db_exports = { workspace = true } +massa_versioning = { workspace = true } +massa_metrics = { workspace = true } [dev-dependencies] -mockall = {workspace = true} -bitvec = {workspace = true, "features" = ["serde"]} -lazy_static = {workspace = true} # BOM UPGRADE Revert to "1.4" if problem -tempfile = {workspace = true} # BOM UPGRADE Revert to "3.3" if problem -serial_test = {workspace = true} # BOM UPGRADE Revert to "2.0.0" if problem -num = {workspace = true} -massa_final_state = {workspace = true, "features" = ["test-exports"]} -massa_async_pool = {workspace = true, "features" = ["test-exports"]} -massa_ledger_exports = {workspace = true} -massa_ledger_worker = {workspace = true, "features" = ["test-exports"]} -massa_executed_ops = {workspace = true} -massa_pos_exports = {workspace = true, "features" = ["test-exports"]} -massa_consensus_exports = {workspace = true, "features" = ["test-exports"]} -massa_db_worker = {workspace = true, "features" = ["test-exports"]} -massa_test_framework = {workspace = true, "features" = ["test-exports"]} +mockall = { workspace = true } +bitvec = { workspace = true, "features" = ["serde"] } +lazy_static = { workspace = true } # BOM UPGRADE Revert to "1.4" if problem +tempfile = { workspace = true } # BOM UPGRADE Revert to "3.3" if problem +serial_test = { workspace = true } # BOM UPGRADE Revert to "2.0.0" if problem +num = { workspace = true } +massa_final_state = { workspace = true, "features" = ["test-exports"] } +massa_async_pool = { workspace = true, "features" = ["test-exports"] } +massa_ledger_exports = { workspace = true } +massa_ledger_worker = { workspace = true, "features" = ["test-exports"] } +massa_executed_ops = { workspace = true } +massa_pos_exports = { workspace = true, "features" = ["test-exports"] } +massa_consensus_exports = { workspace = true, "features" = ["test-exports"] } +massa_db_worker = { workspace = true, "features" = ["test-exports"] } +massa_test_framework = { workspace = true, "features" = ["test-exports"] } +massa_deferred_calls = { workspace = true } From fd69b2e329cd14d565d15be830f7ea3807615300 Mon Sep 17 00:00:00 2001 From: modship Date: Wed, 28 Aug 2024 12:10:19 +0200 Subject: [PATCH 061/100] wrap deferred call execution into a closure --- massa-execution-worker/src/execution.rs | 197 +++++++++--------- .../src/tests/scenarios_mandatories.rs | 2 +- 2 files changed, 103 insertions(+), 96 deletions(-) diff --git a/massa-execution-worker/src/execution.rs b/massa-execution-worker/src/execution.rs index ac484ce28d5..d19c60d72ed 100644 --- a/massa-execution-worker/src/execution.rs +++ b/massa-execution-worker/src/execution.rs @@ -1233,114 +1233,121 @@ impl ExecutionState { let mut result = DeferredCallExecutionResult::new(&call); let snapshot; - // prepare the current slot context for executing the operation - let bytecode; + { - let mut context = context_guard!(self); + let context = context_guard!(self); snapshot = context.get_snapshot(); - // acquire write access to the context - // let mut context = context_guard!(self); - - // Set the call stack - // This needs to be defined before anything can fail, so that the emitted event contains the right stack - context.stack = vec![ - ExecutionStackElement { - address: call.sender_address, - coins: call.coins, - owned_addresses: vec![call.sender_address], - operation_datastore: None, - }, - ExecutionStackElement { - address: call.target_address, - coins: call.coins, - owned_addresses: vec![call.target_address], - operation_datastore: None, - }, - ]; - - // Ensure that the target address is an SC address - // Ensure that the target address exists - if let Err(err) = context.check_target_sc_address(call.target_address) { - context.reset_to_snapshot(snapshot, err.clone()); - context.deferred_call_fail_exec(id, &call); - return Err(err); - } + } - // credit coins to the target address - if let Err(err) = - context.transfer_coins(None, Some(call.target_address), call.coins, false) - { - // coin crediting failed: reset context to snapshot and reimburse sender - let err = ExecutionError::RuntimeError(format!( - "could not credit coins to target of deferred call execution: {}", - err - )); + let deferred_call_execution = || { + let bytecode = { + // acquire write access to the context + let mut context = context_guard!(self); - context.reset_to_snapshot(snapshot, err.clone()); - context.deferred_call_fail_exec(id, &call); - return Err(err); - } + // Set the call stack + // This needs to be defined before anything can fail, so that the emitted event contains the right stack + context.stack = vec![ + ExecutionStackElement { + address: call.sender_address, + coins: call.coins, + owned_addresses: vec![call.sender_address], + operation_datastore: None, + }, + ExecutionStackElement { + address: call.target_address, + coins: call.coins, + owned_addresses: vec![call.target_address], + operation_datastore: None, + }, + ]; + + // Ensure that the target address is an SC address + // Ensure that the target address exists + context.check_target_sc_address(call.target_address)?; + + // credit coins to the target address + if let Err(err) = + context.transfer_coins(None, Some(call.target_address), call.coins, false) + { + // coin crediting failed: reset context to snapshot and reimburse sender + return Err(ExecutionError::RuntimeError(format!( + "could not credit coins to target of deferred call execution: {}", + err + ))); + } - // quit if there is no function to be called - if call.target_function.is_empty() { - return Err(ExecutionError::RuntimeError( - "no function to call in the deferred call".to_string(), - )); - } + // quit if there is no function to be called + if call.target_function.is_empty() { + return Err(ExecutionError::RuntimeError( + "no function to call in the deferred call".to_string(), + )); + } - // Load bytecode. Assume empty bytecode if not found. - bytecode = context - .get_bytecode(&call.target_address) - .unwrap_or_default() - .0; - } + // Load bytecode. Assume empty bytecode if not found. + context + .get_bytecode(&call.target_address) + .ok_or(ExecutionError::DeferredCallsError( + "no bytecode found".to_string(), + ))? + .0 + }; - let module = self - .module_cache - .write() - .load_module(&bytecode, call.max_gas)?; - let response = massa_sc_runtime::run_function( - &*self.execution_interface, - module, - &call.target_function, - &call.parameters, - call.max_gas, - self.config.gas_costs.clone(), - ); + let module = self + .module_cache + .write() + .load_module(&bytecode, call.max_gas)?; + let response = massa_sc_runtime::run_function( + &*self.execution_interface, + module, + &call.target_function, + &call.parameters, + call.max_gas, + self.config.gas_costs.clone(), + ); - match response { - Ok(res) => { - self.module_cache - .write() - .set_init_cost(&bytecode, res.init_gas_cost); - #[cfg(feature = "execution-trace")] - { - result.traces = Some((res.trace.into_iter().map(|t| t.into()).collect(), true)); - } - // #[cfg(feature = "execution-info")] - // { - // result.success = true; - // } - result.success = true; - Ok(result) - } - Err(error) => { - if let VMError::ExecutionError { init_gas_cost, .. } = error { + match response { + Ok(res) => { self.module_cache .write() - .set_init_cost(&bytecode, init_gas_cost); + .set_init_cost(&bytecode, res.init_gas_cost); + #[cfg(feature = "execution-trace")] + { + result.traces = + Some((res.trace.into_iter().map(|t| t.into()).collect(), true)); + } + // #[cfg(feature = "execution-info")] + // { + // result.success = true; + // } + result.success = true; + Ok(result) + } + Err(error) => { + if let VMError::ExecutionError { init_gas_cost, .. } = error { + self.module_cache + .write() + .set_init_cost(&bytecode, init_gas_cost); + } + // execution failed: reset context to snapshot and reimburse sender + Err(ExecutionError::VMError { + context: "Deferred Call".to_string(), + error, + }) } - // execution failed: reset context to snapshot and reimburse sender - let err = ExecutionError::VMError { - context: "Deferred Call".to_string(), - error, - }; - let mut context = context_guard!(self); - context.reset_to_snapshot(snapshot, err.clone()); - context.deferred_call_fail_exec(id, &call); - Err(err) } + }; + + // execute the deferred call + let execution_result = deferred_call_execution(); + + // if the execution failed, reset the context to the snapshot + if let Err(err) = &execution_result { + let mut context = context_guard!(self); + context.reset_to_snapshot(snapshot, err.clone()); + context.deferred_call_fail_exec(id, &call); } + + execution_result } /// Executes a full slot (with or without a block inside) without causing any changes to the state, /// just yielding the execution output. diff --git a/massa-execution-worker/src/tests/scenarios_mandatories.rs b/massa-execution-worker/src/tests/scenarios_mandatories.rs index fda9de20896..50c85a7a460 100644 --- a/massa-execution-worker/src/tests/scenarios_mandatories.rs +++ b/massa-execution-worker/src/tests/scenarios_mandatories.rs @@ -1005,7 +1005,7 @@ fn deferred_calls() { target_function: "receive".to_string(), parameters: vec![42, 42, 42, 42], coins: Amount::from_raw(100), - max_gas: 300000000, + max_gas: 2_300_000, fee: Amount::from_raw(1), cancelled: false, }; From 67ad55f9d02668be742cce66bca10895feabeba6 Mon Sep 17 00:00:00 2001 From: modship Date: Wed, 28 Aug 2024 17:28:58 +0200 Subject: [PATCH 062/100] update sc runtime && wasm test file --- Cargo.lock | 2 +- Cargo.toml | 2 +- massa-execution-worker/src/execution.rs | 4 ++-- massa-execution-worker/src/interface_impl.rs | 9 ++++----- .../tests/wasm/deferred_call_register.wasm | Bin 3657 -> 3657 bytes .../wasm/deferred_call_register_fail.wasm | Bin 3663 -> 3663 bytes 6 files changed, 8 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index eaf070eed2a..8e7baa0ec57 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2571,7 +2571,7 @@ dependencies = [ [[package]] name = "massa-sc-runtime" version = "0.10.0" -source = "git+https://github.com/massalabs/massa-sc-runtime?rev=116dd8a32819c8def8a5aa014f805ee2cab9f384#116dd8a32819c8def8a5aa014f805ee2cab9f384" +source = "git+https://github.com/massalabs/massa-sc-runtime?rev=7c0a48777c2481ceef62e1a1d2b989f6d001acc7#7c0a48777c2481ceef62e1a1d2b989f6d001acc7" dependencies = [ "anyhow", "as-ffi-bindings", diff --git a/Cargo.toml b/Cargo.toml index 50ef2c50b5a..93ebf5f33be 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -108,7 +108,7 @@ massa_wallet = { path = "./massa-wallet" } # Massa projects dependencies massa-proto-rs = { git = "https://github.com/massalabs/massa-proto-rs", "rev" = "38950875a7aa406fedc4f0b8336864e5ff290f2c" } -massa-sc-runtime = { git = "https://github.com/massalabs/massa-sc-runtime", "rev" = "116dd8a32819c8def8a5aa014f805ee2cab9f384" } +massa-sc-runtime = { git = "https://github.com/massalabs/massa-sc-runtime", "rev" = "7c0a48777c2481ceef62e1a1d2b989f6d001acc7" } peernet = { git = "https://github.com/massalabs/PeerNet", "rev" = "04b05ddd320fbe76cc858115af7b5fc28bdb8310" } diff --git a/massa-execution-worker/src/execution.rs b/massa-execution-worker/src/execution.rs index d19c60d72ed..66691b3cacc 100644 --- a/massa-execution-worker/src/execution.rs +++ b/massa-execution-worker/src/execution.rs @@ -1270,7 +1270,7 @@ impl ExecutionState { context.transfer_coins(None, Some(call.target_address), call.coins, false) { // coin crediting failed: reset context to snapshot and reimburse sender - return Err(ExecutionError::RuntimeError(format!( + return Err(ExecutionError::DeferredCallsError(format!( "could not credit coins to target of deferred call execution: {}", err ))); @@ -1278,7 +1278,7 @@ impl ExecutionState { // quit if there is no function to be called if call.target_function.is_empty() { - return Err(ExecutionError::RuntimeError( + return Err(ExecutionError::DeferredCallsError( "no function to call in the deferred call".to_string(), )); } diff --git a/massa-execution-worker/src/interface_impl.rs b/massa-execution-worker/src/interface_impl.rs index ac4ac9e1393..bc7a5b282b0 100644 --- a/massa-execution-worker/src/interface_impl.rs +++ b/massa-execution-worker/src/interface_impl.rs @@ -1358,13 +1358,12 @@ impl Interface for InterfaceImpl { /// Register deferred call /// /// # Arguments - /// * target_slot: tuple containing the period and thread of the target slot /// * target_addr: string representation of the target address /// * target_func: string representation of the target function - /// * params: byte array of the parameters - /// * coins: the amount of coins to send - /// * fee: the amount of fee to send + /// * target_slot: tuple containing the period and thread of the target slot /// * max_gas: the gas limit for the call + /// * coins: the amount of coins to send + /// * params: byte array of the parameters /// /// # Returns /// The id of the call @@ -1374,8 +1373,8 @@ impl Interface for InterfaceImpl { target_func: &str, target_slot: (u64, u8), max_gas: u64, - coins: u64, params: &[u8], + coins: u64, ) -> Result> { // This function spends coins + deferred_call_quote(target_slot, max_gas).unwrap() from the caller, fails if the balance is insufficient or if the quote would return None. diff --git a/massa-execution-worker/src/tests/wasm/deferred_call_register.wasm b/massa-execution-worker/src/tests/wasm/deferred_call_register.wasm index ea7b2c73f232baab8d086b55fb00a381c79fd609..41fc05e0da5597fac881594ba9b426254e5c9728 100644 GIT binary patch delta 27 jcmX>pb5dr48dH7UMvWX64h06Mh7;=-sBWIavX&D7iz5m6 delta 27 jcmX>pb5dr48dF{UMvWX64yT3_>ldghFl?T~vX&D7kX{M+ diff --git a/massa-execution-worker/src/tests/wasm/deferred_call_register_fail.wasm b/massa-execution-worker/src/tests/wasm/deferred_call_register_fail.wasm index 9d58cc40550246b2b6fcf650128b58507c136f60..1d9c6b68a1d1ab63f355090082d6d41666664d6b 100644 GIT binary patch delta 23 fcmX>vb6#eG8dH7UMvYvb6#eG8dF{UMvY Date: Thu, 29 Aug 2024 11:48:46 +0200 Subject: [PATCH 063/100] update interface params from bytes to string --- Cargo.lock | 2 +- Cargo.toml | 2 +- massa-execution-worker/src/interface_impl.rs | 13 ++++++------- .../src/tests/scenarios_mandatories.rs | 8 ++------ .../tests/wasm/deferred_call_register.wasm | Bin 3657 -> 1187 bytes massa-models/src/deferred_calls.rs | 2 +- 6 files changed, 11 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8e7baa0ec57..99d8f5dadec 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2571,7 +2571,7 @@ dependencies = [ [[package]] name = "massa-sc-runtime" version = "0.10.0" -source = "git+https://github.com/massalabs/massa-sc-runtime?rev=7c0a48777c2481ceef62e1a1d2b989f6d001acc7#7c0a48777c2481ceef62e1a1d2b989f6d001acc7" +source = "git+https://github.com/massalabs/massa-sc-runtime?rev=4c44288#4c442887279dc055a91fe3d19291cae6f64e11d9" dependencies = [ "anyhow", "as-ffi-bindings", diff --git a/Cargo.toml b/Cargo.toml index 93ebf5f33be..7f883b57414 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -108,7 +108,7 @@ massa_wallet = { path = "./massa-wallet" } # Massa projects dependencies massa-proto-rs = { git = "https://github.com/massalabs/massa-proto-rs", "rev" = "38950875a7aa406fedc4f0b8336864e5ff290f2c" } -massa-sc-runtime = { git = "https://github.com/massalabs/massa-sc-runtime", "rev" = "7c0a48777c2481ceef62e1a1d2b989f6d001acc7" } +massa-sc-runtime = { git = "https://github.com/massalabs/massa-sc-runtime", "rev" = "4c44288" } peernet = { git = "https://github.com/massalabs/PeerNet", "rev" = "04b05ddd320fbe76cc858115af7b5fc28bdb8310" } diff --git a/massa-execution-worker/src/interface_impl.rs b/massa-execution-worker/src/interface_impl.rs index bc7a5b282b0..760cea164e1 100644 --- a/massa-execution-worker/src/interface_impl.rs +++ b/massa-execution-worker/src/interface_impl.rs @@ -1375,7 +1375,7 @@ impl Interface for InterfaceImpl { max_gas: u64, params: &[u8], coins: u64, - ) -> Result> { + ) -> Result { // This function spends coins + deferred_call_quote(target_slot, max_gas).unwrap() from the caller, fails if the balance is insufficient or if the quote would return None. // let total_booked_gas = get_current_total_booked_async_gas(); @@ -1444,8 +1444,7 @@ impl Interface for InterfaceImpl { ); let call_id = context.deferred_call_register(call)?; - - Ok(call_id.as_bytes().to_vec()) + Ok(call_id.to_string()) } /// Check if an deferred call exists @@ -1455,9 +1454,9 @@ impl Interface for InterfaceImpl { /// /// # Returns /// true if the call exists, false otherwise - fn deferred_call_exists(&self, id: &[u8]) -> Result { + fn deferred_call_exists(&self, id: &str) -> Result { // write-lock context - let call_id = DeferredCallId::from_bytes(id)?; + let call_id = DeferredCallId::from_str(id)?; let context = context_guard!(self); Ok(context.deferred_call_exists(&call_id)) } @@ -1466,7 +1465,7 @@ impl Interface for InterfaceImpl { /// /// # Arguments /// * id: the id of the call - fn deferred_call_cancel(&self, id: &[u8]) -> Result<()> { + fn deferred_call_cancel(&self, id: &str) -> Result<()> { // Reimburses coins to the sender but not the deferred call fee to avoid spam. Cancelled items are not removed from storage to avoid manipulation, just ignored when it is their turn to be executed. let mut context = context_guard!(self); @@ -1474,7 +1473,7 @@ impl Interface for InterfaceImpl { // Can only be called by the creator of the deferred call. let caller = context.get_current_address()?; - let call_id = DeferredCallId::from_bytes(id)?; + let call_id = DeferredCallId::from_str(id)?; context.deferred_call_cancel(&call_id, caller)?; Ok(()) diff --git a/massa-execution-worker/src/tests/scenarios_mandatories.rs b/massa-execution-worker/src/tests/scenarios_mandatories.rs index 50c85a7a460..63e9c59c8a8 100644 --- a/massa-execution-worker/src/tests/scenarios_mandatories.rs +++ b/massa-execution-worker/src/tests/scenarios_mandatories.rs @@ -1335,13 +1335,9 @@ fn deferred_call_register() { assert_eq!(events[0].data, "Deferred call registered"); // call id in the register event - let vec: Vec = events[1] - .data - .split(',') - .map(|s| s.parse::().unwrap()) - .collect(); + let callid_event: String = events[1].data.clone(); - let _call_id = DeferredCallId::from_bytes(&vec).unwrap(); + let _call_id = DeferredCallId::from_str(&callid_event).unwrap(); let keypair = KeyPair::from_str(TEST_SK_2).unwrap(); let block = diff --git a/massa-execution-worker/src/tests/wasm/deferred_call_register.wasm b/massa-execution-worker/src/tests/wasm/deferred_call_register.wasm index 41fc05e0da5597fac881594ba9b426254e5c9728..77110356640cee1f97fc66428d6e394b113478df 100644 GIT binary patch delta 254 zcmX|6J5B>J6nxL$gmsW8k_L)2oB)Xqge9O!O>J*hE+S=j(Z+yico(1m`3Rf7`~+PS-Co7B*`s$DKa z6+suybulj7yj%s2st$GAJu(>Jz~E%>o2fOTqAA$lzVG==T-bDopLm+0I7#nf%$`SS bEw1^Cn0y?_KOE-`Bc1KaM8wEir@V}J#J+9D;5&BMOzf0C~Bp0DN+)- zlH(!>bud~VTr`Iqdg#Ho=2G+@@FD0)hobPQ$-#%9$RR*|=&=U@?(a7%$4!v~HFz_- zGw=7_Z{B;eBT8>NQX-1JE5TC^j$X^ANalX zok=3DKk7}Vz1Pr1qxJ2(-D!U^*iE_{(PlK6L>t|HZ+p8tiM9sQB$|kqs-OFR^{r?e zO?pYxjSix5BFfD#h!0{J^G&Y4A{Ezoam5Kd^R?LQ?ip`b!Mp!M zsbowsF{e3M$--`s3H%^CH1HCe!^3y?O!1(S#ccL^>5>?^3YF~1gJ`V-|5XXxz-u}Z zI5g`TX*ynDha6T^(JSU&)UvR)ftRDOjkbj|Xy{Qw+ zsitpDso}{|7=KS;(^s$oK%c2SlfP!&r7z(G%SN51T`ZOz7`m9-TT3+$;5W@gMU47S51zZhkyNe3A(xhzlm{*E{XyH0U^gXj~Df6ZH~`i^F|$@ zobqwtZ=*+*q}pYL%(;QjGEmqQ6NHq+pj-3S>X6fuL&Q?&B zi0sNK;L8$tE8tDSSN1UD+pS{-qynG(aDaCnHo&kj6NsJnYFpBM8Wr`7kx{2`~891*zyF|v)eBYo*fA_F{)VIsk}gK-

S%Cpmqd*mIEgus)D=S%OZ2eu{n{?-wyn;cY>y@4(xFeuap$kZZ7h0Gq^Z zSo;xXwxItjF^`}Rc1H{Pb?U$NB@eWnG9=RpT2Jmi_jC;8SuywXTKQuBhyiaO=C!6B z5At0!^9b|r!hT-waXy9^xh+*$#&cg z3tCnAndR_?G%*`P@4CDV`GwT6z9J3i{~Wq+;e9Aq<8cZ9=&F$i|PcVEzI-vjt0x6E(PQp1=kyevSck za*P4{zkf;(X>kL>Jl{q?0g`#RAm6gKdRQIEJ9tj>zb_+L978j})4uf*Akz`v*(Zot zWHkarlc=%fS3`Wv@hO|v`-@+d*L`3I*ufGI^g?Ts=Xrg!X!##4>IE`RaA@KxZez*m8vH>=CQF9W{}{4(&%z%K*Ox|%23HQ;N&*MP49Ujx1dJZo~E zDyRcr2fhw`9r!x%b>Lag^HfIz_y+I|;2Xdz z;%>>9UWx44wvL`()D1`k*@Q(_B`b^7!3;A?j5MRg9g{UZ_aJP2$Oa^WY~qa-&8lQ& zu{xMxW{Htzw76rkre~trHXytiHu1#Mz=~#7va(nm%rLXWNHbd8F6vJ@O| Date: Thu, 29 Aug 2024 16:23:00 +0200 Subject: [PATCH 064/100] first metrics --- massa-execution-worker/src/execution.rs | 5 ++++ massa-metrics/src/lib.rs | 35 +++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/massa-execution-worker/src/execution.rs b/massa-execution-worker/src/execution.rs index 66691b3cacc..790b5418001 100644 --- a/massa-execution-worker/src/execution.rs +++ b/massa-execution-worker/src/execution.rs @@ -1392,6 +1392,9 @@ impl ExecutionState { // Deferred calls let calls = execution_context.deferred_calls_advance_slot(*slot); + self.massa_metrics + .set_deferred_calls_total_gas(calls.total_gas); + // Apply the created execution context for slot execution *context_guard!(self) = execution_context; @@ -1403,6 +1406,7 @@ impl ExecutionState { match self.execute_deferred_call(&id, call) { Ok(_exec) => { info!("executed deferred call: {:?}", id); + self.massa_metrics.inc_deferred_calls_executed(); cfg_if::cfg_if! { if #[cfg(feature = "execution-trace")] { // Safe to unwrap @@ -1415,6 +1419,7 @@ impl ExecutionState { } Err(err) => { let msg = format!("failed executing deferred call: {}", err); + self.massa_metrics.inc_deferred_calls_failed(); #[cfg(feature = "execution-info")] exec_info.deferred_calls_messages.push(Err(msg.clone())); debug!(msg); diff --git a/massa-metrics/src/lib.rs b/massa-metrics/src/lib.rs index fb591833d1e..19daa4e3283 100644 --- a/massa-metrics/src/lib.rs +++ b/massa-metrics/src/lib.rs @@ -173,6 +173,11 @@ pub struct MassaMetrics { peers_bandwidth: Arc>>, pub tick_delay: Duration, + + // deferred calls metrics + deferred_calls_executed: IntCounter, + deferred_calls_failed: IntCounter, + deferred_calls_total_gas: IntGauge, } impl MassaMetrics { @@ -406,6 +411,18 @@ impl MassaMetrics { ) .unwrap(); + let deferred_calls_executed = IntCounter::new( + "deferred_calls_executed", + "number of deferred calls executed", + ) + .unwrap(); + + let deferred_calls_failed = + IntCounter::new("deferred_calls_failed", "number of deferred calls failed").unwrap(); + + let deferred_calls_total_gas = + IntGauge::new("deferred_total_gas", "total gas used by deferred calls").unwrap(); + let mut stopper = MetricsStopper::default(); if enabled { @@ -458,6 +475,9 @@ impl MassaMetrics { let _ = prometheus::register(Box::new(current_time_period.clone())); let _ = prometheus::register(Box::new(current_time_thread.clone())); let _ = prometheus::register(Box::new(block_slot_delay.clone())); + let _ = prometheus::register(Box::new(deferred_calls_executed.clone())); + let _ = prometheus::register(Box::new(deferred_calls_failed.clone())); + let _ = prometheus::register(Box::new(deferred_calls_total_gas.clone())); stopper = server::bind_metrics(addr); } @@ -514,6 +534,9 @@ impl MassaMetrics { final_cursor_period, peers_bandwidth: Arc::new(RwLock::new(HashMap::new())), tick_delay, + deferred_calls_executed, + deferred_calls_failed, + deferred_calls_total_gas, }, stopper, ) @@ -702,6 +725,18 @@ impl MassaMetrics { self.block_slot_delay.observe(delay); } + pub fn inc_deferred_calls_executed(&self) { + self.deferred_calls_executed.inc(); + } + + pub fn inc_deferred_calls_failed(&self) { + self.deferred_calls_failed.inc(); + } + + pub fn set_deferred_calls_total_gas(&self, gas: u128) { + self.deferred_calls_total_gas.set(gas as i64); + } + /// Update the bandwidth metrics for all peers /// HashMap pub fn update_peers_tx_rx(&self, data: HashMap) { From d49dda7222ef8a2cb77e822588b65080ed4e26d8 Mon Sep 17 00:00:00 2001 From: modship Date: Thu, 29 Aug 2024 17:30:43 +0200 Subject: [PATCH 065/100] Test: Add check on total_gas after execution --- massa-execution-worker/src/tests/scenarios_mandatories.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/massa-execution-worker/src/tests/scenarios_mandatories.rs b/massa-execution-worker/src/tests/scenarios_mandatories.rs index 63e9c59c8a8..c0df67856b2 100644 --- a/massa-execution-worker/src/tests/scenarios_mandatories.rs +++ b/massa-execution-worker/src/tests/scenarios_mandatories.rs @@ -1060,6 +1060,8 @@ fn deferred_calls() { // call was executed and then deleted assert_eq!(set_delete, &SetOrDelete::Delete); + // total gas was set to 0 + assert_eq!(changes.deferred_call_changes.total_gas, SetOrKeep::Set(0)); finalized_waitpoint_trigger_handle2.trigger(); }); @@ -1070,7 +1072,7 @@ fn deferred_calls() { let mut defer_reg_slot_changes = DeferredRegistrySlotChanges { calls: BTreeMap::new(), - gas: massa_deferred_calls::DeferredRegistryGasChange::Keep, + gas: massa_deferred_calls::DeferredRegistryGasChange::Set(call.max_gas.into()), base_fee: massa_deferred_calls::DeferredRegistryBaseFeeChange::Keep, }; @@ -1084,7 +1086,7 @@ fn deferred_calls() { registry.apply_changes_to_batch( DeferredCallRegistryChanges { slots_change: slot_changes, - total_gas: SetOrKeep::Keep, + total_gas: SetOrKeep::Set(call.max_gas.into()), }, &mut db_batch, ); From f43fdea85d9d84bf543642d37088910f83bf2410 Mon Sep 17 00:00:00 2001 From: modship Date: Fri, 30 Aug 2024 09:54:48 +0200 Subject: [PATCH 066/100] Test : Add 2nd call in scenario and check total_gas --- .../src/tests/scenarios_mandatories.rs | 49 +++++++++++++++++-- 1 file changed, 45 insertions(+), 4 deletions(-) diff --git a/massa-execution-worker/src/tests/scenarios_mandatories.rs b/massa-execution-worker/src/tests/scenarios_mandatories.rs index c0df67856b2..79ffb204bc1 100644 --- a/massa-execution-worker/src/tests/scenarios_mandatories.rs +++ b/massa-execution-worker/src/tests/scenarios_mandatories.rs @@ -1010,6 +1010,22 @@ fn deferred_calls() { cancelled: false, }; + let call2 = DeferredCall { + sender_address: Address::from_str("AU1TyzwHarZMQSVJgxku8co7xjrRLnH74nFbNpoqNd98YhJkWgi") + .unwrap(), + target_slot: Slot { + period: 8, + thread: 1, + }, + target_address: destination, + target_function: "tata".to_string(), + parameters: vec![42, 42, 42, 42], + coins: Amount::from_raw(100), + max_gas: 700_000, + fee: Amount::from_raw(1), + cancelled: false, + }; + let call_id = DeferredCallId::new(0, target_slot, 0, "trail_hash".to_string().as_bytes()).unwrap(); @@ -1060,8 +1076,11 @@ fn deferred_calls() { // call was executed and then deleted assert_eq!(set_delete, &SetOrDelete::Delete); - // total gas was set to 0 - assert_eq!(changes.deferred_call_changes.total_gas, SetOrKeep::Set(0)); + // // total gas was set to 700_000 (call2.max_gas) + assert_eq!( + changes.deferred_call_changes.total_gas, + SetOrKeep::Set(700_000) + ); finalized_waitpoint_trigger_handle2.trigger(); }); @@ -1075,18 +1094,40 @@ fn deferred_calls() { gas: massa_deferred_calls::DeferredRegistryGasChange::Set(call.max_gas.into()), base_fee: massa_deferred_calls::DeferredRegistryBaseFeeChange::Keep, }; - defer_reg_slot_changes.set_call(call_id.clone(), call.clone()); + let call_id2 = DeferredCallId::new( + 0, + Slot { + period: 8, + thread: 1, + }, + 0, + "trail_hash".to_string().as_bytes(), + ) + .unwrap(); + + let mut defer_reg_slot_changes2 = defer_reg_slot_changes.clone(); + defer_reg_slot_changes2.set_gas(call2.max_gas.into()); + defer_reg_slot_changes2.set_call(call_id2, call2.clone()); + let mut slot_changes = BTreeMap::default(); slot_changes.insert(target_slot, defer_reg_slot_changes); + slot_changes.insert( + Slot { + period: 8, + thread: 1, + }, + defer_reg_slot_changes2, + ); + let mut db_batch = DBBatch::default(); registry.apply_changes_to_batch( DeferredCallRegistryChanges { slots_change: slot_changes, - total_gas: SetOrKeep::Set(call.max_gas.into()), + total_gas: SetOrKeep::Set(call.max_gas.saturating_add(call2.max_gas).into()), }, &mut db_batch, ); From 5a58f5f9425e7e98bfcdeaba7fa7a22b3e8133c3 Mon Sep 17 00:00:00 2001 From: modship Date: Mon, 2 Sep 2024 12:10:37 +0200 Subject: [PATCH 067/100] move type Set Update Delete from Ledger to massa_models --- massa-async-pool/src/changes.rs | 4 +-- massa-async-pool/src/mapping_grpc.rs | 2 +- massa-async-pool/src/message.rs | 4 +-- massa-async-pool/src/pool.rs | 2 +- massa-bootstrap/src/tests/tools.rs | 3 +- massa-deferred-calls/src/lib.rs | 2 +- massa-deferred-calls/src/registry_changes.rs | 2 +- massa-deferred-calls/src/slot_changes.rs | 2 +- massa-execution-worker/src/active_history.rs | 5 ++- massa-execution-worker/src/context.rs | 3 +- massa-execution-worker/src/execution.rs | 2 +- massa-execution-worker/src/interface_impl.rs | 3 +- .../src/speculative_async_pool.rs | 3 +- .../src/speculative_ledger.rs | 3 +- .../src/tests/scenarios_mandatories.rs | 31 +++++++++---------- massa-final-state/src/final_state.rs | 5 +-- massa-final-state/src/mapping_grpc.rs | 2 +- massa-final-state/src/state_changes.rs | 13 ++++---- massa-final-state/src/tests/scenarios.rs | 5 ++- massa-ledger-exports/src/ledger_changes.rs | 10 +++--- massa-ledger-exports/src/ledger_entry.rs | 2 +- massa-ledger-exports/src/lib.rs | 6 ---- massa-ledger-exports/src/mapping_grpc.rs | 4 ++- massa-ledger-worker/src/ledger_db.rs | 4 ++- massa-models/src/lib.rs | 2 ++ .../src/types.rs | 2 +- 26 files changed, 64 insertions(+), 62 deletions(-) rename {massa-ledger-exports => massa-models}/src/types.rs (99%) diff --git a/massa-async-pool/src/changes.rs b/massa-async-pool/src/changes.rs index 22756446237..65f4b460579 100644 --- a/massa-async-pool/src/changes.rs +++ b/massa-async-pool/src/changes.rs @@ -14,7 +14,7 @@ use crate::{ AsyncMessageDeserializer, AsyncMessageSerializer, }; -use massa_ledger_exports::{ +use massa_models::types::{ Applicable, SetOrKeep, SetUpdateOrDelete, SetUpdateOrDeleteDeserializer, SetUpdateOrDeleteSerializer, }; @@ -233,7 +233,7 @@ impl AsyncPoolChanges { mod tests { use std::str::FromStr; - use massa_ledger_exports::SetUpdateOrDelete; + use massa_models::types::SetUpdateOrDelete; use massa_models::{address::Address, amount::Amount, slot::Slot}; use massa_serialization::{DeserializeError, Deserializer, Serializer}; diff --git a/massa-async-pool/src/mapping_grpc.rs b/massa-async-pool/src/mapping_grpc.rs index 3aefef50024..4aa5b52c1b1 100644 --- a/massa-async-pool/src/mapping_grpc.rs +++ b/massa-async-pool/src/mapping_grpc.rs @@ -1,7 +1,7 @@ // Copyright (c) 2023 MASSA LABS use crate::{AsyncMessage, AsyncMessageTrigger, AsyncMessageUpdate}; -use massa_ledger_exports::SetOrKeep; +use massa_models::types::SetOrKeep; use massa_proto_rs::massa::model::v1 as grpc_model; impl From for grpc_model::AsyncMessage { diff --git a/massa-async-pool/src/message.rs b/massa-async-pool/src/message.rs index 9b5379426ea..0c1ff814a96 100644 --- a/massa-async-pool/src/message.rs +++ b/massa-async-pool/src/message.rs @@ -2,12 +2,12 @@ //! This file defines the structure representing an asynchronous message -use massa_ledger_exports::{Applicable, SetOrKeep, SetOrKeepDeserializer, SetOrKeepSerializer}; use massa_models::address::{AddressDeserializer, AddressSerializer}; use massa_models::amount::{AmountDeserializer, AmountSerializer}; use massa_models::config::GENESIS_KEY; use massa_models::serialization::{StringDeserializer, StringSerializer}; use massa_models::slot::{SlotDeserializer, SlotSerializer}; +use massa_models::types::{Applicable, SetOrKeep, SetOrKeepDeserializer, SetOrKeepSerializer}; use massa_models::{ address::Address, amount::Amount, @@ -1006,7 +1006,7 @@ impl Applicable for AsyncMessageInfo { #[cfg(test)] mod tests { - use massa_ledger_exports::{Applicable, SetOrKeep}; + use massa_models::types::{Applicable, SetOrKeep}; use massa_serialization::{DeserializeError, Deserializer, Serializer}; use num::rational::Ratio; diff --git a/massa-async-pool/src/pool.rs b/massa-async-pool/src/pool.rs index 403787e3388..df88808f51c 100644 --- a/massa-async-pool/src/pool.rs +++ b/massa-async-pool/src/pool.rs @@ -13,8 +13,8 @@ use massa_db_exports::{ DBBatch, MassaDirection, MassaIteratorMode, ShareableMassaDBController, ASYNC_POOL_PREFIX, MESSAGE_ID_DESER_ERROR, MESSAGE_ID_SER_ERROR, MESSAGE_SER_ERROR, STATE_CF, }; -use massa_ledger_exports::{Applicable, SetOrKeep, SetUpdateOrDelete}; use massa_models::address::Address; +use massa_models::types::{Applicable, SetOrKeep, SetUpdateOrDelete}; use massa_serialization::{ DeserializeError, Deserializer, SerializeError, Serializer, U64VarIntDeserializer, U64VarIntSerializer, diff --git a/massa-bootstrap/src/tests/tools.rs b/massa-bootstrap/src/tests/tools.rs index 584d9759f57..d2242278659 100644 --- a/massa-bootstrap/src/tests/tools.rs +++ b/massa-bootstrap/src/tests/tools.rs @@ -18,7 +18,7 @@ use massa_executed_ops::{ use massa_final_state::test_exports::create_final_state; use massa_final_state::{FinalState, FinalStateConfig, FinalStateController}; use massa_hash::{Hash, HASH_SIZE_BYTES}; -use massa_ledger_exports::{LedgerEntry, SetUpdateOrDelete}; +use massa_ledger_exports::LedgerEntry; use massa_ledger_worker::test_exports::create_final_ledger; use massa_models::bytecode::Bytecode; use massa_models::config::{ @@ -38,6 +38,7 @@ use massa_models::denunciation::DenunciationIndex; use massa_models::node::NodeId; use massa_models::prehash::{CapacityAllocator, PreHashSet}; use massa_models::streaming_step::StreamingStep; +use massa_models::types::SetUpdateOrDelete; use massa_models::version::Version; use massa_models::{ address::Address, diff --git a/massa-deferred-calls/src/lib.rs b/massa-deferred-calls/src/lib.rs index c9257f057db..801cdc8a36e 100644 --- a/massa-deferred-calls/src/lib.rs +++ b/massa-deferred-calls/src/lib.rs @@ -25,7 +25,7 @@ mod tests; mod macros; pub use call::DeferredCall; -use massa_ledger_exports::{SetOrDelete, SetOrKeep}; +use massa_models::types::{SetOrDelete, SetOrKeep}; use massa_models::{ amount::Amount, deferred_calls::{DeferredCallId, DeferredCallIdDeserializer, DeferredCallIdSerializer}, diff --git a/massa-deferred-calls/src/registry_changes.rs b/massa-deferred-calls/src/registry_changes.rs index 9e9a974412f..2c36608c77f 100644 --- a/massa-deferred-calls/src/registry_changes.rs +++ b/massa-deferred-calls/src/registry_changes.rs @@ -1,6 +1,6 @@ use std::{collections::BTreeMap, ops::Bound}; -use massa_ledger_exports::{SetOrKeepDeserializer, SetOrKeepSerializer}; +use massa_models::types::{SetOrKeepDeserializer, SetOrKeepSerializer}; use massa_models::{ amount::Amount, deferred_calls::DeferredCallId, diff --git a/massa-deferred-calls/src/slot_changes.rs b/massa-deferred-calls/src/slot_changes.rs index a784eeb1310..5c7e614d1e5 100644 --- a/massa-deferred-calls/src/slot_changes.rs +++ b/massa-deferred-calls/src/slot_changes.rs @@ -6,7 +6,7 @@ use crate::{ DeferredCall, DeferredRegistryBaseFeeChange, DeferredRegistryCallChange, DeferredRegistryGasChange, }; -use massa_ledger_exports::{ +use massa_models::types::{ SetOrDelete, SetOrDeleteDeserializer, SetOrDeleteSerializer, SetOrKeepDeserializer, SetOrKeepSerializer, }; diff --git a/massa-execution-worker/src/active_history.rs b/massa-execution-worker/src/active_history.rs index 1b4c41ebb6b..3d8a8234a95 100644 --- a/massa-execution-worker/src/active_history.rs +++ b/massa-execution-worker/src/active_history.rs @@ -1,10 +1,9 @@ use massa_async_pool::{AsyncMessage, AsyncMessageId, AsyncMessageUpdate}; use massa_execution_exports::ExecutionOutput; -use massa_ledger_exports::{ - Applicable, LedgerEntry, LedgerEntryUpdate, SetOrDelete, SetOrKeep, SetUpdateOrDelete, -}; +use massa_ledger_exports::{LedgerEntry, LedgerEntryUpdate}; use massa_models::denunciation::DenunciationIndex; use massa_models::prehash::{CapacityAllocator, PreHashMap, PreHashSet}; +use massa_models::types::{Applicable, SetOrDelete, SetOrKeep, SetUpdateOrDelete}; use massa_models::{ address::Address, amount::Amount, bytecode::Bytecode, operation::OperationId, slot::Slot, }; diff --git a/massa-execution-worker/src/context.rs b/massa-execution-worker/src/context.rs index e7e4897330d..41dba9c2db5 100644 --- a/massa-execution-worker/src/context.rs +++ b/massa-execution-worker/src/context.rs @@ -25,13 +25,14 @@ use massa_execution_exports::{ }; use massa_final_state::{FinalStateController, StateChanges}; use massa_hash::Hash; -use massa_ledger_exports::{LedgerChanges, SetOrKeep}; +use massa_ledger_exports::LedgerChanges; use massa_models::address::ExecutionAddressCycleInfo; use massa_models::block_id::BlockIdSerializer; use massa_models::bytecode::Bytecode; use massa_models::deferred_calls::DeferredCallId; use massa_models::denunciation::DenunciationIndex; use massa_models::timeslots::get_block_slot_timestamp; +use massa_models::types::SetOrKeep; use massa_models::{ address::Address, amount::Amount, diff --git a/massa-execution-worker/src/execution.rs b/massa-execution-worker/src/execution.rs index 790b5418001..53006c9fd29 100644 --- a/massa-execution-worker/src/execution.rs +++ b/massa-execution-worker/src/execution.rs @@ -23,10 +23,10 @@ use massa_execution_exports::{ ReadOnlyExecutionTarget, SlotExecutionOutput, }; use massa_final_state::FinalStateController; -use massa_ledger_exports::{SetOrDelete, SetUpdateOrDelete}; use massa_metrics::MassaMetrics; use massa_models::address::ExecutionAddressCycleInfo; use massa_models::bytecode::Bytecode; +use massa_models::types::{SetOrDelete, SetUpdateOrDelete}; use massa_models::datastore::get_prefix_bounds; use massa_models::deferred_calls::DeferredCallId; diff --git a/massa-execution-worker/src/interface_impl.rs b/massa-execution-worker/src/interface_impl.rs index 760cea164e1..bdc98000c27 100644 --- a/massa-execution-worker/src/interface_impl.rs +++ b/massa-execution-worker/src/interface_impl.rs @@ -93,8 +93,9 @@ impl InterfaceImpl { use massa_db_exports::{MassaDBConfig, MassaDBController}; use massa_db_worker::MassaDB; use massa_final_state::test_exports::get_sample_state; - use massa_ledger_exports::{LedgerEntry, SetUpdateOrDelete}; + use massa_ledger_exports::LedgerEntry; use massa_models::config::{MIP_STORE_STATS_BLOCK_CONSIDERED, THREAD_COUNT}; + use massa_models::types::SetUpdateOrDelete; use massa_module_cache::{config::ModuleCacheConfig, controller::ModuleCache}; use massa_pos_exports::SelectorConfig; use massa_pos_worker::start_selector_worker; diff --git a/massa-execution-worker/src/speculative_async_pool.rs b/massa-execution-worker/src/speculative_async_pool.rs index e0d1080a275..d50e51699a7 100644 --- a/massa-execution-worker/src/speculative_async_pool.rs +++ b/massa-execution-worker/src/speculative_async_pool.rs @@ -9,8 +9,9 @@ use massa_async_pool::{ AsyncPoolChanges, }; use massa_final_state::FinalStateController; -use massa_ledger_exports::{Applicable, LedgerChanges, SetUpdateOrDelete}; +use massa_ledger_exports::LedgerChanges; use massa_models::slot::Slot; +use massa_models::types::{Applicable, SetUpdateOrDelete}; use parking_lot::RwLock; use std::{ collections::{BTreeMap, HashMap}, diff --git a/massa-execution-worker/src/speculative_ledger.rs b/massa-execution-worker/src/speculative_ledger.rs index 16bc6a98053..0fa54d2605f 100644 --- a/massa-execution-worker/src/speculative_ledger.rs +++ b/massa-execution-worker/src/speculative_ledger.rs @@ -9,9 +9,10 @@ use crate::active_history::{ActiveHistory, HistorySearchResult}; use massa_execution_exports::ExecutionError; use massa_execution_exports::StorageCostsConstants; use massa_final_state::FinalStateController; -use massa_ledger_exports::{Applicable, LedgerChanges, SetOrDelete, SetUpdateOrDelete}; +use massa_ledger_exports::LedgerChanges; use massa_models::bytecode::Bytecode; use massa_models::datastore::get_prefix_bounds; +use massa_models::types::{Applicable, SetOrDelete, SetUpdateOrDelete}; use massa_models::{address::Address, amount::Amount}; use parking_lot::RwLock; use std::cmp::Ordering; diff --git a/massa-execution-worker/src/tests/scenarios_mandatories.rs b/massa-execution-worker/src/tests/scenarios_mandatories.rs index 79ffb204bc1..48a1ad38bd4 100644 --- a/massa-execution-worker/src/tests/scenarios_mandatories.rs +++ b/massa-execution-worker/src/tests/scenarios_mandatories.rs @@ -14,9 +14,7 @@ use massa_execution_exports::{ use massa_final_state::test_exports::get_initials; use massa_final_state::MockFinalStateController; use massa_hash::Hash; -use massa_ledger_exports::{ - LedgerEntryUpdate, MockLedgerControllerWrapper, SetOrDelete, SetOrKeep, SetUpdateOrDelete, -}; +use massa_ledger_exports::{LedgerEntryUpdate, MockLedgerControllerWrapper}; use massa_models::bytecode::Bytecode; use massa_models::config::{ CHAINID, ENDORSEMENT_COUNT, LEDGER_ENTRY_DATASTORE_BASE_SIZE, THREAD_COUNT, @@ -24,6 +22,7 @@ use massa_models::config::{ use massa_models::deferred_calls::DeferredCallId; use massa_models::prehash::PreHashMap; use massa_models::test_exports::gen_endorsements_for_denunciation; +use massa_models::types::{SetOrDelete, SetOrKeep, SetUpdateOrDelete}; use massa_models::{address::Address, amount::Amount, slot::Slot}; use massa_models::{ denunciation::Denunciation, @@ -314,8 +313,8 @@ fn test_readonly_execution() { assert_eq!( res.out.state_changes.ledger_changes.0.get(&addr).unwrap(), &SetUpdateOrDelete::Update(LedgerEntryUpdate { - balance: massa_ledger_exports::SetOrKeep::Set(Amount::from_str("60").unwrap()), - bytecode: massa_ledger_exports::SetOrKeep::Keep, + balance: massa_models::types::SetOrKeep::Set(Amount::from_str("60").unwrap()), + bytecode: massa_models::types::SetOrKeep::Keep, datastore: BTreeMap::new() }) ); @@ -360,8 +359,8 @@ fn test_readonly_execution() { assert_eq!( res2.out.state_changes.ledger_changes.0.get(&addr).unwrap(), &SetUpdateOrDelete::Update(LedgerEntryUpdate { - balance: massa_ledger_exports::SetOrKeep::Set(Amount::from_str("50").unwrap()), - bytecode: massa_ledger_exports::SetOrKeep::Keep, + balance: massa_models::types::SetOrKeep::Set(Amount::from_str("50").unwrap()), + bytecode: massa_models::types::SetOrKeep::Keep, datastore: BTreeMap::new() }) ); @@ -682,7 +681,7 @@ fn send_and_receive_async_message() { println!("changes: {:?}", changes.async_pool_changes.0); assert_eq!( changes.async_pool_changes.0.first_key_value().unwrap().1, - &massa_ledger_exports::SetUpdateOrDelete::Set(message_cloned.clone()) + &massa_models::types::SetUpdateOrDelete::Set(message_cloned.clone()) ); assert_eq!( changes.async_pool_changes.0.first_key_value().unwrap().0, @@ -731,7 +730,7 @@ fn send_and_receive_async_message() { }, 0, ), - massa_ledger_exports::SetUpdateOrDelete::Set(message), + massa_models::types::SetUpdateOrDelete::Set(message), ); let mut db_batch = DBBatch::default(); async_pool.apply_changes_to_batch(&AsyncPoolChanges(changes), &mut db_batch); @@ -841,10 +840,10 @@ fn cancel_async_message() { assert_eq!( changes.ledger_changes.0.get(&sender_addr).unwrap(), &SetUpdateOrDelete::Update(LedgerEntryUpdate { - balance: massa_ledger_exports::SetOrKeep::Set( + balance: massa_models::types::SetOrKeep::Set( Amount::from_str("100.670399899").unwrap() ), - bytecode: massa_ledger_exports::SetOrKeep::Keep, + bytecode: massa_models::types::SetOrKeep::Keep, datastore: BTreeMap::new() }) ); @@ -893,7 +892,7 @@ fn cancel_async_message() { }, 0, ), - massa_ledger_exports::SetUpdateOrDelete::Set(message), + massa_models::types::SetUpdateOrDelete::Set(message), ); let mut db_batch = DBBatch::default(); async_pool.apply_changes_to_batch(&AsyncPoolChanges(changes), &mut db_batch); @@ -1091,7 +1090,7 @@ fn deferred_calls() { let mut defer_reg_slot_changes = DeferredRegistrySlotChanges { calls: BTreeMap::new(), - gas: massa_deferred_calls::DeferredRegistryGasChange::Set(call.max_gas.into()), + gas: massa_deferred_calls::DeferredRegistryGasChange::Set(call.max_gas), base_fee: massa_deferred_calls::DeferredRegistryBaseFeeChange::Keep, }; defer_reg_slot_changes.set_call(call_id.clone(), call.clone()); @@ -1108,7 +1107,7 @@ fn deferred_calls() { .unwrap(); let mut defer_reg_slot_changes2 = defer_reg_slot_changes.clone(); - defer_reg_slot_changes2.set_gas(call2.max_gas.into()); + defer_reg_slot_changes2.set_gas(call2.max_gas); defer_reg_slot_changes2.set_call(call_id2, call2.clone()); let mut slot_changes = BTreeMap::default(); @@ -1991,8 +1990,8 @@ fn roll_buy() { assert_eq!( changes.ledger_changes.0.get(&address).unwrap(), &SetUpdateOrDelete::Update(LedgerEntryUpdate { - balance: massa_ledger_exports::SetOrKeep::Set(exec_cfg.block_reward), - bytecode: massa_ledger_exports::SetOrKeep::Keep, + balance: massa_models::types::SetOrKeep::Set(exec_cfg.block_reward), + bytecode: massa_models::types::SetOrKeep::Keep, datastore: BTreeMap::new() }) ); diff --git a/massa-final-state/src/final_state.rs b/massa-final-state/src/final_state.rs index 98b47fdf5f7..faf31b34953 100644 --- a/massa-final-state/src/final_state.rs +++ b/massa-final-state/src/final_state.rs @@ -21,10 +21,10 @@ use massa_executed_ops::ExecutedDenunciations; use massa_executed_ops::ExecutedOps; use massa_hash::Hash; use massa_ledger_exports::LedgerController; -use massa_ledger_exports::SetOrKeep; use massa_models::operation::OperationId; use massa_models::slot::Slot; use massa_models::timeslots::get_block_slot_timestamp; +use massa_models::types::SetOrKeep; use massa_pos_exports::{PoSFinalState, SelectorController}; use massa_versioning::versioning::MipStore; use tracing::{debug, info, warn}; @@ -950,11 +950,12 @@ mod test { use massa_db_worker::MassaDB; use massa_executed_ops::{ExecutedDenunciationsConfig, ExecutedOpsConfig}; use massa_hash::Hash; - use massa_ledger_exports::{LedgerChanges, LedgerConfig, LedgerEntryUpdate, SetUpdateOrDelete}; + use massa_ledger_exports::{LedgerChanges, LedgerConfig, LedgerEntryUpdate}; use massa_ledger_worker::FinalLedger; use massa_models::address::Address; use massa_models::amount::Amount; use massa_models::bytecode::Bytecode; + use massa_models::types::SetUpdateOrDelete; use massa_models::config::{ DENUNCIATION_EXPIRE_PERIODS, ENDORSEMENT_COUNT, KEEP_EXECUTED_HISTORY_EXTRA_PERIODS, diff --git a/massa-final-state/src/mapping_grpc.rs b/massa-final-state/src/mapping_grpc.rs index 1f42bf4f402..5c45b997634 100644 --- a/massa-final-state/src/mapping_grpc.rs +++ b/massa-final-state/src/mapping_grpc.rs @@ -2,7 +2,7 @@ use crate::StateChanges; use massa_async_pool::AsyncMessageId; -use massa_ledger_exports::{SetOrKeep, SetUpdateOrDelete}; +use massa_models::types::{SetOrKeep, SetUpdateOrDelete}; use massa_proto_rs::massa::model::v1 as grpc_model; impl From for grpc_model::StateChanges { diff --git a/massa-final-state/src/state_changes.rs b/massa-final-state/src/state_changes.rs index 07b66b248d6..0eadde9c352 100644 --- a/massa-final-state/src/state_changes.rs +++ b/massa-final-state/src/state_changes.rs @@ -18,10 +18,8 @@ use massa_executed_ops::{ ExecutedOpsChangesSerializer, }; use massa_hash::{HashDeserializer, HashSerializer}; -use massa_ledger_exports::{ - LedgerChanges, LedgerChangesDeserializer, LedgerChangesSerializer, SetOrKeep, - SetOrKeepDeserializer, SetOrKeepSerializer, -}; +use massa_ledger_exports::{LedgerChanges, LedgerChangesDeserializer, LedgerChangesSerializer}; +use massa_models::types::{SetOrKeep, SetOrKeepDeserializer, SetOrKeepSerializer}; use massa_pos_exports::{PoSChanges, PoSChangesDeserializer, PoSChangesSerializer}; use massa_serialization::{Deserializer, SerializeError, Serializer}; use nom::{ @@ -235,7 +233,7 @@ impl Deserializer for StateChangesDeserializer { impl StateChanges { /// extends the current `StateChanges` with another one pub fn apply(&mut self, changes: StateChanges) { - use massa_ledger_exports::Applicable; + use massa_models::types::Applicable; self.ledger_changes.apply(changes.ledger_changes); self.async_pool_changes.apply(changes.async_pool_changes); self.pos_changes.extend(changes.pos_changes); @@ -253,11 +251,12 @@ mod test { use massa_async_pool::AsyncMessage; use massa_deferred_calls::config::DeferredCallsConfig; - use massa_ledger_exports::{LedgerEntryUpdate, SetUpdateOrDelete}; + use massa_ledger_exports::LedgerEntryUpdate; use massa_models::address::Address; use massa_models::amount::Amount; use massa_models::bytecode::Bytecode; use massa_models::slot::Slot; + use massa_models::types::SetUpdateOrDelete; use massa_serialization::DeserializeError; use massa_models::config::{ @@ -379,7 +378,7 @@ mod test { let mut datastore = BTreeMap::new(); datastore.insert( b"hello".to_vec(), - massa_ledger_exports::SetOrDelete::Set(b"world".to_vec()), + massa_models::types::SetOrDelete::Set(b"world".to_vec()), ); let ledger_entry = LedgerEntryUpdate { balance: SetOrKeep::Set(amount), diff --git a/massa-final-state/src/tests/scenarios.rs b/massa-final-state/src/tests/scenarios.rs index f280ffe2053..35b3ca8b53d 100644 --- a/massa-final-state/src/tests/scenarios.rs +++ b/massa-final-state/src/tests/scenarios.rs @@ -10,9 +10,7 @@ use massa_db_exports::{DBBatch, MassaDBConfig, MassaDBController}; use massa_db_worker::MassaDB; use massa_deferred_calls::config::DeferredCallsConfig; use massa_executed_ops::{ExecutedDenunciationsConfig, ExecutedOpsConfig}; -use massa_ledger_exports::{ - LedgerChanges, LedgerConfig, LedgerEntryUpdate, SetOrKeep, SetUpdateOrDelete, -}; +use massa_ledger_exports::{LedgerChanges, LedgerConfig, LedgerEntryUpdate}; use massa_ledger_worker::FinalLedger; use massa_models::address::Address; use massa_models::amount::Amount; @@ -23,6 +21,7 @@ use massa_models::config::{ MAX_DEFERRED_CREDITS_LENGTH, MAX_DENUNCIATIONS_PER_BLOCK_HEADER, MAX_FUNCTION_NAME_LENGTH, MAX_PARAMETERS_SIZE, MAX_PRODUCTION_STATS_LENGTH, MAX_ROLLS_COUNT_LENGTH, POS_SAVED_CYCLES, T0, }; +use massa_models::types::{SetOrKeep, SetUpdateOrDelete}; use massa_models::{config::MAX_DATASTORE_VALUE_LENGTH, slot::Slot}; use massa_pos_exports::{PoSConfig, SelectorConfig}; use massa_pos_worker::start_selector_worker; diff --git a/massa-ledger-exports/src/ledger_changes.rs b/massa-ledger-exports/src/ledger_changes.rs index 02551f0b096..e4323592929 100644 --- a/massa-ledger-exports/src/ledger_changes.rs +++ b/massa-ledger-exports/src/ledger_changes.rs @@ -3,16 +3,16 @@ //! This file provides structures representing changes to ledger entries use crate::ledger_entry::{LedgerEntry, LedgerEntryDeserializer, LedgerEntrySerializer}; -use crate::types::{ - Applicable, SetOrDelete, SetOrDeleteDeserializer, SetOrDeleteSerializer, SetOrKeep, - SetOrKeepDeserializer, SetOrKeepSerializer, SetUpdateOrDelete, SetUpdateOrDeleteDeserializer, - SetUpdateOrDeleteSerializer, -}; use massa_models::address::{Address, AddressDeserializer, AddressSerializer}; use massa_models::amount::{Amount, AmountDeserializer, AmountSerializer}; use massa_models::bytecode::{Bytecode, BytecodeDeserializer, BytecodeSerializer}; use massa_models::prehash::PreHashMap; use massa_models::serialization::{VecU8Deserializer, VecU8Serializer}; +use massa_models::types::{ + Applicable, SetOrDelete, SetOrDeleteDeserializer, SetOrDeleteSerializer, SetOrKeep, + SetOrKeepDeserializer, SetOrKeepSerializer, SetUpdateOrDelete, SetUpdateOrDeleteDeserializer, + SetUpdateOrDeleteSerializer, +}; use massa_serialization::{ Deserializer, SerializeError, Serializer, U64VarIntDeserializer, U64VarIntSerializer, }; diff --git a/massa-ledger-exports/src/ledger_entry.rs b/massa-ledger-exports/src/ledger_entry.rs index abac9332072..52f4064d5e0 100644 --- a/massa-ledger-exports/src/ledger_entry.rs +++ b/massa-ledger-exports/src/ledger_entry.rs @@ -3,10 +3,10 @@ //! This file defines the structure representing an entry in the `FinalLedger` use crate::ledger_changes::LedgerEntryUpdate; -use crate::types::{Applicable, SetOrDelete}; use massa_models::amount::{Amount, AmountDeserializer, AmountSerializer}; use massa_models::bytecode::{Bytecode, BytecodeDeserializer, BytecodeSerializer}; use massa_models::datastore::{Datastore, DatastoreDeserializer, DatastoreSerializer}; +use massa_models::types::{Applicable, SetOrDelete}; use massa_serialization::{Deserializer, SerializeError, Serializer}; use nom::error::{context, ContextError, ParseError}; use nom::sequence::tuple; diff --git a/massa-ledger-exports/src/lib.rs b/massa-ledger-exports/src/lib.rs index 161301dc26b..67a099a9c5e 100644 --- a/massa-ledger-exports/src/lib.rs +++ b/massa-ledger-exports/src/lib.rs @@ -9,7 +9,6 @@ mod key; mod ledger_changes; mod ledger_entry; mod mapping_grpc; -mod types; pub use config::LedgerConfig; pub use controller::LedgerController; @@ -24,11 +23,6 @@ pub use ledger_changes::{ LedgerEntryUpdateDeserializer, LedgerEntryUpdateSerializer, }; pub use ledger_entry::{LedgerEntry, LedgerEntryDeserializer, LedgerEntrySerializer}; -pub use types::{ - Applicable, SetOrDelete, SetOrDeleteDeserializer, SetOrDeleteSerializer, SetOrKeep, - SetOrKeepDeserializer, SetOrKeepSerializer, SetUpdateOrDelete, SetUpdateOrDeleteDeserializer, - SetUpdateOrDeleteSerializer, -}; #[cfg(feature = "test-exports")] pub mod test_exports; diff --git a/massa-ledger-exports/src/mapping_grpc.rs b/massa-ledger-exports/src/mapping_grpc.rs index 04aa055dd51..48b9f015dfd 100644 --- a/massa-ledger-exports/src/mapping_grpc.rs +++ b/massa-ledger-exports/src/mapping_grpc.rs @@ -1,6 +1,8 @@ // Copyright (c) 2023 MASSA LABS -use crate::{LedgerEntry, LedgerEntryUpdate, SetOrDelete, SetOrKeep}; +use crate::{LedgerEntry, LedgerEntryUpdate}; + +use massa_models::types::{SetOrDelete, SetOrKeep}; use massa_proto_rs::massa::model::v1 as grpc_model; impl From for grpc_model::LedgerEntry { diff --git a/massa-ledger-worker/src/ledger_db.rs b/massa-ledger-worker/src/ledger_db.rs index 56886211cb3..3a3d8fcd791 100644 --- a/massa-ledger-worker/src/ledger_db.rs +++ b/massa-ledger-worker/src/ledger_db.rs @@ -10,6 +10,7 @@ use massa_ledger_exports::*; use massa_models::amount::AmountDeserializer; use massa_models::bytecode::BytecodeDeserializer; use massa_models::datastore::get_prefix_bounds; +use massa_models::types::{SetOrDelete, SetOrKeep, SetUpdateOrDelete}; use massa_models::{ address::Address, amount::AmountSerializer, bytecode::BytecodeSerializer, slot::Slot, }; @@ -560,7 +561,8 @@ mod tests { use massa_db_exports::{MassaDBConfig, MassaDBController, STATE_HASH_INITIAL_BYTES}; use massa_db_worker::MassaDB; use massa_hash::HashXof; - use massa_ledger_exports::{LedgerEntry, LedgerEntryUpdate, SetOrKeep}; + use massa_ledger_exports::{LedgerEntry, LedgerEntryUpdate}; + use massa_models::types::SetOrKeep; use massa_models::{ address::Address, amount::{Amount, AmountDeserializer}, diff --git a/massa-models/src/lib.rs b/massa-models/src/lib.rs index 5b3026725bc..da5bcf81293 100644 --- a/massa-models/src/lib.rs +++ b/massa-models/src/lib.rs @@ -64,6 +64,8 @@ pub mod stats; pub mod streaming_step; /// management of the relation between time and slots pub mod timeslots; +/// types +pub mod types; /// versions pub mod version; diff --git a/massa-ledger-exports/src/types.rs b/massa-models/src/types.rs similarity index 99% rename from massa-ledger-exports/src/types.rs rename to massa-models/src/types.rs index 38749edd91f..3f4485552a3 100644 --- a/massa-ledger-exports/src/types.rs +++ b/massa-models/src/types.rs @@ -1,6 +1,6 @@ // Copyright (c) 2022 MASSA LABS -//! Provides various tools to manipulate ledger entries and changes happening on them. +#![allow(missing_docs)] use massa_serialization::{Deserializer, SerializeError, Serializer}; use nom::bytes::complete::take; From 3f5f3cc2033cf7f74f49df6809281b3cb0b4b4e7 Mon Sep 17 00:00:00 2001 From: modship Date: Tue, 3 Sep 2024 11:29:37 +0200 Subject: [PATCH 068/100] remove todo --- massa-deferred-calls/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/massa-deferred-calls/src/lib.rs b/massa-deferred-calls/src/lib.rs index 801cdc8a36e..2b71e6a9b43 100644 --- a/massa-deferred-calls/src/lib.rs +++ b/massa-deferred-calls/src/lib.rs @@ -401,7 +401,6 @@ impl DeferredCallRegistry { } } -// TODO put SetOrDelete dans models pub type DeferredRegistryCallChange = SetOrDelete; pub type DeferredRegistryGasChange = SetOrKeep; pub type DeferredRegistryBaseFeeChange = SetOrKeep; From 4df7053f6ce101648a7569fea09ef3d1ac649bfc Mon Sep 17 00:00:00 2001 From: modship Date: Wed, 4 Sep 2024 16:54:00 +0200 Subject: [PATCH 069/100] add vm allocation gas cost --- massa-deferred-calls/src/call.rs | 9 ++- massa-deferred-calls/src/config.rs | 9 ++- massa-deferred-calls/src/lib.rs | 37 ++++++----- massa-deferred-calls/src/registry_changes.rs | 52 ++++++++-------- massa-deferred-calls/src/slot_changes.rs | 17 +++--- massa-deferred-calls/src/tests/mod.rs | 8 +-- massa-execution-worker/src/execution.rs | 19 +++--- massa-execution-worker/src/interface_impl.rs | 25 ++------ .../src/speculative_deferred_calls.rs | 61 +++++++++++-------- .../src/tests/scenarios_mandatories.rs | 42 +++++++------ massa-models/src/config/constants.rs | 2 + massa-node/src/main.rs | 14 +++-- 12 files changed, 159 insertions(+), 136 deletions(-) diff --git a/massa-deferred-calls/src/call.rs b/massa-deferred-calls/src/call.rs index 703053873a6..7ffb6f99dc4 100644 --- a/massa-deferred-calls/src/call.rs +++ b/massa-deferred-calls/src/call.rs @@ -33,7 +33,8 @@ pub struct DeferredCall { pub parameters: Vec, // The amount of coins to send to the contract pub coins: Amount, - // The maximum amount of gas usable + // The maximum amount of gas usable for the call (excluding the vm allocation cost) + // to get the effective gas, use get_effective_gas(&self) pub max_gas: u64, // The fee to pay for the reservation of the space for the call pub fee: Amount, @@ -66,6 +67,12 @@ impl DeferredCall { cancelled, } } + + /// Get the effective gas of a call + /// This is the maximum gas of the call + vm allocation cost + pub fn get_effective_gas(&self, alloc_gas_cost: u64) -> u64 { + self.max_gas.saturating_add(alloc_gas_cost) + } } /// Serializer for `AsyncCall` diff --git a/massa-deferred-calls/src/config.rs b/massa-deferred-calls/src/config.rs index 79464db0e4a..e654f8d3180 100644 --- a/massa-deferred-calls/src/config.rs +++ b/massa-deferred-calls/src/config.rs @@ -1,9 +1,9 @@ use massa_models::{ amount::Amount, config::{ - DEFERRED_CALL_BASE_FEE_MAX_CHANGE_DENOMINATOR, 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_BASE_FEE_MAX_CHANGE_DENOMINATOR, DEFERRED_CALL_CST_GAS_COST, + 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, }, @@ -23,6 +23,8 @@ pub struct DeferredCallsConfig { pub min_gas_increment: u64, /// min gas cost (10 nanomassa) pub min_gas_cost: u64, + /// call gas cost + pub call_cst_gas_cost: u64, /// global overbooking penalty pub global_overbooking_penalty: Amount, /// slot overbooking penalty @@ -50,6 +52,7 @@ impl Default for DeferredCallsConfig { min_gas_cost: DEFERRED_CALL_MIN_GAS_COST, 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, } } } diff --git a/massa-deferred-calls/src/lib.rs b/massa-deferred-calls/src/lib.rs index 2b71e6a9b43..0b07a094743 100644 --- a/massa-deferred-calls/src/lib.rs +++ b/massa-deferred-calls/src/lib.rs @@ -95,8 +95,8 @@ impl DeferredCallRegistry { } to_return.slot_base_fee = self.get_slot_base_fee(&slot); - to_return.slot_gas = self.get_slot_gas(&slot); - to_return.total_gas = self.get_total_gas(); + to_return.effective_slot_gas = self.get_slot_gas(&slot); + to_return.effective_total_gas = self.get_total_gas(); to_return } @@ -128,7 +128,7 @@ impl DeferredCallRegistry { } } - /// Returns the total amount of gas booked for a slot + /// Returns the total effective amount of gas booked for a slot pub fn get_slot_gas(&self, slot: &Slot) -> u64 { // By default, if it is absent, it is 0 let key = deferred_call_slot_total_gas_key!(slot.to_bytes_key()); @@ -172,7 +172,7 @@ impl DeferredCallRegistry { Some(v) => { let result = self .registry_changes_deserializer - .total_gas_deserializer + .effective_total_gas_deserializer .deserialize::(&v) .expect(DEFERRED_CALL_DESER_ERROR) .1; @@ -344,7 +344,7 @@ impl DeferredCallRegistry { } } } - match slot_changes.gas { + match slot_changes.effective_slot_gas { DeferredRegistryGasChange::Set(v) => { let key = deferred_call_slot_total_gas_key!(slot.to_bytes_key()); //Note: if a slot gas is zet to 0, delete the slot gas entry @@ -384,12 +384,12 @@ impl DeferredCallRegistry { } } - match changes.total_gas { + match changes.effective_total_gas { DeferredRegistryGasChange::Set(v) => { let key = DEFERRED_CALL_TOTAL_GAS.as_bytes().to_vec(); let mut value_ser = Vec::new(); self.registry_changes_serializer - .total_gas_serializer + .effective_total_gas_serializer .serialize(&DeferredRegistryGasChange::Set(v), &mut value_ser) .expect(DEFERRED_CALL_SER_ERROR); self.db @@ -411,9 +411,16 @@ pub type DeferredRegistryBaseFeeChange = SetOrKeep; pub struct DeferredSlotCalls { pub slot: Slot, pub slot_calls: BTreeMap, - pub slot_gas: u64, + + // calls gas + gas_alloc_cost + // effective_slot_gas doesn't include gas of cancelled calls + pub effective_slot_gas: u64, + pub slot_base_fee: Amount, - pub total_gas: u128, + + // total gas booked + gas_alloc_cost + // effective_total_gas doesn't include gas of cancelled calls + pub effective_total_gas: u128, } impl DeferredSlotCalls { @@ -421,9 +428,9 @@ impl DeferredSlotCalls { Self { slot, slot_calls: BTreeMap::new(), - slot_gas: 0, + effective_slot_gas: 0, slot_base_fee: Amount::zero(), - total_gas: 0, + effective_total_gas: 0, } } @@ -441,16 +448,16 @@ impl DeferredSlotCalls { } } } - match slot_changes.gas { - DeferredRegistryGasChange::Set(v) => self.slot_gas = v, + match slot_changes.effective_slot_gas { + DeferredRegistryGasChange::Set(v) => self.effective_slot_gas = v, DeferredRegistryGasChange::Keep => {} } match slot_changes.base_fee { DeferredRegistryGasChange::Set(v) => self.slot_base_fee = v, DeferredRegistryGasChange::Keep => {} } - match changes.total_gas { - DeferredRegistryGasChange::Set(v) => self.total_gas = v, + match changes.effective_total_gas { + DeferredRegistryGasChange::Set(v) => self.effective_total_gas = v, DeferredRegistryGasChange::Keep => {} } } diff --git a/massa-deferred-calls/src/registry_changes.rs b/massa-deferred-calls/src/registry_changes.rs index 2c36608c77f..b4c2758dfb7 100644 --- a/massa-deferred-calls/src/registry_changes.rs +++ b/massa-deferred-calls/src/registry_changes.rs @@ -31,7 +31,7 @@ use std::ops::Bound::Included; #[derive(Default, Debug, Clone, Serialize, Deserialize)] pub struct DeferredCallRegistryChanges { pub slots_change: BTreeMap, - pub total_gas: DeferredRegistryGasChange, + pub effective_total_gas: DeferredRegistryGasChange, } impl DeferredCallRegistryChanges { @@ -55,17 +55,17 @@ impl DeferredCallRegistryChanges { .and_then(|slot_changes| slot_changes.get_call(id)) } - pub fn get_slot_gas(&self, target_slot: &Slot) -> Option { + pub fn get_effective_slot_gas(&self, target_slot: &Slot) -> Option { self.slots_change .get(target_slot) - .and_then(|slot_changes| slot_changes.get_gas()) + .and_then(|slot_changes| slot_changes.get_effective_slot_gas()) } - pub fn set_slot_gas(&mut self, target_slot: Slot, gas: u64) { + pub fn set_effective_slot_gas(&mut self, target_slot: Slot, gas: u64) { self.slots_change .entry(target_slot) .or_default() - .set_gas(gas); + .set_effective_slot_gas(gas); } pub fn set_slot_base_fee(&mut self, target_slot: Slot, base_fee: Amount) { @@ -81,12 +81,12 @@ impl DeferredCallRegistryChanges { .and_then(|slot_changes| slot_changes.get_base_fee()) } - pub fn set_total_gas(&mut self, gas: u128) { - self.total_gas = DeferredRegistryGasChange::Set(gas); + pub fn set_effective_total_gas(&mut self, gas: u128) { + self.effective_total_gas = DeferredRegistryGasChange::Set(gas); } - pub fn get_total_gas(&self) -> Option { - match self.total_gas { + pub fn get_effective_total_gas(&self) -> Option { + match self.effective_total_gas { DeferredRegistryGasChange::Set(v) => Some(v), DeferredRegistryGasChange::Keep => None, } @@ -97,7 +97,7 @@ pub struct DeferredRegistryChangesSerializer { slots_length: U64VarIntSerializer, slot_changes_serializer: DeferredRegistrySlotChangesSerializer, slot_serializer: SlotSerializer, - pub(crate) total_gas_serializer: SetOrKeepSerializer, + pub(crate) effective_total_gas_serializer: SetOrKeepSerializer, } impl DeferredRegistryChangesSerializer { @@ -106,7 +106,7 @@ impl DeferredRegistryChangesSerializer { slots_length: U64VarIntSerializer::new(), slot_changes_serializer: DeferredRegistrySlotChangesSerializer::new(), slot_serializer: SlotSerializer::new(), - total_gas_serializer: SetOrKeepSerializer::new(U128VarIntSerializer::new()), + effective_total_gas_serializer: SetOrKeepSerializer::new(U128VarIntSerializer::new()), } } } @@ -135,8 +135,8 @@ impl Serializer for DeferredRegistryChangesSerializ self.slot_changes_serializer.serialize(changes, buffer)?; } - self.total_gas_serializer - .serialize(&value.total_gas, buffer)?; + self.effective_total_gas_serializer + .serialize(&value.effective_total_gas, buffer)?; Ok(()) } @@ -146,8 +146,8 @@ pub struct DeferredRegistryChangesDeserializer { slots_length: U64VarIntDeserializer, slot_changes_deserializer: DeferredRegistrySlotChangesDeserializer, slot_deserializer: SlotDeserializer, - // total gas deserializer should be a u128 or SetOrKeep ? - pub(crate) total_gas_deserializer: SetOrKeepDeserializer, + pub(crate) effective_total_gas_deserializer: + SetOrKeepDeserializer, } impl DeferredRegistryChangesDeserializer { @@ -162,10 +162,9 @@ impl DeferredRegistryChangesDeserializer { (Bound::Included(0), Bound::Included(u64::MAX)), (Bound::Included(0), Bound::Excluded(config.thread_count)), ), - total_gas_deserializer: SetOrKeepDeserializer::new(U128VarIntDeserializer::new( - Included(u128::MIN), - Included(u128::MAX), - )), + effective_total_gas_deserializer: SetOrKeepDeserializer::new( + U128VarIntDeserializer::new(Included(u128::MIN), Included(u128::MAX)), + ), } } } @@ -195,13 +194,13 @@ impl Deserializer for DeferredRegistryChangesDeseri }, ), context("Failed total_gas deserialization", |input| { - self.total_gas_deserializer.deserialize(input) + self.effective_total_gas_deserializer.deserialize(input) }), )), ) .map(|(changes, total_gas)| DeferredCallRegistryChanges { slots_change: changes.into_iter().collect::>(), - total_gas, + effective_total_gas: total_gas, }) .parse(buffer) } @@ -232,12 +231,12 @@ mod tests { let mut changes = DeferredCallRegistryChanges { slots_change: BTreeMap::new(), - total_gas: Default::default(), + effective_total_gas: Default::default(), }; let mut registry_slot_changes = DeferredRegistrySlotChanges::default(); registry_slot_changes.set_base_fee(Amount::from_str("100").unwrap()); - registry_slot_changes.set_gas(100_000); + registry_slot_changes.set_effective_slot_gas(100_000); let target_slot = Slot { thread: 5, period: 1, @@ -270,7 +269,7 @@ mod tests { .slots_change .insert(target_slot, registry_slot_changes); - changes.set_total_gas(100_000); + changes.set_effective_total_gas(100_000); let mut buffer = Vec::new(); let serializer = DeferredRegistryChangesSerializer::new(); @@ -285,6 +284,9 @@ mod tests { let base = changes.slots_change.get(&target_slot).unwrap(); let slot_changes_deser = deserialized.slots_change.get(&target_slot).unwrap(); assert_eq!(base.calls, slot_changes_deser.calls); - assert_eq!(changes.total_gas, deserialized.total_gas); + assert_eq!( + changes.effective_total_gas, + deserialized.effective_total_gas + ); } } diff --git a/massa-deferred-calls/src/slot_changes.rs b/massa-deferred-calls/src/slot_changes.rs index 5c7e614d1e5..7b73d570703 100644 --- a/massa-deferred-calls/src/slot_changes.rs +++ b/massa-deferred-calls/src/slot_changes.rs @@ -29,7 +29,7 @@ use std::ops::Bound::Included; #[derive(Default, Debug, Clone, Serialize, Deserialize)] pub struct DeferredRegistrySlotChanges { pub calls: BTreeMap, - pub gas: DeferredRegistryGasChange, + pub effective_slot_gas: DeferredRegistryGasChange, pub base_fee: DeferredRegistryBaseFeeChange, } @@ -61,12 +61,12 @@ impl DeferredRegistrySlotChanges { } } - pub fn set_gas(&mut self, gas: u64) { - self.gas = DeferredRegistryGasChange::Set(gas); + pub fn set_effective_slot_gas(&mut self, gas: u64) { + self.effective_slot_gas = DeferredRegistryGasChange::Set(gas); } - pub fn get_gas(&self) -> Option { - match self.gas { + pub fn get_effective_slot_gas(&self) -> Option { + match self.effective_slot_gas { DeferredRegistryGasChange::Set(v) => Some(v), DeferredRegistryGasChange::Keep => None, } @@ -129,7 +129,8 @@ impl Serializer for DeferredRegistrySlotChangesSeri self.calls_set_or_delete_serializer .serialize(call, buffer)?; } - self.gas_serializer.serialize(&value.gas, buffer)?; + self.gas_serializer + .serialize(&value.effective_slot_gas, buffer)?; self.base_fee_serializer .serialize(&value.base_fee, buffer)?; @@ -207,7 +208,7 @@ impl Deserializer for DeferredRegistrySlotChangesDe DeferredRegistrySlotChanges { calls, - gas, + effective_slot_gas: gas, base_fee, } }) @@ -235,7 +236,7 @@ mod tests { fn test_slot_changes_ser_deser() { let mut registry_slot_changes = DeferredRegistrySlotChanges::default(); registry_slot_changes.set_base_fee(Amount::from_str("100").unwrap()); - registry_slot_changes.set_gas(100_000); + registry_slot_changes.set_effective_slot_gas(100_000); let target_slot = Slot { thread: 5, period: 1, diff --git a/massa-deferred-calls/src/tests/mod.rs b/massa-deferred-calls/src/tests/mod.rs index a1063261df3..16879e738be 100644 --- a/massa-deferred-calls/src/tests/mod.rs +++ b/massa-deferred-calls/src/tests/mod.rs @@ -110,8 +110,8 @@ fn call_registry_get_slot_calls() { changes.set_call(id.clone(), call.clone()); changes.set_call(id2.clone(), call.clone()); - changes.set_total_gas(100); - changes.set_slot_gas(target_slot, 100_000); + changes.set_effective_total_gas(100); + changes.set_effective_slot_gas(target_slot, 100_000); changes.set_slot_base_fee(target_slot, Amount::from_raw(10000000)); @@ -126,7 +126,7 @@ fn call_registry_get_slot_calls() { assert!(result.slot_calls.len() == 2); assert!(result.slot_calls.contains_key(&id)); assert!(result.slot_calls.contains_key(&id2)); - assert_eq!(result.total_gas, 100); + assert_eq!(result.effective_total_gas, 100); assert_eq!(result.slot_base_fee, Amount::from_raw(10000000)); - assert_eq!(result.slot_gas, 100_000); + assert_eq!(result.effective_slot_gas, 100_000); } diff --git a/massa-execution-worker/src/execution.rs b/massa-execution-worker/src/execution.rs index 53006c9fd29..b05076a07de 100644 --- a/massa-execution-worker/src/execution.rs +++ b/massa-execution-worker/src/execution.rs @@ -1292,16 +1292,16 @@ impl ExecutionState { .0 }; - let module = self - .module_cache - .write() - .load_module(&bytecode, call.max_gas)?; + let module = self.module_cache.write().load_module( + &bytecode, + call.get_effective_gas(self.config.deferred_calls_config.call_cst_gas_cost), + )?; let response = massa_sc_runtime::run_function( &*self.execution_interface, module, &call.target_function, &call.parameters, - call.max_gas, + call.get_effective_gas(self.config.deferred_calls_config.call_cst_gas_cost), self.config.gas_costs.clone(), ); @@ -1393,7 +1393,7 @@ impl ExecutionState { let calls = execution_context.deferred_calls_advance_slot(*slot); self.massa_metrics - .set_deferred_calls_total_gas(calls.total_gas); + .set_deferred_calls_total_gas(calls.effective_total_gas); // Apply the created execution context for slot execution *context_guard!(self) = execution_context; @@ -1684,8 +1684,11 @@ impl ExecutionState { // Get asynchronous messages to execute // The gas available for async messages is the remaining block gas + async remaining gas (max_async - gas used by deferred calls) - let async_msg_gas_available = - self.config.max_async_gas.saturating_sub(calls.slot_gas) + remaining_block_gas; + let async_msg_gas_available = self + .config + .max_async_gas + .saturating_sub(calls.effective_slot_gas) + .saturating_add(remaining_block_gas); let messages = context_guard!(self) .take_async_batch(async_msg_gas_available, self.config.async_msg_cst_gas_cost); diff --git a/massa-execution-worker/src/interface_impl.rs b/massa-execution-worker/src/interface_impl.rs index bdc98000c27..2311212bcee 100644 --- a/massa-execution-worker/src/interface_impl.rs +++ b/massa-execution-worker/src/interface_impl.rs @@ -1350,7 +1350,10 @@ impl Interface for InterfaceImpl { let target_slot = Slot::new(target_slot.0, target_slot.1); - match context.deferred_calls_compute_call_fee(target_slot, gas_limit, current_slot) { + 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) { Ok(fee) => Ok((true, fee.to_raw())), Err(_) => Ok((false, 0)), } @@ -1379,26 +1382,6 @@ impl Interface for InterfaceImpl { ) -> Result { // This function spends coins + deferred_call_quote(target_slot, max_gas).unwrap() from the caller, fails if the balance is insufficient or if the quote would return None. - // let total_booked_gas = get_current_total_booked_async_gas(); - - // const CONST_ASYNC_GAS: u64 = XXXXX; // TODO calibrate: const_gas is the gas used even when gas=0 in order to process the item - // let effective_gas = CONST_ASYNC_GAS + max_gas; - // let fee = get_price(target_slot, effective_gas)?; - - // // make sender pay `coins + fee` - - // let call = /* ... */; - // let id = /* ... */ ; - - // target_slot.booked_calls.push(callID, call); - // target_slot.async_gas_booked += effective_gas; - - // set_current_total_booked_async_gas(total_booked_gas + effective_gas) - - const CONST_DEFERRED_CALL_GAS: u64 = 0; // TODO calibrate: const_gas is the gas used even when gas=0 in order to process the item - - let max_gas = CONST_DEFERRED_CALL_GAS + max_gas; - let target_addr = Address::from_str(target_addr)?; // check that the target address is an SC address diff --git a/massa-execution-worker/src/speculative_deferred_calls.rs b/massa-execution-worker/src/speculative_deferred_calls.rs index a295fb872dc..a3c23e6fc98 100644 --- a/massa-execution-worker/src/speculative_deferred_calls.rs +++ b/massa-execution-worker/src/speculative_deferred_calls.rs @@ -56,9 +56,9 @@ impl SpeculativeDeferredCallRegistry { self.deferred_calls_changes.set_call(id, call); } - pub fn get_total_gas(&self) -> u128 { + pub fn get_effective_total_gas(&self) -> u128 { // get total gas from current changes - if let Some(v) = self.deferred_calls_changes.get_total_gas() { + if let Some(v) = self.deferred_calls_changes.get_effective_total_gas() { return v; } @@ -69,7 +69,7 @@ impl SpeculativeDeferredCallRegistry { if let Some(v) = history_item .state_changes .deferred_call_changes - .get_total_gas() + .get_effective_total_gas() { return v; } @@ -84,9 +84,9 @@ impl SpeculativeDeferredCallRegistry { .get_total_gas(); } - pub fn get_slot_gas(&self, slot: &Slot) -> u64 { + pub fn get_effective_slot_gas(&self, slot: &Slot) -> u64 { // get slot gas from current changes - if let Some(v) = self.deferred_calls_changes.get_slot_gas(slot) { + if let Some(v) = self.deferred_calls_changes.get_effective_slot_gas(slot) { return v; } @@ -97,7 +97,7 @@ impl SpeculativeDeferredCallRegistry { if let Some(v) = history_item .state_changes .deferred_call_changes - .get_slot_gas(slot) + .get_effective_slot_gas(slot) { return v; } @@ -154,7 +154,7 @@ impl SpeculativeDeferredCallRegistry { } slot_calls.apply_changes(&self.deferred_calls_changes); - let total_booked_gas = self.get_total_gas(); + let total_booked_gas = self.get_effective_total_gas(); let avg_booked_gas = total_booked_gas.saturating_div(self.config.max_future_slots as u128); // select the slot that is newly made available and set its base fee let new_slot = current_slot @@ -203,10 +203,11 @@ impl SpeculativeDeferredCallRegistry { // subtract the current slot gas from the total gas let total_gas = slot_calls - .total_gas - .saturating_sub(slot_calls.slot_gas.into()); - if !total_gas.eq(&self.get_total_gas()) { - self.deferred_calls_changes.set_total_gas(total_gas); + .effective_total_gas + .saturating_sub(slot_calls.effective_slot_gas.into()); + if !total_gas.eq(&self.get_effective_total_gas()) { + self.deferred_calls_changes + .set_effective_total_gas(total_gas); } // delete the current slot @@ -290,15 +291,20 @@ impl SpeculativeDeferredCallRegistry { self.deferred_calls_changes .set_call(id.clone(), call.clone()); - let current_gas = self.get_slot_gas(&call.target_slot); + let current_gas = self.get_effective_slot_gas(&call.target_slot); // set slot gas - self.deferred_calls_changes - .set_slot_gas(call.target_slot, current_gas.saturating_sub(call.max_gas)); + // slot_gas = current_gas - (call_gas + call_cst_gas_cost (vm allocation cost)) + self.deferred_calls_changes.set_effective_slot_gas( + call.target_slot, + current_gas.saturating_sub(call.get_effective_gas(self.config.call_cst_gas_cost)), + ); // set total gas - self.deferred_calls_changes - .set_total_gas(self.get_total_gas().saturating_sub(call.max_gas as u128)); + self.deferred_calls_changes.set_effective_total_gas( + self.get_effective_total_gas() + .saturating_sub(call.get_effective_gas(self.config.call_cst_gas_cost) as u128), + ); Ok(res) } @@ -381,7 +387,7 @@ impl SpeculativeDeferredCallRegistry { } // Check that the gas is not too high for the target slot - let slot_occupancy = self.get_slot_gas(&target_slot); + let slot_occupancy = self.get_effective_slot_gas(&target_slot); if slot_occupancy.saturating_add(max_gas_request) > self.config.max_gas { return Err(ExecutionError::DeferredCallsError( "Not enough gas available in the target slot.".into(), @@ -408,7 +414,7 @@ impl SpeculativeDeferredCallRegistry { // TODO check if this is correct let global_occupancy = self .deferred_calls_changes - .get_total_gas() + .get_effective_total_gas() .unwrap_or_default(); let global_overbooking_fee = Self::overbooking_fee( (self.config.max_gas as u128).saturating_mul(self.config.max_future_slots as u128), @@ -468,15 +474,20 @@ impl SpeculativeDeferredCallRegistry { self.push_new_call(id.clone(), call.clone()); - let current_gas = self.get_slot_gas(&call.target_slot); + let current_gas = self.get_effective_slot_gas(&call.target_slot); - // set slot gas - self.deferred_calls_changes - .set_slot_gas(call.target_slot, current_gas.saturating_add(call.max_gas)); + // set slot gas for the target slot + // effective_slot_gas = current_gas + (call_gas + call_cst_gas_cost (vm allocation cost)) + self.deferred_calls_changes.set_effective_slot_gas( + call.target_slot, + current_gas.saturating_add(call.get_effective_gas(self.config.call_cst_gas_cost)), + ); - // set total gas - self.deferred_calls_changes - .set_total_gas(self.get_total_gas().saturating_add(call.max_gas as u128)); + // set total effective gas + self.deferred_calls_changes.set_effective_total_gas( + self.get_effective_total_gas() + .saturating_add(call.get_effective_gas(self.config.call_cst_gas_cost) as u128), + ); Ok(id) } diff --git a/massa-execution-worker/src/tests/scenarios_mandatories.rs b/massa-execution-worker/src/tests/scenarios_mandatories.rs index 48a1ad38bd4..6f6880df074 100644 --- a/massa-execution-worker/src/tests/scenarios_mandatories.rs +++ b/massa-execution-worker/src/tests/scenarios_mandatories.rs @@ -1077,7 +1077,7 @@ fn deferred_calls() { // // total gas was set to 700_000 (call2.max_gas) assert_eq!( - changes.deferred_call_changes.total_gas, + changes.deferred_call_changes.effective_total_gas, SetOrKeep::Set(700_000) ); finalized_waitpoint_trigger_handle2.trigger(); @@ -1090,7 +1090,7 @@ fn deferred_calls() { let mut defer_reg_slot_changes = DeferredRegistrySlotChanges { calls: BTreeMap::new(), - gas: massa_deferred_calls::DeferredRegistryGasChange::Set(call.max_gas), + effective_slot_gas: massa_deferred_calls::DeferredRegistryGasChange::Set(call.max_gas), base_fee: massa_deferred_calls::DeferredRegistryBaseFeeChange::Keep, }; defer_reg_slot_changes.set_call(call_id.clone(), call.clone()); @@ -1107,7 +1107,7 @@ fn deferred_calls() { .unwrap(); let mut defer_reg_slot_changes2 = defer_reg_slot_changes.clone(); - defer_reg_slot_changes2.set_gas(call2.max_gas); + defer_reg_slot_changes2.set_effective_slot_gas(call2.max_gas); defer_reg_slot_changes2.set_call(call_id2, call2.clone()); let mut slot_changes = BTreeMap::default(); @@ -1126,7 +1126,7 @@ fn deferred_calls() { registry.apply_changes_to_batch( DeferredCallRegistryChanges { slots_change: slot_changes, - total_gas: SetOrKeep::Set(call.max_gas.saturating_add(call2.max_gas).into()), + effective_total_gas: SetOrKeep::Set(call.max_gas.saturating_add(call2.max_gas).into()), }, &mut db_batch, ); @@ -1223,13 +1223,12 @@ fn deferred_call_register() { .times(1) .with(predicate::eq(Slot::new(1, 0)), predicate::always()) .returning(move |_, changes| { - dbg!(&changes.deferred_call_changes); - // assert sender was debited ( -10 coins) and -1.50 for fees + // assert sender was debited ( -10 coins) and -5.25 for fees match changes.ledger_changes.0.get(&sender_addr_clone).unwrap() { SetUpdateOrDelete::Update(change_sc_update) => { assert_eq!( change_sc_update.balance, - SetOrKeep::Set(Amount::from_str("89.52").unwrap()) + SetOrKeep::Set(Amount::from_str("85.77").unwrap()) ); } _ => panic!("wrong change type"), @@ -1253,13 +1252,15 @@ fn deferred_call_register() { .get(&Slot::new(1, 1)) .unwrap(); let _call = slot_changes.calls.first_key_value().unwrap().1; - // assert total gas was set to 300000 + + // assert total gas was set to 1050000 = (750_000 + 300_000) = (allocated gas + call gas) assert_eq!( - changes.deferred_call_changes.total_gas, - SetOrKeep::Set(300000) + changes.deferred_call_changes.effective_total_gas, + SetOrKeep::Set(1050000) ); - assert_eq!(slot_changes.get_gas().unwrap(), 300000); + //gas was set to 1050000 = (750_000 + 300_000) = (allocated gas + call gas) + assert_eq!(slot_changes.get_effective_slot_gas().unwrap(), 1050000); finalized_waitpoint_trigger_handle.trigger(); }); @@ -1272,8 +1273,6 @@ fn deferred_call_register() { .times(1) .with(predicate::eq(Slot::new(1, 1)), predicate::always()) .returning(move |_, changes| { - // the deferred call was register and executed but the asc call will fail (sc doesn"t exist) - // so the user should be refunded match changes .ledger_changes .0 @@ -1305,7 +1304,10 @@ fn deferred_call_register() { assert_eq!(set_delete, &SetOrDelete::Delete); // assert total gas was set to 0 - assert_eq!(changes.deferred_call_changes.total_gas, SetOrKeep::Set(0)); + assert_eq!( + changes.deferred_call_changes.effective_total_gas, + SetOrKeep::Set(0) + ); finalized_waitpoint_trigger_handle2.trigger(); }); @@ -1316,7 +1318,7 @@ fn deferred_call_register() { let mut defer_reg_slot_changes = DeferredRegistrySlotChanges { calls: BTreeMap::new(), - gas: massa_deferred_calls::DeferredRegistryGasChange::Keep, + effective_slot_gas: massa_deferred_calls::DeferredRegistryGasChange::Keep, base_fee: massa_deferred_calls::DeferredRegistryBaseFeeChange::Keep, }; @@ -1336,7 +1338,7 @@ fn deferred_call_register() { registry.apply_changes_to_batch( DeferredCallRegistryChanges { slots_change: slot_changes, - total_gas: SetOrKeep::Keep, + effective_total_gas: SetOrKeep::Keep, }, &mut db_batch, ); @@ -1424,7 +1426,7 @@ fn deferred_call_register_fail() { .times(1) .with(predicate::eq(Slot::new(1, 0)), predicate::always()) .returning(move |_, changes| { - assert!(changes.deferred_call_changes.total_gas == SetOrKeep::Keep); + assert!(changes.deferred_call_changes.effective_total_gas == SetOrKeep::Keep); finalized_waitpoint_trigger_handle.trigger(); }); @@ -1438,7 +1440,7 @@ fn deferred_call_register_fail() { .returning(move |_, changes| { assert_eq!(changes.deferred_call_changes.slots_change.len(), 1); // deferred call was not register - assert!(changes.deferred_call_changes.total_gas == SetOrKeep::Keep); + assert!(changes.deferred_call_changes.effective_total_gas == SetOrKeep::Keep); finalized_waitpoint_trigger_handle2.trigger(); }); @@ -1466,7 +1468,7 @@ fn deferred_call_register_fail() { let mut defer_reg_slot_changes = DeferredRegistrySlotChanges { calls: BTreeMap::new(), - gas: massa_deferred_calls::DeferredRegistryGasChange::Set(500), + effective_slot_gas: massa_deferred_calls::DeferredRegistryGasChange::Set(500), base_fee: massa_deferred_calls::DeferredRegistryBaseFeeChange::Keep, }; @@ -1480,7 +1482,7 @@ fn deferred_call_register_fail() { registry.apply_changes_to_batch( DeferredCallRegistryChanges { slots_change: slot_changes, - total_gas: SetOrKeep::Set(2000), + effective_total_gas: SetOrKeep::Set(2000), }, &mut db_batch, ); diff --git a/massa-models/src/config/constants.rs b/massa-models/src/config/constants.rs index 799074759fd..4e9ec5c4030 100644 --- a/massa-models/src/config/constants.rs +++ b/massa-models/src/config/constants.rs @@ -356,6 +356,8 @@ pub const DEFERRED_CALL_MIN_GAS_COST: u64 = 10; pub const DEFERRED_CALL_GLOBAL_OVERBOOKING_PENALTY: Amount = Amount::from_raw(1_000_000_000); /// deferred call slot overbooking penalty pub const DEFERRED_CALL_SLOT_OVERBOOKING_PENALTY: Amount = Amount::from_raw(1_000_000_000 / 10_000); +/// deferred call call gas cost +pub const DEFERRED_CALL_CST_GAS_COST: u64 = 750_000; // Some checks at compile time that should not be ignored! #[allow(clippy::assertions_on_constants)] diff --git a/massa-node/src/main.rs b/massa-node/src/main.rs index 6c008971fdf..0aa1221c549 100644 --- a/massa-node/src/main.rs +++ b/massa-node/src/main.rs @@ -87,12 +87,13 @@ use massa_models::config::constants::{ }; use massa_models::config::{ BASE_OPERATION_GAS_COST, CHAINID, DEFERRED_CALL_BASE_FEE_MAX_CHANGE_DENOMINATOR, - DEFERRED_CALL_GLOBAL_OVERBOOKING_PENALTY, DEFERRED_CALL_MAX_ASYNC_GAS, - DEFERRED_CALL_MAX_POOL_CHANGES, DEFERRED_CALL_MIN_GAS_COST, DEFERRED_CALL_MIN_GAS_INCREMENT, - DEFERRED_CALL_SLOT_OVERBOOKING_PENALTY, KEEP_EXECUTED_HISTORY_EXTRA_PERIODS, - MAX_BOOTSTRAP_FINAL_STATE_PARTS_SIZE, MAX_BOOTSTRAP_VERSIONING_ELEMENTS_SIZE, - MAX_EVENT_DATA_SIZE, MAX_MESSAGE_SIZE, POOL_CONTROLLER_DENUNCIATIONS_CHANNEL_SIZE, - POOL_CONTROLLER_ENDORSEMENTS_CHANNEL_SIZE, POOL_CONTROLLER_OPERATIONS_CHANNEL_SIZE, + DEFERRED_CALL_CST_GAS_COST, DEFERRED_CALL_GLOBAL_OVERBOOKING_PENALTY, + DEFERRED_CALL_MAX_ASYNC_GAS, DEFERRED_CALL_MAX_POOL_CHANGES, DEFERRED_CALL_MIN_GAS_COST, + DEFERRED_CALL_MIN_GAS_INCREMENT, DEFERRED_CALL_SLOT_OVERBOOKING_PENALTY, + KEEP_EXECUTED_HISTORY_EXTRA_PERIODS, MAX_BOOTSTRAP_FINAL_STATE_PARTS_SIZE, + MAX_BOOTSTRAP_VERSIONING_ELEMENTS_SIZE, MAX_EVENT_DATA_SIZE, MAX_MESSAGE_SIZE, + POOL_CONTROLLER_DENUNCIATIONS_CHANNEL_SIZE, POOL_CONTROLLER_ENDORSEMENTS_CHANNEL_SIZE, + POOL_CONTROLLER_OPERATIONS_CHANNEL_SIZE, }; use massa_models::slot::Slot; use massa_models::timeslots::get_block_slot_timestamp; @@ -206,6 +207,7 @@ async fn launch( min_gas_cost: DEFERRED_CALL_MIN_GAS_COST, 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, }; let final_state_config = FinalStateConfig { ledger_config: ledger_config.clone(), From c8ca2a8201baa594a4f5523359cc25d962e5518a Mon Sep 17 00:00:00 2001 From: modship Date: Thu, 5 Sep 2024 15:54:49 +0200 Subject: [PATCH 070/100] remove todo --- massa-deferred-calls/src/call.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/massa-deferred-calls/src/call.rs b/massa-deferred-calls/src/call.rs index 7ffb6f99dc4..55360356e2f 100644 --- a/massa-deferred-calls/src/call.rs +++ b/massa-deferred-calls/src/call.rs @@ -93,8 +93,8 @@ impl DeferredCallSerializer { Self { slot_serializer: SlotSerializer::new(), address_serializer: AddressSerializer::new(), - string_serializer: StringSerializer::new(U16VarIntSerializer::new()), // TODO: use max function name length - vec_u8_serializer: VecU8Serializer::new(), // TODO: use max parameters length + string_serializer: StringSerializer::new(U16VarIntSerializer::new()), + vec_u8_serializer: VecU8Serializer::new(), amount_serializer: AmountSerializer::new(), u64_var_int_serializer: U64VarIntSerializer::new(), bool_serializer: BoolSerializer::new(), From 3dcd4abddb218249fb242b79a77db3a80b01d0a0 Mon Sep 17 00:00:00 2001 From: modship Date: Thu, 5 Sep 2024 15:58:03 +0200 Subject: [PATCH 071/100] Fee: calc relu_occupancy_before --- massa-execution-worker/src/speculative_deferred_calls.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/massa-execution-worker/src/speculative_deferred_calls.rs b/massa-execution-worker/src/speculative_deferred_calls.rs index a3c23e6fc98..786e0a75d1e 100644 --- a/massa-execution-worker/src/speculative_deferred_calls.rs +++ b/massa-execution-worker/src/speculative_deferred_calls.rs @@ -321,8 +321,7 @@ impl SpeculativeDeferredCallRegistry { max_penalty: Amount, ) -> Result { // linear part of the occupancy before booking the requested amount - let relu_occupancy_before = - std::cmp::max(current_occupancy, target_occupancy).saturating_sub(target_occupancy); + let relu_occupancy_before = current_occupancy.saturating_sub(target_occupancy); // linear part of the occupancy after booking the requested amount let relu_occupancy_after = std::cmp::max( From b5dae7ca86d6f59146b53ff808754299522d8cb0 Mon Sep 17 00:00:00 2001 From: modship Date: Thu, 5 Sep 2024 17:14:50 +0200 Subject: [PATCH 072/100] update sc runtime --- Cargo.lock | 4 ++-- Cargo.toml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 99d8f5dadec..f03dcb61851 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=38950875a7aa406fedc4f0b8336864e5ff290f2c#38950875a7aa406fedc4f0b8336864e5ff290f2c" +source = "git+https://github.com/massalabs/massa-proto-rs?rev=8eb7aa8384a407b588e190965c8e501cebdd38e3#8eb7aa8384a407b588e190965c8e501cebdd38e3" 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=4c44288#4c442887279dc055a91fe3d19291cae6f64e11d9" +source = "git+https://github.com/massalabs/massa-sc-runtime?rev=48d42c58c3d46ba68426de0be5143fc3a17f5cc8#48d42c58c3d46ba68426de0be5143fc3a17f5cc8" dependencies = [ "anyhow", "as-ffi-bindings", diff --git a/Cargo.toml b/Cargo.toml index 7f883b57414..03acefe3b55 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" = "38950875a7aa406fedc4f0b8336864e5ff290f2c" } -massa-sc-runtime = { git = "https://github.com/massalabs/massa-sc-runtime", "rev" = "4c44288" } +massa-proto-rs = { git = "https://github.com/massalabs/massa-proto-rs", "rev" = "8eb7aa8384a407b588e190965c8e501cebdd38e3" } +massa-sc-runtime = { git = "https://github.com/massalabs/massa-sc-runtime", "rev" = "48d42c58c3d46ba68426de0be5143fc3a17f5cc8" } peernet = { git = "https://github.com/massalabs/PeerNet", "rev" = "04b05ddd320fbe76cc858115af7b5fc28bdb8310" } From 89c4d1dcd55b39fb2fe0e9c7b20e448baded722b Mon Sep 17 00:00:00 2001 From: modship Date: Thu, 5 Sep 2024 17:59:05 +0200 Subject: [PATCH 073/100] add abi gas cost --- massa-node/base_config/gas_costs/abi_gas_costs.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/massa-node/base_config/gas_costs/abi_gas_costs.json b/massa-node/base_config/gas_costs/abi_gas_costs.json index 66ad4901324..d569299be2d 100644 --- a/massa-node/base_config/gas_costs/abi_gas_costs.json +++ b/massa-node/base_config/gas_costs/abi_gas_costs.json @@ -12,6 +12,10 @@ "assembly_script_date_now": 71, "assembly_script_delete_data": 196, "assembly_script_delete_data_for": 220, + "assembly_script_deferred_call_cancel": 11, + "assembly_script_deferred_call_exists": 11, + "assembly_script_deferred_call_quote": 11, + "assembly_script_deferred_call_register": 11, "assembly_script_function_exists": 575, "assembly_script_generate_event": 172, "assembly_script_get_balance": 149, From 039e9bab196065b4190dcf93bcc719fe23bc0de4 Mon Sep 17 00:00:00 2001 From: modship Date: Fri, 6 Sep 2024 11:57:16 +0200 Subject: [PATCH 074/100] Fix : total gas booked --- massa-deferred-calls/src/lib.rs | 10 +++--- massa-deferred-calls/src/registry_changes.rs | 34 +++++++++++++------ massa-execution-worker/src/interface_impl.rs | 2 +- .../src/speculative_deferred_calls.rs | 28 ++++++++------- 4 files changed, 43 insertions(+), 31 deletions(-) diff --git a/massa-deferred-calls/src/lib.rs b/massa-deferred-calls/src/lib.rs index 0b07a094743..b50f70520c1 100644 --- a/massa-deferred-calls/src/lib.rs +++ b/massa-deferred-calls/src/lib.rs @@ -161,7 +161,7 @@ impl DeferredCallRegistry { } } - /// Returns the total amount of gas booked + /// Returns the total amount of effective gas booked pub fn get_total_gas(&self) -> u128 { match self .db @@ -176,10 +176,8 @@ impl DeferredCallRegistry { .deserialize::(&v) .expect(DEFERRED_CALL_DESER_ERROR) .1; - match result { - SetOrKeep::Set(v) => v, - SetOrKeep::Keep => 0, - } + + result } None => 0, } @@ -390,7 +388,7 @@ impl DeferredCallRegistry { let mut value_ser = Vec::new(); self.registry_changes_serializer .effective_total_gas_serializer - .serialize(&DeferredRegistryGasChange::Set(v), &mut value_ser) + .serialize(&v, &mut value_ser) .expect(DEFERRED_CALL_SER_ERROR); self.db .read() diff --git a/massa-deferred-calls/src/registry_changes.rs b/massa-deferred-calls/src/registry_changes.rs index b4c2758dfb7..a14e95aabde 100644 --- a/massa-deferred-calls/src/registry_changes.rs +++ b/massa-deferred-calls/src/registry_changes.rs @@ -1,6 +1,5 @@ use std::{collections::BTreeMap, ops::Bound}; -use massa_models::types::{SetOrKeepDeserializer, SetOrKeepSerializer}; use massa_models::{ amount::Amount, deferred_calls::DeferredCallId, @@ -28,12 +27,21 @@ use crate::{ }; use std::ops::Bound::Included; -#[derive(Default, Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct DeferredCallRegistryChanges { pub slots_change: BTreeMap, pub effective_total_gas: DeferredRegistryGasChange, } +impl Default for DeferredCallRegistryChanges { + fn default() -> Self { + Self { + slots_change: Default::default(), + effective_total_gas: DeferredRegistryGasChange::Keep, + } + } +} + impl DeferredCallRegistryChanges { pub fn delete_call(&mut self, target_slot: Slot, id: &DeferredCallId) { self.slots_change @@ -97,7 +105,7 @@ pub struct DeferredRegistryChangesSerializer { slots_length: U64VarIntSerializer, slot_changes_serializer: DeferredRegistrySlotChangesSerializer, slot_serializer: SlotSerializer, - pub(crate) effective_total_gas_serializer: SetOrKeepSerializer, + pub(crate) effective_total_gas_serializer: U128VarIntSerializer, } impl DeferredRegistryChangesSerializer { @@ -106,7 +114,7 @@ impl DeferredRegistryChangesSerializer { slots_length: U64VarIntSerializer::new(), slot_changes_serializer: DeferredRegistrySlotChangesSerializer::new(), slot_serializer: SlotSerializer::new(), - effective_total_gas_serializer: SetOrKeepSerializer::new(U128VarIntSerializer::new()), + effective_total_gas_serializer: U128VarIntSerializer::new(), } } } @@ -135,8 +143,12 @@ impl Serializer for DeferredRegistryChangesSerializ self.slot_changes_serializer.serialize(changes, buffer)?; } - self.effective_total_gas_serializer - .serialize(&value.effective_total_gas, buffer)?; + match &value.effective_total_gas { + DeferredRegistryGasChange::Set(v) => { + self.effective_total_gas_serializer.serialize(v, buffer)?; + } + DeferredRegistryGasChange::Keep => {} + } Ok(()) } @@ -146,8 +158,7 @@ pub struct DeferredRegistryChangesDeserializer { slots_length: U64VarIntDeserializer, slot_changes_deserializer: DeferredRegistrySlotChangesDeserializer, slot_deserializer: SlotDeserializer, - pub(crate) effective_total_gas_deserializer: - SetOrKeepDeserializer, + pub(crate) effective_total_gas_deserializer: U128VarIntDeserializer, } impl DeferredRegistryChangesDeserializer { @@ -162,8 +173,9 @@ impl DeferredRegistryChangesDeserializer { (Bound::Included(0), Bound::Included(u64::MAX)), (Bound::Included(0), Bound::Excluded(config.thread_count)), ), - effective_total_gas_deserializer: SetOrKeepDeserializer::new( - U128VarIntDeserializer::new(Included(u128::MIN), Included(u128::MAX)), + effective_total_gas_deserializer: U128VarIntDeserializer::new( + Included(u128::MIN), + Included(u128::MAX), ), } } @@ -200,7 +212,7 @@ impl Deserializer for DeferredRegistryChangesDeseri ) .map(|(changes, total_gas)| DeferredCallRegistryChanges { slots_change: changes.into_iter().collect::>(), - effective_total_gas: total_gas, + effective_total_gas: massa_models::types::SetOrKeep::Set(total_gas), }) .parse(buffer) } diff --git a/massa-execution-worker/src/interface_impl.rs b/massa-execution-worker/src/interface_impl.rs index 2311212bcee..ce1af0429dc 100644 --- a/massa-execution-worker/src/interface_impl.rs +++ b/massa-execution-worker/src/interface_impl.rs @@ -1400,7 +1400,7 @@ impl Interface for InterfaceImpl { // check fee, slot, gas let (available, fee_raw) = self.deferred_call_quote(target_slot, max_gas)?; if !available { - bail!("The ASC 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."); + 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."); } let fee = Amount::from_raw(fee_raw); let coins = Amount::from_raw(coins); diff --git a/massa-execution-worker/src/speculative_deferred_calls.rs b/massa-execution-worker/src/speculative_deferred_calls.rs index 786e0a75d1e..9f4722dae9d 100644 --- a/massa-execution-worker/src/speculative_deferred_calls.rs +++ b/massa-execution-worker/src/speculative_deferred_calls.rs @@ -143,6 +143,8 @@ impl SpeculativeDeferredCallRegistry { /// Consumes and deletes the current slot, prepares a new slot in the future /// and returns the calls that need to be executed in the current slot pub fn advance_slot(&mut self, current_slot: Slot) -> DeferredSlotCalls { + let total_booked_gas_before = self.get_effective_total_gas(); + // get the state of the current slot let mut slot_calls: DeferredSlotCalls = self .final_state @@ -154,8 +156,8 @@ impl SpeculativeDeferredCallRegistry { } slot_calls.apply_changes(&self.deferred_calls_changes); - let total_booked_gas = self.get_effective_total_gas(); - let avg_booked_gas = total_booked_gas.saturating_div(self.config.max_future_slots as u128); + let avg_booked_gas = + total_booked_gas_before.saturating_div(self.config.max_future_slots as u128); // select the slot that is newly made available and set its base fee let new_slot = current_slot .skip(self.config.max_future_slots, self.config.thread_count) @@ -183,7 +185,7 @@ impl SpeculativeDeferredCallRegistry { ) } std::cmp::Ordering::Less => { - let gas_used_delta = TARGET_BOOKING.saturating_sub(total_booked_gas); + let gas_used_delta = TARGET_BOOKING.saturating_sub(total_booked_gas_before); let factor = gas_used_delta as u64 / TARGET_BOOKING as u64 @@ -201,15 +203,15 @@ impl SpeculativeDeferredCallRegistry { .set_slot_base_fee(new_slot, new_slot_base_fee); // subtract the current slot gas from the total gas - - let total_gas = slot_calls - .effective_total_gas - .saturating_sub(slot_calls.effective_slot_gas.into()); - if !total_gas.eq(&self.get_effective_total_gas()) { + let total_gas_after = + total_booked_gas_before.saturating_sub(slot_calls.effective_slot_gas.into()); + if !total_gas_after.eq(&total_booked_gas_before) { self.deferred_calls_changes - .set_effective_total_gas(total_gas); + .set_effective_total_gas(total_gas_after); } + slot_calls.effective_total_gas = total_gas_after; + // delete the current slot for id in slot_calls.slot_calls.keys() { self.delete_call(id, current_slot); @@ -483,10 +485,10 @@ impl SpeculativeDeferredCallRegistry { ); // set total effective gas - self.deferred_calls_changes.set_effective_total_gas( - self.get_effective_total_gas() - .saturating_add(call.get_effective_gas(self.config.call_cst_gas_cost) as u128), - ); + let effective_total_gas = self.get_effective_total_gas(); + let call_effective_gas = call.get_effective_gas(self.config.call_cst_gas_cost) as u128; + self.deferred_calls_changes + .set_effective_total_gas(effective_total_gas.saturating_add(call_effective_gas)); Ok(id) } From 562c16fa487d719b888df4de2cfb376fd8c7544d Mon Sep 17 00:00:00 2001 From: modship Date: Wed, 18 Sep 2024 11:40:54 +0200 Subject: [PATCH 075/100] BugFix && add nb_call_registered --- Cargo.lock | 4 +- Cargo.toml | 2 +- massa-deferred-calls/Cargo.toml | 2 + massa-deferred-calls/src/lib.rs | 47 +++++++++-- massa-deferred-calls/src/macros.rs | 2 + massa-deferred-calls/src/registry_changes.rs | 78 +++++++++++++------ massa-execution-worker/src/context.rs | 2 +- massa-execution-worker/src/execution.rs | 15 ++-- .../src/speculative_deferred_calls.rs | 60 ++++++++++++-- .../src/tests/scenarios_mandatories.rs | 5 +- massa-final-state/src/state_changes.rs | 1 + massa-metrics/src/lib.rs | 22 ++++++ 12 files changed, 193 insertions(+), 47 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f03dcb61851..561d01d951a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2571,7 +2571,7 @@ dependencies = [ [[package]] name = "massa-sc-runtime" version = "0.10.0" -source = "git+https://github.com/massalabs/massa-sc-runtime?rev=48d42c58c3d46ba68426de0be5143fc3a17f5cc8#48d42c58c3d46ba68426de0be5143fc3a17f5cc8" +source = "git+https://github.com/massalabs/massa-sc-runtime?rev=b582bcd83120cfe980211ea7bcdaf994a784c714#b582bcd83120cfe980211ea7bcdaf994a784c714" dependencies = [ "anyhow", "as-ffi-bindings", @@ -2846,6 +2846,8 @@ dependencies = [ "nom", "parking_lot", "serde", + "serde_json", + "serde_with", "tempfile", ] diff --git a/Cargo.toml b/Cargo.toml index 03acefe3b55..a575055a05f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -108,7 +108,7 @@ massa_wallet = { path = "./massa-wallet" } # Massa projects dependencies massa-proto-rs = { git = "https://github.com/massalabs/massa-proto-rs", "rev" = "8eb7aa8384a407b588e190965c8e501cebdd38e3" } -massa-sc-runtime = { git = "https://github.com/massalabs/massa-sc-runtime", "rev" = "48d42c58c3d46ba68426de0be5143fc3a17f5cc8" } +massa-sc-runtime = { git = "https://github.com/massalabs/massa-sc-runtime", "rev" = "b582bcd83120cfe980211ea7bcdaf994a784c714" } peernet = { git = "https://github.com/massalabs/PeerNet", "rev" = "04b05ddd320fbe76cc858115af7b5fc28bdb8310" } diff --git a/massa-deferred-calls/Cargo.toml b/massa-deferred-calls/Cargo.toml index 10a8fe70fc6..36093eb7d4c 100644 --- a/massa-deferred-calls/Cargo.toml +++ b/massa-deferred-calls/Cargo.toml @@ -15,6 +15,8 @@ massa_db_exports = { workspace = true } massa_ledger_exports = { workspace = true } massa_models = { workspace = true } massa_serialization = { workspace = true } +serde_with = { workspace = true } +serde_json = { workspace = true } [dev-dependencies] tempfile = { workspace = true } diff --git a/massa-deferred-calls/src/lib.rs b/massa-deferred-calls/src/lib.rs index b50f70520c1..d6098aee8d9 100644 --- a/massa-deferred-calls/src/lib.rs +++ b/massa-deferred-calls/src/lib.rs @@ -1,6 +1,6 @@ use call::{DeferredCallDeserializer, DeferredCallSerializer}; use config::DeferredCallsConfig; -use macros::DEFERRED_CALL_TOTAL_GAS; +use macros::{DEFERRED_CALL_TOTAL_GAS, DEFERRED_CALL_TOTAL_REGISTERED}; use massa_db_exports::{ DBBatch, ShareableMassaDBController, CRUD_ERROR, DEFERRED_CALLS_PREFIX, DEFERRED_CALL_DESER_ERROR, DEFERRED_CALL_SER_ERROR, KEY_DESER_ERROR, STATE_CF, @@ -47,7 +47,8 @@ pub struct DeferredCallRegistry { impl DeferredCallRegistry { /* DB layout: - [DEFERRED_CALL_TOTAL_GAS] -> u64 // total currently booked gas + [DEFERRED_CALL_TOTAL_GAS] -> u128 // total currently booked gas + [DEFERRED_CALL_TOTAL_REGISTERED] -> u64 // total call registered [DEFERRED_CALLS_PREFIX][slot][SLOT_TOTAL_GAS] -> u64 // total gas booked for a slot (optional, default 0, deleted when set to 0) [DEFERRED_CALLS_PREFIX][slot][SLOT_BASE_FEE] -> u64 // deleted when set to 0 [DEFERRED_CALLS_PREFIX][slot][CALLS_TAG][id][CALL_FIELD_X_TAG] -> DeferredCalls.x // call data @@ -65,6 +66,24 @@ impl DeferredCallRegistry { } } + pub fn get_nb_call_registered(&self) -> u64 { + match self + .db + .read() + .get_cf(STATE_CF, DEFERRED_CALL_TOTAL_REGISTERED.as_bytes().to_vec()) + .expect(CRUD_ERROR) + { + Some(v) => { + self.registry_changes_deserializer + .u64_deserializer + .deserialize::(&v) + .expect(DEFERRED_CALL_DESER_ERROR) + .1 + } + None => 0, + } + } + /// Returns the DeferredSlotCalls for a given slot pub fn get_slot_calls(&self, slot: Slot) -> DeferredSlotCalls { let mut to_return = DeferredSlotCalls::new(slot); @@ -177,7 +196,10 @@ impl DeferredCallRegistry { .expect(DEFERRED_CALL_DESER_ERROR) .1; - result + match result { + DeferredRegistryGasChange::Set(v) => v, + DeferredRegistryGasChange::Keep => 0, + } } None => 0, } @@ -383,12 +405,27 @@ impl DeferredCallRegistry { } match changes.effective_total_gas { - DeferredRegistryGasChange::Set(v) => { + DeferredRegistryGasChange::Set(_) => { let key = DEFERRED_CALL_TOTAL_GAS.as_bytes().to_vec(); let mut value_ser = Vec::new(); self.registry_changes_serializer .effective_total_gas_serializer - .serialize(&v, &mut value_ser) + .serialize(&changes.effective_total_gas, &mut value_ser) + .expect(DEFERRED_CALL_SER_ERROR); + self.db + .read() + .put_or_update_entry_value(batch, key, &value_ser); + } + DeferredRegistryGasChange::Keep => {} + } + + match changes.total_calls_registered { + DeferredRegistryGasChange::Set(_) => { + let key = DEFERRED_CALL_TOTAL_REGISTERED.as_bytes().to_vec(); + let mut value_ser = Vec::new(); + self.registry_changes_serializer + .total_calls_registered_serializer + .serialize(&changes.total_calls_registered, &mut value_ser) .expect(DEFERRED_CALL_SER_ERROR); self.db .read() diff --git a/massa-deferred-calls/src/macros.rs b/massa-deferred-calls/src/macros.rs index f881e758f4a..93b902b9760 100644 --- a/massa-deferred-calls/src/macros.rs +++ b/massa-deferred-calls/src/macros.rs @@ -1,5 +1,7 @@ pub(crate) const DEFERRED_CALL_TOTAL_GAS: &str = "deferred_call_total_gas"; +pub(crate) const DEFERRED_CALL_TOTAL_REGISTERED: &str = "deferred_call_total_registered"; + pub(crate) const CALLS_TAG: u8 = 0u8; // slot fields pub(crate) const SLOT_TOTAL_GAS: u8 = 1u8; diff --git a/massa-deferred-calls/src/registry_changes.rs b/massa-deferred-calls/src/registry_changes.rs index a14e95aabde..c6475df304f 100644 --- a/massa-deferred-calls/src/registry_changes.rs +++ b/massa-deferred-calls/src/registry_changes.rs @@ -4,6 +4,7 @@ use massa_models::{ amount::Amount, deferred_calls::DeferredCallId, slot::{Slot, SlotDeserializer, SlotSerializer}, + types::{SetOrKeep, SetOrKeepDeserializer, SetOrKeepSerializer}, }; use massa_serialization::{ Deserializer, SerializeError, Serializer, U128VarIntDeserializer, U128VarIntSerializer, @@ -16,6 +17,7 @@ use nom::{ IResult, Parser, }; use serde::{Deserialize, Serialize}; +use serde_with::serde_as; use crate::{ config::DeferredCallsConfig, @@ -27,10 +29,14 @@ use crate::{ }; use std::ops::Bound::Included; +#[serde_as] #[derive(Debug, Clone, Serialize, Deserialize)] pub struct DeferredCallRegistryChanges { + #[serde_as(as = "Vec<(_, _)>")] pub slots_change: BTreeMap, + pub effective_total_gas: DeferredRegistryGasChange, + pub total_calls_registered: SetOrKeep, } impl Default for DeferredCallRegistryChanges { @@ -38,6 +44,7 @@ impl Default for DeferredCallRegistryChanges { Self { slots_change: Default::default(), effective_total_gas: DeferredRegistryGasChange::Keep, + total_calls_registered: SetOrKeep::Keep, } } } @@ -99,22 +106,35 @@ impl DeferredCallRegistryChanges { DeferredRegistryGasChange::Keep => None, } } + + pub fn set_total_calls_registered(&mut self, total_calls_registered: u64) { + self.total_calls_registered = SetOrKeep::Set(total_calls_registered); + } + + pub fn get_total_calls_registered(&self) -> Option { + match self.total_calls_registered { + SetOrKeep::Set(v) => Some(v), + SetOrKeep::Keep => None, + } + } } pub struct DeferredRegistryChangesSerializer { - slots_length: U64VarIntSerializer, + pub(crate) u64_serializer: U64VarIntSerializer, slot_changes_serializer: DeferredRegistrySlotChangesSerializer, slot_serializer: SlotSerializer, - pub(crate) effective_total_gas_serializer: U128VarIntSerializer, + pub(crate) effective_total_gas_serializer: SetOrKeepSerializer, + pub(crate) total_calls_registered_serializer: SetOrKeepSerializer, } impl DeferredRegistryChangesSerializer { pub fn new() -> Self { Self { - slots_length: U64VarIntSerializer::new(), + u64_serializer: U64VarIntSerializer::new(), slot_changes_serializer: DeferredRegistrySlotChangesSerializer::new(), slot_serializer: SlotSerializer::new(), - effective_total_gas_serializer: U128VarIntSerializer::new(), + effective_total_gas_serializer: SetOrKeepSerializer::new(U128VarIntSerializer::new()), + total_calls_registered_serializer: SetOrKeepSerializer::new(U64VarIntSerializer::new()), } } } @@ -131,7 +151,7 @@ impl Serializer for DeferredRegistryChangesSerializ value: &DeferredCallRegistryChanges, buffer: &mut Vec, ) -> Result<(), SerializeError> { - self.slots_length.serialize( + self.u64_serializer.serialize( &(value.slots_change.len().try_into().map_err(|_| { SerializeError::GeneralError("Fail to transform usize to u64".to_string()) })?), @@ -143,39 +163,40 @@ impl Serializer for DeferredRegistryChangesSerializ self.slot_changes_serializer.serialize(changes, buffer)?; } - match &value.effective_total_gas { - DeferredRegistryGasChange::Set(v) => { - self.effective_total_gas_serializer.serialize(v, buffer)?; - } - DeferredRegistryGasChange::Keep => {} - } + self.effective_total_gas_serializer + .serialize(&value.effective_total_gas, buffer)?; + + self.total_calls_registered_serializer + .serialize(&value.total_calls_registered, buffer)?; Ok(()) } } pub struct DeferredRegistryChangesDeserializer { - slots_length: U64VarIntDeserializer, + pub(crate) u64_deserializer: U64VarIntDeserializer, slot_changes_deserializer: DeferredRegistrySlotChangesDeserializer, slot_deserializer: SlotDeserializer, - pub(crate) effective_total_gas_deserializer: U128VarIntDeserializer, + pub(crate) effective_total_gas_deserializer: + SetOrKeepDeserializer, + pub(crate) total_calls_registered_deserializer: + SetOrKeepDeserializer, } impl DeferredRegistryChangesDeserializer { pub fn new(config: DeferredCallsConfig) -> Self { Self { - slots_length: U64VarIntDeserializer::new( - Included(u64::MIN), - Included(config.max_pool_changes), - ), + u64_deserializer: U64VarIntDeserializer::new(Included(u64::MIN), Included(u64::MAX)), slot_changes_deserializer: DeferredRegistrySlotChangesDeserializer::new(config), slot_deserializer: SlotDeserializer::new( (Bound::Included(0), Bound::Included(u64::MAX)), (Bound::Included(0), Bound::Excluded(config.thread_count)), ), - effective_total_gas_deserializer: U128VarIntDeserializer::new( - Included(u128::MIN), - Included(u128::MAX), + effective_total_gas_deserializer: SetOrKeepDeserializer::new( + U128VarIntDeserializer::new(Included(u128::MIN), Included(u128::MAX)), + ), + total_calls_registered_deserializer: SetOrKeepDeserializer::new( + U64VarIntDeserializer::new(Included(u64::MIN), Included(u64::MAX)), ), } } @@ -191,7 +212,7 @@ impl Deserializer for DeferredRegistryChangesDeseri tuple(( length_count( context("Failed length deserialization", |input| { - self.slots_length.deserialize(input) + self.u64_deserializer.deserialize(input) }), |input| { tuple(( @@ -208,12 +229,18 @@ impl Deserializer for DeferredRegistryChangesDeseri context("Failed total_gas deserialization", |input| { self.effective_total_gas_deserializer.deserialize(input) }), + context("Failed total call registered deserialization", |input| { + self.total_calls_registered_deserializer.deserialize(input) + }), )), ) - .map(|(changes, total_gas)| DeferredCallRegistryChanges { - slots_change: changes.into_iter().collect::>(), - effective_total_gas: massa_models::types::SetOrKeep::Set(total_gas), - }) + .map( + |(changes, total_gas, total_calls_registered)| DeferredCallRegistryChanges { + slots_change: changes.into_iter().collect::>(), + effective_total_gas: total_gas, + total_calls_registered, + }, + ) .parse(buffer) } } @@ -244,6 +271,7 @@ mod tests { let mut changes = DeferredCallRegistryChanges { slots_change: BTreeMap::new(), effective_total_gas: Default::default(), + total_calls_registered: Default::default(), }; let mut registry_slot_changes = DeferredRegistrySlotChanges::default(); diff --git a/massa-execution-worker/src/context.rs b/massa-execution-worker/src/context.rs index 41dba9c2db5..e55e0b07a04 100644 --- a/massa-execution-worker/src/context.rs +++ b/massa-execution-worker/src/context.rs @@ -1165,7 +1165,7 @@ impl ExecutionContext { /// If it has been cancelled, return false pub fn deferred_call_exists(&self, call_id: &DeferredCallId) -> bool { if let Some(call) = self.speculative_deferred_calls.get_call(call_id) { - return call.cancelled; + return !call.cancelled; } false } diff --git a/massa-execution-worker/src/execution.rs b/massa-execution-worker/src/execution.rs index b05076a07de..7a784233657 100644 --- a/massa-execution-worker/src/execution.rs +++ b/massa-execution-worker/src/execution.rs @@ -1232,12 +1232,10 @@ impl ExecutionState { ) -> Result { let mut result = DeferredCallExecutionResult::new(&call); - let snapshot; - - { + let snapshot = { let context = context_guard!(self); - snapshot = context.get_snapshot(); - } + context.get_snapshot() + }; let deferred_call_execution = || { let bytecode = { @@ -1345,6 +1343,9 @@ impl ExecutionState { let mut context = context_guard!(self); context.reset_to_snapshot(snapshot, err.clone()); context.deferred_call_fail_exec(id, &call); + self.massa_metrics.inc_deferred_calls_failed(); + } else { + self.massa_metrics.inc_deferred_calls_executed(); } execution_result @@ -1406,7 +1407,6 @@ impl ExecutionState { match self.execute_deferred_call(&id, call) { Ok(_exec) => { info!("executed deferred call: {:?}", id); - self.massa_metrics.inc_deferred_calls_executed(); cfg_if::cfg_if! { if #[cfg(feature = "execution-trace")] { // Safe to unwrap @@ -1419,10 +1419,9 @@ impl ExecutionState { } Err(err) => { let msg = format!("failed executing deferred call: {}", err); - self.massa_metrics.inc_deferred_calls_failed(); #[cfg(feature = "execution-info")] exec_info.deferred_calls_messages.push(Err(msg.clone())); - debug!(msg); + dbg!(msg); } } } diff --git a/massa-execution-worker/src/speculative_deferred_calls.rs b/massa-execution-worker/src/speculative_deferred_calls.rs index 9f4722dae9d..b41124a0e03 100644 --- a/massa-execution-worker/src/speculative_deferred_calls.rs +++ b/massa-execution-worker/src/speculative_deferred_calls.rs @@ -56,6 +56,31 @@ impl SpeculativeDeferredCallRegistry { self.deferred_calls_changes.set_call(id, call); } + pub fn get_total_calls_registered(&self) -> u64 { + if let Some(v) = self.deferred_calls_changes.get_total_calls_registered() { + return v; + } + + { + let history = self.active_history.read(); + for history_item in history.0.iter().rev() { + if let Some(v) = history_item + .state_changes + .deferred_call_changes + .get_total_calls_registered() + { + return v; + } + } + } + + return self + .final_state + .read() + .get_deferred_call_registry() + .get_nb_call_registered(); + } + pub fn get_effective_total_gas(&self) -> u128 { // get total gas from current changes if let Some(v) = self.deferred_calls_changes.get_effective_total_gas() { @@ -143,8 +168,6 @@ impl SpeculativeDeferredCallRegistry { /// Consumes and deletes the current slot, prepares a new slot in the future /// and returns the calls that need to be executed in the current slot pub fn advance_slot(&mut self, current_slot: Slot) -> DeferredSlotCalls { - let total_booked_gas_before = self.get_effective_total_gas(); - // get the state of the current slot let mut slot_calls: DeferredSlotCalls = self .final_state @@ -155,6 +178,7 @@ impl SpeculativeDeferredCallRegistry { slot_calls.apply_changes(&hist_item.state_changes.deferred_call_changes); } slot_calls.apply_changes(&self.deferred_calls_changes); + let total_booked_gas_before = self.get_effective_total_gas(); let avg_booked_gas = total_booked_gas_before.saturating_div(self.config.max_future_slots as u128); @@ -203,6 +227,7 @@ impl SpeculativeDeferredCallRegistry { .set_slot_base_fee(new_slot, new_slot_base_fee); // subtract the current slot gas from the total gas + // cancelled call gas is already decremented from the effective slot gas let total_gas_after = total_booked_gas_before.saturating_sub(slot_calls.effective_slot_gas.into()); if !total_gas_after.eq(&total_booked_gas_before) { @@ -212,11 +237,22 @@ impl SpeculativeDeferredCallRegistry { slot_calls.effective_total_gas = total_gas_after; - // delete the current slot - for id in slot_calls.slot_calls.keys() { + // delete call in the current slot + let mut nb_call_to_execute = 0; + for (id, call) in &slot_calls.slot_calls { + // cancelled call is already decremented from the total calls registered + if !call.cancelled { + nb_call_to_execute += 1; + } self.delete_call(id, current_slot); } + if nb_call_to_execute > 0 { + let total_calls_registered = self.get_total_calls_registered(); + let new_call_registered = total_calls_registered.saturating_sub(nb_call_to_execute); + self.set_total_calls_registered(new_call_registered); + } + slot_calls } @@ -302,12 +338,16 @@ impl SpeculativeDeferredCallRegistry { current_gas.saturating_sub(call.get_effective_gas(self.config.call_cst_gas_cost)), ); + let effective_gas_call = call.get_effective_gas(self.config.call_cst_gas_cost) as u128; // set total gas self.deferred_calls_changes.set_effective_total_gas( self.get_effective_total_gas() - .saturating_sub(call.get_effective_gas(self.config.call_cst_gas_cost) as u128), + .saturating_sub(effective_gas_call), ); + let new_total_calls_registered = self.get_total_calls_registered().saturating_sub(1); + self.set_total_calls_registered(new_total_calls_registered); + Ok(res) } @@ -490,6 +530,10 @@ impl SpeculativeDeferredCallRegistry { self.deferred_calls_changes .set_effective_total_gas(effective_total_gas.saturating_add(call_effective_gas)); + // increment total calls registered + let new_total_calls_registered = self.get_total_calls_registered().saturating_add(1); + self.set_total_calls_registered(new_total_calls_registered); + Ok(id) } @@ -497,6 +541,12 @@ impl SpeculativeDeferredCallRegistry { pub(crate) fn take(&mut self) -> DeferredCallRegistryChanges { std::mem::take(&mut self.deferred_calls_changes) } + + fn set_total_calls_registered(&mut self, nb_calls: u64) { + massa_metrics::set_deferred_calls_registered(nb_calls as usize); + self.deferred_calls_changes + .set_total_calls_registered(nb_calls); + } } #[cfg(test)] diff --git a/massa-execution-worker/src/tests/scenarios_mandatories.rs b/massa-execution-worker/src/tests/scenarios_mandatories.rs index 6f6880df074..a9ed9767f93 100644 --- a/massa-execution-worker/src/tests/scenarios_mandatories.rs +++ b/massa-execution-worker/src/tests/scenarios_mandatories.rs @@ -1127,6 +1127,7 @@ fn deferred_calls() { DeferredCallRegistryChanges { slots_change: slot_changes, effective_total_gas: SetOrKeep::Set(call.max_gas.saturating_add(call2.max_gas).into()), + total_calls_registered: SetOrKeep::Set(2), }, &mut db_batch, ); @@ -1339,6 +1340,7 @@ fn deferred_call_register() { DeferredCallRegistryChanges { slots_change: slot_changes, effective_total_gas: SetOrKeep::Keep, + total_calls_registered: SetOrKeep::Set(0), }, &mut db_batch, ); @@ -1483,6 +1485,7 @@ fn deferred_call_register_fail() { DeferredCallRegistryChanges { slots_change: slot_changes, effective_total_gas: SetOrKeep::Set(2000), + total_calls_registered: SetOrKeep::Set(1), }, &mut db_batch, ); @@ -1533,7 +1536,7 @@ fn deferred_call_register_fail() { let ev = events[1].clone(); assert!(ev.context.is_error); - assert!(ev.data.contains("The ASC 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")); + assert!(ev.data.contains("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")); // // update base fee at slot 1,10 // defer_reg_slot_changes.set_base_fee(Amount::from_str("0.0005").unwrap()); diff --git a/massa-final-state/src/state_changes.rs b/massa-final-state/src/state_changes.rs index 0eadde9c352..34211a5c3a0 100644 --- a/massa-final-state/src/state_changes.rs +++ b/massa-final-state/src/state_changes.rs @@ -233,6 +233,7 @@ impl Deserializer for StateChangesDeserializer { impl StateChanges { /// extends the current `StateChanges` with another one pub fn apply(&mut self, changes: StateChanges) { + // TODO deferred_call_changes ? use massa_models::types::Applicable; self.ledger_changes.apply(changes.ledger_changes); self.async_pool_changes.apply(changes.async_pool_changes); diff --git a/massa-metrics/src/lib.rs b/massa-metrics/src/lib.rs index 19daa4e3283..1d803bbcfe7 100644 --- a/massa-metrics/src/lib.rs +++ b/massa-metrics/src/lib.rs @@ -30,6 +30,26 @@ lazy_static! { register_int_gauge!("blocks_storage_counter", "blocks storage counter len").unwrap(); static ref ENDORSEMENTS_COUNTER: IntGauge = register_int_gauge!("endorsements_storage_counter", "endorsements storage counter len").unwrap(); + + static ref DEFERRED_CALL_REGISTERED: IntGauge = register_int_gauge!( + "deferred_calls_registered", "number of deferred calls registered" ).unwrap(); + +} + +pub fn dec_deferred_calls_registered() { + DEFERRED_CALL_REGISTERED.dec(); +} + +pub fn inc_deferred_calls_registered() { + DEFERRED_CALL_REGISTERED.inc(); +} + +pub fn set_deferred_calls_registered(val: usize) { + DEFERRED_CALL_REGISTERED.set(val as i64); +} + +pub fn get_deferred_calls_registered() -> i64 { + DEFERRED_CALL_REGISTERED.get() } pub fn set_blocks_counter(val: usize) { @@ -204,6 +224,8 @@ impl MassaMetrics { consensus_vec.push(gauge); } + set_deferred_calls_registered(0); + // set available processors let process_available_processors = IntGauge::new("process_available_processors", "number of processors") From 9583fc7cb211ff59992ec34c8ac4c82fe2c32ec1 Mon Sep 17 00:00:00 2001 From: modship Date: Fri, 20 Sep 2024 16:27:41 +0200 Subject: [PATCH 076/100] API : Jsonrpc DeferredCallQuote --- Cargo.lock | 1 + massa-api-exports/Cargo.toml | 1 + massa-api-exports/src/config.rs | 3 ++ massa-api-exports/src/execution.rs | 22 +++++++++ massa-api/src/lib.rs | 9 +++- massa-api/src/private.rs | 12 ++++- massa-api/src/public.rs | 50 ++++++++++++++++++++- massa-deferred-calls/src/config.rs | 3 +- massa-execution-exports/src/mapping_grpc.rs | 1 + massa-execution-exports/src/types.rs | 6 +++ massa-execution-worker/src/controller.rs | 10 +++++ massa-execution-worker/src/execution.rs | 15 +++++++ massa-node/src/main.rs | 1 + 13 files changed, 130 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 561d01d951a..9d183c8e4bd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2648,6 +2648,7 @@ version = "2.2.0" dependencies = [ "displaydoc", "jsonrpsee", + "massa_deferred_calls", "massa_final_state", "massa_hash", "massa_models", diff --git a/massa-api-exports/Cargo.toml b/massa-api-exports/Cargo.toml index e042ead5ebb..281ca989ffa 100644 --- a/massa-api-exports/Cargo.toml +++ b/massa-api-exports/Cargo.toml @@ -22,6 +22,7 @@ massa_final_state = {workspace = true} massa_hash = {workspace = true} massa_wallet = {workspace = true} massa_versioning = {workspace = true} +massa_deferred_calls = { workspace = true } [dev-dependencies] serial_test = {workspace = true} diff --git a/massa-api-exports/src/config.rs b/massa-api-exports/src/config.rs index 6ec7e31abc3..7412d3e4af9 100644 --- a/massa-api-exports/src/config.rs +++ b/massa-api-exports/src/config.rs @@ -1,5 +1,6 @@ // Copyright (c) 2022 MASSA LABS +use massa_deferred_calls::config::DeferredCallsConfig; use massa_models::amount::Amount; use massa_signature::KeyPair; use massa_time::MassaTime; @@ -84,4 +85,6 @@ pub struct APIConfig { pub deferred_credits_delta: MassaTime, /// minimal fees to include an operation in a block pub minimal_fees: Amount, + /// deferred calls config + pub deferred_calls_config: DeferredCallsConfig, } diff --git a/massa-api-exports/src/execution.rs b/massa-api-exports/src/execution.rs index c90cc7eb538..e2d857d2520 100644 --- a/massa-api-exports/src/execution.rs +++ b/massa-api-exports/src/execution.rs @@ -121,3 +121,25 @@ pub struct Transfer { /// Context pub context: TransferContext, } + +/// request for deferred call quote +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct DeferredCallQuoteRequest { + /// The slot at which the deferred call is to be executed. + pub target_slot: Slot, + /// The maximum gas requested. + pub max_gas_request: u64, +} + +/// The response to a request for a deferred call quote. +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct DeferredCallQuoteResponse { + /// The slot at which the deferred call is to be executed. + pub target_slot: Slot, + /// The maximum gas requested. + pub max_gas_request: u64, + /// if the slot is bookable + pub available: bool, + /// the cost for booking the call + pub price: u64, +} diff --git a/massa-api/src/lib.rs b/massa-api/src/lib.rs index 8055167d489..5900e223d8e 100644 --- a/massa-api/src/lib.rs +++ b/massa-api/src/lib.rs @@ -11,7 +11,7 @@ use jsonrpsee::proc_macros::rpc; use jsonrpsee::server::middleware::HostFilterLayer; use jsonrpsee::server::{BatchRequestConfig, ServerBuilder, ServerHandle}; use jsonrpsee::RpcModule; -use massa_api_exports::execution::Transfer; +use massa_api_exports::execution::{DeferredCallQuoteRequest, DeferredCallQuoteResponse, Transfer}; use massa_api_exports::{ address::{AddressFilter, AddressInfo}, block::{BlockInfo, BlockSummary}, @@ -400,6 +400,13 @@ pub trait MassaRpc { /// Get OpenRPC specification. #[method(name = "rpc.discover")] async fn get_openrpc_spec(&self) -> RpcResult; + + /// DeferredCall quote + #[method(name = "get_deferred_call_quote")] + async fn get_deferred_call_quote( + &self, + arg: Vec, + ) -> RpcResult>; } fn wrong_api() -> RpcResult { diff --git a/massa-api/src/private.rs b/massa-api/src/private.rs index a22adc3f7c4..32977a21d6d 100644 --- a/massa-api/src/private.rs +++ b/massa-api/src/private.rs @@ -11,7 +11,10 @@ use massa_api_exports::{ datastore::{DatastoreEntryInput, DatastoreEntryOutput}, endorsement::EndorsementInfo, error::ApiError, - execution::{ExecuteReadOnlyResponse, ReadOnlyBytecodeExecution, ReadOnlyCall, Transfer}, + execution::{ + DeferredCallQuoteRequest, DeferredCallQuoteResponse, ExecuteReadOnlyResponse, + ReadOnlyBytecodeExecution, ReadOnlyCall, Transfer, + }, node::NodeStatus, operation::{OperationInfo, OperationInput}, page::{PageRequest, PagedVec}, @@ -351,6 +354,13 @@ impl MassaRpcServer for API { ) } + async fn get_deferred_call_quote( + &self, + _req: Vec, + ) -> RpcResult> { + crate::wrong_api::>() + } + async fn get_openrpc_spec(&self) -> RpcResult { crate::wrong_api::() } diff --git a/massa-api/src/public.rs b/massa-api/src/public.rs index 12fb80efada..37cd74302e6 100644 --- a/massa-api/src/public.rs +++ b/massa-api/src/public.rs @@ -13,7 +13,8 @@ use massa_api_exports::{ endorsement::EndorsementInfo, error::ApiError, execution::{ - ExecuteReadOnlyResponse, ReadOnlyBytecodeExecution, ReadOnlyCall, ReadOnlyResult, Transfer, + DeferredCallQuoteRequest, DeferredCallQuoteResponse, ExecuteReadOnlyResponse, + ReadOnlyBytecodeExecution, ReadOnlyCall, ReadOnlyResult, Transfer, }, node::NodeStatus, operation::{OperationInfo, OperationInput}, @@ -1157,6 +1158,53 @@ impl MassaRpcServer for API { Ok(res?) } + async fn get_deferred_call_quote( + &self, + req: Vec, + ) -> RpcResult> { + let queries: Vec = req + .into_iter() + .map(|call| { + // add the gas cost of vm allocation + let effective_gas_request = call + .max_gas_request + .saturating_add(self.0.api_settings.deferred_calls_config.call_cst_gas_cost); + ExecutionQueryRequestItem::DeferredCallQuote( + call.target_slot, + effective_gas_request, + ) + }) + .collect(); + + let result = self + .0 + .execution_controller + .query_state(ExecutionQueryRequest { requests: queries }) + .responses + .into_iter() + .map(|response| match response { + Ok(ExecutionQueryResponseItem::DeferredCallQuote( + target_slot, + max_gas_request, + available, + price, + )) => Ok(DeferredCallQuoteResponse { + target_slot, + max_gas_request, + available, + price, + }), + + Ok(_) => Err(ApiError::InternalServerError( + "unexpected response type".to_string(), + )), + Err(err) => Err(ApiError::InternalServerError(err.to_string())), + }) + .collect::, ApiError>>()?; + + Ok(result) + } + /// send operations async fn send_operations(&self, ops: Vec) -> RpcResult> { let mut cmd_sender = self.0.pool_command_sender.clone(); diff --git a/massa-deferred-calls/src/config.rs b/massa-deferred-calls/src/config.rs index e654f8d3180..e0e4f1b8ef2 100644 --- a/massa-deferred-calls/src/config.rs +++ b/massa-deferred-calls/src/config.rs @@ -8,8 +8,9 @@ use massa_models::{ MAX_FUNCTION_NAME_LENGTH, MAX_PARAMETERS_SIZE, THREAD_COUNT, }, }; +use serde::Deserialize; -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, Deserialize)] pub struct DeferredCallsConfig { /// thread count pub thread_count: u8, diff --git a/massa-execution-exports/src/mapping_grpc.rs b/massa-execution-exports/src/mapping_grpc.rs index 828e226a0c8..c3f7fefb1d8 100644 --- a/massa-execution-exports/src/mapping_grpc.rs +++ b/massa-execution-exports/src/mapping_grpc.rs @@ -265,6 +265,7 @@ fn to_execution_query_result( }, ) } + ExecutionQueryResponseItem::DeferredCallQuote(_, _, _, _) => todo!(), }; grpc_api::ExecutionQueryResponseItem { diff --git a/massa-execution-exports/src/types.rs b/massa-execution-exports/src/types.rs index dee597eb67d..085f28cb48c 100644 --- a/massa-execution-exports/src/types.rs +++ b/massa-execution-exports/src/types.rs @@ -99,6 +99,10 @@ pub enum ExecutionQueryRequestItem { OpExecutionStatusCandidate(OperationId), /// gets the execution status (final) for an operation, returns ExecutionQueryResponseItem::ExecutionStatus(status) OpExecutionStatusFinal(OperationId), + + /// gets the deferred call quote (candidate) for a slot, returns ExecutionQueryResponseItem::DeferredCallQuote(available, price) + DeferredCallQuote(Slot, u64), + /// gets the execution status (candidate) for an denunciation, returns ExecutionQueryResponseItem::ExecutionStatus(status) DenunciationExecutionStatusCandidate(DenunciationIndex), /// gets the execution status (final) for an denunciation, returns ExecutionQueryResponseItem::ExecutionStatus(status) @@ -139,6 +143,8 @@ pub enum ExecutionQueryResponseItem { DatastoreValue(Vec), /// list of keys KeyList(BTreeSet>), + /// deferred call quote (target_slot, gas_request, available, price) + DeferredCallQuote(Slot, u64, bool, u64), /// deferred credits value DeferredCredits(BTreeMap), /// execution status value diff --git a/massa-execution-worker/src/controller.rs b/massa-execution-worker/src/controller.rs index 1bd253f4d8a..7fca7d1e168 100644 --- a/massa-execution-worker/src/controller.rs +++ b/massa-execution-worker/src/controller.rs @@ -331,6 +331,16 @@ impl ExecutionController for ExecutionControllerImpl { execution_lock.get_filtered_sc_output_event(filter), )) } + ExecutionQueryRequestItem::DeferredCallQuote(slot, max_request_gas) => { + let (target_slot, gas_request, available, price) = + execution_lock.deferred_call_quote(slot, max_request_gas); + Ok(ExecutionQueryResponseItem::DeferredCallQuote( + target_slot, + gas_request, + available, + price, + )) + } }; resp.responses.push(resp_item); } diff --git a/massa-execution-worker/src/execution.rs b/massa-execution-worker/src/execution.rs index 7a784233657..fcd64ea24fc 100644 --- a/massa-execution-worker/src/execution.rs +++ b/massa-execution-worker/src/execution.rs @@ -2437,4 +2437,19 @@ impl ExecutionState { .map(|i| (i.current_version, i.announced_version)), ); } + + pub fn deferred_call_quote( + &self, + target_slot: Slot, + max_request_gas: u64, + ) -> (Slot, u64, bool, u64) { + 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) { + Ok(fee) => (target_slot, gas_request, true, fee.to_raw()), + Err(_) => (target_slot, gas_request, false, 0), + } + } } diff --git a/massa-node/src/main.rs b/massa-node/src/main.rs index 0aa1221c549..4424cf21e57 100644 --- a/massa-node/src/main.rs +++ b/massa-node/src/main.rs @@ -900,6 +900,7 @@ async fn launch( chain_id: *CHAINID, deferred_credits_delta: SETTINGS.api.deferred_credits_delta, minimal_fees: SETTINGS.pool.minimal_fees, + deferred_calls_config, }; // spawn Massa API From 341db029509a6f5391dece15d127c88394f3dcc0 Mon Sep 17 00:00:00 2001 From: modship Date: Mon, 23 Sep 2024 17:42:32 +0200 Subject: [PATCH 077/100] API : JsonRpc get_deferred_call_info && list_deferred_calls_by_slot --- massa-api-exports/src/execution.rs | 23 +++- massa-api/src/lib.rs | 23 +++- massa-api/src/private.rs | 24 +++- massa-api/src/public.rs | 117 +++++++++++++++--- massa-api/src/tests/mock.rs | 2 + massa-execution-exports/src/mapping_grpc.rs | 4 + massa-execution-exports/src/types.rs | 10 ++ massa-execution-worker/src/context.rs | 12 ++ massa-execution-worker/src/controller.rs | 15 +++ massa-execution-worker/src/execution.rs | 9 ++ .../src/speculative_deferred_calls.rs | 23 ++-- 11 files changed, 229 insertions(+), 33 deletions(-) diff --git a/massa-api-exports/src/execution.rs b/massa-api-exports/src/execution.rs index e2d857d2520..909573fcb77 100644 --- a/massa-api-exports/src/execution.rs +++ b/massa-api-exports/src/execution.rs @@ -1,5 +1,6 @@ // Copyright (c) 2022 MASSA LABS +use massa_deferred_calls::DeferredCall; use massa_final_state::StateChanges; use massa_models::{ address::Address, amount::Amount, block_id::BlockId, operation::OperationId, @@ -124,7 +125,7 @@ pub struct Transfer { /// request for deferred call quote #[derive(Clone, Debug, Deserialize, Serialize)] -pub struct DeferredCallQuoteRequest { +pub struct DeferredCallsQuoteRequest { /// The slot at which the deferred call is to be executed. pub target_slot: Slot, /// The maximum gas requested. @@ -133,7 +134,7 @@ pub struct DeferredCallQuoteRequest { /// The response to a request for a deferred call quote. #[derive(Clone, Debug, Deserialize, Serialize)] -pub struct DeferredCallQuoteResponse { +pub struct DeferredCallsQuoteResponse { /// The slot at which the deferred call is to be executed. pub target_slot: Slot, /// The maximum gas requested. @@ -143,3 +144,21 @@ pub struct DeferredCallQuoteResponse { /// the cost for booking the call pub price: u64, } + +/// response for deferred call +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct DeferredCallResponse { + /// deferred call id + pub call_id: String, + /// deferred call + pub call: DeferredCall, +} + +/// response for deferred calls by slot +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct DeferredCallsSlotResponse { + /// deferred calls + pub slot: Slot, + /// deferred calls + pub calls: Vec, +} diff --git a/massa-api/src/lib.rs b/massa-api/src/lib.rs index 5900e223d8e..0ec5c5bcddd 100644 --- a/massa-api/src/lib.rs +++ b/massa-api/src/lib.rs @@ -11,7 +11,10 @@ use jsonrpsee::proc_macros::rpc; use jsonrpsee::server::middleware::HostFilterLayer; use jsonrpsee::server::{BatchRequestConfig, ServerBuilder, ServerHandle}; use jsonrpsee::RpcModule; -use massa_api_exports::execution::{DeferredCallQuoteRequest, DeferredCallQuoteResponse, Transfer}; +use massa_api_exports::execution::{ + DeferredCallResponse, DeferredCallsQuoteRequest, DeferredCallsQuoteResponse, + DeferredCallsSlotResponse, Transfer, +}; use massa_api_exports::{ address::{AddressFilter, AddressInfo}, block::{BlockInfo, BlockSummary}, @@ -405,8 +408,22 @@ pub trait MassaRpc { #[method(name = "get_deferred_call_quote")] async fn get_deferred_call_quote( &self, - arg: Vec, - ) -> RpcResult>; + arg: Vec, + ) -> RpcResult>; + + /// DeferredCall get info + #[method(name = "get_deferred_call_info")] + async fn get_deferred_call_info( + &self, + arg: Vec, + ) -> RpcResult>; + + /// List deferred calls for given slot + #[method(name = "list_deferred_calls_by_slot")] + async fn list_deferred_calls_by_slot( + &self, + arg: Vec, + ) -> RpcResult>; } fn wrong_api() -> RpcResult { diff --git a/massa-api/src/private.rs b/massa-api/src/private.rs index 32977a21d6d..3f813da48bc 100644 --- a/massa-api/src/private.rs +++ b/massa-api/src/private.rs @@ -12,8 +12,9 @@ use massa_api_exports::{ endorsement::EndorsementInfo, error::ApiError, execution::{ - DeferredCallQuoteRequest, DeferredCallQuoteResponse, ExecuteReadOnlyResponse, - ReadOnlyBytecodeExecution, ReadOnlyCall, Transfer, + DeferredCallResponse, DeferredCallsQuoteRequest, DeferredCallsQuoteResponse, + DeferredCallsSlotResponse, ExecuteReadOnlyResponse, ReadOnlyBytecodeExecution, + ReadOnlyCall, Transfer, }, node::NodeStatus, operation::{OperationInfo, OperationInput}, @@ -356,9 +357,22 @@ impl MassaRpcServer for API { async fn get_deferred_call_quote( &self, - _req: Vec, - ) -> RpcResult> { - crate::wrong_api::>() + _req: Vec, + ) -> RpcResult> { + crate::wrong_api::>() + } + async fn get_deferred_call_info( + &self, + _arg: Vec, + ) -> RpcResult> { + crate::wrong_api::>() + } + + async fn list_deferred_calls_by_slot( + &self, + _slot: Vec, + ) -> RpcResult> { + crate::wrong_api::>() } async fn get_openrpc_spec(&self) -> RpcResult { diff --git a/massa-api/src/public.rs b/massa-api/src/public.rs index 37cd74302e6..8080d60d949 100644 --- a/massa-api/src/public.rs +++ b/massa-api/src/public.rs @@ -13,8 +13,9 @@ use massa_api_exports::{ endorsement::EndorsementInfo, error::ApiError, execution::{ - DeferredCallQuoteRequest, DeferredCallQuoteResponse, ExecuteReadOnlyResponse, - ReadOnlyBytecodeExecution, ReadOnlyCall, ReadOnlyResult, Transfer, + DeferredCallResponse, DeferredCallsQuoteRequest, DeferredCallsQuoteResponse, + DeferredCallsSlotResponse, ExecuteReadOnlyResponse, ReadOnlyBytecodeExecution, + ReadOnlyCall, ReadOnlyResult, Transfer, }, node::NodeStatus, operation::{OperationInfo, OperationInput}, @@ -38,20 +39,17 @@ use massa_models::{ composite::PubkeySig, config::CompactConfig, datastore::DatastoreDeserializer, - endorsement::EndorsementId, - endorsement::SecureShareEndorsement, + deferred_calls::DeferredCallId, + endorsement::{EndorsementId, SecureShareEndorsement}, error::ModelsError, execution::EventFilter, node::NodeId, - operation::OperationDeserializer, - operation::OperationId, - operation::{OperationType, SecureShareOperation}, + operation::{OperationDeserializer, OperationId, OperationType, SecureShareOperation}, output_event::SCOutputEvent, prehash::{PreHashMap, PreHashSet}, secure_share::SecureShareDeserializer, slot::{IndexedSlot, Slot}, - timeslots, - timeslots::{get_latest_block_slot_at_timestamp, time_range_to_slot_range}, + timeslots::{self, get_latest_block_slot_at_timestamp, time_range_to_slot_range}, version::Version, }; use massa_pool_exports::PoolController; @@ -64,8 +62,8 @@ use massa_versioning::versioning_factory::FactoryStrategy; use massa_versioning::{ keypair_factory::KeyPairFactory, versioning::MipStore, versioning_factory::VersioningFactory, }; -use std::collections::BTreeMap; use std::net::{IpAddr, SocketAddr}; +use std::{collections::BTreeMap, str::FromStr}; impl API { /// generate a new public API @@ -1160,8 +1158,9 @@ impl MassaRpcServer for API { async fn get_deferred_call_quote( &self, - req: Vec, - ) -> RpcResult> { + req: Vec, + ) -> RpcResult> { + // TODO limit let queries: Vec = req .into_iter() .map(|call| { @@ -1188,7 +1187,7 @@ impl MassaRpcServer for API { max_gas_request, available, price, - )) => Ok(DeferredCallQuoteResponse { + )) => Ok(DeferredCallsQuoteResponse { target_slot, max_gas_request, available, @@ -1200,11 +1199,101 @@ impl MassaRpcServer for API { )), Err(err) => Err(ApiError::InternalServerError(err.to_string())), }) - .collect::, ApiError>>()?; + .collect::, ApiError>>()?; Ok(result) } + async fn get_deferred_call_info( + &self, + arg: Vec, + ) -> RpcResult> { + // TODO limit + // if id_str.len() > self.0.api_settings.max_deferred_call_id_length as usize { + // return Err(ApiError::BadRequest(format!( + // "deferred call id too long: {}", + // id_str + // )) + // .into()); + // } + + let requests: Vec = arg + .into_iter() + .map(|id_str| { + DeferredCallId::from_str(&id_str) + .map_err(|e| ApiError::BadRequest(e.to_string())) + .map(ExecutionQueryRequestItem::DeferredCallInfo) + }) + .collect::>()?; + + let result: Vec = self + .0 + .execution_controller + .query_state(ExecutionQueryRequest { requests }) + .responses + .into_iter() + .map(|exec| match exec { + Ok(ExecutionQueryResponseItem::DeferredCallInfo(id, call)) => { + Ok(DeferredCallResponse { + call_id: id.to_string(), + call, + }) + } + Ok(_) => Err(ApiError::InternalServerError( + "unexpected response type".to_string(), + )), + Err(err) => Err(ApiError::InternalServerError(err.to_string())), + }) + .collect::>()?; + + Ok(result) + } + + async fn list_deferred_calls_by_slot( + &self, + slots: Vec, + ) -> RpcResult> { + // TODO limit slot count + + let requests: Vec = slots + .into_iter() + .map(ExecutionQueryRequestItem::DeferredCallSlotCalls) + .collect(); + + let mut slot_calls = Vec::new(); + + for exec in self + .0 + .execution_controller + .query_state(ExecutionQueryRequest { requests }) + .responses + .into_iter() + { + match exec { + Ok(ExecutionQueryResponseItem::DeferredCallSlotCalls(slot, result)) => { + let calls = result + .into_iter() + .map(|(id, call)| DeferredCallResponse { + call_id: id.to_string(), + call, + }) + .collect(); + + slot_calls.push(DeferredCallsSlotResponse { slot, calls }); + } + Ok(_) => { + return Err(ApiError::InternalServerError( + "unexpected response type".to_string(), + ) + .into()) + } + Err(err) => return Err(ApiError::InternalServerError(err.to_string()).into()), + } + } + + Ok(slot_calls) + } + /// send operations async fn send_operations(&self, ops: Vec) -> RpcResult> { let mut cmd_sender = self.0.pool_command_sender.clone(); diff --git a/massa-api/src/tests/mock.rs b/massa-api/src/tests/mock.rs index 735da5266b9..9f1f714d215 100644 --- a/massa-api/src/tests/mock.rs +++ b/massa-api/src/tests/mock.rs @@ -70,6 +70,7 @@ pub(crate) fn get_apiv2_server(addr: &SocketAddr) -> (API, APIConfig) { chain_id: *CHAINID, deferred_credits_delta: MassaTime::from_millis(24 * 3600 * 2), minimal_fees: Amount::zero(), + deferred_calls_config: Default::default(), }; // let shared_storage: massa_storage::Storage = massa_storage::Storage::create_root(); @@ -146,6 +147,7 @@ pub(crate) fn start_public_api(addr: SocketAddr) -> (API, APIConfig) { chain_id: *CHAINID, deferred_credits_delta: MassaTime::from_millis(24 * 3600 * 2), minimal_fees: Amount::zero(), + deferred_calls_config: Default::default(), }; let shared_storage: massa_storage::Storage = massa_storage::Storage::create_root(); diff --git a/massa-execution-exports/src/mapping_grpc.rs b/massa-execution-exports/src/mapping_grpc.rs index c3f7fefb1d8..cb668f76b4c 100644 --- a/massa-execution-exports/src/mapping_grpc.rs +++ b/massa-execution-exports/src/mapping_grpc.rs @@ -266,6 +266,10 @@ fn to_execution_query_result( ) } ExecutionQueryResponseItem::DeferredCallQuote(_, _, _, _) => todo!(), + ExecutionQueryResponseItem::DeferredCallInfo(_, _) => todo!(), + ExecutionQueryResponseItem::DeferredCallSlotCalls(_deferred_call_id, _deferred_call) => { + todo!() + } }; grpc_api::ExecutionQueryResponseItem { diff --git a/massa-execution-exports/src/types.rs b/massa-execution-exports/src/types.rs index 085f28cb48c..a836534e187 100644 --- a/massa-execution-exports/src/types.rs +++ b/massa-execution-exports/src/types.rs @@ -4,11 +4,13 @@ use crate::error::ExecutionQueryError; use crate::event_store::EventStore; +use massa_deferred_calls::DeferredCall; use massa_final_state::StateChanges; use massa_hash::Hash; use massa_models::block_id::BlockId; use massa_models::bytecode::Bytecode; use massa_models::datastore::Datastore; +use massa_models::deferred_calls::DeferredCallId; use massa_models::denunciation::DenunciationIndex; use massa_models::execution::EventFilter; use massa_models::operation::OperationId; @@ -102,6 +104,10 @@ pub enum ExecutionQueryRequestItem { /// gets the deferred call quote (candidate) for a slot, returns ExecutionQueryResponseItem::DeferredCallQuote(available, price) DeferredCallQuote(Slot, u64), + /// get info of deferred calls + DeferredCallInfo(DeferredCallId), + /// retrieves the deferred call for given slot + DeferredCallSlotCalls(Slot), /// gets the execution status (candidate) for an denunciation, returns ExecutionQueryResponseItem::ExecutionStatus(status) DenunciationExecutionStatusCandidate(DenunciationIndex), @@ -145,6 +151,10 @@ pub enum ExecutionQueryResponseItem { KeyList(BTreeSet>), /// deferred call quote (target_slot, gas_request, available, price) DeferredCallQuote(Slot, u64, bool, u64), + /// deferred call info value + DeferredCallInfo(DeferredCallId, DeferredCall), + /// deferred call slot calls value + DeferredCallSlotCalls(Slot, BTreeMap), /// deferred credits value DeferredCredits(BTreeMap), /// execution status value diff --git a/massa-execution-worker/src/context.rs b/massa-execution-worker/src/context.rs index e55e0b07a04..2af9caa89cd 100644 --- a/massa-execution-worker/src/context.rs +++ b/massa-execution-worker/src/context.rs @@ -1170,6 +1170,11 @@ impl ExecutionContext { false } + /// Get a deferred call by its id + pub fn get_deferred_call(&self, call_id: &DeferredCallId) -> Option { + self.speculative_deferred_calls.get_call(call_id) + } + /// when a deferred call execution fails we need to refund the coins to the caller pub fn deferred_call_fail_exec( &mut self, @@ -1236,6 +1241,13 @@ impl ExecutionContext { )))?, } } + + /// find the deferred calls for a given slot + pub fn get_deferred_calls_by_slot(&self, slot: Slot) -> BTreeMap { + self.speculative_deferred_calls + .get_calls_by_slot(slot) + .slot_calls + } } /// Generate the execution trail hash diff --git a/massa-execution-worker/src/controller.rs b/massa-execution-worker/src/controller.rs index 7fca7d1e168..99666b37d37 100644 --- a/massa-execution-worker/src/controller.rs +++ b/massa-execution-worker/src/controller.rs @@ -341,6 +341,21 @@ impl ExecutionController for ExecutionControllerImpl { price, )) } + ExecutionQueryRequestItem::DeferredCallInfo(deferred_call_id) => execution_lock + .deferred_call_info(&deferred_call_id) + .ok_or_else(|| { + ExecutionQueryError::NotFound(format!( + "Deferred call id {}", + deferred_call_id + )) + }) + .map(|call| { + ExecutionQueryResponseItem::DeferredCallInfo(deferred_call_id, call) + }), + ExecutionQueryRequestItem::DeferredCallSlotCalls(slot) => { + let res = execution_lock.get_deferred_calls_by_slot(slot); + Ok(ExecutionQueryResponseItem::DeferredCallSlotCalls(slot, res)) + } }; resp.responses.push(resp_item); } diff --git a/massa-execution-worker/src/execution.rs b/massa-execution-worker/src/execution.rs index fcd64ea24fc..10b2b8f8b81 100644 --- a/massa-execution-worker/src/execution.rs +++ b/massa-execution-worker/src/execution.rs @@ -2452,4 +2452,13 @@ impl ExecutionState { Err(_) => (target_slot, gas_request, false, 0), } } + + pub fn deferred_call_info(&self, call_id: &DeferredCallId) -> Option { + let context = context_guard!(self); + context.get_deferred_call(call_id) + } + + pub fn get_deferred_calls_by_slot(&self, slot: Slot) -> BTreeMap { + context_guard!(self).get_deferred_calls_by_slot(slot) + } } diff --git a/massa-execution-worker/src/speculative_deferred_calls.rs b/massa-execution-worker/src/speculative_deferred_calls.rs index b41124a0e03..e80b57a317f 100644 --- a/massa-execution-worker/src/speculative_deferred_calls.rs +++ b/massa-execution-worker/src/speculative_deferred_calls.rs @@ -169,15 +169,7 @@ impl SpeculativeDeferredCallRegistry { /// and returns the calls that need to be executed in the current slot pub fn advance_slot(&mut self, current_slot: Slot) -> DeferredSlotCalls { // get the state of the current slot - let mut slot_calls: DeferredSlotCalls = self - .final_state - .read() - .get_deferred_call_registry() - .get_slot_calls(current_slot); - for hist_item in self.active_history.read().0.iter() { - slot_calls.apply_changes(&hist_item.state_changes.deferred_call_changes); - } - slot_calls.apply_changes(&self.deferred_calls_changes); + let mut slot_calls = self.get_calls_by_slot(current_slot); let total_booked_gas_before = self.get_effective_total_gas(); let avg_booked_gas = @@ -256,6 +248,19 @@ impl SpeculativeDeferredCallRegistry { slot_calls } + pub fn get_calls_by_slot(&self, slot: Slot) -> DeferredSlotCalls { + let mut slot_calls: DeferredSlotCalls = self + .final_state + .read() + .get_deferred_call_registry() + .get_slot_calls(slot); + for hist_item in self.active_history.read().0.iter() { + slot_calls.apply_changes(&hist_item.state_changes.deferred_call_changes); + } + slot_calls.apply_changes(&self.deferred_calls_changes); + slot_calls + } + pub fn get_call(&self, id: &DeferredCallId) -> Option { let slot = match id.get_slot() { Ok(slot) => slot, From 4f7524d563642b35ed6890232dd25a97ab299909 Mon Sep 17 00:00:00 2001 From: modship Date: Tue, 24 Sep 2024 17:25:23 +0200 Subject: [PATCH 078/100] API : openrpc spec --- massa-node/base_config/openrpc.json | 217 ++++++++++++++++++++++++++++ 1 file changed, 217 insertions(+) diff --git a/massa-node/base_config/openrpc.json b/massa-node/base_config/openrpc.json index 737e7b9e468..4e63b1f6698 100644 --- a/massa-node/base_config/openrpc.json +++ b/massa-node/base_config/openrpc.json @@ -489,6 +489,105 @@ "summary": "Summary of the current state", "description": "Summary of the current state: time, last final blocks (hash, thread, slot, timestamp), clique count, connected nodes count." }, + { + "tags": [ + { + "name": "public", + "description": "Massa public api" + } + ], + "params": [ + { + "name": "req", + "description": "Deferred calls quote request", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DeferredCallsQuoteRequest" + } + }, + "required": true + } + ], + "result": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DeferredCallsQuoteResponse" + } + }, + "name": "DeferredCallsQuoteResponse" + }, + "name": "get_deferred_call_quote", + "summary": "Get deferred call quote", + "description": "Returns if slot is available and the price to book the requested gas." + }, + { + "tags": [ + { + "name": "public", + "description": "Massa public api" + } + ], + "params": [ + { + "name": "arg", + "description": "Deferred calls ids", + "schema": { + "type": "array", + "items": { + "type": "string" + } + }, + "required": true + } + ], + "result": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DeferredCallResponse" + } + }, + "name": "DeferredCallResponse" + }, + "name": "get_deferred_call_info", + "summary": "Get deferred calls information", + "description": "Returns information about deferred calls." + }, + { + "tags": [ + { + "name": "public", + "description": "Massa public api" + } + ], + "params": [ + { + "name": "slots", + "description": "Deferred calls ids", + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Slot" + } + }, + "required": true + } + ], + "result": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DeferredCallsSlotResponse" + } + }, + "name": "DeferredCallResponse" + }, + "name": "list_deferred_calls_by_slot", + "summary": "List deferred calls by slots", + "description": "Returns deferred calls list for given slots." + }, { "tags": [ { @@ -2006,6 +2105,119 @@ }, "additionalProperties": false }, + "DeferredCall": { + "type": "object", + "required": [ + "sender_address", + "target_slot", + "target_address", + "target_function", + "parameters", + "coins", + "max_gas", + "fee", + "cancelled" + ], + "properties": { + "sender_address": { + "$ref": "#/components/schemas/Address" + }, + "target_slot": { + "$ref": "#/components/schemas/Slot" + }, + "target_address": { + "$ref": "#/components/schemas/Address" + }, + "target_function": { + "type": "string" + }, + "parameters": { + "type": "array", + "items": { + "type": "number" + } + }, + "coins": { + "type": "number" + }, + "max_gas": { + "type": "number" + }, + "fee": { + "type": "number" + }, + "cancelled": { + "type": "boolean" + } + } + }, + "DeferredCallsQuoteRequest": { + "type": "object", + "required": [ + "target_slot", + "max_gas_request" + ], + "properties": { + "target_slot": { + "$ref": "#/components/schemas/Slot" + }, + "max_gas_request": { + "type": "number" + } + } + }, + "DeferredCallsQuoteResponse": { + "type": "object", + "required": [ + "target_slot", + "max_gas_request", + "available", + "price" + ], + "properties": { + "target_slot": { + "$ref": "#/components/schemas/Slot" + }, + "max_gas_request": { + "type": "number" + }, + "available": { + "type": "boolean" + }, + "price": { + "type": "number" + } + } + }, + "DeferredCallResponse": { + "type": "object", + "required": [ + "call_id", + "call" + ], + "properties": { + "call_id": { + "type": "string" + }, + "call": { + "$ref": "#/components/schemas/DeferredCall" + } + } + }, + "DeferredCallsSlotResponse": { + "type": "object", + "properties": { + "slot": { + "$ref": "#/components/schemas/Slot" + }, + "calls": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DeferredCallResponse" + } + } + } + }, "Denunciation": { "oneOf": [ { @@ -3310,6 +3522,7 @@ "required": [ "async_pool_changes", "executed_ops_changes", + "deferred_call_changes", "ledger_changes", "pos_changes", "executed_denunciations_changes", @@ -3336,6 +3549,10 @@ "description": "executed operations changes", "type": "object" }, + "deferred_call_changes": { + "description": "deferred call changes", + "type": "object" + }, "executed_denunciations_changes": { "description": "executed denunciation changes", "type": "object" From 5b68c00c88366b3c0fb54cd5183774473399d05d Mon Sep 17 00:00:00 2001 From: modship Date: Thu, 26 Sep 2024 17:07:00 +0200 Subject: [PATCH 079/100] grpc api --- Cargo.lock | 5 +- Cargo.toml | 4 +- massa-api-exports/src/execution.rs | 2 +- massa-api/src/public.rs | 33 ++++++----- massa-deferred-calls/Cargo.toml | 1 + massa-deferred-calls/src/call.rs | 17 ++++++ massa-execution-exports/src/mapping_grpc.rs | 63 +++++++++++++++++++-- massa-execution-exports/src/types.rs | 13 +++-- massa-execution-worker/src/controller.rs | 17 +++--- massa-execution-worker/src/execution.rs | 6 +- 10 files changed, 119 insertions(+), 42 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9d183c8e4bd..073a749a20b 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=8eb7aa8384a407b588e190965c8e501cebdd38e3#8eb7aa8384a407b588e190965c8e501cebdd38e3" +source = "git+https://github.com/massalabs/massa-proto-rs?rev=a274d8b374f627f16a0113b6bbc974bf5934dcc7#a274d8b374f627f16a0113b6bbc974bf5934dcc7" 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=b582bcd83120cfe980211ea7bcdaf994a784c714#b582bcd83120cfe980211ea7bcdaf994a784c714" +source = "git+https://github.com/massalabs/massa-sc-runtime?rev=f51d2472212be10838b2318aade1bc14d49f90d9#f51d2472212be10838b2318aade1bc14d49f90d9" dependencies = [ "anyhow", "as-ffi-bindings", @@ -2839,6 +2839,7 @@ dependencies = [ name = "massa_deferred_calls" version = "2.2.0" dependencies = [ + "massa-proto-rs", "massa_db_exports", "massa_db_worker", "massa_ledger_exports", diff --git a/Cargo.toml b/Cargo.toml index a575055a05f..b4a49756204 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" = "8eb7aa8384a407b588e190965c8e501cebdd38e3" } -massa-sc-runtime = { git = "https://github.com/massalabs/massa-sc-runtime", "rev" = "b582bcd83120cfe980211ea7bcdaf994a784c714" } +massa-proto-rs = { git = "https://github.com/massalabs/massa-proto-rs", "rev" = "a274d8b374f627f16a0113b6bbc974bf5934dcc7" } +massa-sc-runtime = { git = "https://github.com/massalabs/massa-sc-runtime", "rev" = "f51d2472212be10838b2318aade1bc14d49f90d9" } 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 909573fcb77..d8754150eab 100644 --- a/massa-api-exports/src/execution.rs +++ b/massa-api-exports/src/execution.rs @@ -142,7 +142,7 @@ pub struct DeferredCallsQuoteResponse { /// if the slot is bookable pub available: bool, /// the cost for booking the call - pub price: u64, + pub price: Amount, } /// response for deferred call diff --git a/massa-api/src/public.rs b/massa-api/src/public.rs index 8080d60d949..019b9d7e81e 100644 --- a/massa-api/src/public.rs +++ b/massa-api/src/public.rs @@ -1160,7 +1160,10 @@ impl MassaRpcServer for API { &self, req: Vec, ) -> RpcResult> { - // TODO limit + if req.len() as u64 > self.0.api_settings.max_arguments { + return Err(ApiError::BadRequest("too many arguments".into()).into()); + } + let queries: Vec = req .into_iter() .map(|call| { @@ -1168,10 +1171,10 @@ impl MassaRpcServer for API { let effective_gas_request = call .max_gas_request .saturating_add(self.0.api_settings.deferred_calls_config.call_cst_gas_cost); - ExecutionQueryRequestItem::DeferredCallQuote( - call.target_slot, - effective_gas_request, - ) + ExecutionQueryRequestItem::DeferredCallQuote { + target_slot: call.target_slot, + max_gas_request: effective_gas_request, + } }) .collect(); @@ -1193,7 +1196,6 @@ impl MassaRpcServer for API { available, price, }), - Ok(_) => Err(ApiError::InternalServerError( "unexpected response type".to_string(), )), @@ -1208,14 +1210,9 @@ impl MassaRpcServer for API { &self, arg: Vec, ) -> RpcResult> { - // TODO limit - // if id_str.len() > self.0.api_settings.max_deferred_call_id_length as usize { - // return Err(ApiError::BadRequest(format!( - // "deferred call id too long: {}", - // id_str - // )) - // .into()); - // } + if arg.len() as u64 > self.0.api_settings.max_arguments { + return Err(ApiError::BadRequest("too many arguments".into()).into()); + } let requests: Vec = arg .into_iter() @@ -1253,11 +1250,13 @@ impl MassaRpcServer for API { &self, slots: Vec, ) -> RpcResult> { - // TODO limit slot count + if slots.len() as u64 > self.0.api_settings.max_arguments { + return Err(ApiError::BadRequest("too many arguments".into()).into()); + } let requests: Vec = slots .into_iter() - .map(ExecutionQueryRequestItem::DeferredCallSlotCalls) + .map(ExecutionQueryRequestItem::DeferredCallsBySlot) .collect(); let mut slot_calls = Vec::new(); @@ -1270,7 +1269,7 @@ impl MassaRpcServer for API { .into_iter() { match exec { - Ok(ExecutionQueryResponseItem::DeferredCallSlotCalls(slot, result)) => { + Ok(ExecutionQueryResponseItem::DeferredCallsBySlot(slot, result)) => { let calls = result .into_iter() .map(|(id, call)| DeferredCallResponse { diff --git a/massa-deferred-calls/Cargo.toml b/massa-deferred-calls/Cargo.toml index 36093eb7d4c..6df8d5a9b71 100644 --- a/massa-deferred-calls/Cargo.toml +++ b/massa-deferred-calls/Cargo.toml @@ -17,6 +17,7 @@ massa_models = { workspace = true } massa_serialization = { workspace = true } serde_with = { workspace = true } serde_json = { workspace = true } +massa-proto-rs = { workspace = true, "features" = ["tonic"] } [dev-dependencies] tempfile = { workspace = true } diff --git a/massa-deferred-calls/src/call.rs b/massa-deferred-calls/src/call.rs index 55360356e2f..afd19083d3f 100644 --- a/massa-deferred-calls/src/call.rs +++ b/massa-deferred-calls/src/call.rs @@ -4,6 +4,7 @@ use massa_models::{ serialization::{StringDeserializer, StringSerializer, VecU8Deserializer, VecU8Serializer}, slot::{Slot, SlotDeserializer, SlotSerializer}, }; +use massa_proto_rs::massa::api::v1 as grpc_api; use massa_serialization::{ BoolDeserializer, BoolSerializer, Deserializer, SerializeError, Serializer, U16VarIntDeserializer, U16VarIntSerializer, U64VarIntDeserializer, U64VarIntSerializer, @@ -75,6 +76,22 @@ impl DeferredCall { } } +impl From for grpc_api::DeferredCallInfoEntry { + fn from(call: DeferredCall) -> Self { + grpc_api::DeferredCallInfoEntry { + sender_address: call.sender_address.to_string(), + target_slot: Some(call.target_slot.into()), + target_address: call.target_address.to_string(), + target_function: call.target_function, + parameters: call.parameters, + coins: Some(call.coins.into()), + max_gas: call.max_gas, + fee: Some(call.fee.into()), + cancelled: call.cancelled, + } + } +} + /// Serializer for `AsyncCall` #[derive(Clone)] pub struct DeferredCallSerializer { diff --git a/massa-execution-exports/src/mapping_grpc.rs b/massa-execution-exports/src/mapping_grpc.rs index cb668f76b4c..826c25ba35a 100644 --- a/massa-execution-exports/src/mapping_grpc.rs +++ b/massa-execution-exports/src/mapping_grpc.rs @@ -9,6 +9,7 @@ use crate::{ }; use grpc_api::execution_query_request_item as exec; use massa_models::address::Address; +use massa_models::deferred_calls::DeferredCallId; use massa_models::error::ModelsError; use massa_models::execution::EventFilter; use massa_models::mapping_grpc::to_denunciation_index; @@ -133,6 +134,29 @@ pub fn to_querystate_filter( let event_filter = to_event_filter(value.filters)?; Ok(ExecutionQueryRequestItem::Events(event_filter)) } + exec::RequestItem::DeferredCallQuote(value) => { + Ok(ExecutionQueryRequestItem::DeferredCallQuote { + target_slot: value + .target_slot + .ok_or(ModelsError::ErrorRaised( + "target slot is required".to_string(), + ))? + .into(), + max_gas_request: value.max_gas_request, + }) + } + exec::RequestItem::DeferredCallInfo(info) => { + let id = DeferredCallId::from_str(&info.call_id)?; + Ok(ExecutionQueryRequestItem::DeferredCallInfo(id)) + } + exec::RequestItem::DeferredCallsBySlot(value) => { + Ok(ExecutionQueryRequestItem::DeferredCallsBySlot( + value + .slot + .ok_or(ModelsError::ErrorRaised("slot is required".to_string()))? + .into(), + )) + } } } else { Err(ModelsError::ErrorRaised("no filter provided".to_string())) @@ -265,10 +289,41 @@ fn to_execution_query_result( }, ) } - ExecutionQueryResponseItem::DeferredCallQuote(_, _, _, _) => todo!(), - ExecutionQueryResponseItem::DeferredCallInfo(_, _) => todo!(), - ExecutionQueryResponseItem::DeferredCallSlotCalls(_deferred_call_id, _deferred_call) => { - todo!() + ExecutionQueryResponseItem::DeferredCallQuote( + target_slot, + max_gas_request, + available, + price, + ) => grpc_api::execution_query_response_item::ResponseItem::DeferredCallQuote( + grpc_api::DeferredCallQuoteResponse { + target_slot: Some(target_slot.into()), + max_gas_request, + available, + price: Some(price.into()), + }, + ), + ExecutionQueryResponseItem::DeferredCallInfo(call_id, call) => { + grpc_api::execution_query_response_item::ResponseItem::DeferredCallInfo( + grpc_api::DeferredCallInfoResponse { + call_id: call_id.to_string(), + call: Some(call.into()), + }, + ) + } + ExecutionQueryResponseItem::DeferredCallsBySlot(slot, calls) => { + let arr = calls + .into_iter() + .map(|(id, call)| grpc_api::DeferredCallInfoResponse { + call_id: id.to_string(), + call: Some(call.into()), + }) + .collect(); + grpc_api::execution_query_response_item::ResponseItem::DeferredCallsBySlot( + grpc_api::DeferredCallsBySlotResponse { + slot: Some(slot.into()), + calls: arr, + }, + ) } }; diff --git a/massa-execution-exports/src/types.rs b/massa-execution-exports/src/types.rs index a836534e187..655c7837322 100644 --- a/massa-execution-exports/src/types.rs +++ b/massa-execution-exports/src/types.rs @@ -103,11 +103,16 @@ pub enum ExecutionQueryRequestItem { OpExecutionStatusFinal(OperationId), /// gets the deferred call quote (candidate) for a slot, returns ExecutionQueryResponseItem::DeferredCallQuote(available, price) - DeferredCallQuote(Slot, u64), + DeferredCallQuote { + /// slot to query + target_slot: Slot, + /// gas request + max_gas_request: u64, + }, /// get info of deferred calls DeferredCallInfo(DeferredCallId), /// retrieves the deferred call for given slot - DeferredCallSlotCalls(Slot), + DeferredCallsBySlot(Slot), /// gets the execution status (candidate) for an denunciation, returns ExecutionQueryResponseItem::ExecutionStatus(status) DenunciationExecutionStatusCandidate(DenunciationIndex), @@ -150,11 +155,11 @@ pub enum ExecutionQueryResponseItem { /// list of keys KeyList(BTreeSet>), /// deferred call quote (target_slot, gas_request, available, price) - DeferredCallQuote(Slot, u64, bool, u64), + DeferredCallQuote(Slot, u64, bool, Amount), /// deferred call info value DeferredCallInfo(DeferredCallId, DeferredCall), /// deferred call slot calls value - DeferredCallSlotCalls(Slot, BTreeMap), + DeferredCallsBySlot(Slot, BTreeMap), /// deferred credits value DeferredCredits(BTreeMap), /// execution status value diff --git a/massa-execution-worker/src/controller.rs b/massa-execution-worker/src/controller.rs index 99666b37d37..051487efef0 100644 --- a/massa-execution-worker/src/controller.rs +++ b/massa-execution-worker/src/controller.rs @@ -331,14 +331,13 @@ impl ExecutionController for ExecutionControllerImpl { execution_lock.get_filtered_sc_output_event(filter), )) } - ExecutionQueryRequestItem::DeferredCallQuote(slot, max_request_gas) => { - let (target_slot, gas_request, available, price) = - execution_lock.deferred_call_quote(slot, max_request_gas); + ExecutionQueryRequestItem::DeferredCallQuote { + target_slot, + max_gas_request, + } => { + let result = execution_lock.deferred_call_quote(target_slot, max_gas_request); Ok(ExecutionQueryResponseItem::DeferredCallQuote( - target_slot, - gas_request, - available, - price, + result.0, result.1, result.2, result.3, )) } ExecutionQueryRequestItem::DeferredCallInfo(deferred_call_id) => execution_lock @@ -352,9 +351,9 @@ impl ExecutionController for ExecutionControllerImpl { .map(|call| { ExecutionQueryResponseItem::DeferredCallInfo(deferred_call_id, call) }), - ExecutionQueryRequestItem::DeferredCallSlotCalls(slot) => { + ExecutionQueryRequestItem::DeferredCallsBySlot(slot) => { let res = execution_lock.get_deferred_calls_by_slot(slot); - Ok(ExecutionQueryResponseItem::DeferredCallSlotCalls(slot, res)) + Ok(ExecutionQueryResponseItem::DeferredCallsBySlot(slot, res)) } }; resp.responses.push(resp_item); diff --git a/massa-execution-worker/src/execution.rs b/massa-execution-worker/src/execution.rs index 10b2b8f8b81..665f3fcdf0c 100644 --- a/massa-execution-worker/src/execution.rs +++ b/massa-execution-worker/src/execution.rs @@ -2442,14 +2442,14 @@ impl ExecutionState { &self, target_slot: Slot, max_request_gas: u64, - ) -> (Slot, u64, bool, 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) { - Ok(fee) => (target_slot, gas_request, true, fee.to_raw()), - Err(_) => (target_slot, gas_request, false, 0), + Ok(fee) => (target_slot, gas_request, true, fee), + Err(_) => (target_slot, gas_request, false, Amount::zero()), } } From 815ed4cb7cbea0dfef5d77043355d27d47e32c40 Mon Sep 17 00:00:00 2001 From: modship Date: Fri, 27 Sep 2024 09:22:39 +0200 Subject: [PATCH 080/100] Fix grpc log error --- massa-grpc/src/public.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/massa-grpc/src/public.rs b/massa-grpc/src/public.rs index 40a330525d7..9da185f5d7b 100644 --- a/massa-grpc/src/public.rs +++ b/massa-grpc/src/public.rs @@ -1006,7 +1006,7 @@ pub(crate) fn query_state( } if queries.len() as u32 > grpc.grpc_config.max_query_items_per_request { - return Err(GrpcError::InvalidArgument(format!("too many query items received. Only a maximum of {} operations are accepted per request", grpc.grpc_config.max_operation_ids_per_request))); + return Err(GrpcError::InvalidArgument(format!("too many query items received. Only a maximum of {} operations are accepted per request", grpc.grpc_config.max_query_items_per_request))); } let response = grpc From fd9d9457713c8bfbfea702a87249e72c14b0dbb8 Mon Sep 17 00:00:00 2001 From: modship Date: Fri, 27 Sep 2024 11:44:12 +0200 Subject: [PATCH 081/100] API : Update list call ids by slot --- Cargo.lock | 4 ++-- Cargo.toml | 4 ++-- massa-api-exports/src/execution.rs | 2 +- massa-api/src/lib.rs | 4 ++-- massa-api/src/private.rs | 2 +- massa-api/src/public.rs | 14 ++++---------- massa-execution-exports/src/mapping_grpc.rs | 12 +++--------- massa-execution-exports/src/types.rs | 2 +- massa-execution-worker/src/execution.rs | 7 +++++-- 9 files changed, 21 insertions(+), 30 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 073a749a20b..453653c4389 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=a274d8b374f627f16a0113b6bbc974bf5934dcc7#a274d8b374f627f16a0113b6bbc974bf5934dcc7" +source = "git+https://github.com/massalabs/massa-proto-rs?rev=1cce8ec75e0df66af6ce3c5a86350adaea8ac463#1cce8ec75e0df66af6ce3c5a86350adaea8ac463" 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=f51d2472212be10838b2318aade1bc14d49f90d9#f51d2472212be10838b2318aade1bc14d49f90d9" +source = "git+https://github.com/massalabs/massa-sc-runtime?rev=4220039f113291003674f574a1a7ae4035506e81#4220039f113291003674f574a1a7ae4035506e81" dependencies = [ "anyhow", "as-ffi-bindings", diff --git a/Cargo.toml b/Cargo.toml index b4a49756204..be2dd5cdc04 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" = "a274d8b374f627f16a0113b6bbc974bf5934dcc7" } -massa-sc-runtime = { git = "https://github.com/massalabs/massa-sc-runtime", "rev" = "f51d2472212be10838b2318aade1bc14d49f90d9" } +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" = "4220039f113291003674f574a1a7ae4035506e81" } 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 d8754150eab..e43cdf89f0a 100644 --- a/massa-api-exports/src/execution.rs +++ b/massa-api-exports/src/execution.rs @@ -160,5 +160,5 @@ pub struct DeferredCallsSlotResponse { /// deferred calls pub slot: Slot, /// deferred calls - pub calls: Vec, + pub call_ids: Vec, } diff --git a/massa-api/src/lib.rs b/massa-api/src/lib.rs index 0ec5c5bcddd..955ef0f7a39 100644 --- a/massa-api/src/lib.rs +++ b/massa-api/src/lib.rs @@ -419,8 +419,8 @@ pub trait MassaRpc { ) -> RpcResult>; /// List deferred calls for given slot - #[method(name = "list_deferred_calls_by_slot")] - async fn list_deferred_calls_by_slot( + #[method(name = "get_deferred_call_ids_by_slot")] + async fn get_deferred_call_ids_by_slot( &self, arg: Vec, ) -> RpcResult>; diff --git a/massa-api/src/private.rs b/massa-api/src/private.rs index 3f813da48bc..e41c554a6d4 100644 --- a/massa-api/src/private.rs +++ b/massa-api/src/private.rs @@ -368,7 +368,7 @@ impl MassaRpcServer for API { crate::wrong_api::>() } - async fn list_deferred_calls_by_slot( + async fn get_deferred_call_ids_by_slot( &self, _slot: Vec, ) -> RpcResult> { diff --git a/massa-api/src/public.rs b/massa-api/src/public.rs index 019b9d7e81e..e171b46dfd8 100644 --- a/massa-api/src/public.rs +++ b/massa-api/src/public.rs @@ -1246,7 +1246,7 @@ impl MassaRpcServer for API { Ok(result) } - async fn list_deferred_calls_by_slot( + async fn get_deferred_call_ids_by_slot( &self, slots: Vec, ) -> RpcResult> { @@ -1270,15 +1270,9 @@ impl MassaRpcServer for API { { match exec { Ok(ExecutionQueryResponseItem::DeferredCallsBySlot(slot, result)) => { - let calls = result - .into_iter() - .map(|(id, call)| DeferredCallResponse { - call_id: id.to_string(), - call, - }) - .collect(); - - slot_calls.push(DeferredCallsSlotResponse { slot, calls }); + let call_ids = result.into_iter().map(|id| id.to_string()).collect(); + + slot_calls.push(DeferredCallsSlotResponse { slot, call_ids }); } Ok(_) => { return Err(ApiError::InternalServerError( diff --git a/massa-execution-exports/src/mapping_grpc.rs b/massa-execution-exports/src/mapping_grpc.rs index 826c25ba35a..20130a9e4f7 100644 --- a/massa-execution-exports/src/mapping_grpc.rs +++ b/massa-execution-exports/src/mapping_grpc.rs @@ -310,18 +310,12 @@ fn to_execution_query_result( }, ) } - ExecutionQueryResponseItem::DeferredCallsBySlot(slot, calls) => { - let arr = calls - .into_iter() - .map(|(id, call)| grpc_api::DeferredCallInfoResponse { - call_id: id.to_string(), - call: Some(call.into()), - }) - .collect(); + ExecutionQueryResponseItem::DeferredCallsBySlot(slot, ids) => { + let arr = ids.into_iter().map(|id| id.to_string()).collect(); grpc_api::execution_query_response_item::ResponseItem::DeferredCallsBySlot( grpc_api::DeferredCallsBySlotResponse { slot: Some(slot.into()), - calls: arr, + call_ids: arr, }, ) } diff --git a/massa-execution-exports/src/types.rs b/massa-execution-exports/src/types.rs index 655c7837322..2a55a098fec 100644 --- a/massa-execution-exports/src/types.rs +++ b/massa-execution-exports/src/types.rs @@ -159,7 +159,7 @@ pub enum ExecutionQueryResponseItem { /// deferred call info value DeferredCallInfo(DeferredCallId, DeferredCall), /// deferred call slot calls value - DeferredCallsBySlot(Slot, BTreeMap), + DeferredCallsBySlot(Slot, Vec), /// deferred credits value DeferredCredits(BTreeMap), /// execution status value diff --git a/massa-execution-worker/src/execution.rs b/massa-execution-worker/src/execution.rs index 665f3fcdf0c..0273ea84f39 100644 --- a/massa-execution-worker/src/execution.rs +++ b/massa-execution-worker/src/execution.rs @@ -2458,7 +2458,10 @@ impl ExecutionState { context.get_deferred_call(call_id) } - pub fn get_deferred_calls_by_slot(&self, slot: Slot) -> BTreeMap { - context_guard!(self).get_deferred_calls_by_slot(slot) + pub fn get_deferred_calls_by_slot(&self, slot: Slot) -> Vec { + context_guard!(self) + .get_deferred_calls_by_slot(slot) + .into_keys() + .collect() } } From ed88731c851cc6f088322bf27b78273c876c33c6 Mon Sep 17 00:00:00 2001 From: modship Date: Fri, 27 Sep 2024 14:22:30 +0200 Subject: [PATCH 082/100] rename openrpc method --- massa-node/base_config/openrpc.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/massa-node/base_config/openrpc.json b/massa-node/base_config/openrpc.json index 4e63b1f6698..9f4309de115 100644 --- a/massa-node/base_config/openrpc.json +++ b/massa-node/base_config/openrpc.json @@ -584,8 +584,8 @@ }, "name": "DeferredCallResponse" }, - "name": "list_deferred_calls_by_slot", - "summary": "List deferred calls by slots", + "name": "get_deferred_call_ids_by_slot", + "summary": "List deferred call ids by slot", "description": "Returns deferred calls list for given slots." }, { @@ -2210,10 +2210,10 @@ "slot": { "$ref": "#/components/schemas/Slot" }, - "calls": { + "call_ids": { "type": "array", "items": { - "$ref": "#/components/schemas/DeferredCallResponse" + "type": "string" } } } From 7cd95b373aa3542cd8299e2c38cf7c6ce080ab4b Mon Sep 17 00:00:00 2001 From: modship Date: Tue, 1 Oct 2024 09:50:41 +0200 Subject: [PATCH 083/100] Fix : reset_to_snapshot move reset of addr stack after event_emit --- massa-execution-worker/src/context.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/massa-execution-worker/src/context.rs b/massa-execution-worker/src/context.rs index 2af9caa89cd..149dd1652d5 100644 --- a/massa-execution-worker/src/context.rs +++ b/massa-execution-worker/src/context.rs @@ -308,7 +308,6 @@ impl ExecutionContext { self.created_addr_index = snapshot.created_addr_index; self.created_event_index = snapshot.created_event_index; self.created_message_index = snapshot.created_message_index; - self.stack = snapshot.stack; self.unsafe_rng = snapshot.unsafe_rng; self.gas_remaining_before_subexecution = snapshot.gas_remaining_before_subexecution; @@ -323,6 +322,8 @@ impl ExecutionContext { serde_json::json!({ "massa_execution_error": format!("{}", error) }).to_string(), true, )); + // Reset address stack after emitting the error event. + self.stack = snapshot.stack; } /// Create a new `ExecutionContext` for read-only execution From 08be8a9e0fbcf8065e6b5fcbdcdf7afdce19989f Mon Sep 17 00:00:00 2001 From: modship Date: Tue, 1 Oct 2024 10:34:33 +0200 Subject: [PATCH 084/100] Fix: reset_to_snapshot remove reset of created_event_index move event_emit --- massa-execution-worker/src/context.rs | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/massa-execution-worker/src/context.rs b/massa-execution-worker/src/context.rs index 149dd1652d5..a86f7f053e0 100644 --- a/massa-execution-worker/src/context.rs +++ b/massa-execution-worker/src/context.rs @@ -292,6 +292,13 @@ impl ExecutionContext { /// * `snapshot`: a saved snapshot to be restored /// * `error`: an execution error to emit as an event conserved after snapshot reset. pub fn reset_to_snapshot(&mut self, snapshot: ExecutionContextSnapshot, error: ExecutionError) { + // Emit the error event. + // Note that the context event counter is properly handled by event_emit (see doc). + self.event_emit(self.event_create( + serde_json::json!({ "massa_execution_error": format!("{}", error) }).to_string(), + true, + )); + // Reset context to snapshot. self.speculative_ledger .reset_to_snapshot(snapshot.ledger_changes); @@ -306,7 +313,7 @@ impl ExecutionContext { self.speculative_executed_denunciations .reset_to_snapshot(snapshot.executed_denunciations); self.created_addr_index = snapshot.created_addr_index; - self.created_event_index = snapshot.created_event_index; + self.stack = snapshot.stack; self.created_message_index = snapshot.created_message_index; self.unsafe_rng = snapshot.unsafe_rng; self.gas_remaining_before_subexecution = snapshot.gas_remaining_before_subexecution; @@ -315,15 +322,6 @@ impl ExecutionContext { for event in self.events.0.range_mut(snapshot.event_count..) { event.context.is_error = true; } - - // Emit the error event. - // Note that the context event counter is properly handled by event_emit (see doc). - self.event_emit(self.event_create( - serde_json::json!({ "massa_execution_error": format!("{}", error) }).to_string(), - true, - )); - // Reset address stack after emitting the error event. - self.stack = snapshot.stack; } /// Create a new `ExecutionContext` for read-only execution From bc225ecc58d02d610cf3d170c627c84b1afa7b91 Mon Sep 17 00:00:00 2001 From: modship Date: Wed, 2 Oct 2024 11:22:57 +0200 Subject: [PATCH 085/100] FIX : Api double alloc vm cst --- massa-api/src/public.rs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/massa-api/src/public.rs b/massa-api/src/public.rs index e171b46dfd8..32b238a74da 100644 --- a/massa-api/src/public.rs +++ b/massa-api/src/public.rs @@ -1166,15 +1166,9 @@ impl MassaRpcServer for API { let queries: Vec = req .into_iter() - .map(|call| { - // add the gas cost of vm allocation - let effective_gas_request = call - .max_gas_request - .saturating_add(self.0.api_settings.deferred_calls_config.call_cst_gas_cost); - ExecutionQueryRequestItem::DeferredCallQuote { - target_slot: call.target_slot, - max_gas_request: effective_gas_request, - } + .map(|call| ExecutionQueryRequestItem::DeferredCallQuote { + target_slot: call.target_slot, + max_gas_request: call.max_gas_request, }) .collect(); From a4e21a38993e9b8c900b673c7fa510405c8f47f2 Mon Sep 17 00:00:00 2001 From: modship Date: Wed, 2 Oct 2024 11:29:58 +0200 Subject: [PATCH 086/100] Fix : compute_fee get_effective_total_gas() --- massa-execution-worker/src/speculative_deferred_calls.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/massa-execution-worker/src/speculative_deferred_calls.rs b/massa-execution-worker/src/speculative_deferred_calls.rs index e80b57a317f..e9c29a901ee 100644 --- a/massa-execution-worker/src/speculative_deferred_calls.rs +++ b/massa-execution-worker/src/speculative_deferred_calls.rs @@ -458,10 +458,7 @@ impl SpeculativeDeferredCallRegistry { // Global overbooking fee // TODO check if this is correct - let global_occupancy = self - .deferred_calls_changes - .get_effective_total_gas() - .unwrap_or_default(); + let global_occupancy = self.get_effective_total_gas(); let global_overbooking_fee = Self::overbooking_fee( (self.config.max_gas as u128).saturating_mul(self.config.max_future_slots as u128), (self.config.max_future_slots as u128).saturating_mul(TARGET_BOOKING), From a4f3a6ded33200f23bd5c8b9151524c6d214e16f Mon Sep 17 00:00:00 2001 From: modship Date: Wed, 2 Oct 2024 12:08:18 +0200 Subject: [PATCH 087/100] Update runtime --- Cargo.lock | 2 +- Cargo.toml | 2 +- massa-execution-worker/src/interface_impl.rs | 8 ++++++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 453653c4389..dfe2957a583 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2571,7 +2571,7 @@ dependencies = [ [[package]] name = "massa-sc-runtime" version = "0.10.0" -source = "git+https://github.com/massalabs/massa-sc-runtime?rev=4220039f113291003674f574a1a7ae4035506e81#4220039f113291003674f574a1a7ae4035506e81" +source = "git+https://github.com/massalabs/massa-sc-runtime?rev=f5fd64c9e05c6d7cc01a30d1ef1dc0c202456a4b#f5fd64c9e05c6d7cc01a30d1ef1dc0c202456a4b" dependencies = [ "anyhow", "as-ffi-bindings", diff --git a/Cargo.toml b/Cargo.toml index be2dd5cdc04..faecffa0288 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -108,7 +108,7 @@ 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" = "4220039f113291003674f574a1a7ae4035506e81" } +massa-sc-runtime = { git = "https://github.com/massalabs/massa-sc-runtime", "rev" = "f5fd64c9e05c6d7cc01a30d1ef1dc0c202456a4b" } peernet = { git = "https://github.com/massalabs/PeerNet", "rev" = "04b05ddd320fbe76cc858115af7b5fc28bdb8310" } diff --git a/massa-execution-worker/src/interface_impl.rs b/massa-execution-worker/src/interface_impl.rs index ce1af0429dc..1bb39d2d611 100644 --- a/massa-execution-worker/src/interface_impl.rs +++ b/massa-execution-worker/src/interface_impl.rs @@ -1341,7 +1341,11 @@ impl Interface for InterfaceImpl { /// /// # Returns /// A tuple containing a boolean indicating if the call is possible and the amount of fees needed - fn deferred_call_quote(&self, target_slot: (u64, u8), gas_limit: u64) -> Result<(bool, u64)> { + fn get_deferred_call_quote( + &self, + target_slot: (u64, u8), + gas_limit: u64, + ) -> Result<(bool, u64)> { // write-lock context let context = context_guard!(self); @@ -1398,7 +1402,7 @@ impl Interface for InterfaceImpl { } // check fee, slot, gas - let (available, fee_raw) = self.deferred_call_quote(target_slot, max_gas)?; + let (available, fee_raw) = self.get_deferred_call_quote(target_slot, max_gas)?; 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."); } From 34d9975c3a21f898ea9ce092f71ad7985b65f6c4 Mon Sep 17 00:00:00 2001 From: modship Date: Wed, 2 Oct 2024 14:48:43 +0200 Subject: [PATCH 088/100] Fix abi gas cost --- massa-node/base_config/gas_costs/abi_gas_costs.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/massa-node/base_config/gas_costs/abi_gas_costs.json b/massa-node/base_config/gas_costs/abi_gas_costs.json index d569299be2d..87ffd3908a7 100644 --- a/massa-node/base_config/gas_costs/abi_gas_costs.json +++ b/massa-node/base_config/gas_costs/abi_gas_costs.json @@ -14,7 +14,7 @@ "assembly_script_delete_data_for": 220, "assembly_script_deferred_call_cancel": 11, "assembly_script_deferred_call_exists": 11, - "assembly_script_deferred_call_quote": 11, + "assembly_script_get_deferred_call_quote": 11, "assembly_script_deferred_call_register": 11, "assembly_script_function_exists": 575, "assembly_script_generate_event": 172, From 9e57b5300255d7aa3f32b17c9a3ba7a7dba9004c Mon Sep 17 00:00:00 2001 From: modship Date: Wed, 2 Oct 2024 17:58:22 +0200 Subject: [PATCH 089/100] Test : compute_call_fee setup && first basic test --- .../src/speculative_deferred_calls.rs | 101 +++++++++++++++++- 1 file changed, 100 insertions(+), 1 deletion(-) diff --git a/massa-execution-worker/src/speculative_deferred_calls.rs b/massa-execution-worker/src/speculative_deferred_calls.rs index e9c29a901ee..8c0090c7b5c 100644 --- a/massa-execution-worker/src/speculative_deferred_calls.rs +++ b/massa-execution-worker/src/speculative_deferred_calls.rs @@ -553,6 +553,105 @@ impl SpeculativeDeferredCallRegistry { #[cfg(test)] mod tests { + use std::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 parking_lot::RwLock; + use tempfile::TempDir; + + use super::SpeculativeDeferredCallRegistry; + #[test] - fn test_compute_call_fee() {} + fn test_compute_call_fee() { + let disk_ledger = TempDir::new().expect("cannot create temp directory"); + let db_config = MassaDBConfig { + path: disk_ledger.path().to_path_buf(), + max_history_length: 10, + max_final_state_elements_size: 100_000, + max_versioning_elements_size: 100_000, + thread_count: THREAD_COUNT, + max_ledger_backups: 10, + }; + + let db = Arc::new(RwLock::new( + Box::new(MassaDB::new(db_config)) as Box<(dyn MassaDBController + 'static)> + )); + let mock_final_state = Arc::new(RwLock::new(MockFinalStateController::new())); + + let deferred_call_registry = + DeferredCallRegistry::new(db.clone(), DeferredCallsConfig::default()); + + mock_final_state + .write() + .expect_get_deferred_call_registry() + .return_const(deferred_call_registry); + let config = DeferredCallsConfig::default(); + + let mut speculative = SpeculativeDeferredCallRegistry::new( + mock_final_state, + Arc::new(Default::default()), + config.clone(), + ); + + let max_period = config.max_future_slots / THREAD_COUNT as u64; + + let slot_too_far = Slot { + period: max_period + 2, + thread: 1, + }; + + let good_slot = Slot { + period: 10, + thread: 1, + }; + + // slot to far in the future + assert!(speculative + .compute_call_fee( + slot_too_far, + 1_000_000, + Slot { + period: 1, + thread: 1, + }, + ) + .is_err()); + + // slot is in the past + assert!(speculative + .compute_call_fee( + Slot { + period: 2, + thread: 1, + }, + 1_000_000, + Slot { + period: 5, + thread: 1, + }, + ) + .is_err()); + + // gas too high + speculative + .deferred_calls_changes + .set_effective_slot_gas(good_slot, 999_000_000); + + assert!(speculative + .compute_call_fee( + good_slot, + 1_100_000, + Slot { + period: 1, + thread: 1, + }, + ) + .is_err()); + + // TODO : add more tests with different values and check the results of the fee + } } From 6d25ee632266d4b9446967c859fcc72526a2a27a Mon Sep 17 00:00:00 2001 From: modship Date: Thu, 3 Oct 2024 19:09:41 +0200 Subject: [PATCH 090/100] Test : add test for deferred call exists --- .../src/tests/scenarios_mandatories.rs | 161 ++++++++++++++++++ .../src/tests/wasm/deferred_call_exists.wasm | Bin 0 -> 3387 bytes .../tests/wasm/deferred_call_register.wasm | Bin 1187 -> 1232 bytes .../wasm/deferred_call_register_fail.wasm | Bin 3663 -> 1236 bytes 4 files changed, 161 insertions(+) create mode 100644 massa-execution-worker/src/tests/wasm/deferred_call_exists.wasm diff --git a/massa-execution-worker/src/tests/scenarios_mandatories.rs b/massa-execution-worker/src/tests/scenarios_mandatories.rs index a9ed9767f93..71c2d1145ba 100644 --- a/massa-execution-worker/src/tests/scenarios_mandatories.rs +++ b/massa-execution-worker/src/tests/scenarios_mandatories.rs @@ -1579,6 +1579,167 @@ fn deferred_call_register_fail() { // let ev = events[1].clone(); } + +#[test] +fn deferred_call_exists() { + // setup the period duration + let exec_cfg = ExecutionConfig::default(); + let finalized_waitpoint = WaitPoint::new(); + let mut foreign_controllers = ExecutionForeignControllers::new_with_mocks(); + let target_slot = Slot { + period: 10, + thread: 1, + }; + + foreign_controllers + .ledger_controller + .set_expectations(|ledger_controller| { + ledger_controller + .expect_get_balance() + .returning(move |_| Some(Amount::from_str("100").unwrap())); + + ledger_controller + .expect_entry_exists() + .times(2) + .returning(move |_| false); + + ledger_controller + .expect_entry_exists() + .times(1) + .returning(move |_| true); + }); + + selector_boilerplate(&mut foreign_controllers.selector_controller); + + let saved_bytecode = expect_finalize_deploy_and_call_blocks( + Slot::new(1, 1), + Some(Slot::new(1, 2)), + finalized_waitpoint.get_trigger_handle(), + &mut foreign_controllers.final_state, + ); + + let finalized_waitpoint_trigger_handle = finalized_waitpoint.get_trigger_handle(); + foreign_controllers + .final_state + .write() + .expect_finalize() + .times(1) + .with(predicate::eq(Slot::new(1, 0)), predicate::always()) + .returning(move |_, changes| { + assert!(changes.deferred_call_changes.effective_total_gas == SetOrKeep::Keep); + finalized_waitpoint_trigger_handle.trigger(); + }); + + let call = DeferredCall { + sender_address: Address::from_str("AU1TyzwHarZMQSVJgxku8co7xjrRLnH74nFbNpoqNd98YhJkWgi") + .unwrap(), + target_slot, + target_address: Address::from_str("AS12jc7fTsSKwQ9hSk97C3iMNgNT1XrrD6MjSJRJZ4NE53YgQ4kFV") + .unwrap(), + target_function: "toto".to_string(), + parameters: vec![42, 42, 42, 42], + coins: Amount::from_raw(100), + max_gas: 1000000, + fee: Amount::from_raw(1), + cancelled: false, + }; + + let call_id = + DeferredCallId::new(0, target_slot, 0, "trail_hash".to_string().as_bytes()).unwrap(); + let registry = DeferredCallRegistry::new( + foreign_controllers.db.clone(), + DeferredCallsConfig::default(), + ); + + let mut defer_reg_slot_changes = DeferredRegistrySlotChanges { + calls: BTreeMap::new(), + effective_slot_gas: massa_deferred_calls::DeferredRegistryGasChange::Set(500), + base_fee: massa_deferred_calls::DeferredRegistryBaseFeeChange::Keep, + }; + + defer_reg_slot_changes.set_call(call_id.clone(), call.clone()); + + let mut slot_changes = BTreeMap::default(); + slot_changes.insert(target_slot, defer_reg_slot_changes); + + let mut db_batch = DBBatch::default(); + + registry.apply_changes_to_batch( + DeferredCallRegistryChanges { + slots_change: slot_changes, + effective_total_gas: SetOrKeep::Set(2000), + total_calls_registered: SetOrKeep::Set(1), + }, + &mut db_batch, + ); + + foreign_controllers + .db + .write() + .write_batch(db_batch, DBBatch::default(), Some(Slot::new(1, 0))); + + final_state_boilerplate( + &mut foreign_controllers.final_state, + foreign_controllers.db.clone(), + &foreign_controllers.selector_controller, + &mut foreign_controllers.ledger_controller, + Some(saved_bytecode), + None, + None, + Some(registry), + ); + + let mut universe = ExecutionTestUniverse::new(foreign_controllers, exec_cfg); + + let keypair = KeyPair::from_str(TEST_SK_2).unwrap(); + let block = + ExecutionTestUniverse::create_block(&keypair, Slot::new(1, 0), vec![], vec![], vec![]); + + universe.send_and_finalize(&keypair, block); + + finalized_waitpoint.wait(); + + // block 1,1 + universe.deploy_bytecode_block( + &keypair, + Slot::new(1, 1), + include_bytes!("./wasm/deferred_call_exists.wasm"), + include_bytes!("./wasm/deferred_call_exists.wasm"), + ); + finalized_waitpoint.wait(); + let address_sc = universe.get_address_sc_deployed(Slot::new(1, 1)); + + // block 1,2 + let operation = ExecutionTestUniverse::create_call_sc_operation( + &KeyPair::from_str(TEST_SK_3).unwrap(), + 10000000, + Amount::from_str("0.01").unwrap(), + Amount::from_str("20").unwrap(), + Address::from_str(&address_sc).unwrap(), + String::from("exists"), + call_id.to_string().as_bytes().to_vec(), + ) + .unwrap(); + + universe.call_sc_block( + &KeyPair::from_str(TEST_SK_3).unwrap(), + Slot { + period: 1, + thread: 2, + }, + operation, + ); + finalized_waitpoint.wait(); + let events = universe + .module_controller + .get_filtered_sc_output_event(EventFilter { + emitter_address: Some(Address::from_str(&address_sc).unwrap()), + ..Default::default() + }); + + assert_eq!(events[1].data, "true"); +} + /// Context /// /// Functional test for local smart-contract execution diff --git a/massa-execution-worker/src/tests/wasm/deferred_call_exists.wasm b/massa-execution-worker/src/tests/wasm/deferred_call_exists.wasm new file mode 100644 index 0000000000000000000000000000000000000000..eb6ce3d0076e0ee70eca757b8206363dde03b6cc GIT binary patch literal 3387 zcmaJ^J#1Uo6+ZXAAM)`&lFvy|AZ6;@$0(_aMs|x98PWjpDNxsrn;K}5nWn^NRiq?R zk56(01SOH8K!yw+I~Zt24<3w69x`|;0wf4BwHZ7Z=#oK$M-Kwj@4WjY+H6n}m*@U` z=jVRsoC}Kj(;Y=bYNd8V&D0EEbVJW%=FMi96W#DJk(rw5FIDJey9YskeVi8*1Uvod zwBNy3wzIx{*qd(TTa%)fMr>xg zSuU9DAlofSIYTSUut9b+%kyl|+vsm^_p%SRrp1)VYc)x0Pm`wqW>_h=f?jVoyG1p~2@cw|UT=R_W=YiRZH%|KvyFnznO-k1 ziml#yf0}tJ+{t#v`Jtw|dLgPQVr5hutJTJr?dIQ<3TBr0_~hioyXIfwPwV`+&ME&m zAu_L0SFu0rY9L-5@??+wQJ02Y?;Yy;oD|%a&29ii>s!wTBZiqF&*vZRadOZNup7MF zxkOA?012uI8Dp%sLRMLNQ^TMzJfikiH7K(*yqpHGl?=P#8KbENP2p7` z2qRq1#jiN60@uT?59Wgf^Pw;=EQd?Xhu94l%!ki1?}K^IYA_#wIG0g5Ui9bLwQ#)d`q zQ{`Pkp#)N@z$cPBg_<0uLSmV^G(qj%*ckdgycxa3EQe^_#>C9+UJbwr^Lq*20UN?zoj zm*BEH>n=~OAtD>O<@HWC0%IYRE5SJ8z@e2Zp z1tLJeDr541%;&yTGq@|=Ldw<%ZP7U3`F&56PGDpHz{~OM<}O(p$uf8x5jNC}WKz{ZY~g_;%ZLkuZMT<~g3qB*k^+qE!s0ZG6VGL47J{3$tCAC?Lm> z+t|%%lQQD3obI=E^P1?M$M_4*w`iR%0#o37itl}_FF;P=Ei&p2c#F)dqVY1uRaifO zP0<^a_A~5k0{>^?&w)pDUqoh2@UK7TL2SDSCDI(9J{_KVI)>)U#2+_|3W)DOV0E`) zjM(up-ol4Jcl%#JDB?#D@b+E9{8CVFU@S*B!o3f1lRrV`%hBF3MtuS=#{5-@fe$ej zgj}K>1USVD^VjcLyip&Azm?o�T4of&@e_Y8BX>w z-vYX#`(9jL=t2B_^ere`hu%$momrDt+JRNv`i{GKYC8* ze>^+_8YS>u%S0_8>ljG+vD^K)ZICg(1A+3q+g_CCA`0O-M+9=yilwiBhs|%>rY#YO zO~LF76G!gsY1^EWGyJ9jSCaXuoZ`oNvyCl#Hu!F0(gBuQVK7D{t?2%KQ%Os|NT%cc id?S0WKf$l~&G-NK`&TYp{J#GiF5JSuOc!?glm7yz+Es!8 literal 0 HcmV?d00001 diff --git a/massa-execution-worker/src/tests/wasm/deferred_call_register.wasm b/massa-execution-worker/src/tests/wasm/deferred_call_register.wasm index 77110356640cee1f97fc66428d6e394b113478df..523f6a86a5b02f867d732255f82ee6cb66b870bd 100644 GIT binary patch delta 134 zcmZ3?d4Y4nKc-gZNsOm`6Brrm9XTD@1(=l>oEXfR859^C8LSvM6d0TsAv{JP&ym5A z6{v#Iv4O{t;SU!BgX0A*#|zvF44NPfx(pmn50(olFiw8Qn8!GIb1c&jMi~wU2A~uS UJO1F|=1c){nHYgWlk-?i0TUA$BLDyZ delta 89 zcmcb>xtMdpKc?GElNe7cn=v>tII;>bD=|1W@HjI3;bLHLyujsnf!m4EkarT{Ft6t(~W diff --git a/massa-execution-worker/src/tests/wasm/deferred_call_register_fail.wasm b/massa-execution-worker/src/tests/wasm/deferred_call_register_fail.wasm index 1d9c6b68a1d1ab63f355090082d6d41666664d6b..c8189911c8c2a78f55e37daa0af30622b09485ae 100644 GIT binary patch delta 385 zcmX|-ze)o^5XQf`y??p8glkNtaEJ;Pf?XhmIEPkw1dF{(yds#pNOCGRZXUqG5WzO@ zVBss+nIffyg`L)7A;b+4XBlRGGqWGeysXbF2S|rG0ibO=A%z4;Or;Hpp%kgaQR-&- zbV{0yju2UKX{GJ{poB3#+98b3_LXA`ON)>t2xJF_B8IQPZ-MU|J7%7C3s{zvMRo@c^FsJPji3 zEHJ^uUJUj7Hv_0qNpo{mlP$D zS8`kgp$Y`82N%tdp+g6cS@Iuf2s(KvicC!g4@Kc2Kr?jAAi(|o&Xwb)$Uq%@=lT7< z_qj)u-gH}ui26Zx&6&;AY)#E%O=QiR;ZN4Gv)Q|BIB@NT0*}*o-DrH^_ttkNiMalD zZ#wOrLl25{iXwplfZgdch6HzJKh5u*Uh&H3iB--fqd!tcz5^W8p zNi-49%`b=#!!pWod{<#oaAwMgo{4$Cq_ZnoZ@V`bOV;mp$I)Gw(e3VHoy&H+`(w@) z7P{U3&S(_%6UpmtcakK7?s{(;xhk_AZSPF(Ig(Slpw8!ims@zGRAv^4`Qqu*r|wPf zvU!*@|IC?xh&fjj(Kso_70(=h{kUwt$I}<3;u{@-O4;_PI%3|8)p%PKe#;x9ZYGIKi<|rzsbQWyiQMB)@7@j1i`lQr`kq^a7+(i_$&hjrWOIV_>#RC1gbq$KcgtdTzzmtC8$%>T&n zzmidr8;pPv(v4Du`TEZAqEnxfsF*8g7^l#-pw$ndZ9%_C#97dFNI!r~;x?@O2s>Nge@n~} z_+j0n1^qJlFMLe{Wv3R>(g|8m?mg3V4CGlc_w!o$V*Y{ws}J*9Q;rAv5t=!|{w>JQ z>sPp62PKem4|co;4>v)S8(GV!g^>yD&KB&Y1>`Ufv{vuHFRk||Ck7e0BUM?(ye}2mi$y|ko3CThR?UbRh3^_ov%p~yD|7~$eW;F!@AqDA`S5W z3cPP%J(R2R3urH-Q7!22Qu`u^HupgT#1@%40tftmgaOfboUT5{fLb}m0Nd}M(nF#* zK+N?W8;OC<#YOqP^}2`CfxL}*S_AvC4e4WW2AJ*Jcm&9Hgf;sF-bR)qKqQD7+ep^n zn>jvZb9;aBn{vAk>;SP|0)kp7ZSpL)M~kU9i+X_;lR|j4sQ=`Kn1zU82z?26Ze)6+JUl1z#0>Rq$28R|Q`cd{yvK3OSZ-tD&!h8lWbq1!{vjRuiR= zqh?zjJ#*CrwLoo9$67;8ltPZWZ4LBIPz%%sb*#m-hMFja91Yu==v$yRr~?!|qt&#C z+9;_3VrzlgAl4bZr)RX97Ev1|k&CSj>Y!(Y=si87)wGD(D2ZHb9keuxj1ax2XSA9Y zQ5z+Z%Y5;IcFuZYzI;LdA;(Pd^39v25ET<5_aSOIMCF92f)IC!`JE?wRp6_@SAnkr zUj@Dj{JdFR27Vd%W#E^AUj}{|c-GZC*{%U!1HJ})4fq=HHQ-s3^Hf0{_&V@);OoHG zfv*G4dY-2`8o)PzZvfu_z5#p#_<5_Q349ayCh$$*o4_}LpSPM?z_);J0p9|?1w6ln z^Hy0K_%`ru;M>5rfo}spZ}oM6?*QKcz5{#*_zv)_Dpm%w%M3Bfj1;}4#neh<&$e~+ z{Pu5vBG4uzvMO0wtPWw`8x5oi-DRy3=UmBs2{hM6Tsn$e=i zw3?cUX4?SqtG3Kcu#P{^qR Date: Thu, 3 Oct 2024 19:15:04 +0200 Subject: [PATCH 091/100] clippy --- massa-execution-worker/src/speculative_deferred_calls.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/massa-execution-worker/src/speculative_deferred_calls.rs b/massa-execution-worker/src/speculative_deferred_calls.rs index 8c0090c7b5c..6a3490bf11d 100644 --- a/massa-execution-worker/src/speculative_deferred_calls.rs +++ b/massa-execution-worker/src/speculative_deferred_calls.rs @@ -594,7 +594,7 @@ mod tests { let mut speculative = SpeculativeDeferredCallRegistry::new( mock_final_state, Arc::new(Default::default()), - config.clone(), + config, ); let max_period = config.max_future_slots / THREAD_COUNT as u64; From 46fccbec957ce8f925f2b388ccdae8cb3eceae0a Mon Sep 17 00:00:00 2001 From: modship Date: Mon, 7 Oct 2024 16:43:58 +0200 Subject: [PATCH 092/100] Fix : fee calculation --- .../src/speculative_deferred_calls.rs | 77 +++++++++++-------- 1 file changed, 43 insertions(+), 34 deletions(-) diff --git a/massa-execution-worker/src/speculative_deferred_calls.rs b/massa-execution-worker/src/speculative_deferred_calls.rs index 6a3490bf11d..a3e6711a6a1 100644 --- a/massa-execution-worker/src/speculative_deferred_calls.rs +++ b/massa-execution-worker/src/speculative_deferred_calls.rs @@ -12,7 +12,10 @@ use massa_models::{ slot::Slot, }; use parking_lot::RwLock; -use std::{cmp::max, sync::Arc}; +use std::{ + cmp::{max, min}, + sync::Arc, +}; const TARGET_BOOKING: u128 = (MAX_ASYNC_GAS / 2) as u128; @@ -172,6 +175,7 @@ impl SpeculativeDeferredCallRegistry { let mut slot_calls = self.get_calls_by_slot(current_slot); let total_booked_gas_before = self.get_effective_total_gas(); + // get the previous average booking rate per slot let avg_booked_gas = total_booked_gas_before.saturating_div(self.config.max_future_slots as u128); // select the slot that is newly made available and set its base fee @@ -183,29 +187,40 @@ impl SpeculativeDeferredCallRegistry { .get_prev_slot(self.config.thread_count) .expect("cannot get prev slot"); - let prev_slot_base_fee = self.get_slot_base_fee(&prev_slot); + let prev_slot_base_fee = { + let temp_slot_fee = self.get_slot_base_fee(&prev_slot); + if temp_slot_fee.eq(&Amount::zero()) { + Amount::from_raw(self.config.min_gas_cost) + } else { + temp_slot_fee + } + }; let new_slot_base_fee = match avg_booked_gas.cmp(&TARGET_BOOKING) { + // the previous booking rate was exactly the expected one: do not adjust the base fee std::cmp::Ordering::Equal => prev_slot_base_fee, + // more gas was booked than expected: increase the base fee std::cmp::Ordering::Greater => { let gas_used_delta = avg_booked_gas.saturating_sub(TARGET_BOOKING); - let factor = gas_used_delta as u64 - / TARGET_BOOKING as u64 - / self.config.base_fee_max_max_change_denominator as u64; + let factor = gas_used_delta + .saturating_div(TARGET_BOOKING) + .saturating_div(self.config.base_fee_max_max_change_denominator as u128) + as u64; - max( - prev_slot_base_fee - .saturating_add(prev_slot_base_fee.saturating_mul_u64(factor)), + prev_slot_base_fee.saturating_add(max( + prev_slot_base_fee.saturating_mul_u64(factor), Amount::from_raw(self.config.min_gas_increment), - ) + )) } + // less gas was booked than expected: decrease the base fee std::cmp::Ordering::Less => { - let gas_used_delta = TARGET_BOOKING.saturating_sub(total_booked_gas_before); + let gas_used_delta = TARGET_BOOKING.saturating_sub(avg_booked_gas); - let factor = gas_used_delta as u64 - / TARGET_BOOKING as u64 - / self.config.base_fee_max_max_change_denominator as u64; + let factor = gas_used_delta + .saturating_div(TARGET_BOOKING) + .saturating_div(self.config.base_fee_max_max_change_denominator as u128) + as u64; max( prev_slot_base_fee @@ -387,23 +402,18 @@ impl SpeculativeDeferredCallRegistry { return Err(ExecutionError::DeferredCallsError( "Denominator is zero on overbooking fee".into(), )); - // OR - // return Ok(Amount::from_raw(0)); } // compute using the raw fee and u128 to avoid u64 overflows let raw_max_penalty = max_penalty.to_raw() as u128; - let raw_fee = (raw_max_penalty * relu_occupancy_after / denominator * relu_occupancy_after - / denominator) - .saturating_sub( - raw_max_penalty * relu_occupancy_before / denominator * relu_occupancy_before - / denominator, - ); - - Ok(Amount::from_raw( - std::cmp::min(raw_fee, u64::MAX as u128) as u64 + let raw_fee = (raw_max_penalty.saturating_mul( + (relu_occupancy_after.saturating_mul(relu_occupancy_after)) + .saturating_sub(relu_occupancy_before.saturating_mul(relu_occupancy_before)), )) + .saturating_div(denominator.saturating_mul(denominator)); + + Ok(Amount::from_raw(min(raw_fee, u64::MAX as u128) as u64)) } /// Compute call fee @@ -457,23 +467,22 @@ impl SpeculativeDeferredCallRegistry { // A fee that linearly depends on the total load over `deferred_call_max_future_slots` slots but only when the average load is above `target_async_gas` to not penalize normal use. Booking all the gas from all slots within the booking period requires using the whole initial coin supply. // Global overbooking fee - // TODO check if this is correct let global_occupancy = self.get_effective_total_gas(); let global_overbooking_fee = Self::overbooking_fee( - (self.config.max_gas as u128).saturating_mul(self.config.max_future_slots as u128), - (self.config.max_future_slots as u128).saturating_mul(TARGET_BOOKING), - global_occupancy, - max_gas_request as u128, - self.config.global_overbooking_penalty, // total_supply + (self.config.max_gas as u128).saturating_mul(self.config.max_future_slots as u128), // total available async gas during the booking period + (self.config.max_future_slots as u128).saturating_mul(TARGET_BOOKING), // target a 50% async gas usage over the booking period + global_occupancy, // total amount of async gas currently booked in the booking period + max_gas_request as u128, // amount of gas to book + self.config.global_overbooking_penalty, // fully booking all slots of the booking period requires spending the whole initial supply of coins )?; // Finally, a per-slot proportional fee is also added to prevent attackers from denying significant ranges of consecutive slots within the long booking period. // Slot overbooking fee let slot_overbooking_fee = Self::overbooking_fee( - self.config.max_gas as u128, - TARGET_BOOKING, - slot_occupancy as u128, - max_gas_request as u128, + self.config.max_gas as u128, // total available async gas during the target slot + TARGET_BOOKING, // target a 50% async gas usage during the target slot + slot_occupancy as u128, // total amount of async gas currently booked in the target slot + max_gas_request as u128, // amount of gas to book in the target slot self.config.slot_overbooking_penalty, // total_initial_coin_supply/10000 )?; From 8ebf906b8026eb4d4029808bce5c490273595677 Mon Sep 17 00:00:00 2001 From: modship Date: Wed, 16 Oct 2024 15:21:33 +0200 Subject: [PATCH 093/100] add storage cost for deferred call --- Cargo.lock | 4 +- Cargo.toml | 4 +- massa-api-exports/src/execution.rs | 2 + massa-api/src/public.rs | 1 + massa-deferred-calls/src/config.rs | 5 +- massa-execution-exports/src/mapping_grpc.rs | 3 +- massa-execution-exports/src/types.rs | 2 + massa-execution-worker/src/context.rs | 11 ++- massa-execution-worker/src/controller.rs | 7 +- massa-execution-worker/src/execution.rs | 8 +- massa-execution-worker/src/interface_impl.rs | 11 ++- .../src/speculative_deferred_calls.rs | 73 ++++++++++++++++++- massa-node/base_config/openrpc.json | 6 +- massa-node/src/main.rs | 1 + 14 files changed, 121 insertions(+), 17 deletions(-) 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(), From 88ecb0da22c594fb5d880fb8b2dff24a4644fc82 Mon Sep 17 00:00:00 2001 From: modship Date: Fri, 18 Oct 2024 12:35:00 +0200 Subject: [PATCH 094/100] Storage: Refund sender (storage cost for params) --- massa-execution-worker/src/execution.rs | 227 +++++++++--------- .../src/speculative_deferred_calls.rs | 17 +- .../src/tests/scenarios_mandatories.rs | 170 ++++++------- massa-metrics/src/lib.rs | 17 +- 4 files changed, 222 insertions(+), 209 deletions(-) diff --git a/massa-execution-worker/src/execution.rs b/massa-execution-worker/src/execution.rs index eb19716b001..d419873b72e 100644 --- a/massa-execution-worker/src/execution.rs +++ b/massa-execution-worker/src/execution.rs @@ -1248,123 +1248,135 @@ impl ExecutionState { let mut result = DeferredCallExecutionResult::new(&call); let snapshot = { - let context = context_guard!(self); + let mut context = context_guard!(self); + + // refund the sender for the storage costs + let amount = self + .config + .storage_costs_constants + .ledger_cost_per_byte + .saturating_mul_u64(call.parameters.len() as u64); + context.transfer_coins(None, Some(call.sender_address), amount, false)?; + context.get_snapshot() }; - let deferred_call_execution = || { - let bytecode = { - // acquire write access to the context - let mut context = context_guard!(self); + if call.cancelled { + Ok(result) + } else { + let deferred_call_execution = || { + let bytecode = { + // acquire write access to the context + let mut context = context_guard!(self); - // Set the call stack - // This needs to be defined before anything can fail, so that the emitted event contains the right stack - context.stack = vec![ - ExecutionStackElement { - address: call.sender_address, - coins: Default::default(), - owned_addresses: vec![call.sender_address], - operation_datastore: None, - }, - ExecutionStackElement { - address: call.target_address, - coins: call.coins, - owned_addresses: vec![call.target_address], - operation_datastore: None, - }, - ]; - - // Ensure that the target address is an SC address - // Ensure that the target address exists - context.check_target_sc_address(call.target_address)?; - - // credit coins to the target address - if let Err(err) = - context.transfer_coins(None, Some(call.target_address), call.coins, false) - { - // coin crediting failed: reset context to snapshot and reimburse sender - return Err(ExecutionError::DeferredCallsError(format!( - "could not credit coins to target of deferred call execution: {}", - err - ))); - } + // Set the call stack + // This needs to be defined before anything can fail, so that the emitted event contains the right stack + context.stack = vec![ + ExecutionStackElement { + address: call.sender_address, + coins: Default::default(), + owned_addresses: vec![call.sender_address], + operation_datastore: None, + }, + ExecutionStackElement { + address: call.target_address, + coins: call.coins, + owned_addresses: vec![call.target_address], + operation_datastore: None, + }, + ]; + + // Ensure that the target address is an SC address + // Ensure that the target address exists + context.check_target_sc_address(call.target_address)?; + + // credit coins to the target address + if let Err(err) = + context.transfer_coins(None, Some(call.target_address), call.coins, false) + { + // coin crediting failed: reset context to snapshot and reimburse sender + return Err(ExecutionError::DeferredCallsError(format!( + "could not credit coins to target of deferred call execution: {}", + err + ))); + } - // quit if there is no function to be called - if call.target_function.is_empty() { - return Err(ExecutionError::DeferredCallsError( - "no function to call in the deferred call".to_string(), - )); - } + // quit if there is no function to be called + if call.target_function.is_empty() { + return Err(ExecutionError::DeferredCallsError( + "no function to call in the deferred call".to_string(), + )); + } - // Load bytecode. Assume empty bytecode if not found. - context - .get_bytecode(&call.target_address) - .ok_or(ExecutionError::DeferredCallsError( - "no bytecode found".to_string(), - ))? - .0 - }; + // Load bytecode. Assume empty bytecode if not found. + context + .get_bytecode(&call.target_address) + .ok_or(ExecutionError::DeferredCallsError( + "no bytecode found".to_string(), + ))? + .0 + }; - let module = self.module_cache.write().load_module( - &bytecode, - call.get_effective_gas(self.config.deferred_calls_config.call_cst_gas_cost), - )?; - let response = massa_sc_runtime::run_function( - &*self.execution_interface, - module, - &call.target_function, - &call.parameters, - call.get_effective_gas(self.config.deferred_calls_config.call_cst_gas_cost), - self.config.gas_costs.clone(), - self.config.condom_limits.clone(), - ); + let module = self.module_cache.write().load_module( + &bytecode, + call.get_effective_gas(self.config.deferred_calls_config.call_cst_gas_cost), + )?; + let response = massa_sc_runtime::run_function( + &*self.execution_interface, + module, + &call.target_function, + &call.parameters, + call.get_effective_gas(self.config.deferred_calls_config.call_cst_gas_cost), + self.config.gas_costs.clone(), + self.config.condom_limits.clone(), + ); - match response { - Ok(res) => { - self.module_cache - .write() - .set_init_cost(&bytecode, res.init_gas_cost); - #[cfg(feature = "execution-trace")] - { - result.traces = - Some((res.trace.into_iter().map(|t| t.into()).collect(), true)); - } - // #[cfg(feature = "execution-info")] - // { - // result.success = true; - // } - result.success = true; - Ok(result) - } - Err(error) => { - if let VMError::ExecutionError { init_gas_cost, .. } = error { + match response { + Ok(res) => { self.module_cache .write() - .set_init_cost(&bytecode, init_gas_cost); + .set_init_cost(&bytecode, res.init_gas_cost); + #[cfg(feature = "execution-trace")] + { + result.traces = + Some((res.trace.into_iter().map(|t| t.into()).collect(), true)); + } + // #[cfg(feature = "execution-info")] + // { + // result.success = true; + // } + result.success = true; + Ok(result) + } + Err(error) => { + if let VMError::ExecutionError { init_gas_cost, .. } = error { + self.module_cache + .write() + .set_init_cost(&bytecode, init_gas_cost); + } + // execution failed: reset context to snapshot and reimburse sender + Err(ExecutionError::VMError { + context: "Deferred Call".to_string(), + error, + }) } - // execution failed: reset context to snapshot and reimburse sender - Err(ExecutionError::VMError { - context: "Deferred Call".to_string(), - error, - }) } - } - }; + }; - // execute the deferred call - let execution_result = deferred_call_execution(); + // execute the deferred call + let execution_result = deferred_call_execution(); - // if the execution failed, reset the context to the snapshot - if let Err(err) = &execution_result { - let mut context = context_guard!(self); - context.reset_to_snapshot(snapshot, err.clone()); - context.deferred_call_fail_exec(id, &call); - self.massa_metrics.inc_deferred_calls_failed(); - } else { - self.massa_metrics.inc_deferred_calls_executed(); + // if the execution failed, reset the context to the snapshot + if let Err(err) = &execution_result { + let mut context = context_guard!(self); + context.reset_to_snapshot(snapshot, err.clone()); + context.deferred_call_fail_exec(id, &call); + self.massa_metrics.inc_deferred_calls_failed(); + } else { + self.massa_metrics.inc_deferred_calls_executed(); + } + execution_result } - - execution_result } /// Executes a full slot (with or without a block inside) without causing any changes to the state, /// just yielding the execution output. @@ -1409,19 +1421,16 @@ impl ExecutionState { // Deferred calls let calls = execution_context.deferred_calls_advance_slot(*slot); - self.massa_metrics - .set_deferred_calls_total_gas(calls.effective_total_gas); - // Apply the created execution context for slot execution *context_guard!(self) = execution_context; for (id, call) in calls.slot_calls { - if call.cancelled { - // Skip cancelled calls - continue; - } + let cancelled = call.cancelled; match self.execute_deferred_call(&id, call) { Ok(_exec) => { + if cancelled { + continue; + } info!("executed deferred call: {:?}", id); cfg_if::cfg_if! { if #[cfg(feature = "execution-trace")] { diff --git a/massa-execution-worker/src/speculative_deferred_calls.rs b/massa-execution-worker/src/speculative_deferred_calls.rs index 37ea08ed332..f7f0eaac66d 100644 --- a/massa-execution-worker/src/speculative_deferred_calls.rs +++ b/massa-execution-worker/src/speculative_deferred_calls.rs @@ -244,6 +244,8 @@ impl SpeculativeDeferredCallRegistry { slot_calls.effective_total_gas = total_gas_after; + massa_metrics::set_deferred_calls_total_gas(slot_calls.effective_total_gas); + // delete call in the current slot let mut nb_call_to_execute = 0; for (id, call) in &slot_calls.slot_calls { @@ -494,15 +496,7 @@ impl SpeculativeDeferredCallRegistry { )?; // 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(), - ) - })?; + let storage_cost = self.get_storage_cost_by_size(params_size); // return the fee Ok(integral_fee @@ -511,6 +505,11 @@ impl SpeculativeDeferredCallRegistry { .saturating_add(storage_cost)) } + /// Get the storage cost for a given size + pub fn get_storage_cost_by_size(&self, size: u64) -> Amount { + self.config.ledger_cost_per_byte.saturating_mul_u64(size) + } + /// Register a new call /// Returns the call id /// # Arguments diff --git a/massa-execution-worker/src/tests/scenarios_mandatories.rs b/massa-execution-worker/src/tests/scenarios_mandatories.rs index e107f3462cb..22dc54986bb 100644 --- a/massa-execution-worker/src/tests/scenarios_mandatories.rs +++ b/massa-execution-worker/src/tests/scenarios_mandatories.rs @@ -514,6 +514,7 @@ fn test_nested_call_recursion_limit_reached() { Some(saved_bytecode), None, None, + None, ); let mut universe = ExecutionTestUniverse::new(foreign_controllers, exec_cfg); @@ -604,6 +605,7 @@ fn test_nested_call_recursion_limit_not_reached() { Some(saved_bytecode), None, None, + None, ); let mut universe = ExecutionTestUniverse::new(foreign_controllers, exec_cfg); @@ -1023,6 +1025,7 @@ fn send_and_receive_async_message_expired() { Some(saved_bytecode), None, None, + None, ); let mut universe = ExecutionTestUniverse::new(foreign_controllers, exec_cfg.clone()); @@ -1111,6 +1114,7 @@ fn send_and_receive_async_message_expired_2() { Some(saved_bytecode), None, None, + None, ); let mut universe = ExecutionTestUniverse::new(foreign_controllers, exec_cfg.clone()); @@ -1201,6 +1205,7 @@ fn send_and_receive_async_message_without_init_gas() { Some(saved_bytecode), None, None, + None, ); let mut universe = ExecutionTestUniverse::new(foreign_controllers, exec_cfg.clone()); @@ -1291,9 +1296,7 @@ fn cancel_async_message() { assert_eq!( changes.ledger_changes.0.get(&sender_addr).unwrap(), &SetUpdateOrDelete::Update(LedgerEntryUpdate { - balance: massa_ledger_exports::SetOrKeep::Set( - Amount::from_str("90.298635211").unwrap() - ), + balance: SetOrKeep::Set(Amount::from_str("90.298635211").unwrap()), bytecode: massa_models::types::SetOrKeep::Keep, datastore: BTreeMap::new() }) @@ -1613,7 +1616,7 @@ fn deferred_calls() { let block = ExecutionTestUniverse::create_block(&keypair, Slot::new(1, 1), vec![], vec![], vec![]); - universe.send_and_finalize(&keypair, block); + universe.send_and_finalize(&keypair, block, None); finalized_waitpoint.wait(); // retrieve events emitted by smart contracts let events = universe @@ -1636,6 +1639,7 @@ fn deferred_call_register() { let finalized_waitpoint = WaitPoint::new(); let mut foreign_controllers = ExecutionForeignControllers::new_with_mocks(); let keypair = KeyPair::from_str(TEST_SK_1).unwrap(); + let keypair2 = KeyPair::from_str(TEST_SK_3).unwrap(); let saved_bytecode = Arc::new(RwLock::new(None)); let db_lock = foreign_controllers.db.clone(); @@ -1645,6 +1649,8 @@ fn deferred_call_register() { let sender_addr_clone = sender_addr; + dbg!(Address::from_public_key(&keypair2.get_public_key()).to_string()); + selector_boilerplate(&mut foreign_controllers.selector_controller); foreign_controllers @@ -1675,44 +1681,45 @@ fn deferred_call_register() { .times(1) .with(predicate::eq(Slot::new(1, 0)), predicate::always()) .returning(move |_, changes| { + dbg!(&changes); // assert sender was debited ( -10 coins) and -5.25 for fees - match changes.ledger_changes.0.get(&sender_addr_clone).unwrap() { - SetUpdateOrDelete::Update(change_sc_update) => { - assert_eq!( - change_sc_update.balance, - SetOrKeep::Set(Amount::from_str("85.77").unwrap()) - ); - } - _ => panic!("wrong change type"), - }; - - { - // manually write the deferred call to the db - // then in the next slot (1,1) we will find and execute it - let reg = - DeferredCallRegistry::new(db_lock.clone(), DeferredCallsConfig::default()); - let mut batch = DBBatch::default(); - reg.apply_changes_to_batch(changes.deferred_call_changes.clone(), &mut batch); - db_lock - .write() - .write_batch(batch, DBBatch::default(), Some(Slot::new(1, 0))); - } - - let slot_changes = changes - .deferred_call_changes - .slots_change - .get(&Slot::new(1, 1)) - .unwrap(); - let _call = slot_changes.calls.first_key_value().unwrap().1; - - // assert total gas was set to 1050000 = (750_000 + 300_000) = (allocated gas + call gas) - assert_eq!( - changes.deferred_call_changes.effective_total_gas, - SetOrKeep::Set(1050000) - ); - - //gas was set to 1050000 = (750_000 + 300_000) = (allocated gas + call gas) - assert_eq!(slot_changes.get_effective_slot_gas().unwrap(), 1050000); + // match changes.ledger_changes.0.get(&sender_addr_clone).unwrap() { + // SetUpdateOrDelete::Update(change_sc_update) => { + // assert_eq!( + // change_sc_update.balance, + // SetOrKeep::Set(Amount::from_str("85.77").unwrap()) + // ); + // } + // _ => panic!("wrong change type"), + // }; + + // { + // // manually write the deferred call to the db + // // then in the next slot (1,1) we will find and execute it + // let reg = + // DeferredCallRegistry::new(db_lock.clone(), DeferredCallsConfig::default()); + // let mut batch = DBBatch::default(); + // reg.apply_changes_to_batch(changes.deferred_call_changes.clone(), &mut batch); + // db_lock + // .write() + // .write_batch(batch, DBBatch::default(), Some(Slot::new(1, 0))); + // } + + // let slot_changes = changes + // .deferred_call_changes + // .slots_change + // .get(&Slot::new(1, 1)) + // .unwrap(); + // let _call = slot_changes.calls.first_key_value().unwrap().1; + + // // assert total gas was set to 1050000 = (750_000 + 300_000) = (allocated gas + call gas) + // assert_eq!( + // changes.deferred_call_changes.effective_total_gas, + // SetOrKeep::Set(1050000) + // ); + + // //gas was set to 1050000 = (750_000 + 300_000) = (allocated gas + call gas) + // assert_eq!(slot_changes.get_effective_slot_gas().unwrap(), 1050000); finalized_waitpoint_trigger_handle.trigger(); }); @@ -1725,41 +1732,42 @@ fn deferred_call_register() { .times(1) .with(predicate::eq(Slot::new(1, 1)), predicate::always()) .returning(move |_, changes| { - match changes - .ledger_changes - .0 - .get( - &Address::from_str("AU1TyzwHarZMQSVJgxku8co7xjrRLnH74nFbNpoqNd98YhJkWgi") - .unwrap(), - ) - .unwrap() - { - SetUpdateOrDelete::Update(change_sc_update) => { - assert_eq!( - change_sc_update.balance, - SetOrKeep::Set(Amount::from_str("110").unwrap()) - ); - } - _ => panic!("wrong change type"), - } - - assert_eq!(changes.deferred_call_changes.slots_change.len(), 2); - let (_slot, slot_change) = changes - .deferred_call_changes - .slots_change - .first_key_value() - .unwrap(); - - let (_id, set_delete) = slot_change.calls.first_key_value().unwrap(); - - // call was executed and then deleted - assert_eq!(set_delete, &SetOrDelete::Delete); - - // assert total gas was set to 0 - assert_eq!( - changes.deferred_call_changes.effective_total_gas, - SetOrKeep::Set(0) - ); + dbg!(&changes); + // match changes + // .ledger_changes + // .0 + // .get( + // &Address::from_str("AU1TyzwHarZMQSVJgxku8co7xjrRLnH74nFbNpoqNd98YhJkWgi") + // .unwrap(), + // ) + // .unwrap() + // { + // SetUpdateOrDelete::Update(change_sc_update) => { + // assert_eq!( + // change_sc_update.balance, + // SetOrKeep::Set(Amount::from_str("110").unwrap()) + // ); + // } + // _ => panic!("wrong change type"), + // } + + // assert_eq!(changes.deferred_call_changes.slots_change.len(), 2); + // let (_slot, slot_change) = changes + // .deferred_call_changes + // .slots_change + // .first_key_value() + // .unwrap(); + + // let (_id, set_delete) = slot_change.calls.first_key_value().unwrap(); + + // // call was executed and then deleted + // assert_eq!(set_delete, &SetOrDelete::Delete); + + // // assert total gas was set to 0 + // assert_eq!( + // changes.deferred_call_changes.effective_total_gas, + // SetOrKeep::Set(0) + // ); finalized_waitpoint_trigger_handle2.trigger(); }); @@ -1840,7 +1848,7 @@ fn deferred_call_register() { let block = ExecutionTestUniverse::create_block(&keypair, Slot::new(1, 1), vec![], vec![], vec![]); - universe.send_and_finalize(&keypair, block); + universe.send_and_finalize(&keypair, block, None); // match the events finalized_waitpoint.wait(); } @@ -1963,7 +1971,7 @@ fn deferred_call_register_fail() { let block = ExecutionTestUniverse::create_block(&keypair, Slot::new(1, 0), vec![], vec![], vec![]); - universe.send_and_finalize(&keypair, block); + universe.send_and_finalize(&keypair, block, None); finalized_waitpoint.wait(); @@ -2146,7 +2154,7 @@ fn deferred_call_exists() { let block = ExecutionTestUniverse::create_block(&keypair, Slot::new(1, 0), vec![], vec![], vec![]); - universe.send_and_finalize(&keypair, block); + universe.send_and_finalize(&keypair, block, None); finalized_waitpoint.wait(); @@ -2625,8 +2633,8 @@ fn roll_buy() { assert_eq!( changes.ledger_changes.0.get(&address).unwrap(), &SetUpdateOrDelete::Update(LedgerEntryUpdate { - balance: massa_ledger_exports::SetOrKeep::Set(rewards_for_block_creator), - bytecode: massa_ledger_exports::SetOrKeep::Keep, + balance: SetOrKeep::Set(rewards_for_block_creator), + bytecode: SetOrKeep::Keep, datastore: BTreeMap::new() }) ); diff --git a/massa-metrics/src/lib.rs b/massa-metrics/src/lib.rs index 1d803bbcfe7..6e8c6909df5 100644 --- a/massa-metrics/src/lib.rs +++ b/massa-metrics/src/lib.rs @@ -34,6 +34,9 @@ lazy_static! { static ref DEFERRED_CALL_REGISTERED: IntGauge = register_int_gauge!( "deferred_calls_registered", "number of deferred calls registered" ).unwrap(); + static ref DEFERRED_CALLS_TOTAL_GAS: IntGauge = register_int_gauge!( + "deferred_calls_total_gas", "total gas used by deferred calls" ).unwrap(); + } pub fn dec_deferred_calls_registered() { @@ -48,6 +51,10 @@ pub fn set_deferred_calls_registered(val: usize) { DEFERRED_CALL_REGISTERED.set(val as i64); } +pub fn set_deferred_calls_total_gas(val: u128) { + DEFERRED_CALLS_TOTAL_GAS.set(val as i64); +} + pub fn get_deferred_calls_registered() -> i64 { DEFERRED_CALL_REGISTERED.get() } @@ -197,7 +204,6 @@ pub struct MassaMetrics { // deferred calls metrics deferred_calls_executed: IntCounter, deferred_calls_failed: IntCounter, - deferred_calls_total_gas: IntGauge, } impl MassaMetrics { @@ -442,9 +448,6 @@ impl MassaMetrics { let deferred_calls_failed = IntCounter::new("deferred_calls_failed", "number of deferred calls failed").unwrap(); - let deferred_calls_total_gas = - IntGauge::new("deferred_total_gas", "total gas used by deferred calls").unwrap(); - let mut stopper = MetricsStopper::default(); if enabled { @@ -499,7 +502,6 @@ impl MassaMetrics { let _ = prometheus::register(Box::new(block_slot_delay.clone())); let _ = prometheus::register(Box::new(deferred_calls_executed.clone())); let _ = prometheus::register(Box::new(deferred_calls_failed.clone())); - let _ = prometheus::register(Box::new(deferred_calls_total_gas.clone())); stopper = server::bind_metrics(addr); } @@ -558,7 +560,6 @@ impl MassaMetrics { tick_delay, deferred_calls_executed, deferred_calls_failed, - deferred_calls_total_gas, }, stopper, ) @@ -755,10 +756,6 @@ impl MassaMetrics { self.deferred_calls_failed.inc(); } - pub fn set_deferred_calls_total_gas(&self, gas: u128) { - self.deferred_calls_total_gas.set(gas as i64); - } - /// Update the bandwidth metrics for all peers /// HashMap pub fn update_peers_tx_rx(&self, data: HashMap) { From ff2837532864a1702fb84ad9ff463e6f2af6beb3 Mon Sep 17 00:00:00 2001 From: modship Date: Mon, 21 Oct 2024 11:00:56 +0200 Subject: [PATCH 095/100] Test : deferred call quote --- .../src/tests/scenarios_mandatories.rs | 210 ++++++++++++------ .../src/tests/wasm/deferred_call_quote.wasm | Bin 0 -> 3352 bytes 2 files changed, 136 insertions(+), 74 deletions(-) create mode 100644 massa-execution-worker/src/tests/wasm/deferred_call_quote.wasm diff --git a/massa-execution-worker/src/tests/scenarios_mandatories.rs b/massa-execution-worker/src/tests/scenarios_mandatories.rs index 22dc54986bb..370f1865cdf 100644 --- a/massa-execution-worker/src/tests/scenarios_mandatories.rs +++ b/massa-execution-worker/src/tests/scenarios_mandatories.rs @@ -1681,45 +1681,44 @@ fn deferred_call_register() { .times(1) .with(predicate::eq(Slot::new(1, 0)), predicate::always()) .returning(move |_, changes| { - dbg!(&changes); // assert sender was debited ( -10 coins) and -5.25 for fees - // match changes.ledger_changes.0.get(&sender_addr_clone).unwrap() { - // SetUpdateOrDelete::Update(change_sc_update) => { - // assert_eq!( - // change_sc_update.balance, - // SetOrKeep::Set(Amount::from_str("85.77").unwrap()) - // ); - // } - // _ => panic!("wrong change type"), - // }; - - // { - // // manually write the deferred call to the db - // // then in the next slot (1,1) we will find and execute it - // let reg = - // DeferredCallRegistry::new(db_lock.clone(), DeferredCallsConfig::default()); - // let mut batch = DBBatch::default(); - // reg.apply_changes_to_batch(changes.deferred_call_changes.clone(), &mut batch); - // db_lock - // .write() - // .write_batch(batch, DBBatch::default(), Some(Slot::new(1, 0))); - // } - - // let slot_changes = changes - // .deferred_call_changes - // .slots_change - // .get(&Slot::new(1, 1)) - // .unwrap(); - // let _call = slot_changes.calls.first_key_value().unwrap().1; - - // // assert total gas was set to 1050000 = (750_000 + 300_000) = (allocated gas + call gas) - // assert_eq!( - // changes.deferred_call_changes.effective_total_gas, - // SetOrKeep::Set(1050000) - // ); - - // //gas was set to 1050000 = (750_000 + 300_000) = (allocated gas + call gas) - // assert_eq!(slot_changes.get_effective_slot_gas().unwrap(), 1050000); + match changes.ledger_changes.0.get(&sender_addr_clone).unwrap() { + SetUpdateOrDelete::Update(change_sc_update) => { + assert_eq!( + change_sc_update.balance, + SetOrKeep::Set(Amount::from_str("75.398235312").unwrap()) + ); + } + _ => panic!("wrong change type"), + }; + + { + // manually write the deferred call to the db + // then in the next slot (1,1) we will find and execute it + let reg = + DeferredCallRegistry::new(db_lock.clone(), DeferredCallsConfig::default()); + let mut batch = DBBatch::default(); + reg.apply_changes_to_batch(changes.deferred_call_changes.clone(), &mut batch); + db_lock + .write() + .write_batch(batch, DBBatch::default(), Some(Slot::new(1, 0))); + } + + let slot_changes = changes + .deferred_call_changes + .slots_change + .get(&Slot::new(1, 1)) + .unwrap(); + let _call = slot_changes.calls.first_key_value().unwrap().1; + + // assert total gas was set to 1050000 = (750_000 + 300_000) = (allocated gas + call gas) + assert_eq!( + changes.deferred_call_changes.effective_total_gas, + SetOrKeep::Set(1050000) + ); + + //gas was set to 1050000 = (750_000 + 300_000) = (allocated gas + call gas) + assert_eq!(slot_changes.get_effective_slot_gas().unwrap(), 1050000); finalized_waitpoint_trigger_handle.trigger(); }); @@ -1732,42 +1731,41 @@ fn deferred_call_register() { .times(1) .with(predicate::eq(Slot::new(1, 1)), predicate::always()) .returning(move |_, changes| { - dbg!(&changes); - // match changes - // .ledger_changes - // .0 - // .get( - // &Address::from_str("AU1TyzwHarZMQSVJgxku8co7xjrRLnH74nFbNpoqNd98YhJkWgi") - // .unwrap(), - // ) - // .unwrap() - // { - // SetUpdateOrDelete::Update(change_sc_update) => { - // assert_eq!( - // change_sc_update.balance, - // SetOrKeep::Set(Amount::from_str("110").unwrap()) - // ); - // } - // _ => panic!("wrong change type"), - // } - - // assert_eq!(changes.deferred_call_changes.slots_change.len(), 2); - // let (_slot, slot_change) = changes - // .deferred_call_changes - // .slots_change - // .first_key_value() - // .unwrap(); - - // let (_id, set_delete) = slot_change.calls.first_key_value().unwrap(); - - // // call was executed and then deleted - // assert_eq!(set_delete, &SetOrDelete::Delete); - - // // assert total gas was set to 0 - // assert_eq!( - // changes.deferred_call_changes.effective_total_gas, - // SetOrKeep::Set(0) - // ); + match changes + .ledger_changes + .0 + .get( + &Address::from_str("AU1TyzwHarZMQSVJgxku8co7xjrRLnH74nFbNpoqNd98YhJkWgi") + .unwrap(), + ) + .unwrap() + { + SetUpdateOrDelete::Update(change_sc_update) => { + assert_eq!( + change_sc_update.balance, + SetOrKeep::Set(Amount::from_str("110").unwrap()) + ); + } + _ => panic!("wrong change type"), + } + + assert_eq!(changes.deferred_call_changes.slots_change.len(), 2); + let (_slot, slot_change) = changes + .deferred_call_changes + .slots_change + .first_key_value() + .unwrap(); + + let (_id, set_delete) = slot_change.calls.first_key_value().unwrap(); + + // call was executed and then deleted + assert_eq!(set_delete, &SetOrDelete::Delete); + + // assert total gas was set to 0 + assert_eq!( + changes.deferred_call_changes.effective_total_gas, + SetOrKeep::Set(0) + ); finalized_waitpoint_trigger_handle2.trigger(); }); @@ -2199,6 +2197,70 @@ fn deferred_call_exists() { assert_eq!(events[1].data, "true"); } +#[test] +fn deferred_call_quote() { + // setup the period duration + let exec_cfg = ExecutionConfig::default(); + let finalized_waitpoint = WaitPoint::new(); + let mut foreign_controllers = ExecutionForeignControllers::new_with_mocks(); + + selector_boilerplate(&mut foreign_controllers.selector_controller); + + let saved_bytecode = expect_finalize_deploy_and_call_blocks( + Slot::new(1, 1), + None, + finalized_waitpoint.get_trigger_handle(), + &mut foreign_controllers.final_state, + ); + + let finalized_waitpoint_trigger_handle = finalized_waitpoint.get_trigger_handle(); + foreign_controllers + .final_state + .write() + .expect_finalize() + .times(1) + .with(predicate::eq(Slot::new(1, 0)), predicate::always()) + .returning(move |_, changes| { + assert!(changes.deferred_call_changes.effective_total_gas == SetOrKeep::Keep); + finalized_waitpoint_trigger_handle.trigger(); + }); + + final_state_boilerplate( + &mut foreign_controllers.final_state, + foreign_controllers.db.clone(), + &foreign_controllers.selector_controller, + &mut foreign_controllers.ledger_controller, + Some(saved_bytecode), + None, + None, + None, + ); + + let mut universe = ExecutionTestUniverse::new(foreign_controllers, exec_cfg); + + let keypair = KeyPair::from_str(TEST_SK_2).unwrap(); + let block = + ExecutionTestUniverse::create_block(&keypair, Slot::new(1, 0), vec![], vec![], vec![]); + + universe.send_and_finalize(&keypair, block, None); + + finalized_waitpoint.wait(); + + // block 1,1 + universe.deploy_bytecode_block( + &keypair, + Slot::new(1, 1), + include_bytes!("./wasm/deferred_call_quote.wasm"), + include_bytes!("./wasm/deferred_call_quote.wasm"), + ); + finalized_waitpoint.wait(); + let events = universe + .module_controller + .get_filtered_sc_output_event(EventFilter::default()); + + assert_eq!(events[0].data, "100000000"); +} + /// Context /// /// Functional test for local smart-contract execution diff --git a/massa-execution-worker/src/tests/wasm/deferred_call_quote.wasm b/massa-execution-worker/src/tests/wasm/deferred_call_quote.wasm new file mode 100644 index 0000000000000000000000000000000000000000..5db659087ea4fe39e90e202982bf60ec71173a16 GIT binary patch literal 3352 zcma)9TWB0r82-=9>?M0rvMSgXYniOAreK@BU%X&XK&V!UcmWB*W|N(?*o@LS2c78j6gowv3C6J8k@A+-kQ~d)!%WFE6X*aXZ*k*s`j&?KPG{m5I5QFIK2t zSy-stfyt{+%pNH(Otz+*e))jsm#f~C*J^py@?>RpwmiQ$=X>IG^|$|9zu~nizE}2^ zyoN7gMxZg_{p#T|6lmPA!wzuFr6B@$UxD%^I({Cw@&HG99a z*Q`X%rKmYCW_w&j<0M{7IOgic<3V#PPj8ciZJb)davgJ1%{1qYGn2qNbe|-`ChnU7 zZYCnI>xSKs8<{ciQZt>-(RmYJN<^?5dGMCKVq_mwB5OCIwRS^0#I;=~Z;5NstZgK3 zIc{)?;zZ@Geq68_heEuj&nl(b_Fh++g`SBOR7h!%;rW)fXIH`n!tEW{y!9{dmx`$s?Urq(QXHA8_Z zHM4es4F9}?ka?pg-~|!Y_~*5E}gt_N7i z{m$uXojrE%s0jypofAKOV~?6BH9H@FH4I&it|;GFh}J?zcH9ZUai{b8+drPZtR9Cy ztX59E^~$Yl_g{Sd$sg93iPdkt=Zr zOta#acFH$yE&luEnPXlngF` zj@G{oY!&lzRI7W$ycX5N7G8ft5F@h~b22Fv@nsr!4Vdt8ox^n&yDd2&o|to8?1iY_ zN$hsWGR~)ELWZH^V_v|#i1i*^7vQZ=t2^PXPv1twHpm08z66`ZRRjATb`C)QpqMkz zM|7)wdN=iN-{66^yAd+d7Dh#mtb4i&@=$PQ|pQ9S3q3hB<@%qp%;- zGu*F2nCD}dTZo5o49PA;McY;E9L9Y&|3#^z1`TMsxLXV|b&;uuHD_NAVWx&F=>XLT z^2sRe0?vj#%q#+qd7LtSH zAq7YgQVKLum{ZV8K`#Zp6!cQiOF=IMy%h9lg&OH#WH4tTIY=H-fD|F6z!R-dBNL1) z<{TssDL{&lQV&&(J#BceB2 zqLz7QKwH}!F&_-*7ozMGiPvkFlHgeqy-(sfOoBN{uplW@h>tz~|L&!LPXV6-J_URV z_!RKHb~O!r8u&EuY2eeqr-3K0dg*os_zdtF;4{EyfX@I=PWHlrEbv+2v%qJ8&jOzX zo_y|w9Xa50z~_L^0iOdt2Yj!r$pfDUJ`a2z_&o4=;Cp3L0r&#&1>g(77l1DS-z&?C zz!!lp0$&8a2z(LvUfEXyz65*;_!96X;7h=hRb&Rc%MP*1tQ50l#PmvJB^VQ!`F5>B zJjfI*l9gl@*})F8ORO}j#f%v>Jy#$claMOJgG^yXMw69f7TLiLvrDWrtHq2NH9Zr} zQH6MrDctdCAfw4jGK=hBhuI}on$=>)jGCT_=I|g>nE52}X&|G?N-~S=V29ZyR+`mf z#*CVtiRPHX=styflK3=`(PSl=MRu^m>=G-@YB6I*P0vJ|bDOn#O3a1LdX(>keZd=? zZ&|((`S#+QhV^Ie^gD&G&_R3=YBGbbLLFa)Icdr~z6ss0>k_^+hw-<02a|r*3_S7rQzW`X6U@iav literal 0 HcmV?d00001 From 64f4cdb0ca35f3371c9eba222e52818f4c5a6b4a Mon Sep 17 00:00:00 2001 From: modship Date: Mon, 21 Oct 2024 11:35:11 +0200 Subject: [PATCH 096/100] update runtime --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ecfb5d8ac7f..0f5f87231b9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2798,7 +2798,7 @@ dependencies = [ [[package]] name = "massa-sc-runtime" version = "0.10.0" -source = "git+https://github.com/massalabs/massa-sc-runtime?rev=1af16885f454d77df86a2968f04052c890b93ceb#1af16885f454d77df86a2968f04052c890b93ceb" +source = "git+https://github.com/massalabs/massa-sc-runtime?rev=27afc0f6d8e50bda682bd86d3a29f37de41a3814#27afc0f6d8e50bda682bd86d3a29f37de41a3814" dependencies = [ "anyhow", "as-ffi-bindings", diff --git a/Cargo.toml b/Cargo.toml index 26940adf9f2..9bf449de0eb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -110,7 +110,7 @@ massa_wallet = { path = "./massa-wallet" } # massa-proto-rs = { git = "https://github.com/massalabs/massa-proto-rs", branch = "deferred_calls" } # massa-sc-runtime = { git = "https://github.com/massalabs/massa-sc-runtime", "branch" = "deferred_calls" } massa-proto-rs = { git = "https://github.com/massalabs/massa-proto-rs", "rev" = "b5267178eaf266ec724691d7de163e4c34343416" } -massa-sc-runtime = { git = "https://github.com/massalabs/massa-sc-runtime", "rev" = "1af16885f454d77df86a2968f04052c890b93ceb" } +massa-sc-runtime = { git = "https://github.com/massalabs/massa-sc-runtime", "rev" = "27afc0f6d8e50bda682bd86d3a29f37de41a3814" } peernet = { git = "https://github.com/massalabs/PeerNet", "rev" = "04b05ddd320fbe76cc858115af7b5fc28bdb8310" } From 95e1bc846a0477e338be0d2a278a24e7405bc910 Mon Sep 17 00:00:00 2001 From: modship Date: Mon, 21 Oct 2024 14:12:51 +0200 Subject: [PATCH 097/100] Fix all feature && update runtime --- Cargo.lock | 2 +- Cargo.toml | 2 +- massa-execution-worker/src/tests/scenarios_mandatories.rs | 3 +++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0f5f87231b9..c9c5a8d98cb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2798,7 +2798,7 @@ dependencies = [ [[package]] name = "massa-sc-runtime" version = "0.10.0" -source = "git+https://github.com/massalabs/massa-sc-runtime?rev=27afc0f6d8e50bda682bd86d3a29f37de41a3814#27afc0f6d8e50bda682bd86d3a29f37de41a3814" +source = "git+https://github.com/massalabs/massa-sc-runtime?rev=82dd714d38cbcd863ae0bb215c06442917bb6404#82dd714d38cbcd863ae0bb215c06442917bb6404" dependencies = [ "anyhow", "as-ffi-bindings", diff --git a/Cargo.toml b/Cargo.toml index 9bf449de0eb..0390ccbe859 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -110,7 +110,7 @@ massa_wallet = { path = "./massa-wallet" } # massa-proto-rs = { git = "https://github.com/massalabs/massa-proto-rs", branch = "deferred_calls" } # massa-sc-runtime = { git = "https://github.com/massalabs/massa-sc-runtime", "branch" = "deferred_calls" } massa-proto-rs = { git = "https://github.com/massalabs/massa-proto-rs", "rev" = "b5267178eaf266ec724691d7de163e4c34343416" } -massa-sc-runtime = { git = "https://github.com/massalabs/massa-sc-runtime", "rev" = "27afc0f6d8e50bda682bd86d3a29f37de41a3814" } +massa-sc-runtime = { git = "https://github.com/massalabs/massa-sc-runtime", "rev" = "82dd714d38cbcd863ae0bb215c06442917bb6404" } peernet = { git = "https://github.com/massalabs/PeerNet", "rev" = "04b05ddd320fbe76cc858115af7b5fc28bdb8310" } diff --git a/massa-execution-worker/src/tests/scenarios_mandatories.rs b/massa-execution-worker/src/tests/scenarios_mandatories.rs index 370f1865cdf..336a67456ed 100644 --- a/massa-execution-worker/src/tests/scenarios_mandatories.rs +++ b/massa-execution-worker/src/tests/scenarios_mandatories.rs @@ -4075,6 +4075,7 @@ fn execution_trace() { None, None, None, + None, ); let mut universe = ExecutionTestUniverse::new(foreign_controllers, exec_cfg); @@ -4191,6 +4192,7 @@ fn execution_trace_nested() { None, None, None, + None, ); // let rt = tokio::runtime::Runtime::new().unwrap(); @@ -4303,6 +4305,7 @@ fn test_dump_block() { None, None, None, + None, ); foreign_controllers .final_state From c8e45d8667c7f9a114c92955f8ec188f0ae4cef3 Mon Sep 17 00:00:00 2001 From: modship Date: Mon, 21 Oct 2024 15:18:58 +0200 Subject: [PATCH 098/100] fix doc --- massa-ledger-exports/src/ledger_changes.rs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/massa-ledger-exports/src/ledger_changes.rs b/massa-ledger-exports/src/ledger_changes.rs index 59ec2017619..829d205e949 100644 --- a/massa-ledger-exports/src/ledger_changes.rs +++ b/massa-ledger-exports/src/ledger_changes.rs @@ -66,8 +66,9 @@ impl Serializer, SetOrDelete>>> for DatastoreUpdateSeri /// ## Example /// ```rust /// use std::collections::BTreeMap; - /// use massa_ledger_exports::{DatastoreUpdateSerializer, SetOrDelete}; + /// use massa_ledger_exports::{DatastoreUpdateSerializer}; /// use massa_serialization::Serializer; + /// use massa_models::types::SetOrDelete; /// /// let serializer = DatastoreUpdateSerializer::new(); /// let mut buffer = Vec::new(); @@ -131,8 +132,9 @@ impl Deserializer, SetOrDelete>>> for DatastoreUpdateDe /// ## Example /// ```rust /// use std::collections::BTreeMap; - /// use massa_ledger_exports::{DatastoreUpdateDeserializer, DatastoreUpdateSerializer, SetOrDelete}; + /// use massa_ledger_exports::{DatastoreUpdateDeserializer, DatastoreUpdateSerializer}; /// use massa_serialization::{Serializer, Deserializer, DeserializeError}; + /// use massa_models::types::SetOrDelete; /// /// let serializer = DatastoreUpdateSerializer::new(); /// let deserializer = DatastoreUpdateDeserializer::new(255, 255, 255); @@ -203,7 +205,8 @@ impl Serializer for LedgerEntryUpdateSerializer { /// use massa_models::{prehash::PreHashMap, address::Address, amount::Amount, bytecode::Bytecode}; /// use std::str::FromStr; /// use std::collections::BTreeMap; - /// use massa_ledger_exports::{SetOrDelete, SetOrKeep, LedgerEntryUpdate, LedgerEntryUpdateSerializer}; + /// use massa_models::types::{SetOrDelete, SetOrKeep}; + /// use massa_ledger_exports::{LedgerEntryUpdate, LedgerEntryUpdateSerializer}; /// /// let key = "hello world".as_bytes().to_vec(); /// let mut datastore = BTreeMap::default(); @@ -270,8 +273,9 @@ impl Deserializer for LedgerEntryUpdateDeserializer { /// use massa_serialization::{Deserializer, Serializer, DeserializeError}; /// use massa_models::{prehash::PreHashMap, address::Address, amount::Amount, bytecode::Bytecode}; /// use std::str::FromStr; + /// use massa_models::types::{SetOrDelete, SetOrKeep}; /// use std::collections::BTreeMap; - /// use massa_ledger_exports::{SetOrDelete, SetOrKeep, LedgerEntryUpdate, LedgerEntryUpdateSerializer, LedgerEntryUpdateDeserializer}; + /// use massa_ledger_exports::{LedgerEntryUpdate, LedgerEntryUpdateSerializer, LedgerEntryUpdateDeserializer}; /// /// let key = "hello world".as_bytes().to_vec(); /// let mut datastore = BTreeMap::default(); @@ -369,8 +373,9 @@ impl Serializer for LedgerChangesSerializer { /// ## Example /// ``` /// use massa_serialization::Serializer; - /// use massa_ledger_exports::{LedgerEntry, SetUpdateOrDelete, LedgerChanges, LedgerChangesSerializer}; + /// use massa_ledger_exports::{LedgerEntry, LedgerChanges, LedgerChangesSerializer}; /// use std::str::FromStr; + /// use massa_models::types::{SetUpdateOrDelete}; /// use std::collections::BTreeMap; /// use massa_models::{amount::Amount, address::Address, bytecode::Bytecode}; /// @@ -451,9 +456,10 @@ impl Deserializer for LedgerChangesDeserializer { /// ## Example /// ``` /// use massa_serialization::{Deserializer, Serializer, DeserializeError}; - /// use massa_ledger_exports::{LedgerEntry, SetUpdateOrDelete, LedgerChanges, LedgerChangesSerializer, LedgerChangesDeserializer}; + /// use massa_ledger_exports::{LedgerEntry, LedgerChanges, LedgerChangesSerializer, LedgerChangesDeserializer}; /// use std::str::FromStr; /// use std::collections::BTreeMap; + /// use massa_models::types::{SetUpdateOrDelete}; /// use massa_models::{amount::Amount, address::Address, bytecode::Bytecode}; /// /// let key = "hello world".as_bytes().to_vec(); From 2453a8075e94efb12734e075bfcfc6852df7127c Mon Sep 17 00:00:00 2001 From: modship Date: Wed, 30 Oct 2024 14:25:34 +0100 Subject: [PATCH 099/100] Update storage cost for deferred calls and set MAX_FUNCTION_NAME_LENGTH to 255 --- massa-deferred-calls/src/call.rs | 13 +++++++++++++ massa-execution-worker/src/execution.rs | 14 ++++++++------ .../src/speculative_deferred_calls.rs | 17 +++++++---------- .../src/tests/scenarios_mandatories.rs | 8 ++++---- massa-models/src/config/constants.rs | 2 +- 5 files changed, 33 insertions(+), 21 deletions(-) diff --git a/massa-deferred-calls/src/call.rs b/massa-deferred-calls/src/call.rs index afd19083d3f..99b11b8a717 100644 --- a/massa-deferred-calls/src/call.rs +++ b/massa-deferred-calls/src/call.rs @@ -74,6 +74,19 @@ impl DeferredCall { pub fn get_effective_gas(&self, alloc_gas_cost: u64) -> u64 { self.max_gas.saturating_add(alloc_gas_cost) } + + /// Get the storage cost for a call + pub fn get_storage_cost( + cost_per_byte: Amount, + params_size: u64, + max_function_name_length: u16, + ) -> Amount { + // 35 (sender_address) + 16 (target_slot) + 35 (target_address) + target_function.len() + params_size + 8 (coins) + 8 (max_gas) + 8 (fee) + 1 (cancelled) + let total_size = params_size + .saturating_add(max_function_name_length as u64) + .saturating_add(111); // 35 + 16 + 35 + 8 + 8 + 8 + 1 + cost_per_byte.saturating_mul_u64(total_size) + } } impl From for grpc_api::DeferredCallInfoEntry { diff --git a/massa-execution-worker/src/execution.rs b/massa-execution-worker/src/execution.rs index d419873b72e..8fffb05d7c6 100644 --- a/massa-execution-worker/src/execution.rs +++ b/massa-execution-worker/src/execution.rs @@ -1251,12 +1251,14 @@ impl ExecutionState { let mut context = context_guard!(self); // refund the sender for the storage costs - let amount = self - .config - .storage_costs_constants - .ledger_cost_per_byte - .saturating_mul_u64(call.parameters.len() as u64); - context.transfer_coins(None, Some(call.sender_address), amount, false)?; + let amount = DeferredCall::get_storage_cost( + self.config.storage_costs_constants.ledger_cost_per_byte, + call.parameters.len() as u64, + self.config.max_function_length, + ); + context + .transfer_coins(None, Some(call.sender_address), amount, false) + .expect("Error refunding storage costs"); context.get_snapshot() }; diff --git a/massa-execution-worker/src/speculative_deferred_calls.rs b/massa-execution-worker/src/speculative_deferred_calls.rs index f7f0eaac66d..ddd53d8e82d 100644 --- a/massa-execution-worker/src/speculative_deferred_calls.rs +++ b/massa-execution-worker/src/speculative_deferred_calls.rs @@ -496,7 +496,11 @@ impl SpeculativeDeferredCallRegistry { )?; // Storage cost for the parameters - let storage_cost = self.get_storage_cost_by_size(params_size); + let storage_cost = DeferredCall::get_storage_cost( + self.config.ledger_cost_per_byte, + params_size, + self.config.max_function_name_length, + ); // return the fee Ok(integral_fee @@ -505,11 +509,6 @@ impl SpeculativeDeferredCallRegistry { .saturating_add(storage_cost)) } - /// Get the storage cost for a given size - pub fn get_storage_cost_by_size(&self, size: u64) -> Amount { - self.config.ledger_cost_per_byte.saturating_mul_u64(size) - } - /// Register a new call /// Returns the call id /// # Arguments @@ -708,7 +707,7 @@ mod tests { 0, ) .unwrap(), - Amount::from_str("0.000000079").unwrap() + Amount::from_str("0.036600079").unwrap() ); // 10Ko params size @@ -724,9 +723,7 @@ mod tests { 10_000, ) .unwrap(), - Amount::from_str("1.000000079").unwrap() + Amount::from_str("1.036600079").unwrap() ); - - // TODO : add more tests with different values and check the results of the fee } } diff --git a/massa-execution-worker/src/tests/scenarios_mandatories.rs b/massa-execution-worker/src/tests/scenarios_mandatories.rs index 336a67456ed..21348d00401 100644 --- a/massa-execution-worker/src/tests/scenarios_mandatories.rs +++ b/massa-execution-worker/src/tests/scenarios_mandatories.rs @@ -1681,12 +1681,12 @@ fn deferred_call_register() { .times(1) .with(predicate::eq(Slot::new(1, 0)), predicate::always()) .returning(move |_, changes| { - // assert sender was debited ( -10 coins) and -5.25 for fees + // assert sender was debited ( -10 coins) and -5.2866 for fees match changes.ledger_changes.0.get(&sender_addr_clone).unwrap() { SetUpdateOrDelete::Update(change_sc_update) => { assert_eq!( change_sc_update.balance, - SetOrKeep::Set(Amount::from_str("75.398235312").unwrap()) + SetOrKeep::Set(Amount::from_str("75.361635312").unwrap()) ); } _ => panic!("wrong change type"), @@ -1743,7 +1743,7 @@ fn deferred_call_register() { SetUpdateOrDelete::Update(change_sc_update) => { assert_eq!( change_sc_update.balance, - SetOrKeep::Set(Amount::from_str("110").unwrap()) + SetOrKeep::Set(Amount::from_str("110.1111").unwrap()) ); } _ => panic!("wrong change type"), @@ -2258,7 +2258,7 @@ fn deferred_call_quote() { .module_controller .get_filtered_sc_output_event(EventFilter::default()); - assert_eq!(events[0].data, "100000000"); + assert_eq!(events[0].data, "136600000"); } /// Context diff --git a/massa-models/src/config/constants.rs b/massa-models/src/config/constants.rs index cf24803cc71..201b0530178 100644 --- a/massa-models/src/config/constants.rs +++ b/massa-models/src/config/constants.rs @@ -196,7 +196,7 @@ pub const MAX_DATASTORE_ENTRY_COUNT: u64 = u64::MAX; /// Maximum number of key/values in the datastore of a `ExecuteSC` operation pub const MAX_OPERATION_DATASTORE_ENTRY_COUNT: u64 = 128; /// Maximum length function name in call SC -pub const MAX_FUNCTION_NAME_LENGTH: u16 = u16::MAX; +pub const MAX_FUNCTION_NAME_LENGTH: u16 = 255; /// Maximum size of parameters in call SC pub const MAX_PARAMETERS_SIZE: u32 = 10_000_000; /// Maximum length of `rng_seed` in thread cycle From 1ef9d71aa8f7a6fd2f658619ec10dd0fe896473c Mon Sep 17 00:00:00 2001 From: modship Date: Wed, 30 Oct 2024 14:36:41 +0100 Subject: [PATCH 100/100] Fix comment --- massa-models/src/config/constants.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/massa-models/src/config/constants.rs b/massa-models/src/config/constants.rs index 201b0530178..d7a49b4c572 100644 --- a/massa-models/src/config/constants.rs +++ b/massa-models/src/config/constants.rs @@ -401,7 +401,7 @@ pub const DEFERRED_CALL_MAX_ASYNC_GAS: u64 = MAX_ASYNC_GAS; pub const DEFERRED_CALL_BASE_FEE_MAX_CHANGE_DENOMINATOR: usize = 8; /// deferred call min gas increment (1 nanomassa) pub const DEFERRED_CALL_MIN_GAS_INCREMENT: u64 = 1; -/// deferred call max gas cost (10 nanomassa) +/// deferred call min gas cost (10 nanomassa) pub const DEFERRED_CALL_MIN_GAS_COST: u64 = 10; /// deferred call global overbooking penalty pub const DEFERRED_CALL_GLOBAL_OVERBOOKING_PENALTY: Amount = Amount::from_raw(1_000_000_000);