Skip to content

Commit

Permalink
Refactor fee computation during runtime execution (#1539)
Browse files Browse the repository at this point in the history
* refactor runtime fees

* nit: better int conversion

* Use ResourceController in ChainStateView::execute_block as well

* clarify comments on message pricing

* Update linera-execution/tests/wasm.rs

Co-authored-by: Andreas Fackler <afck@users.noreply.github.com>
Signed-off-by: Mathieu Baudet <1105398+ma2bd@users.noreply.github.com>

* fix typo

---------

Signed-off-by: Mathieu Baudet <1105398+ma2bd@users.noreply.github.com>
Co-authored-by: Andreas Fackler <afck@users.noreply.github.com>
  • Loading branch information
ma2bd and afck authored Jan 24, 2024
1 parent ca9edfc commit 7c3fef3
Show file tree
Hide file tree
Showing 18 changed files with 508 additions and 404 deletions.
4 changes: 4 additions & 0 deletions CLI.md
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,7 @@ View or update the resource control policy
* `--block <BLOCK>` — Set the base price for creating a block
* `--fuel-unit <FUEL_UNIT>` — Set the price per unit of fuel
* `--read-operation <READ_OPERATION>` — Set the price per read operation
* `--write-operation <WRITE_OPERATION>` — Set the price per write operation
* `--byte-read <BYTE_READ>` — Set the price per byte read
* `--byte-written <BYTE_WRITTEN>` — Set the price per byte written
* `--byte-stored <BYTE_STORED>` — Set the price per byte stored
Expand Down Expand Up @@ -290,6 +291,9 @@ Create genesis configuration for a Linera deployment. Create initial user chains
Default value: `0`
* `--read-operation-price <READ_OPERATION_PRICE>` — Set the price per read operation

Default value: `0`
* `--write-operation-price <WRITE_OPERATION_PRICE>` — Set the price per write operation

Default value: `0`
* `--byte-read-price <BYTE_READ_PRICE>` — Set the price per byte read

Expand Down
1 change: 0 additions & 1 deletion linera-base/src/data_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,6 @@ pub struct Resources {
/// A number of read operations to be executed.
pub read_operations: u32,
/// A number of write operations to be executed.
// TODO(#1530): This is not used at the moment.
pub write_operations: u32,
/// A number of bytes to read.
pub bytes_to_read: u32,
Expand Down
90 changes: 40 additions & 50 deletions linera-chain/src/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,17 @@ use async_graphql::SimpleObject;
use futures::stream::{self, StreamExt, TryStreamExt};
use linera_base::{
crypto::CryptoHash,
data_types::{Amount, ArithmeticError, BlockHeight, Timestamp},
data_types::{ArithmeticError, BlockHeight, Timestamp},
ensure,
identifiers::{ChainId, Destination, MessageId},
prometheus_util,
sync::Lazy,
};
use linera_execution::{
system::{SystemExecutionError, SystemMessage},
ExecutionError, ExecutionOutcome, ExecutionRuntimeContext, ExecutionStateView,
system::SystemMessage, ExecutionOutcome, ExecutionRuntimeContext, ExecutionStateView,
GenericApplicationId, Message, MessageContext, OperationContext, Query, QueryContext,
RawExecutionOutcome, RawOutgoingMessage, ResourceTracker, Response, UserApplicationDescription,
UserApplicationId,
RawExecutionOutcome, RawOutgoingMessage, ResourceController, ResourceTracker, Response,
UserApplicationDescription, UserApplicationId,
};
use linera_views::{
common::Context,
Expand All @@ -39,6 +38,7 @@ use prometheus::{HistogramVec, IntCounterVec};
use serde::{Deserialize, Serialize};
use std::{
collections::{BTreeMap, HashSet},
sync::Arc,
time::Instant,
};

Expand Down Expand Up @@ -271,22 +271,6 @@ where
ViewError: From<C::Error>,
C::Extra: ExecutionRuntimeContext,
{
/// Substracts an amount from a balance and reports an error if that is impossible
fn sub_assign_fees(
balance: &mut Amount,
fees: Amount,
chain_execution_context: ChainExecutionContext,
) -> Result<(), ChainError> {
balance.try_sub_assign(fees).map_err(|_| {
ChainError::ExecutionError(
ExecutionError::SystemError(SystemExecutionError::InsufficientFunding {
current_balance: *balance,
}),
chain_execution_context,
)
})
}

pub fn chain_id(&self) -> ChainId {
self.context().extra().chain_id()
}
Expand Down Expand Up @@ -602,11 +586,15 @@ where
let Some((_, committee)) = self.execution_state.system.current_committee() else {
return Err(ChainError::InactiveChain(chain_id));
};

let policy = committee.policy().clone();
let mut resource_controller = ResourceController {
policy: Arc::new(committee.policy().clone()),
tracker: ResourceTracker::default(),
// TODO(#1537): Allow using the personal account of the block producer.
account: None,
};
let mut messages = Vec::new();
let mut message_counts = Vec::new();
let mut tracker = ResourceTracker::default();

// The first incoming message of any child chain must be `OpenChain`. A root chain must
// already be initialized
if block.height == BlockHeight::ZERO
Expand Down Expand Up @@ -654,8 +642,7 @@ where
.execute_message(
context,
message.event.message.clone(),
&policy,
&mut tracker,
&mut resource_controller,
)
.await
.map_err(|err| ChainError::ExecutionError(err, chain_execution_context))?,
Expand Down Expand Up @@ -686,13 +673,12 @@ where
.process_execution_outcomes(context.height, outcomes)
.await?;
if let MessageAction::Accept = message.action {
let balance = self.execution_state.system.balance.get_mut();
for message_out in &messages_out {
Self::sub_assign_fees(
balance,
policy.message_price(&message_out.message)?,
chain_execution_context,
)?;
resource_controller
.with(&mut self.execution_state)
.await?
.track_message(&message_out.message)
.map_err(|err| ChainError::ExecutionError(err, chain_execution_context))?;
}
}
messages.append(&mut messages_out);
Expand All @@ -714,31 +700,35 @@ where
};
let outcomes = self
.execution_state
.execute_operation(context, operation.clone(), &policy, &mut tracker)
.execute_operation(context, operation.clone(), &mut resource_controller)
.await
.map_err(|err| ChainError::ExecutionError(err, chain_execution_context))?;
let mut messages_out = self
.process_execution_outcomes(context.height, outcomes)
.await?;
let balance = self.execution_state.system.balance.get_mut();
Self::sub_assign_fees(
balance,
policy.operation_price(operation)?,
chain_execution_context,
)?;
resource_controller
.with(&mut self.execution_state)
.await?
.track_operation(operation)
.map_err(|err| ChainError::ExecutionError(err, chain_execution_context))?;
for message_out in &messages_out {
Self::sub_assign_fees(
balance,
policy.message_price(&message_out.message)?,
chain_execution_context,
)?;
resource_controller
.with(&mut self.execution_state)
.await?
.track_message(&message_out.message)
.map_err(|err| ChainError::ExecutionError(err, chain_execution_context))?;
}
messages.append(&mut messages_out);
message_counts
.push(u32::try_from(messages.len()).map_err(|_| ArithmeticError::Overflow)?);
}
let balance = self.execution_state.system.balance.get_mut();
Self::sub_assign_fees(balance, policy.block_price(), ChainExecutionContext::Block)?;

// Finally, charge for the block fee.
resource_controller
.with(&mut self.execution_state)
.await?
.track_block()
.map_err(|err| ChainError::ExecutionError(err, ChainExecutionContext::Block))?;

// Recompute the state hash.
let state_hash = self.execution_state.crypto_hash().await?;
Expand All @@ -757,16 +747,16 @@ where
.observe(start_time.elapsed().as_secs_f64() * 1000.0);
WASM_FUEL_USED_PER_BLOCK
.with_label_values(&[])
.observe(tracker.used_fuel as f64);
.observe(resource_controller.tracker.fuel as f64);
WASM_NUM_READS_PER_BLOCK
.with_label_values(&[])
.observe(tracker.num_reads as f64);
.observe(resource_controller.tracker.read_operations as f64);
WASM_BYTES_READ_PER_BLOCK
.with_label_values(&[])
.observe(tracker.bytes_read as f64);
.observe(resource_controller.tracker.bytes_read as f64);
WASM_BYTES_WRITTEN_PER_BLOCK
.with_label_values(&[])
.observe(tracker.bytes_written as f64);
.observe(resource_controller.tracker.bytes_written as f64);

assert_eq!(
message_counts.len(),
Expand Down
4 changes: 1 addition & 3 deletions linera-chain/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use linera_base::{
data_types::{ArithmeticError, BlockHeight, Round, Timestamp},
identifiers::ChainId,
};
use linera_execution::{policy::PricingError, ExecutionError};
use linera_execution::ExecutionError;
use linera_views::views::ViewError;
use rand_distr::WeightedError;
use thiserror::Error;
Expand All @@ -35,8 +35,6 @@ pub enum ChainError {
ViewError(#[from] ViewError),
#[error("Execution error: {0} during {1:?}")]
ExecutionError(ExecutionError, ChainExecutionContext),
#[error("Pricing error: {0}")]
PricingError(#[from] PricingError),

#[error("The chain being queried is not active {0:?}")]
InactiveChain(ChainId),
Expand Down
9 changes: 3 additions & 6 deletions linera-core/src/unit_tests/wasm_worker_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,10 @@ use linera_chain::{
};
use linera_execution::{
committee::Epoch,
policy::ResourceControlPolicy,
system::{SystemChannel, SystemMessage, SystemOperation},
Bytecode, BytecodeLocation, ChainOwnership, ChannelSubscription, ExecutionRuntimeConfig,
ExecutionStateView, GenericApplicationId, Message, MessageKind, Operation, OperationContext,
ResourceTracker, SystemExecutionState, UserApplicationDescription, UserApplicationId,
ResourceController, SystemExecutionState, UserApplicationDescription, UserApplicationId,
WasmContractModule, WasmRuntime,
};
use linera_storage::{MemoryStorage, Storage};
Expand Down Expand Up @@ -430,17 +429,15 @@ where
index: 0,
next_message_index: 0,
};
let mut tracker = ResourceTracker::default();
let policy = ResourceControlPolicy::default();
let mut controller = ResourceController::default();
creator_state
.execute_operation(
operation_context,
Operation::User {
application_id,
bytes: user_operation,
},
&policy,
&mut tracker,
&mut controller,
)
.await?;
creator_state.system.timestamp.set(Timestamp::from(5));
Expand Down
Loading

0 comments on commit 7c3fef3

Please sign in to comment.