Skip to content

Commit

Permalink
execute deferred call, advance_slot, snapshot
Browse files Browse the repository at this point in the history
  • Loading branch information
modship committed Jul 24, 2024
1 parent 14ca8d5 commit 4a0c7db
Show file tree
Hide file tree
Showing 10 changed files with 291 additions and 30 deletions.
9 changes: 6 additions & 3 deletions massa-deferred-calls/src/slot_changes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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},
Expand Down Expand Up @@ -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) {
Expand Down
2 changes: 1 addition & 1 deletion massa-execution-exports/src/test_exports/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
}
}
26 changes: 25 additions & 1 deletion massa-execution-worker/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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<AsyncMessageId, AsyncMessageInfo>,

Expand Down Expand Up @@ -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(),
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand Down
142 changes: 141 additions & 1 deletion massa-execution-worker/src/execution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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;
Expand All @@ -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")]
Expand Down Expand Up @@ -1221,6 +1225,123 @@ impl ExecutionState {
}
}

fn execute_deferred_call(
&self,
call: DeferredCall,
) -> Result<DeferredCallExecutionResult, ExecutionError> {
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.
///
Expand Down Expand Up @@ -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,
Expand Down
23 changes: 23 additions & 0 deletions massa-execution-worker/src/execution_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

use std::collections::HashMap;

use massa_deferred_calls::DeferredCall;
use schnellru::{ByLength, LruMap};
// use massa_execution_exports::Transfer;

Expand Down Expand Up @@ -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<ExecutionResult>,
}

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,
}
}
}
Loading

0 comments on commit 4a0c7db

Please sign in to comment.