355 lines
9.6 KiB
Rust
Raw Normal View History

2026-03-03 23:21:08 +03:00
use std::{
fmt::{Display, Write as _},
str::FromStr,
};
2026-03-04 18:42:33 +03:00
use base58::{FromBase58 as _, ToBase58 as _};
2025-11-27 06:03:43 +02:00
use borsh::{BorshDeserialize, BorshSerialize};
pub use data::Data;
2026-03-18 10:28:52 -04:00
use risc0_zkvm::sha::{Impl, Sha256 as _};
2025-11-27 06:03:43 +02:00
use serde::{Deserialize, Serialize};
use serde_with::{DeserializeFromStr, SerializeDisplay};
2025-11-27 06:03:43 +02:00
2026-02-12 19:22:03 -05:00
use crate::{NullifierPublicKey, NullifierSecretKey, program::ProgramId};
pub mod data;
2026-03-02 11:54:41 -05:00
#[derive(Copy, Debug, Default, Clone, Eq, PartialEq)]
2026-02-12 19:22:03 -05:00
pub struct Nonce(pub u128);
impl Nonce {
2026-03-18 10:28:52 -04:00
pub const fn public_account_nonce_increment(&mut self) {
self.0 = self
.0
.checked_add(1)
.expect("Overflow when incrementing nonce");
2026-02-12 19:22:03 -05:00
}
2026-03-18 10:28:52 -04:00
#[must_use]
pub fn private_account_nonce_init(npk: &NullifierPublicKey) -> Self {
let mut bytes: [u8; 64] = [0_u8; 64];
2026-02-16 19:53:32 -05:00
bytes[..32].copy_from_slice(&npk.0);
let result: [u8; 32] = Impl::hash_bytes(&bytes).as_bytes().try_into().unwrap();
let result = result.first_chunk::<16>().unwrap();
2026-03-18 10:28:52 -04:00
Self(u128::from_le_bytes(*result))
2026-02-12 19:22:03 -05:00
}
2026-03-18 10:28:52 -04:00
#[must_use]
pub fn private_account_nonce_increment(self, nsk: &NullifierSecretKey) -> Self {
let mut bytes: [u8; 64] = [0_u8; 64];
2026-02-16 19:53:32 -05:00
bytes[..32].copy_from_slice(nsk);
bytes[32..48].copy_from_slice(&self.0.to_le_bytes());
let result: [u8; 32] = Impl::hash_bytes(&bytes).as_bytes().try_into().unwrap();
let result = result.first_chunk::<16>().unwrap();
2026-02-12 19:22:03 -05:00
2026-03-18 10:28:52 -04:00
Self(u128::from_le_bytes(*result))
2026-02-16 19:53:32 -05:00
}
2026-02-12 19:22:03 -05:00
}
2026-03-02 11:54:41 -05:00
impl From<u128> for Nonce {
fn from(value: u128) -> Self {
Self(value)
}
}
impl From<Nonce> for u128 {
fn from(value: Nonce) -> Self {
value.0
}
}
impl Serialize for Nonce {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
Serialize::serialize(&self.0, serializer)
}
}
impl<'de> Deserialize<'de> for Nonce {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
Ok(<u128 as Deserialize>::deserialize(deserializer)?.into())
}
}
impl BorshSerialize for Nonce {
fn serialize<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
BorshSerialize::serialize(&self.0, writer)
}
}
impl BorshDeserialize for Nonce {
fn deserialize_reader<R: std::io::Read>(reader: &mut R) -> std::io::Result<Self> {
Ok(<u128 as BorshDeserialize>::deserialize_reader(reader)?.into())
}
}
2026-02-19 19:15:04 -05:00
pub type Balance = u128;
2025-08-06 20:05:04 -03:00
2026-03-10 00:17:43 +03:00
/// Account to be used both in public and private contexts.
#[derive(
Default, Clone, Eq, PartialEq, Serialize, Deserialize, BorshSerialize, BorshDeserialize,
)]
2025-08-06 20:05:04 -03:00
pub struct Account {
pub program_owner: ProgramId,
2026-02-19 19:15:04 -05:00
pub balance: Balance,
2025-08-06 20:05:04 -03:00
pub data: Data,
pub nonce: Nonce,
}
impl std::fmt::Debug for Account {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2026-03-03 23:21:08 +03:00
let program_owner_hex = self
.program_owner
.iter()
.flat_map(|n| n.to_le_bytes())
2026-03-03 23:21:08 +03:00
.fold(String::new(), |mut acc, bytes| {
write!(acc, "{bytes:02x}").expect("writing to string should not fail");
acc
});
f.debug_struct("Account")
.field("program_owner", &program_owner_hex)
.field("balance", &self.balance)
.field("data", &self.data)
.field("nonce", &self.nonce)
.finish()
}
}
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
2025-08-06 20:05:04 -03:00
pub struct AccountWithMetadata {
pub account: Account,
2025-09-09 17:03:58 -03:00
pub is_authorized: bool,
2025-09-12 09:18:40 -03:00
pub account_id: AccountId,
2025-08-06 20:05:04 -03:00
}
2025-12-15 18:55:38 -05:00
2025-09-11 16:37:28 -03:00
#[cfg(feature = "host")]
impl AccountWithMetadata {
2025-09-12 09:18:40 -03:00
pub fn new(account: Account, is_authorized: bool, account_id: impl Into<AccountId>) -> Self {
2025-09-11 16:37:28 -03:00
Self {
account,
is_authorized,
2025-09-12 09:18:40 -03:00
account_id: account_id.into(),
2025-09-11 16:37:28 -03:00
}
}
}
#[derive(
Default,
2025-12-22 05:12:48 +02:00
Copy,
Clone,
SerializeDisplay,
DeserializeFromStr,
2025-12-22 05:12:48 +02:00
PartialEq,
Eq,
Hash,
BorshSerialize,
BorshDeserialize,
)]
#[cfg_attr(any(feature = "host", test), derive(PartialOrd, Ord))]
pub struct AccountId {
value: [u8; 32],
}
impl std::fmt::Debug for AccountId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.value.to_base58())
}
}
impl AccountId {
2026-03-03 23:21:08 +03:00
#[must_use]
2026-03-09 18:27:56 +03:00
pub const fn new(value: [u8; 32]) -> Self {
Self { value }
}
2026-03-03 23:21:08 +03:00
#[must_use]
2026-03-09 18:27:56 +03:00
pub const fn value(&self) -> &[u8; 32] {
&self.value
}
2026-03-03 23:21:08 +03:00
#[must_use]
2026-03-09 18:27:56 +03:00
pub const fn into_value(self) -> [u8; 32] {
self.value
}
}
impl AsRef<[u8]> for AccountId {
fn as_ref(&self) -> &[u8] {
&self.value
}
}
#[derive(Debug, thiserror::Error)]
pub enum AccountIdError {
#[error("invalid base58: {0:?}")]
InvalidBase58(base58::FromBase58Error),
#[error("invalid length: expected 32 bytes, got {0}")]
InvalidLength(usize),
}
impl FromStr for AccountId {
type Err = AccountIdError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let bytes = s.from_base58().map_err(AccountIdError::InvalidBase58)?;
if bytes.len() != 32 {
return Err(AccountIdError::InvalidLength(bytes.len()));
}
2026-03-04 18:42:33 +03:00
let mut value = [0_u8; 32];
value.copy_from_slice(&bytes);
2026-03-09 18:27:56 +03:00
Ok(Self { value })
}
}
impl Display for AccountId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.value.to_base58())
}
}
2025-08-08 13:32:50 -03:00
#[cfg(test)]
mod tests {
use super::*;
2025-11-26 00:27:20 +03:00
use crate::program::DEFAULT_PROGRAM_ID;
2025-08-08 13:32:50 -03:00
#[test]
2026-03-04 18:42:33 +03:00
fn zero_balance_account_data_creation() {
2025-08-08 13:32:50 -03:00
let new_acc = Account::default();
assert_eq!(new_acc.balance, 0);
}
#[test]
2026-03-04 18:42:33 +03:00
fn zero_nonce_account_data_creation() {
2025-08-08 13:32:50 -03:00
let new_acc = Account::default();
2026-02-12 19:22:03 -05:00
assert_eq!(new_acc.nonce.0, 0);
2025-08-08 13:32:50 -03:00
}
#[test]
2026-03-04 18:42:33 +03:00
fn empty_data_account_data_creation() {
2025-08-08 13:32:50 -03:00
let new_acc = Account::default();
2025-08-10 18:59:29 -03:00
assert!(new_acc.data.is_empty());
2025-08-08 13:32:50 -03:00
}
#[test]
2026-03-04 18:42:33 +03:00
fn default_program_owner_account_data_creation() {
2025-08-08 13:32:50 -03:00
let new_acc = Account::default();
assert_eq!(new_acc.program_owner, DEFAULT_PROGRAM_ID);
2025-08-06 20:05:04 -03:00
}
2025-09-11 16:37:28 -03:00
#[cfg(feature = "host")]
2025-09-11 16:37:28 -03:00
#[test]
2026-03-04 18:42:33 +03:00
fn account_with_metadata_constructor() {
2025-09-11 16:37:28 -03:00
let account = Account {
program_owner: [1, 2, 3, 4, 5, 6, 7, 8],
balance: 1337,
data: b"testing_account_with_metadata_constructor"
.to_vec()
.try_into()
.unwrap(),
2026-03-18 13:10:36 -04:00
nonce: Nonce(0xdead_beef),
2025-09-11 16:37:28 -03:00
};
2025-09-12 09:18:40 -03:00
let fingerprint = AccountId::new([8; 32]);
2025-10-03 08:08:54 -03:00
let new_acc_with_metadata = AccountWithMetadata::new(account.clone(), true, fingerprint);
2025-09-11 16:37:28 -03:00
assert_eq!(new_acc_with_metadata.account, account);
assert!(new_acc_with_metadata.is_authorized);
2025-09-12 09:18:40 -03:00
assert_eq!(new_acc_with_metadata.account_id, fingerprint);
2025-09-11 16:37:28 -03:00
}
2026-02-11 11:43:23 -05:00
#[cfg(feature = "host")]
#[test]
fn parse_valid_account_id() {
let base58_str = "11111111111111111111111111111111";
let account_id: AccountId = base58_str.parse().unwrap();
2026-03-04 18:42:33 +03:00
assert_eq!(account_id.value, [0_u8; 32]);
}
2026-02-11 11:43:23 -05:00
#[cfg(feature = "host")]
#[test]
fn parse_invalid_base58() {
let base58_str = "00".repeat(32); // invalid base58 chars
let result = base58_str.parse::<AccountId>().unwrap_err();
assert!(matches!(result, AccountIdError::InvalidBase58(_)));
}
2026-02-11 11:43:23 -05:00
#[cfg(feature = "host")]
#[test]
fn parse_wrong_length_short() {
let base58_str = "11".repeat(31); // 62 chars = 31 bytes
let result = base58_str.parse::<AccountId>().unwrap_err();
assert!(matches!(result, AccountIdError::InvalidLength(_)));
}
2026-02-11 11:43:23 -05:00
#[cfg(feature = "host")]
#[test]
fn parse_wrong_length_long() {
let base58_str = "11".repeat(33); // 66 chars = 33 bytes
let result = base58_str.parse::<AccountId>().unwrap_err();
assert!(matches!(result, AccountIdError::InvalidLength(_)));
}
2025-12-02 15:20:16 -05:00
#[test]
fn default_account_id() {
let default_account_id = AccountId::default();
let expected_account_id = AccountId::new([0; 32]);
2025-12-02 15:20:16 -05:00
assert!(default_account_id == expected_account_id);
}
2026-02-17 19:10:35 -05:00
#[test]
fn initialize_private_nonce() {
let npk = NullifierPublicKey([42; 32]);
2026-03-17 09:29:00 -04:00
let nonce = Nonce::private_account_nonce_init(&npk);
2026-03-18 13:10:36 -04:00
let expected_nonce = Nonce(37_937_661_125_547_691_021_612_781_941_709_513_486);
2026-02-17 19:10:35 -05:00
assert_eq!(nonce, expected_nonce);
}
#[test]
fn increment_private_nonce() {
2026-03-18 13:10:36 -04:00
let nsk: NullifierSecretKey = [42_u8; 32];
2026-03-18 13:47:21 -04:00
let nonce = Nonce(37_937_661_125_547_691_021_612_781_941_709_513_486)
.private_account_nonce_increment(&nsk);
2026-03-18 13:10:36 -04:00
let expected_nonce = Nonce(327_300_903_218_789_900_388_409_116_014_290_259_894);
2026-02-17 19:10:35 -05:00
assert_eq!(nonce, expected_nonce);
}
2026-03-02 11:54:41 -05:00
2026-03-02 16:13:23 -05:00
#[test]
fn increment_public_nonce() {
2026-03-18 13:10:36 -04:00
let value = 42_u128;
2026-03-02 16:13:23 -05:00
let mut nonce = Nonce(value);
nonce.public_account_nonce_increment();
let expected_nonce = Nonce(value + 1);
assert_eq!(nonce, expected_nonce);
}
2026-03-02 11:54:41 -05:00
#[test]
2026-03-18 13:10:36 -04:00
fn serde_roundtrip_for_nonce() {
let nonce: Nonce = 7_u128.into();
2026-03-02 11:54:41 -05:00
let serde_serialized_nonce = serde_json::to_vec(&nonce).unwrap();
let nonce_restored = serde_json::from_slice(&serde_serialized_nonce).unwrap();
assert_eq!(nonce, nonce_restored);
}
#[test]
2026-03-18 13:10:36 -04:00
fn borsh_roundtrip_for_nonce() {
let nonce: Nonce = 7_u128.into();
2026-03-02 11:54:41 -05:00
let borsh_serialized_nonce = borsh::to_vec(&nonce).unwrap();
let nonce_restored = borsh::from_slice(&borsh_serialized_nonce).unwrap();
assert_eq!(nonce, nonce_restored);
}
2025-08-06 20:05:04 -03:00
}