Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
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
27 changes: 27 additions & 0 deletions plt/plt-block-state/src/block_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,15 @@ impl<C: EntityContextTypes> BlockStateOperations for ExecutionTimeBlockStateP9<C
) {
panic!("no locks on P9")
}

fn remove_lock_balance_ref(
&mut self,
_lock: &LockId,
_account: &Self::Account,
_token: &Self::Token,
) {
panic!("no locks on P9")
}
}

/// Runtime/execution state relevant for providing an implementation of
Expand Down Expand Up @@ -503,4 +512,22 @@ impl<C: EntityContextTypes> BlockStateOperations for ExecutionTimeBlockStateP11<
lock.add_lock_balance_ref(account.account_index(), *token);
self.block_state.update_lock(&self.context, lock).unwrap();
}

fn remove_lock_balance_ref(
&mut self,
lock: &LockId,
account: &Self::Account,
token: &Self::Token,
) {
let mut lock = self
.block_state
.lock_by_id(&self.context, lock)
.unwrap()
.unwrap();
let removed = lock.remove_lock_balance_ref(account.account_index(), *token);
if removed {
// Only update on a change.
self.block_state.update_lock(&self.context, lock).unwrap();
}
}
}
22 changes: 22 additions & 0 deletions plt/plt-block-state/src/block_state_interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,28 @@ pub trait BlockStateOperations: BlockStateQuery {
/// - The `lock` MUST already exist in the block state, i.e.
/// `s.lock_by_id(lock_id).expect("lock exists")`.
fn add_lock_balance_ref(&mut self, lock: &LockId, account: &Self::Account, token: &Self::Token);

/// Stop tracking that a lock holds a balance for the given account and token.
///
/// This removes the account/token pair from the lock state, so it will no longer be
/// returned by [`BlockStateQuery::lock_balances`].
///
/// # Arguments
/// - `lock` The lock to update.
/// - `account` The account whose locked balance is no longer tracked.
/// - `token` The token whose locked balance is no longer tracked.
///
/// The caller must ensure the following conditions are true, and failing to do so results in
/// undefined behavior.
///
/// - The `lock` MUST already exist in the block state, i.e.
/// `s.lock_by_id(lock_id).expect("lock exists")`.
fn remove_lock_balance_ref(
Comment thread
soerenbf marked this conversation as resolved.
&mut self,
lock: &LockId,
account: &Self::Account,
token: &Self::Token,
);
}

/// The computation resulted in overflow (negative or above maximum value).
Expand Down
22 changes: 22 additions & 0 deletions plt/plt-block-state/src/entity/protocol_level_locks/p11.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,4 +120,26 @@ impl LockP11 {
.locked_balances
.insert((account_index, token_index));
}

/// Stop tracking that the lock holds a balance for the given account and token.
/// This removes the account/token pair from the lock state, so it will no longer be
/// returned by [`Self::lock_balance_refs`].
///
/// # Arguments
///
/// - `account_index` The index of the account whose locked balance is no longer tracked.
/// - `token_index` Index of the token whose locked balance is no longer tracked.
///
/// # Returns
/// `true` if the account/token pair was previously tracked and has been removed,
/// `false` if the account/token pair was not previously tracked.
pub fn remove_lock_balance_ref(
&mut self,
account_index: AccountIndex,
token_index: TokenIndex,
) -> bool {
self.persistent
.locked_balances
.remove(&(account_index, token_index))
}
}
10 changes: 10 additions & 0 deletions plt/plt-scheduler-types/src/types/tokens.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,16 @@ pub struct RawTokenAmount(pub u64);
impl RawTokenAmount {
/// Maximum representable raw token amount.
pub const MAX: Self = Self(u64::MAX);

/// Checked addition of raw token amounts. Returns `None` if the result would overflow.
pub fn checked_add(self, other: RawTokenAmount) -> Option<RawTokenAmount> {
self.0.checked_add(other.0).map(RawTokenAmount)
}

/// Checked subtraction of raw token amounts. Returns `None` if the result would overflow.
pub fn checked_sub(self, other: RawTokenAmount) -> Option<RawTokenAmount> {
self.0.checked_sub(other.0).map(RawTokenAmount)
}
}

/// Serialization of 'TokenRawAmount' is as a variable length quantity (VLQ).
Expand Down
48 changes: 46 additions & 2 deletions plt/plt-scheduler/src/scheduler.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
//! Entry points to calling the scheduler. The scheduler is responsible for executing
//! transaction and update instruction payloads.

use crate::token_module::errors::TokenStateInvariantError;
use crate::token_module::errors::{TokenStateInvariantError, TokenTransferError};
use crate::token_module::util;
use crate::transaction_execution::{TransactionContext, TransactionExecution};
use concordium_base::base::ProtocolVersion;
use concordium_base::protocol_level_tokens::{
TokenBalanceInsufficientRejectReason, TokenModuleRejectReason,
};
use concordium_base::transactions::Payload;
use concordium_base::updates::UpdatePayload;
use plt_block_state::block_state_interface::BlockStateOperations;
use plt_block_state::persistent::protocol_level_tokens::p9::TokenConfiguration;
use plt_scheduler_types::types::execution::{ChainUpdateOutcome, TransactionExecutionSummary};
use plt_scheduler_types::types::reject_reasons::TransactionRejectReason;
use plt_scheduler_types::types::reject_reasons::{
EncodedTokenModuleRejectReason, TransactionRejectReason,
};

pub mod helpers;
mod plt_scheduler;
Expand Down Expand Up @@ -53,6 +60,43 @@ impl From<TokenStateInvariantError> for TransactionFailure {
}
}

impl TransactionFailure {
fn from_token_transfer_error(
index: u64,
token_configuration: &TokenConfiguration,
error: TokenTransferError,
) -> Self {
match error {
TokenTransferError::StateInvariantViolation(token_state_invariant_error) => {
token_state_invariant_error.into()
}
TokenTransferError::InsufficientBalance(insufficient_balance_error) => {
let (reason, details) = TokenModuleRejectReason::TokenBalanceInsufficient(
TokenBalanceInsufficientRejectReason {
index,
available_balance: util::to_token_amount(
token_configuration,
insufficient_balance_error.available,
),
required_balance: util::to_token_amount(
token_configuration,
insufficient_balance_error.required,
),
},
)
.encode_reject_reason();
Self::Reject(TransactionRejectReason::TokenUpdateTransactionFailed(
EncodedTokenModuleRejectReason {
token_id: token_configuration.token_id.clone(),
reason_type: reason.to_type_discriminator(),
details: Some(details),
},
))
}
}
}
}

/// Execute a transaction payload modifying `block_state` accordingly.
/// Returns the events produced if successful, otherwise a reject reason. Additionally, the
/// amount of energy used by the execution is returned. The returned values are represented
Expand Down
Loading
Loading