Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Add versioning to mainnet update 2.3 #4711

Draft
wants to merge 35 commits into
base: mainnet_2_3
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
6c3858c
Asc message execution - requery message bytecode after each message e…
Leo-Besancon Jun 18, 2024
c316e44
Create MIP "MIP-0001-ASC-BugFix"
Leo-Besancon Jun 18, 2024
ab29c86
Add versioning to asc execution context
Leo-Besancon Jun 18, 2024
93b2b3b
Asc message execution - requery message bytecode after each message e…
Leo-Besancon Jun 18, 2024
ca5eaf2
Merge branch 'mainnet_2_3' into mainnet_2_3_versioning_mip
Leo-Besancon Jun 18, 2024
b5c548c
Merge branch 'mainnet_2_3' into mainnet_2_3_versioning_mip
Leo-Besancon Jul 17, 2024
a7cc744
Improve versioning
Leo-Besancon Jul 18, 2024
4f89e6a
fmt
Leo-Besancon Jul 18, 2024
f581540
Update ci.yml
Leo-Besancon Jul 18, 2024
72bd77c
Add ledger changes versioning
Leo-Besancon Jul 18, 2024
44a1874
Add runtime module versioning
Leo-Besancon Jul 18, 2024
59a5052
Add send_message versioning
Leo-Besancon Jul 18, 2024
361427f
Add address category versioning
Leo-Besancon Jul 18, 2024
99d8abe
Add Fix eliminated msg versioning
Leo-Besancon Jul 18, 2024
5df2700
add versioning test-exports mip
Leo-Besancon Jul 23, 2024
f848daa
fmt
Leo-Besancon Jul 23, 2024
9ea25d4
Merge branch 'mainnet_2_3' into mainnet_2_3_versioning_mip
Leo-Besancon Aug 1, 2024
5aa1fb8
Add ledger delete_entry versioning
Leo-Besancon Aug 1, 2024
0eb5ffc
Add versioning for Consistent expiry period
Leo-Besancon Aug 1, 2024
462caa7
Merge branch 'mainnet_2_3' into mainnet_2_3_versioning_mip
Leo-Besancon Aug 1, 2024
d1224b4
Merge branch 'mainnet_2_3' into mainnet_2_3_versioning_mip
Leo-Besancon Aug 1, 2024
6b19df6
Update speculative_async_pool.rs
Leo-Besancon Aug 1, 2024
8de2a7d
Merge branch 'mainnet_2_3' into mainnet_2_3_versioning_mip
Leo-Besancon Aug 1, 2024
f78ee71
Add versioning to fees fix
Leo-Besancon Aug 1, 2024
a4da3c5
Merge branch 'mainnet_2_3' into mainnet_2_3_versioning_mip
Leo-Besancon Aug 2, 2024
4ca00b0
Add versioning for Fix amount remaining to slash 2
Leo-Besancon Aug 2, 2024
133af5a
Fix conflict
Leo-Besancon Aug 2, 2024
de4bf07
Add versioning for LedgerChanges::Delete
Leo-Besancon Aug 2, 2024
15fe3ea
Merge branch 'mainnet_2_3' into mainnet_2_3_versioning_mip
Leo-Besancon Nov 7, 2024
f6d2f97
cargo fmt + check pass
Leo-Besancon Nov 7, 2024
641b99e
Add Condom Middleware versioning
Leo-Besancon Nov 7, 2024
9ddf5ae
fmt
Leo-Besancon Nov 7, 2024
d40efaa
Add versioning to max_recursive_calls_depth
Leo-Besancon Nov 7, 2024
7ed039a
Fix deadlock
Leo-Besancon Nov 7, 2024
84c0e4c
Add versioning to Fix potential ledger keys boundaries issue
Leo-Besancon Nov 8, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions massa-bootstrap/src/tests/universe_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ impl BootstrapServerTestUniverseBuilder {
let mut batch = DBBatch::default();
let versioning_batch = DBBatch::default();
self.final_ledger
.apply_changes_to_batch(ledger_changes, &mut batch);
.apply_changes_to_batch(ledger_changes, &mut batch, 1);
self.controllers
.database
.write()
Expand All @@ -216,7 +216,7 @@ impl BootstrapServerTestUniverseBuilder {
let mut batch = DBBatch::default();
let versioning_batch = DBBatch::default();
self.final_ledger
.apply_changes_to_batch(ledger_changes, &mut batch);
.apply_changes_to_batch(ledger_changes, &mut batch, 1);
self.controllers
.database
.write()
Expand All @@ -232,7 +232,7 @@ impl BootstrapServerTestUniverseBuilder {
let mut batch = DBBatch::default();
let versioning_batch = DBBatch::default();
self.final_ledger
.apply_changes_to_batch(ledger_changes, &mut batch);
.apply_changes_to_batch(ledger_changes, &mut batch, 1);
self.controllers
.database
.write()
Expand Down
2 changes: 2 additions & 0 deletions massa-execution-worker/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ test-exports = [
"massa_pos_worker",
"massa_metrics/test-exports",
"massa_metrics/test-exports",
"massa_versioning/test-exports",
"massa_db_worker",
"tempfile",
]
Expand Down Expand Up @@ -106,6 +107,7 @@ massa_metrics = { workspace = true, features = ["test-exports"] }
massa_db_worker = { workspace = true }
tempfile = { workspace = true }
massa_test_framework = { workspace = true, "features" = ["test-exports"] }
massa_versioning = { workspace = true, "features" = ["test-exports"] }
tokio = { workspace = true, features = ["sync"] }
hex-literal = { workspace = true }
mockall = { workspace = true }
233 changes: 217 additions & 16 deletions massa-execution-worker/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,10 @@ use massa_models::{
};
use massa_module_cache::controller::ModuleCache;
use massa_pos_exports::PoSChanges;
use massa_sc_runtime::CondomLimits;
use massa_serialization::Serializer;
use massa_versioning::address_factory::{AddressArgs, AddressFactory};
use massa_versioning::versioning::MipStore;
use massa_versioning::versioning::{MipComponent, MipStore};
use massa_versioning::versioning_factory::{FactoryStrategy, VersioningFactory};
use parking_lot::RwLock;
use rand::SeedableRng;
Expand Down Expand Up @@ -185,6 +186,9 @@ pub struct ExecutionContext {
/// so *excluding* the gas used by the last sc call.
pub gas_remaining_before_subexecution: Option<u64>,

/// The version of the execution component
pub execution_component_version: u32,

/// recursion counter, incremented for each new nested call
pub recursion_counter: u16,
}
Expand All @@ -210,6 +214,15 @@ impl ExecutionContext {
mip_store: MipStore,
execution_trail_hash: massa_hash::Hash,
) -> Self {
let slot = Slot::new(0, 0);
let ts = get_block_slot_timestamp(
config.thread_count,
config.t0,
config.genesis_timestamp,
slot,
)
.unwrap();

ExecutionContext {
speculative_ledger: SpeculativeLedger::new(
final_state.clone(),
Expand All @@ -236,7 +249,7 @@ impl ExecutionContext {
active_history,
),
creator_min_balance: Default::default(),
slot: Slot::new(0, 0),
slot,
created_addr_index: Default::default(),
created_event_index: Default::default(),
created_message_index: Default::default(),
Expand All @@ -249,9 +262,13 @@ impl ExecutionContext {
origin_operation_id: Default::default(),
module_cache,
config,
address_factory: AddressFactory { mip_store },
address_factory: AddressFactory {
mip_store: mip_store.clone(),
},
execution_trail_hash,
gas_remaining_before_subexecution: None,
execution_component_version: mip_store
.get_latest_component_version_at(&MipComponent::Execution, ts),
recursion_counter: 0,
}
}
Expand Down Expand Up @@ -347,11 +364,21 @@ impl ExecutionContext {
let execution_trail_hash =
generate_execution_trail_hash(&prev_execution_trail_hash, &slot, None, true);

let ts = get_block_slot_timestamp(
config.thread_count,
config.t0,
config.genesis_timestamp,
slot,
)
.unwrap();

// return readonly context
ExecutionContext {
slot,
stack: call_stack,
read_only: true,
execution_component_version: mip_store
.get_latest_component_version_at(&MipComponent::Execution, ts),
..ExecutionContext::new(
config,
final_state,
Expand All @@ -372,7 +399,19 @@ impl ExecutionContext {
/// A vector of `(Option<Bytecode>, AsyncMessage)` pairs where:
/// * `Option<Bytecode>` is the bytecode to execute (or `None` if not found)
/// * `AsyncMessage` is the asynchronous message to execute
pub(crate) fn take_async_batch(
pub(crate) fn take_async_batch_v0(
&mut self,
max_gas: u64,
async_msg_cst_gas_cost: u64,
) -> Vec<(Option<Bytecode>, AsyncMessage)> {
self.speculative_async_pool
.take_batch_to_execute(self.slot, max_gas, async_msg_cst_gas_cost)
.into_iter()
.map(|(_id, msg)| (self.get_bytecode(&msg.destination), msg))
.collect()
}

pub(crate) fn take_async_batch_v1(
&mut self,
max_gas: u64,
async_msg_cst_gas_cost: u64,
Expand Down Expand Up @@ -417,10 +456,20 @@ impl ExecutionContext {
false,
);

let ts = get_block_slot_timestamp(
config.thread_count,
config.t0,
config.genesis_timestamp,
slot,
)
.unwrap();

// return active slot execution context
ExecutionContext {
slot,
opt_block_id,
execution_component_version: mip_store
.get_latest_component_version_at(&MipComponent::Execution, ts),
..ExecutionContext::new(
config,
final_state,
Expand Down Expand Up @@ -785,6 +834,76 @@ impl ExecutionContext {
&mut self,
denounced_addr: &Address,
roll_count: u64,
) -> Result<Amount, ExecutionError> {
let execution_component_version = self.execution_component_version;

match execution_component_version {
0 => self.try_slash_rolls_v0(denounced_addr, roll_count),
_ => self.try_slash_rolls_v1(denounced_addr, roll_count),
}
}

pub fn try_slash_rolls_v0(
&mut self,
denounced_addr: &Address,
roll_count: u64,
) -> Result<Amount, ExecutionError> {
// try to slash as many roll as available
let slashed_rolls = self
.speculative_roll_state
.try_slash_rolls(denounced_addr, roll_count);
// convert slashed rolls to coins (as deferred credits => coins)
let mut slashed_coins = self
.config
.roll_price
.checked_mul_u64(slashed_rolls.unwrap_or_default())
.ok_or_else(|| {
ExecutionError::RuntimeError(format!(
"Cannot multiply roll price by {}",
roll_count
))
})?;

// what remains to slash (then will try to slash as many deferred credits as avail/what remains to be slashed)
let amount_remaining_to_slash = self
.config
.roll_price
.checked_mul_u64(roll_count)
.ok_or_else(|| {
ExecutionError::RuntimeError(format!(
"Cannot multiply roll price by {}",
roll_count
))
})?
.saturating_sub(slashed_coins);

if amount_remaining_to_slash > Amount::zero() {
// There is still an amount to slash for this denunciation so we need to slash
// in deferred credits
let slashed_coins_in_deferred_credits = self
.speculative_roll_state
.try_slash_deferred_credits(&self.slot, denounced_addr, &amount_remaining_to_slash);

slashed_coins = slashed_coins.saturating_add(slashed_coins_in_deferred_credits);

let amount_remaining_to_slash_2 =
slashed_coins.saturating_sub(slashed_coins_in_deferred_credits);
if amount_remaining_to_slash_2 > Amount::zero() {
// Use saturating_mul_u64 to avoid an error (for just a warn!(..))
warn!("Slashed {} coins (by selling rolls) and {} coins from deferred credits of address: {} but cumulative amount is lower than expected: {} coins",
slashed_coins, slashed_coins_in_deferred_credits, denounced_addr,
self.config.roll_price.saturating_mul_u64(roll_count)
);
}
}

Ok(slashed_coins)
}

pub fn try_slash_rolls_v1(
&mut self,
denounced_addr: &Address,
roll_count: u64,
) -> Result<Amount, ExecutionError> {
// try to slash as many roll as available
let slashed_rolls = self
Expand Down Expand Up @@ -896,23 +1015,91 @@ impl ExecutionContext {
result
}

/// Finishes a slot and generates the execution output.
/// Settles emitted asynchronous messages, reimburse the senders of deleted messages.
/// Moves the output of the execution out of the context,
/// resetting some context fields in the process.
///
/// This is used to get the output of an execution before discarding the context.
/// Note that we are not taking self by value to consume it because the context is shared.
pub fn settle_slot(&mut self, block_info: Option<ExecutedBlockInfo>) -> ExecutionOutput {
fn settle_slot_v0(&mut self, block_info: Option<ExecutedBlockInfo>) -> ExecutionOutput {
let slot = self.slot;
// execute the deferred credits coming from roll sells
let deferred_credits_transfers = self.execute_deferred_credits(&slot);

// take the ledger changes first as they are needed for async messages and cache
let ledger_changes = self.speculative_ledger.take();

// settle emitted async messages and reimburse the senders of deleted messages
let deleted_messages =
self.speculative_async_pool
.settle_slot(&slot, &ledger_changes, false);

let mut cancel_async_message_transfers = vec![];
for (_msg_id, msg) in deleted_messages {
if let Some(t) = self.cancel_async_message(&msg) {
cancel_async_message_transfers.push(t)
}
}

// update module cache
let bc_updates = ledger_changes.get_bytecode_updates();

{
let mut cache_write_lock = self.module_cache.write();
for bytecode in bc_updates {
cache_write_lock.save_module(&bytecode.0, CondomLimits::default());
}
}
// if the current slot is last in cycle check the production stats and act accordingly
let auto_sell_rolls = if self
.slot
.is_last_of_cycle(self.config.periods_per_cycle, self.config.thread_count)
{
self.speculative_roll_state.settle_production_stats(
&slot,
self.config.periods_per_cycle,
self.config.thread_count,
self.config.roll_price,
self.config.max_miss_ratio,
)
} else {
vec![]
};

// generate the execution output
let state_changes = StateChanges {
ledger_changes,
async_pool_changes: self.speculative_async_pool.take(),
pos_changes: self.speculative_roll_state.take(),
executed_ops_changes: self.speculative_executed_ops.take(),
executed_denunciations_changes: self.speculative_executed_denunciations.take(),
execution_trail_hash_change: SetOrKeep::Set(self.execution_trail_hash),
};
std::mem::take(&mut self.opt_block_id);
ExecutionOutput {
slot,
block_info,
state_changes,
events: std::mem::take(&mut self.events),
#[cfg(feature = "execution-trace")]
slot_trace: None,
#[cfg(feature = "dump-block")]
storage: None,
deferred_credits_execution: deferred_credits_transfers,
cancel_async_message_execution: cancel_async_message_transfers,
auto_sell_execution: auto_sell_rolls,
}
}

fn settle_slot_with_fixed_ledger_change_handling(
&mut self,
block_info: Option<ExecutedBlockInfo>,
) -> ExecutionOutput {
let slot = self.slot;

// execute the deferred credits coming from roll sells
let deferred_credits_transfers = self.execute_deferred_credits(&slot);

// settle emitted async messages and reimburse the senders of deleted messages
let deleted_messages = self
.speculative_async_pool
.settle_slot(&slot, &self.speculative_ledger.added_changes);
let deleted_messages = self.speculative_async_pool.settle_slot(
&slot,
&self.speculative_ledger.added_changes,
true,
);

let mut cancel_async_message_transfers = vec![];
for (_msg_id, msg) in deleted_messages {
Expand All @@ -926,7 +1113,7 @@ impl ExecutionContext {
{
let mut cache_write_lock = self.module_cache.write();
for bytecode in bc_updates {
cache_write_lock.save_module(&bytecode.0);
cache_write_lock.save_module(&bytecode.0, self.config.condom_limits.clone());
}
}

Expand Down Expand Up @@ -972,6 +1159,20 @@ impl ExecutionContext {
}
}

/// Finishes a slot and generates the execution output.
/// Settles emitted asynchronous messages, reimburse the senders of deleted messages.
/// Moves the output of the execution out of the context,
/// resetting some context fields in the process.
///
/// This is used to get the output of an execution before discarding the context.
/// Note that we are not taking self by value to consume it because the context is shared.
pub fn settle_slot(&mut self, block_info: Option<ExecutedBlockInfo>) -> ExecutionOutput {
match self.execution_component_version {
0 => self.settle_slot_v0(block_info),
_ => self.settle_slot_with_fixed_ledger_change_handling(block_info),
}
}

/// Sets a bytecode for an address in the speculative ledger.
/// Fail if the address is absent from the ledger.
///
Expand Down
Loading
Loading