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

Allow applications to hold native tokens #2978

Merged
merged 58 commits into from
Nov 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
5d8d144
Use `AccountOwner` as the key for `balances`
jvff Oct 29, 2024
56a5a7a
Use `AccountOwner` in `ChainInfoRequest`
jvff Nov 18, 2024
361c836
Allow client to query application balances
jvff Nov 19, 2024
c638f11
Use `AccountOwner` in `OwnerBalance` request
jvff Nov 16, 2024
d8a7a0a
Update parameter in runtime's `read_owner_balance`
jvff Nov 16, 2024
b708d91
Update `read_owner_balance` WIT interface
jvff Nov 16, 2024
11e6481
Derive `Hash` for `AccountOwner`
jvff Oct 29, 2024
a66c088
Use `AccountOwner` inside `MockContractRuntime`
jvff Nov 15, 2024
e801dfd
Use `AccountOwner` inside `MockServiceRuntime`
jvff Nov 19, 2024
2cfa602
Use `AccountOwner` in runtime's `owner_balance`
jvff Nov 19, 2024
ed4f944
Use `AccountOwner` in cached `owner_balances`
jvff Nov 19, 2024
afae2a0
Use `AccountOwner` in `OwnerBalances` request
jvff Nov 20, 2024
0284300
Update return type of `read_owner_balances`
jvff Nov 20, 2024
ea2915d
Update `read_owner_balances` WIT interface
jvff Nov 20, 2024
0a0e866
Update runtime's `owner_balances` signature
jvff Nov 20, 2024
853849c
Use `AccountOwner` in cached `balance_owners`
jvff Nov 19, 2024
6470ad6
Use `AccountOwner` in `BalanceOwners` request
jvff Nov 20, 2024
5f4fbd0
Update return type of `read_balance_owners`
jvff Nov 20, 2024
a47926c
Update `read_balance_owners` WIT interface
jvff Nov 20, 2024
5bb53c1
Update runtime's `balance_owners` signature
jvff Nov 20, 2024
3823709
Remove redundant authentication check
jvff Oct 29, 2024
f12fdd2
Use `AccountOwner` in `SystemMessage`
jvff Oct 29, 2024
42b4c9c
Change `transfer` parameter into `AccountOwner`
jvff Nov 14, 2024
10062b9
Verify application token transfers
jvff Nov 14, 2024
14e91b7
Send application ID to execution state actor
jvff Nov 14, 2024
4a72c77
Accept application transfers in execution actor
jvff Nov 14, 2024
dd78c42
Update the runtime trait to support app. transfers
jvff Nov 14, 2024
33d55b4
Update `transfer` WIT interface
jvff Nov 15, 2024
2fd16ba
Update `ContractRuntime::transfer` SDK interface
jvff Nov 19, 2024
adc2c57
Send authenticated application ID to `claim` func.
jvff Nov 15, 2024
143a491
Verify application claims
jvff Nov 15, 2024
a57b0ef
Send application ID in `ExecutionRequest::Claim`
jvff Nov 27, 2024
217a97c
Tweak `Account` constructors documentation
jvff Nov 28, 2024
868e0ad
Refactor `FromStr` implementation for `Account`
jvff Nov 28, 2024
c4df960
Use `AccountOwner` in `Account` type
jvff Nov 15, 2024
8c54715
Box some futures to reduce their size
jvff Nov 26, 2024
33abae5
Support app. accounts in native token example
jvff Nov 21, 2024
c7d3492
Use `AccountOwner` in `SystemExecuteState` helper
jvff Nov 22, 2024
693e059
Refactor to move test helpers to `test_utils`
jvff Nov 27, 2024
ec359ca
Test `transfer` contract runtime API
jvff Nov 27, 2024
ce299e3
Test `claim` contract runtime API
jvff Nov 27, 2024
a7ce701
Derive `Arbitrary` for `Amount`
jvff Nov 27, 2024
81280c7
Test `read_chain_balance` contract runtime API
jvff Nov 27, 2024
7acd9bf
Test `read_owner_balance` contract runtime API
jvff Nov 27, 2024
5231fa5
Test `read_owner_balances` contract runtime API
jvff Nov 27, 2024
28b5ee4
Test `read_balance_owners` contract runtime API
jvff Nov 27, 2024
f538542
Test reading the balance of a missing account
jvff Nov 27, 2024
d2fb2da
Test unauthorized transfers from applications
jvff Nov 27, 2024
fa033f1
Test unauthorized claims from applications
jvff Nov 27, 2024
8efd1c6
Add a `create_dummy_query_context` helper function
jvff Nov 27, 2024
8ef6da1
Test `read_chain_balance` service runtime API
jvff Nov 27, 2024
c1918f4
Move `test_accounts_strategy` to `test_utils`
jvff Nov 27, 2024
9cd3cb2
Test `read_owner_balance` service runtime API
jvff Nov 27, 2024
a050518
Test `read_owner_balances` service runtime API
jvff Nov 27, 2024
5eb8cec
Test `read_balance_owners` service runtime API
jvff Nov 27, 2024
a681d7b
Test reading the balance of a missing account
jvff Nov 27, 2024
f079628
Replace `ok_or_else` with `context`
jvff Nov 28, 2024
49c439e
Expect returned accounts to be sorted
jvff Nov 28, 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
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions examples/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 2 additions & 14 deletions examples/native-fungible/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

use fungible::{FungibleResponse, FungibleTokenAbi, InitialState, Operation, Parameters};
use linera_sdk::{
base::{Account, AccountOwner, ChainId, Owner, WithContractAbi},
base::{Account, AccountOwner, ChainId, WithContractAbi},
Contract, ContractRuntime,
};
use native_fungible::{Message, TICKER_SYMBOL};
Expand Down Expand Up @@ -36,7 +36,6 @@ impl Contract for NativeFungibleTokenContract {
"Only NAT is accepted as ticker symbol"
);
for (owner, amount) in state.accounts {
let owner = self.normalize_owner(owner);
let account = Account {
chain_id: self.runtime.chain_id(),
owner: Some(owner),
Expand All @@ -48,8 +47,6 @@ impl Contract for NativeFungibleTokenContract {
async fn execute_operation(&mut self, operation: Self::Operation) -> Self::Response {
match operation {
Operation::Balance { owner } => {
let owner = self.normalize_owner(owner);

let balance = self.runtime.owner_balance(owner);
FungibleResponse::Balance(balance)
}
Expand All @@ -62,7 +59,6 @@ impl Contract for NativeFungibleTokenContract {
target_account,
} => {
self.check_account_authentication(owner);
let owner = self.normalize_owner(owner);

let fungible_target_account = target_account;
let target_account = self.normalize_account(target_account);
Expand Down Expand Up @@ -130,18 +126,10 @@ impl NativeFungibleTokenContract {
}
}

fn normalize_owner(&self, account_owner: AccountOwner) -> Owner {
match account_owner {
AccountOwner::User(owner) => owner,
AccountOwner::Application(_) => panic!("Applications not supported yet!"),
}
}

fn normalize_account(&self, account: fungible::Account) -> Account {
let owner = self.normalize_owner(account.owner);
Account {
chain_id: account.chain_id,
owner: Some(owner),
owner: Some(account.owner),
}
}

Expand Down
19 changes: 5 additions & 14 deletions examples/native-fungible/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,19 +49,14 @@ struct Accounts {
impl Accounts {
// Define a field that lets you query by key
async fn entry(&self, key: AccountOwner) -> AccountEntry {
let owner = match key {
AccountOwner::User(owner) => owner,
AccountOwner::Application(_) => panic!("Applications not supported yet"),
};
let runtime = self
.runtime
.try_lock()
.expect("Services only run in a single thread");

AccountEntry {
key,
value: runtime.owner_balance(owner),
}
let value = runtime.owner_balance(key);

AccountEntry { key, value }
}

async fn entries(&self) -> Vec<AccountEntry> {
Expand All @@ -73,7 +68,7 @@ impl Accounts {
.owner_balances()
.into_iter()
.map(|(owner, amount)| AccountEntry {
key: AccountOwner::User(owner),
key: owner,
value: amount,
})
.collect()
Expand All @@ -84,11 +79,7 @@ impl Accounts {
.runtime
.try_lock()
.expect("Services only run in a single thread");
runtime
.balance_owners()
.into_iter()
.map(AccountOwner::User)
.collect()
runtime.balance_owners()
}
}

Expand Down
4 changes: 4 additions & 0 deletions linera-base/src/data_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ use crate::{
#[derive(
Eq, PartialEq, Ord, PartialOrd, Copy, Clone, Hash, Default, Debug, WitType, WitLoad, WitStore,
)]
#[cfg_attr(
all(with_testing, not(target_arch = "wasm32")),
derive(test_strategy::Arbitrary)
)]
pub struct Amount(u128);

#[derive(Serialize, Deserialize)]
Expand Down
44 changes: 24 additions & 20 deletions linera-base/src/identifiers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ use crate::{
pub struct Owner(pub CryptoHash);

/// An account owner.
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, WitLoad, WitStore, WitType)]
#[cfg_attr(with_testing, derive(test_strategy::Arbitrary))]
pub enum AccountOwner {
/// An account owned by a user.
User(Owner),
Expand All @@ -47,23 +48,23 @@ pub struct Account {
pub chain_id: ChainId,
/// The owner of the account, or `None` for the chain balance.
#[debug(skip_if = Option::is_none)]
pub owner: Option<Owner>,
pub owner: Option<AccountOwner>,
afck marked this conversation as resolved.
Show resolved Hide resolved
}

impl Account {
/// Creates an Account with a ChainId
/// Creates an [`Account`] representing the balance shared by a chain's owners.
pub fn chain(chain_id: ChainId) -> Self {
Account {
chain_id,
owner: None,
}
}

/// Creates an Account with a ChainId and an Owner
pub fn owner(chain_id: ChainId, owner: Owner) -> Self {
/// Creates an [`Account`] for a specific [`Owner`] on a chain.
pub fn owner(chain_id: ChainId, owner: impl Into<AccountOwner>) -> Self {
Account {
chain_id,
owner: Some(owner),
owner: Some(owner.into()),
}
}
}
Expand All @@ -80,18 +81,21 @@ impl Display for Account {
impl FromStr for Account {
type Err = anyhow::Error;

fn from_str(s: &str) -> Result<Self, Self::Err> {
let parts = s.split(':').collect::<Vec<_>>();
anyhow::ensure!(
parts.len() <= 2,
"Expecting format `chain-id:address` or `chain-id`"
);
if parts.len() == 1 {
Ok(Account::chain(s.parse()?))
} else {
let chain_id = parts[0].parse()?;
let owner = parts[1].parse()?;
fn from_str(string: &str) -> Result<Self, Self::Err> {
let mut parts = string.splitn(2, ':');

let chain_id = parts
.next()
.context(
"Expecting an account formatted as `chain-id` or `chain-id:owner-type:address`",
)?
.parse()?;

if let Some(owner_string) = parts.next() {
let owner = owner_string.parse::<AccountOwner>()?;
Ok(Account::owner(chain_id, owner))
} else {
Ok(Account::chain(chain_id))
}
}
}
Expand Down Expand Up @@ -292,7 +296,7 @@ impl<'a> Deserialize<'a> for BlobId {
WitStore,
WitType,
)]
#[cfg_attr(with_testing, derive(Default))]
#[cfg_attr(with_testing, derive(Default, test_strategy::Arbitrary))]
pub struct MessageId {
/// The chain ID that created the message.
pub chain_id: ChainId,
Expand All @@ -304,7 +308,7 @@ pub struct MessageId {

/// A unique identifier for a user application.
#[derive(Debug, WitLoad, WitStore, WitType)]
#[cfg_attr(with_testing, derive(Default))]
#[cfg_attr(with_testing, derive(Default, test_strategy::Arbitrary))]
pub struct ApplicationId<A = ()> {
/// The bytecode to use for the application.
pub bytecode_id: BytecodeId<A>,
Expand Down Expand Up @@ -358,7 +362,7 @@ impl From<ApplicationId> for GenericApplicationId {

/// A unique identifier for an application bytecode.
#[derive(Debug, WitLoad, WitStore, WitType)]
#[cfg_attr(with_testing, derive(Default))]
#[cfg_attr(with_testing, derive(Default, test_strategy::Arbitrary))]
pub struct BytecodeId<Abi = (), Parameters = (), InstantiationArgument = ()> {
/// The hash of the blob containing the contract bytecode.
pub contract_blob_hash: CryptoHash,
Expand Down
5 changes: 3 additions & 2 deletions linera-base/src/unit_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ use crate::{
crypto::{CryptoHash, PublicKey},
data_types::{Amount, BlockHeight, Resources, SendMessageRequest, TimeDelta, Timestamp},
identifiers::{
Account, ApplicationId, BytecodeId, ChainId, ChannelName, Destination, MessageId, Owner,
Account, AccountOwner, ApplicationId, BytecodeId, ChainId, ChannelName, Destination,
MessageId, Owner,
},
ownership::{ChainOwnership, TimeoutConfig},
};
Expand Down Expand Up @@ -83,7 +84,7 @@ fn send_message_request_test_case() -> SendMessageRequest<Vec<u8>> {
fn account_test_case() -> Account {
Account {
chain_id: ChainId::root(10),
owner: Some(Owner(CryptoHash::test_hash("account"))),
owner: Some(AccountOwner::User(Owner(CryptoHash::test_hash("account")))),
}
}

Expand Down
44 changes: 21 additions & 23 deletions linera-chain/src/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -767,7 +767,7 @@ where
.track_executed_block_size_of(&incoming_bundle)
.with_execution_context(chain_execution_context)?;
for (message_id, posted_message) in incoming_bundle.messages_and_ids() {
self.execute_message_in_block(
Box::pin(self.execute_message_in_block(
message_id,
posted_message,
incoming_bundle,
Expand All @@ -776,7 +776,7 @@ where
local_time,
&mut txn_tracker,
&mut resource_controller,
)
))
.await?;
}
}
Expand All @@ -793,16 +793,15 @@ where
authenticated_signer: block.authenticated_signer,
authenticated_caller_id: None,
};
self.execution_state
.execute_operation(
context,
local_time,
operation.clone(),
&mut txn_tracker,
&mut resource_controller,
)
.await
.with_execution_context(chain_execution_context)?;
Box::pin(self.execution_state.execute_operation(
context,
local_time,
operation.clone(),
&mut txn_tracker,
&mut resource_controller,
))
.await
.with_execution_context(chain_execution_context)?;
resource_controller
.with_state(&mut self.execution_state)
.await?
Expand Down Expand Up @@ -942,17 +941,16 @@ where
// Once a chain is closed, accepting incoming messages is not allowed.
ensure!(!self.is_closed(), ChainError::ClosedChain);

self.execution_state
.execute_message(
context,
local_time,
posted_message.message.clone(),
(grant > Amount::ZERO).then_some(&mut grant),
txn_tracker,
resource_controller,
)
.await
.with_execution_context(ChainExecutionContext::IncomingBundle(txn_index))?;
Box::pin(self.execution_state.execute_message(
context,
local_time,
posted_message.message.clone(),
(grant > Amount::ZERO).then_some(&mut grant),
txn_tracker,
resource_controller,
))
.await
.with_execution_context(ChainExecutionContext::IncomingBundle(txn_index))?;
if grant > Amount::ZERO {
if let Some(refund_grant_to) = posted_message.refund_grant_to {
self.execution_state
Expand Down
4 changes: 2 additions & 2 deletions linera-core/src/chain_worker/state/temporary_changes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
use linera_base::{
data_types::{ArithmeticError, Blob, BlobContent, Timestamp, UserApplicationDescription},
ensure,
identifiers::{GenericApplicationId, UserApplicationId},
identifiers::{AccountOwner, GenericApplicationId, UserApplicationId},
};
use linera_chain::{
data_types::{
Expand Down Expand Up @@ -139,7 +139,7 @@ where
.execution_state
.system
.balances
.get(&signer)
.get(&AccountOwner::User(signer))
.await?;
}

Expand Down
Loading
Loading