Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
3 changes: 3 additions & 0 deletions examples/amm/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,9 @@ impl AmmContract {
"Unauthorized"
)
}
AccountOwner::Chain => {
panic!("Using chain balance is not authorized")
}
}
}

Expand Down
3 changes: 3 additions & 0 deletions examples/fungible/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,9 @@ impl FungibleTokenContract {
"The requested transfer is not correctly authenticated."
)
}
AccountOwner::Chain => {
panic!("Chain account is not supported")
}
}
}

Expand Down
3 changes: 3 additions & 0 deletions examples/gen-nft/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,9 @@ impl GenNftContract {
"The requested transfer is not correctly authenticated."
)
}
AccountOwner::Chain => {
panic!("Chain account is not supported")
}
}
}

Expand Down
3 changes: 3 additions & 0 deletions examples/matching-engine/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,9 @@ impl MatchingEngineContract {
"Unauthorized"
)
}
AccountOwner::Chain => {
panic!("Chain account is not supported")
}
}
}

Expand Down
11 changes: 7 additions & 4 deletions examples/native-fungible/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ impl Contract for NativeFungibleTokenContract {
for (owner, amount) in state.accounts {
let account = Account {
chain_id: self.runtime.chain_id(),
owner: Some(owner),
owner,
};
self.runtime.transfer(None, account, amount);
self.runtime.transfer(AccountOwner::Chain, account, amount);
}
}

Expand All @@ -63,7 +63,7 @@ impl Contract for NativeFungibleTokenContract {
let fungible_target_account = target_account;
let target_account = self.normalize_account(target_account);

self.runtime.transfer(Some(owner), target_account, amount);
self.runtime.transfer(owner, target_account, amount);

self.transfer(fungible_target_account.chain_id);
FungibleResponse::Ok
Expand Down Expand Up @@ -129,7 +129,7 @@ impl NativeFungibleTokenContract {
fn normalize_account(&self, account: fungible::Account) -> Account {
Account {
chain_id: account.chain_id,
owner: Some(account.owner),
owner: account.owner,
}
}

Expand All @@ -144,6 +144,9 @@ impl NativeFungibleTokenContract {
);
}
AccountOwner::Application(_) => panic!("Applications not supported yet"),
Copy link
Contributor

@ma2bd ma2bd Mar 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should fix that (not here but soon)

AccountOwner::Chain => {
panic!("Chain accounts are not supported")
}
}
}
}
3 changes: 3 additions & 0 deletions examples/non-fungible/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,9 @@ impl NonFungibleTokenContract {
"The requested transfer is not correctly authenticated."
)
}
AccountOwner::Chain => {
panic!("Chain account is not supported")
}
}
}

Expand Down
26 changes: 15 additions & 11 deletions linera-base/src/identifiers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@ pub enum AccountOwner {
/// An account owned by a user.
User(Owner),
/// An account for an application.
Application(ApplicationId),
Application(UserApplicationId),
/// Chain account.
Chain,
}

/// A system account.
Expand All @@ -48,34 +50,30 @@ pub struct Account {
/// The chain of the 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<AccountOwner>,
pub owner: AccountOwner,
}

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

/// 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.into()),
owner: owner.into(),
}
}
}

impl Display for Account {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.owner {
Some(owner) => write!(f, "{}:{}", self.chain_id, owner),
None => write!(f, "{}", self.chain_id),
}
write!(f, "{}:{}", self.chain_id, self.owner)
}
}

Expand Down Expand Up @@ -306,7 +304,7 @@ pub struct ApplicationId<A = ()> {

/// Alias for `ApplicationId`. Use this alias in the core
/// protocol where the distinction with the more general enum `GenericApplicationId` matters.
pub type UserApplicationId<A = ()> = ApplicationId<A>;
pub type UserApplicationId = ApplicationId<()>;

/// A unique identifier for an application.
#[derive(
Expand All @@ -328,7 +326,7 @@ pub enum GenericApplicationId {
/// The system application.
System,
/// A user application.
User(ApplicationId),
User(UserApplicationId),
}

impl GenericApplicationId {
Expand Down Expand Up @@ -951,6 +949,7 @@ impl<'de> serde::de::Visitor<'de> for OwnerVisitor {
enum SerializableAccountOwner {
User(Owner),
Application(ApplicationId),
Chain,
}

impl Serialize for AccountOwner {
Expand All @@ -961,6 +960,7 @@ impl Serialize for AccountOwner {
match self {
AccountOwner::Application(app_id) => SerializableAccountOwner::Application(*app_id),
AccountOwner::User(owner) => SerializableAccountOwner::User(*owner),
AccountOwner::Chain => SerializableAccountOwner::Chain,
}
.serialize(serializer)
}
Expand All @@ -980,6 +980,7 @@ impl<'de> Deserialize<'de> for AccountOwner {
Ok(AccountOwner::Application(app_id))
}
SerializableAccountOwner::User(owner) => Ok(AccountOwner::User(owner)),
SerializableAccountOwner::Chain => Ok(AccountOwner::Chain),
}
}
}
Expand All @@ -990,6 +991,7 @@ impl Display for AccountOwner {
match self {
AccountOwner::User(owner) => write!(f, "User:{}", owner)?,
AccountOwner::Application(app_id) => write!(f, "Application:{}", app_id)?,
AccountOwner::Chain => write!(f, "Chain")?,
Copy link
Contributor

@ma2bd ma2bd Mar 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I look forward to removing these tags

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ::Chain variant might not be so easy to remove b/c there are flow paths where the Chain is still a valid identifier. Right now I can see two ways to get rid of it:

  1. Do not let chain own a balance.
  2. Turn ::Chain variant into a special case of address ([u8; 32]).

The first one isn't just a refactor (internal change) as it requires making some high-level design decisions around opening new chains etc.

I think the second option is the easier one and we should try to do it. We could hash a string like "Linera Chain Address" (note it cannot simply be [0u8; 32] b/c in Ed25519 a private key for all zeros public key is well-known).

Copy link
Contributor

@ma2bd ma2bd Mar 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note it cannot simply be [0u8; 32] b/c in Ed25519 a private key for all zeros public key is well-known)

Addresses are not public keys but hash values, so [0u8; 32] would work. I proposed 0x0 (Reserved(0)) in the internal doc.

};

Ok(())
Expand All @@ -1008,6 +1010,8 @@ impl FromStr for AccountOwner {
Ok(AccountOwner::Application(
ApplicationId::from_str(app_id).context("Getting ApplicationId should not fail")?,
))
} else if s.strip_prefix("Chain").is_some() {
Ok(AccountOwner::Chain)
} else {
Err(anyhow!("Invalid enum! Enum: {}", s))
}
Expand Down
2 changes: 1 addition & 1 deletion linera-base/src/unit_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ fn send_message_request_test_case() -> SendMessageRequest<Vec<u8>> {
fn account_test_case() -> Account {
Account {
chain_id: ChainId::root(10),
owner: Some(AccountOwner::User(Owner(CryptoHash::test_hash("account")))),
owner: AccountOwner::User(Owner(CryptoHash::test_hash("account"))),
}
}

Expand Down
11 changes: 8 additions & 3 deletions linera-core/src/chain_worker/state/temporary_changes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -219,9 +219,14 @@ where
if query.request_committees {
info.requested_committees = Some(chain.execution_state.system.committees.get().clone());
}
if let Some(owner) = query.request_owner_balance {
info.requested_owner_balance =
chain.execution_state.system.balances.get(&owner).await?;
match query.request_owner_balance {
owner @ AccountOwner::Application(_) | owner @ AccountOwner::User(_) => {
info.requested_owner_balance =
chain.execution_state.system.balances.get(&owner).await?;
}
AccountOwner::Chain => {
info.requested_owner_balance = Some(*chain.execution_state.system.balance.get());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here or very soon we should remove SystemExecutionStateView::balance by the way

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I took a quick stab at removing the chains' balances entirely and it wasn't very difficult. I can propose something in a separate PR.

}
}
if let Some(next_block_height) = query.test_next_block_height {
ensure!(
Expand Down
21 changes: 11 additions & 10 deletions linera-core/src/client/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2260,7 +2260,7 @@ where
#[instrument(level = "trace", skip(application_id, query))]
pub async fn query_user_application<A: Abi>(
&self,
application_id: UserApplicationId<A>,
application_id: ApplicationId<A>,
query: &A::Query,
) -> Result<QueryOutcome<A::QueryResponse>, ChainClientError> {
let query = Query::user(application_id, query)?;
Expand Down Expand Up @@ -2294,7 +2294,7 @@ where
/// block.
#[instrument(level = "trace")]
pub async fn query_balance(&self) -> Result<Amount, ChainClientError> {
let (balance, _) = self.query_balances_with_owner(None).await?;
let (balance, _) = self.query_balances_with_owner(AccountOwner::Chain).await?;
Ok(balance)
}

Expand All @@ -2310,7 +2310,7 @@ where
owner: AccountOwner,
) -> Result<Amount, ChainClientError> {
Ok(self
.query_balances_with_owner(Some(owner))
.query_balances_with_owner(owner)
.await?
.1
.unwrap_or(Amount::ZERO))
Expand All @@ -2325,7 +2325,7 @@ where
#[instrument(level = "trace", skip(owner))]
async fn query_balances_with_owner(
&self,
owner: Option<AccountOwner>,
owner: AccountOwner,
) -> Result<(Amount, Option<Amount>), ChainClientError> {
let incoming_bundles = self.pending_message_bundles().await?;
let (previous_block_hash, height, timestamp) = {
Expand All @@ -2343,10 +2343,11 @@ where
operations: Vec::new(),
previous_block_hash,
height,
authenticated_signer: owner.and_then(|owner| match owner {
authenticated_signer: match owner {
AccountOwner::User(user) => Some(user),
AccountOwner::Application(_) => None,
}),
AccountOwner::Chain => None, // These should be unreachable?
},
timestamp,
};
match self
Expand Down Expand Up @@ -2382,7 +2383,7 @@ where
/// Does not process the inbox or attempt to synchronize with validators.
#[instrument(level = "trace")]
pub async fn local_balance(&self) -> Result<Amount, ChainClientError> {
let (balance, _) = self.local_balances_with_owner(None).await?;
let (balance, _) = self.local_balances_with_owner(AccountOwner::Chain).await?;
Ok(balance)
}

Expand All @@ -2395,7 +2396,7 @@ where
owner: AccountOwner,
) -> Result<Amount, ChainClientError> {
Ok(self
.local_balances_with_owner(Some(owner))
.local_balances_with_owner(owner)
.await?
.1
.unwrap_or(Amount::ZERO))
Expand All @@ -2407,7 +2408,7 @@ where
#[instrument(level = "trace", skip(owner))]
async fn local_balances_with_owner(
&self,
owner: Option<AccountOwner>,
owner: AccountOwner,
) -> Result<(Amount, Option<Amount>), ChainClientError> {
let next_block_height = self.next_block_height();
ensure!(
Expand Down Expand Up @@ -2936,7 +2937,7 @@ where
parameters: &Parameters,
instantiation_argument: &InstantiationArgument,
required_application_ids: Vec<UserApplicationId>,
) -> Result<ClientOutcome<(UserApplicationId<A>, ConfirmedBlockCertificate)>, ChainClientError>
) -> Result<ClientOutcome<(ApplicationId<A>, ConfirmedBlockCertificate)>, ChainClientError>
{
let instantiation_argument = serde_json::to_vec(instantiation_argument)?;
let parameters = serde_json::to_vec(parameters)?;
Expand Down
7 changes: 3 additions & 4 deletions linera-core/src/data_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,7 @@ pub struct ChainInfoQuery {
#[debug(skip_if = Option::is_none)]
pub test_next_block_height: Option<BlockHeight>,
/// Request the balance of a given [`AccountOwner`].
#[debug(skip_if = Option::is_none)]
pub request_owner_balance: Option<AccountOwner>,
pub request_owner_balance: AccountOwner,
/// Query the current committees.
#[debug(skip_if = Not::not)]
pub request_committees: bool,
Expand Down Expand Up @@ -102,7 +101,7 @@ impl ChainInfoQuery {
chain_id,
test_next_block_height: None,
request_committees: false,
request_owner_balance: None,
request_owner_balance: AccountOwner::Chain,
request_pending_message_bundles: false,
request_sent_certificate_hashes_in_range: None,
request_received_log_excluding_first_n: None,
Expand All @@ -123,7 +122,7 @@ impl ChainInfoQuery {
}

pub fn with_owner_balance(mut self, owner: AccountOwner) -> Self {
self.request_owner_balance = Some(owner);
self.request_owner_balance = owner;
self
}

Expand Down
10 changes: 2 additions & 8 deletions linera-core/src/unit_tests/client_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,10 +195,7 @@ where
Amount::from_tokens(3)
);
assert_eq!(
receiver
.local_balances_with_owner(Some(owner))
.await
.unwrap(),
receiver.local_balances_with_owner(owner).await.unwrap(),
(Amount::ZERO, Some(Amount::from_tokens(3)))
);
assert_eq!(receiver.query_balance().await.unwrap(), Amount::ZERO);
Expand All @@ -207,10 +204,7 @@ where
Amount::from_millis(2999)
);
assert_eq!(
receiver
.query_balances_with_owner(Some(owner))
.await
.unwrap(),
receiver.query_balances_with_owner(owner).await.unwrap(),
(Amount::ZERO, Some(Amount::from_millis(2999)))
);

Expand Down
Loading