Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 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
2 changes: 1 addition & 1 deletion .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ on:

env:
UBUNTU_VERSION: '22.04'
STATIC_LIBRARIES_IMAGE_TAG: 'rust-1.94_ghc-9.10.2'
STATIC_LIBRARIES_IMAGE_TAG: 'rust-1.95.0_ghc-9.10.2'
STACK_VERSION: '3.7.1'
FLATBUFFERS_VERSION: '23.5.26'
GHC_VERSION: '9.10.2'
Expand Down
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
## Unreleased changes

- Add support for the following "meta update" operations:
- `lockFund`: move protocol-level tokens from an account's available balance into a PLT Lock.
- `lockSend`: move protocol-level tokens from a PLT Lock to a recipient account's available balance.
- `lockReturn`: release protocol-level tokens from a PLT Lock back to the owner's available balance.
- `lockCancel`: cancel a PLT Lock, releasing all funds to their owners.
- Populate the protocol-level token account `module_state` returned by `GetAccountInfo` with available balance and lock details.

Expand Down
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 @@ -287,6 +287,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 @@ -567,4 +576,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 @@ -329,4 +329,26 @@ 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,
);
}
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
12 changes: 8 additions & 4 deletions plt/plt-scheduler/src/locks/lock_controller.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//! Runtime interface for protocol-level lock controllers.

use concordium_base::contracts_common::AccountAddress;
use concordium_base::protocol_level_tokens::meta_operations::{
MetaLockCancelDetails, MetaLockFundDetails, MetaLockReturnDetails, MetaLockSendDetails,
};
Expand All @@ -23,17 +24,19 @@ pub enum LockOperation {

/// Runtime interface implemented by protocol-level locks.
pub trait LockController {
/// Approve or reject a lock operation. Returns `true` if the operation is authorized.
/// Approve or reject a lock operation. Returns `Ok(())` if the operation is authorized, or
/// a `TransactionRejectReason` if it is not.
///
/// * `bsq`: the block state to query on
/// * `sender`: the transaction sender reference
/// * `operation`: the lock operation to approve/reject.
fn validate_operation<BSQ: BlockStateQuery>(
&self,
bsq: &BSQ,
sender_address: AccountAddress,
sender: &BSQ::Account,
operation: &LockOperation,
) -> bool;
) -> Result<(), TransactionRejectReason>;

/// Convert this controller configuration to its canonical CBOR
/// [`concordium_base::protocol_level_locks::LockController`] representation, used by the
Expand Down Expand Up @@ -67,12 +70,13 @@ impl LockController for LockControllerConfig {
fn validate_operation<BSQ: BlockStateQuery>(
&self,
bsq: &BSQ,
sender_address: AccountAddress,
sender: &BSQ::Account,
operation: &LockOperation,
) -> bool {
) -> Result<(), TransactionRejectReason> {
match self {
LockControllerConfig::SimpleV0(lock_controller_simple_v0) => {
lock_controller_simple_v0.validate_operation(bsq, sender, operation)
lock_controller_simple_v0.validate_operation(bsq, sender_address, sender, operation)
}
}
}
Expand Down
52 changes: 44 additions & 8 deletions plt/plt-scheduler/src/locks/lock_controller_simple.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use concordium_base::base::AccountIndex;
use concordium_base::contracts_common::AccountAddress;
use concordium_base::protocol_level_locks::LockControllerSimpleV0Capability;
use concordium_base::protocol_level_tokens::{CborHolderAccount, TokenId};
use plt_block_state::block_state_interface::BlockStateQuery;
Expand All @@ -15,17 +16,52 @@ impl LockController for LockControllerSimpleV0 {
fn validate_operation<BSQ: BlockStateQuery>(
&self,
bsq: &BSQ,
sender_address: AccountAddress,
sender: &BSQ::Account,
operation: &LockOperation,
) -> bool {
) -> Result<(), TransactionRejectReason> {
let sender_index = bsq.account_index(sender);
let role = match operation {
LockOperation::Fund(_) => LockControllerSimpleV0Capability::Fund,
LockOperation::Send(_) => LockControllerSimpleV0Capability::Send,
LockOperation::Return(_) => LockControllerSimpleV0Capability::Return,
LockOperation::Cancel(_) => LockControllerSimpleV0Capability::Cancel,
};
self.has_role(sender_index, role)
match operation {
LockOperation::Fund(fund_details) => {
if !self.has_role(sender_index, LockControllerSimpleV0Capability::Fund) {
return Err(TransactionRejectReason::LockFundNotAuthorized(
fund_details.lock.clone(),
sender_address,
));
}
if !self.tokens.contains(&fund_details.token) {
return Err(TransactionRejectReason::LockTokenNotPermitted(
fund_details.lock.clone(),
fund_details.token.clone(),
));
}
}
LockOperation::Send(send_details) => {
if !self.has_role(sender_index, LockControllerSimpleV0Capability::Send) {
return Err(TransactionRejectReason::LockSendNotAuthorized(
send_details.lock.clone(),
sender_address,
));
}
}
LockOperation::Return(return_details) => {
if !self.has_role(sender_index, LockControllerSimpleV0Capability::Return) {
return Err(TransactionRejectReason::LockReturnNotAuthorized(
return_details.lock.clone(),
sender_address,
));
}
}
LockOperation::Cancel(cancel_details) => {
if !self.has_role(sender_index, LockControllerSimpleV0Capability::Cancel) {
return Err(TransactionRejectReason::LockCancelNotAuthorized(
cancel_details.lock.clone(),
sender_address,
));
}
}
}
Ok(())
}

fn to_cbor_controller<BSQ: BlockStateQuery>(
Expand Down
5 changes: 3 additions & 2 deletions plt/plt-scheduler/src/scheduler/p11.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,14 +105,14 @@ where
};

// Execute operations
for operation in operations {
for (index, operation) in operations.into_iter().enumerate() {
match MetaUpdateOperationKind::from(operation) {
MetaUpdateOperationKind::Token(token_id, token_operation) => {
match protocol_level_tokens::p11::execute_token_update_operation(
context,
transaction_execution,
block_state,
0,
index,
&token_id,
token_operation,
&mut events,
Expand All @@ -128,6 +128,7 @@ where
context,
transaction_execution,
block_state,
index,
lock_operation,
&mut events,
) {
Expand Down
Loading
Loading