Merge ce136348e7a746a28b1e9380848aef1c88ac1593 into fb083ce91ec10487fc17137a48c47f4322f9c768

This commit is contained in:
Pravdyvy 2026-03-23 19:23:03 +02:00 committed by GitHub
commit 4d21b18386
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 666 additions and 355 deletions

51
Cargo.lock generated
View File

@ -162,7 +162,7 @@ version = "1.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc"
dependencies = [
"windows-sys 0.61.2",
"windows-sys 0.60.2",
]
[[package]]
@ -173,7 +173,7 @@ checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d"
dependencies = [
"anstyle",
"once_cell_polyfill",
"windows-sys 0.61.2",
"windows-sys 0.60.2",
]
[[package]]
@ -629,9 +629,9 @@ checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
[[package]]
name = "astral-tokio-tar"
version = "0.5.6"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec179a06c1769b1e42e1e2cbe74c7dcdb3d6383c838454d063eaac5bbb7ebbe5"
checksum = "3c23f3af104b40a3430ccb90ed5f7bd877a8dc5c26fc92fde51a22b40890dcf9"
dependencies = [
"filetime",
"futures-core",
@ -1504,7 +1504,6 @@ dependencies = [
"log",
"logos-blockchain-common-http-client",
"nssa",
"nssa_core",
"serde",
"serde_with",
"sha2",
@ -1939,7 +1938,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ab67060fc6b8ef687992d439ca0fa36e7ed17e9a0b16b25b601e8757df720de"
dependencies = [
"data-encoding",
"syn 2.0.117",
"syn 1.0.109",
]
[[package]]
@ -2088,7 +2087,7 @@ dependencies = [
"libc",
"option-ext",
"redox_users",
"windows-sys 0.61.2",
"windows-sys 0.59.0",
]
[[package]]
@ -2389,7 +2388,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
dependencies = [
"libc",
"windows-sys 0.61.2",
"windows-sys 0.59.0",
]
[[package]]
@ -3442,6 +3441,7 @@ dependencies = [
"serde_json",
"storage",
"tempfile",
"testnet_initial_state",
"tokio",
"url",
]
@ -3568,6 +3568,7 @@ dependencies = [
"serde_json",
"tempfile",
"testcontainers",
"testnet_initial_state",
"token_core",
"tokio",
"url",
@ -5930,7 +5931,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d"
dependencies = [
"anyhow",
"itertools 0.14.0",
"itertools 0.10.5",
"proc-macro2",
"quote",
"syn 2.0.117",
@ -5943,7 +5944,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "27c6023962132f4b30eb4c172c91ce92d933da334c59c23cddee82358ddafb0b"
dependencies = [
"anyhow",
"itertools 0.14.0",
"itertools 0.10.5",
"proc-macro2",
"quote",
"syn 2.0.117",
@ -6861,7 +6862,7 @@ dependencies = [
"errno",
"libc",
"linux-raw-sys",
"windows-sys 0.61.2",
"windows-sys 0.59.0",
]
[[package]]
@ -6930,9 +6931,9 @@ checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f"
[[package]]
name = "rustls-webpki"
version = "0.103.9"
version = "0.103.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7df23109aa6c1567d1c575b9952556388da57401e4ace1d15f79eedad0d8f53"
checksum = "df33b2b81ac578cabaf06b89b0631153a3f416b0a886e8a7a1707fb51abbd1ef"
dependencies = [
"ring",
"rustls-pki-types",
@ -7137,7 +7138,6 @@ name = "sequencer_core"
version = "0.1.0"
dependencies = [
"anyhow",
"base58",
"bedrock_client",
"borsh",
"bytesize",
@ -7157,6 +7157,7 @@ dependencies = [
"serde_json",
"storage",
"tempfile",
"testnet_initial_state",
"tokio",
"url",
]
@ -7538,7 +7539,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e"
dependencies = [
"libc",
"windows-sys 0.61.2",
"windows-sys 0.60.2",
]
[[package]]
@ -7789,7 +7790,7 @@ dependencies = [
"getrandom 0.4.2",
"once_cell",
"rustix",
"windows-sys 0.61.2",
"windows-sys 0.59.0",
]
[[package]]
@ -7842,9 +7843,9 @@ dependencies = [
[[package]]
name = "testcontainers"
version = "0.27.1"
version = "0.27.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1c0624faaa317c56d6d19136580be889677259caf5c897941c6f446b4655068"
checksum = "0bd36b06a2a6c0c3c81a83be1ab05fe86460d054d4d51bf513bc56b3e15bdc22"
dependencies = [
"astral-tokio-tar",
"async-trait",
@ -7873,6 +7874,17 @@ dependencies = [
"uuid",
]
[[package]]
name = "testnet_initial_state"
version = "0.1.0"
dependencies = [
"common",
"key_protocol",
"nssa",
"nssa_core",
"serde",
]
[[package]]
name = "thiserror"
version = "1.0.69"
@ -8669,6 +8681,7 @@ dependencies = [
"serde",
"serde_json",
"sha2",
"testnet_initial_state",
"thiserror 2.0.18",
"token_core",
"tokio",
@ -8941,7 +8954,7 @@ version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
dependencies = [
"windows-sys 0.61.2",
"windows-sys 0.59.0",
]
[[package]]

View File

@ -34,6 +34,7 @@ members = [
"examples/program_deployment/methods",
"examples/program_deployment/methods/guest",
"bedrock_client",
"testnet_initial_state",
]
[workspace.dependencies]
@ -59,6 +60,7 @@ amm_core = { path = "programs/amm/core" }
amm_program = { path = "programs/amm" }
test_program_methods = { path = "test_program_methods" }
bedrock_client = { path = "bedrock_client" }
testnet_initial_state = { path = "testnet_initial_state" }
tokio = { version = "1.50", features = [
"net",

View File

@ -9,7 +9,6 @@ workspace = true
[dependencies]
nssa.workspace = true
nssa_core.workspace = true
anyhow.workspace = true
thiserror.workspace = true

View File

@ -1,5 +1,4 @@
use borsh::{BorshDeserialize, BorshSerialize};
use nssa::AccountId;
use serde::{Deserialize, Serialize};
use sha2::{Digest as _, Sha256, digest::FixedOutput as _};
@ -123,20 +122,6 @@ impl From<Block> for HashableBlockData {
}
}
/// Helper struct for account (de-)serialization.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AccountInitialData {
pub account_id: AccountId,
pub balance: u128,
}
/// Helper struct to (de-)serialize initial commitments.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CommitmentsInitialData {
pub npk: nssa_core::NullifierPublicKey,
pub account: nssa_core::account::Account,
}
#[cfg(test)]
mod tests {
use crate::{HashType, block::HashableBlockData, test_utils};

View File

@ -13,6 +13,7 @@ bedrock_client.workspace = true
nssa.workspace = true
nssa_core.workspace = true
storage.workspace = true
testnet_initial_state.workspace = true
anyhow.workspace = true
log.workspace = true

View File

@ -7,13 +7,11 @@ use std::{
use anyhow::{Context as _, Result};
pub use bedrock_client::BackoffConfig;
use common::{
block::{AccountInitialData, CommitmentsInitialData},
config::BasicAuth,
};
use common::config::BasicAuth;
use humantime_serde;
pub use logos_blockchain_core::mantle::ops::channel::ChannelId;
use serde::{Deserialize, Serialize};
use testnet_initial_state::{PrivateAccountPublicInitialData, PublicAccountPublicInitialData};
use url::Url;
#[derive(Debug, Clone, Serialize, Deserialize)]
@ -29,16 +27,16 @@ pub struct ClientConfig {
pub struct IndexerConfig {
/// Home dir of sequencer storage.
pub home: PathBuf,
/// List of initial accounts data.
pub initial_accounts: Vec<AccountInitialData>,
/// List of initial commitments.
pub initial_commitments: Vec<CommitmentsInitialData>,
/// Sequencers signing key.
pub signing_key: [u8; 32],
#[serde(with = "humantime_serde")]
pub consensus_info_polling_interval: Duration,
pub bedrock_client_config: ClientConfig,
pub channel_id: ChannelId,
#[serde(skip_serializing_if = "Option::is_none")]
pub initial_public_accounts: Option<Vec<PublicAccountPublicInitialData>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub initial_private_accounts: Option<Vec<PrivateAccountPublicInitialData>>,
}
impl IndexerConfig {

View File

@ -2,14 +2,17 @@ use std::collections::VecDeque;
use anyhow::Result;
use bedrock_client::{BedrockClient, HeaderId};
use common::block::{Block, HashableBlockData};
// ToDo: Remove after testnet
use common::{HashType, PINATA_BASE58};
use common::{
HashType, PINATA_BASE58,
block::{Block, HashableBlockData},
};
use log::{debug, error, info};
use logos_blockchain_core::mantle::{
Op, SignedMantleTx,
ops::channel::{ChannelId, inscribe::InscriptionOp},
};
use nssa::V03State;
use testnet_initial_state::initial_state_testnet;
use crate::{block_store::IndexerStore, config::IndexerConfig};
@ -54,36 +57,50 @@ impl IndexerCore {
let channel_genesis_msg_id = [0; 32];
let genesis_block = hashable_data.into_pending_block(&signing_key, channel_genesis_msg_id);
// This is a troubling moment, because changes in key protocol can
// affect this. And indexer can not reliably ask this data from sequencer
// because indexer must be independent from it.
// ToDo: move initial state generation into common and use the same method
// for indexer and sequencer. This way both services buit at same version
// could be in sync.
let initial_commitments: Vec<nssa_core::Commitment> = config
.initial_commitments
.iter()
.map(|init_comm_data| {
let npk = &init_comm_data.npk;
let initial_commitments: Option<Vec<nssa_core::Commitment>> = config
.initial_private_accounts
.as_ref()
.map(|initial_commitments| {
initial_commitments
.iter()
.map(|init_comm_data| {
let npk = &init_comm_data.npk;
let mut acc = init_comm_data.account.clone();
let mut acc = init_comm_data.account.clone();
acc.program_owner = nssa::program::Program::authenticated_transfer_program().id();
acc.program_owner =
nssa::program::Program::authenticated_transfer_program().id();
nssa_core::Commitment::new(npk, &acc)
})
.collect();
nssa_core::Commitment::new(npk, &acc)
})
.collect()
});
let init_accs: Vec<(nssa::AccountId, u128)> = config
.initial_accounts
.iter()
.map(|acc_data| (acc_data.account_id, acc_data.balance))
.collect();
let init_accs: Option<Vec<(nssa::AccountId, u128)>> = config
.initial_public_accounts
.as_ref()
.map(|initial_accounts| {
initial_accounts
.iter()
.map(|acc_data| (acc_data.account_id, acc_data.balance))
.collect()
});
let mut state = nssa::V03State::new_with_genesis_accounts(&init_accs, &initial_commitments);
// If initial commitments or accounts are present in config, need to construct state from
// them
let state = if initial_commitments.is_some() || init_accs.is_some() {
let mut state = V03State::new_with_genesis_accounts(
&init_accs.unwrap_or_default(),
&initial_commitments.unwrap_or_default(),
);
// ToDo: Remove after testnet
state.add_pinata_program(PINATA_BASE58.parse().unwrap());
// ToDo: Remove after testnet
state.add_pinata_program(PINATA_BASE58.parse().unwrap());
state
} else {
initial_state_testnet()
};
let home = config.home.join("rocksdb");

View File

@ -21,6 +21,7 @@ token_core.workspace = true
indexer_service_rpc.workspace = true
sequencer_service_rpc = { workspace = true, features = ["client"] }
wallet-ffi.workspace = true
testnet_initial_state.workspace = true
url.workspace = true

View File

@ -2,16 +2,17 @@ use std::{net::SocketAddr, path::PathBuf, time::Duration};
use anyhow::{Context as _, Result};
use bytesize::ByteSize;
use common::block::{AccountInitialData, CommitmentsInitialData};
use indexer_service::{BackoffConfig, ChannelId, ClientConfig, IndexerConfig};
use key_protocol::key_management::KeyChain;
use nssa::{Account, AccountId, PrivateKey, PublicKey};
use nssa_core::{account::Data, program::DEFAULT_PROGRAM_ID};
use sequencer_core::config::{BedrockConfig, SequencerConfig};
use url::Url;
use wallet::config::{
InitialAccountData, InitialAccountDataPrivate, InitialAccountDataPublic, WalletConfig,
use testnet_initial_state::{
PrivateAccountPrivateInitialData, PrivateAccountPublicInitialData,
PublicAccountPrivateInitialData, PublicAccountPublicInitialData,
};
use url::Url;
use wallet::config::{InitialAccountData, WalletConfig};
/// Sequencer config options available for custom changes in integration tests.
#[derive(Debug, Clone, Copy)]
@ -102,13 +103,13 @@ impl InitialData {
}
}
fn sequencer_initial_accounts(&self) -> Vec<AccountInitialData> {
fn sequencer_initial_public_accounts(&self) -> Vec<PublicAccountPublicInitialData> {
self.public_accounts
.iter()
.map(|(priv_key, balance)| {
let pub_key = PublicKey::new_from_private_key(priv_key);
let account_id = AccountId::from(&pub_key);
AccountInitialData {
PublicAccountPublicInitialData {
account_id,
balance: *balance,
}
@ -116,10 +117,10 @@ impl InitialData {
.collect()
}
fn sequencer_initial_commitments(&self) -> Vec<CommitmentsInitialData> {
fn sequencer_initial_private_accounts(&self) -> Vec<PrivateAccountPublicInitialData> {
self.private_accounts
.iter()
.map(|(key_chain, account)| CommitmentsInitialData {
.map(|(key_chain, account)| PrivateAccountPublicInitialData {
npk: key_chain.nullifier_public_key.clone(),
account: account.clone(),
})
@ -132,14 +133,14 @@ impl InitialData {
.map(|(priv_key, _)| {
let pub_key = PublicKey::new_from_private_key(priv_key);
let account_id = AccountId::from(&pub_key);
InitialAccountData::Public(InitialAccountDataPublic {
InitialAccountData::Public(PublicAccountPrivateInitialData {
account_id,
pub_sign_key: priv_key.clone(),
})
})
.chain(self.private_accounts.iter().map(|(key_chain, account)| {
let account_id = AccountId::from(&key_chain.nullifier_public_key);
InitialAccountData::Private(Box::new(InitialAccountDataPrivate {
InitialAccountData::Private(Box::new(PrivateAccountPrivateInitialData {
account_id,
account: account.clone(),
key_chain: key_chain.clone(),
@ -181,8 +182,8 @@ pub fn indexer_config(
max_retries: 10,
},
},
initial_accounts: initial_data.sequencer_initial_accounts(),
initial_commitments: initial_data.sequencer_initial_commitments(),
initial_public_accounts: Some(initial_data.sequencer_initial_public_accounts()),
initial_private_accounts: Some(initial_data.sequencer_initial_private_accounts()),
signing_key: [37; 32],
channel_id: bedrock_channel_id(),
})
@ -211,8 +212,8 @@ pub fn sequencer_config(
mempool_max_size,
block_create_timeout,
retry_pending_blocks_timeout: Duration::from_secs(120),
initial_accounts: initial_data.sequencer_initial_accounts(),
initial_commitments: initial_data.sequencer_initial_commitments(),
initial_public_accounts: Some(initial_data.sequencer_initial_public_accounts()),
initial_private_accounts: Some(initial_data.sequencer_initial_private_accounts()),
signing_key: [37; 32],
bedrock_config: BedrockConfig {
backoff: BackoffConfig {
@ -240,7 +241,7 @@ pub fn wallet_config(
seq_tx_poll_max_blocks: 15,
seq_poll_max_retries: 10,
seq_block_poll_max_amount: 100,
initial_accounts: initial_data.wallet_initial_accounts(),
initial_accounts: Some(initial_data.wallet_initial_accounts()),
basic_auth: None,
})
}

View File

@ -20,17 +20,16 @@ pub struct SeedHolder {
/// Secret spending key object. Can produce `PrivateKeyHolder` objects.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
pub struct SecretSpendingKey(pub(crate) [u8; 32]);
pub struct SecretSpendingKey(pub [u8; 32]);
pub type ViewingSecretKey = Scalar;
#[derive(Serialize, Deserialize, Debug, Clone)]
/// Private key holder. Produces public keys. Can produce `account_id`. Can produce shared secret
/// for recepient.
#[expect(clippy::partial_pub_fields, reason = "TODO: fix later")]
pub struct PrivateKeyHolder {
pub nullifier_secret_key: NullifierSecretKey,
pub(crate) viewing_secret_key: ViewingSecretKey,
pub viewing_secret_key: ViewingSecretKey,
}
impl SeedHolder {

View File

@ -14,8 +14,8 @@ common.workspace = true
storage.workspace = true
mempool.workspace = true
bedrock_client.workspace = true
testnet_initial_state.workspace = true
base58.workspace = true
anyhow.workspace = true
serde.workspace = true
serde_json.workspace = true

View File

@ -8,13 +8,11 @@ use std::{
use anyhow::Result;
use bedrock_client::BackoffConfig;
use bytesize::ByteSize;
use common::{
block::{AccountInitialData, CommitmentsInitialData},
config::BasicAuth,
};
use common::config::BasicAuth;
use humantime_serde;
use logos_blockchain_core::mantle::ops::channel::ChannelId;
use serde::{Deserialize, Serialize};
use testnet_initial_state::{PrivateAccountPublicInitialData, PublicAccountPublicInitialData};
use url::Url;
// TODO: Provide default values
@ -39,16 +37,16 @@ pub struct SequencerConfig {
/// Interval in which pending blocks are retried.
#[serde(with = "humantime_serde")]
pub retry_pending_blocks_timeout: Duration,
/// List of initial accounts data.
pub initial_accounts: Vec<AccountInitialData>,
/// List of initial commitments.
pub initial_commitments: Vec<CommitmentsInitialData>,
/// Sequencer own signing key.
pub signing_key: [u8; 32],
/// Bedrock configuration options.
pub bedrock_config: BedrockConfig,
/// Indexer RPC URL.
pub indexer_rpc_url: Url,
#[serde(skip_serializing_if = "Option::is_none")]
pub initial_public_accounts: Option<Vec<PublicAccountPublicInitialData>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub initial_private_accounts: Option<Vec<PrivateAccountPublicInitialData>>,
}
#[derive(Clone, Serialize, Deserialize)]

View File

@ -15,7 +15,9 @@ use logos_blockchain_key_management_system_service::keys::{ED25519_SECRET_KEY_SI
use mempool::{MemPool, MemPoolHandle};
#[cfg(feature = "mock")]
pub use mock::SequencerCoreWithMockClients;
use nssa::V03State;
pub use storage::error::DbError;
use testnet_initial_state::initial_state;
use crate::{
block_settlement_client::{BlockSettlementClient, BlockSettlementClientTrait, MsgId},
@ -98,30 +100,48 @@ impl<BC: BlockSettlementClientTrait, IC: IndexerClientTrait> SequencerCore<BC, I
state
} else {
info!(
"No database found when starting the sequencer. Creating a fresh new with the initial data in config"
"No database found when starting the sequencer. Creating a fresh new with the initial data"
);
let initial_commitments: Vec<nssa_core::Commitment> = config
.initial_commitments
.iter()
.map(|init_comm_data| {
let npk = &init_comm_data.npk;
let mut acc = init_comm_data.account.clone();
let initial_commitments: Option<Vec<nssa_core::Commitment>> = config
.initial_private_accounts
.clone()
.map(|initial_commitments| {
initial_commitments
.iter()
.map(|init_comm_data| {
let npk = &init_comm_data.npk;
acc.program_owner =
nssa::program::Program::authenticated_transfer_program().id();
let mut acc = init_comm_data.account.clone();
nssa_core::Commitment::new(npk, &acc)
})
.collect();
acc.program_owner =
nssa::program::Program::authenticated_transfer_program().id();
let init_accs: Vec<(nssa::AccountId, u128)> = config
.initial_accounts
.iter()
.map(|acc_data| (acc_data.account_id, acc_data.balance))
.collect();
nssa_core::Commitment::new(npk, &acc)
})
.collect()
});
nssa::V03State::new_with_genesis_accounts(&init_accs, &initial_commitments)
let init_accs: Option<Vec<(nssa::AccountId, u128)>> = config
.initial_public_accounts
.clone()
.map(|initial_accounts| {
initial_accounts
.iter()
.map(|acc_data| (acc_data.account_id, acc_data.balance))
.collect()
});
// If initial commitments or accounts are present in config, need to construct state
// from them
if initial_commitments.is_some() || init_accs.is_some() {
V03State::new_with_genesis_accounts(
&init_accs.unwrap_or_default(),
&initial_commitments.unwrap_or_default(),
)
} else {
initial_state()
}
};
#[cfg(feature = "testnet")]
@ -363,26 +383,20 @@ fn load_or_create_signing_key(path: &Path) -> Result<Ed25519Key> {
mod tests {
#![expect(clippy::shadow_unrelated, reason = "We don't care about it in tests")]
use std::{pin::pin, str::FromStr as _, time::Duration};
use std::{pin::pin, time::Duration};
use base58::ToBase58 as _;
use bedrock_client::BackoffConfig;
use common::{
block::AccountInitialData, test_utils::sequencer_sign_key_for_testing,
transaction::NSSATransaction,
};
use common::{test_utils::sequencer_sign_key_for_testing, transaction::NSSATransaction};
use logos_blockchain_core::mantle::ops::channel::ChannelId;
use mempool::MemPoolHandle;
use nssa::{AccountId, PrivateKey};
use testnet_initial_state::{initial_accounts, initial_pub_accounts_private_keys};
use crate::{
config::{BedrockConfig, SequencerConfig},
mock::SequencerCoreWithMockClients,
};
fn setup_sequencer_config_variable_initial_accounts(
initial_accounts: Vec<AccountInitialData>,
) -> SequencerConfig {
fn setup_sequencer_config() -> SequencerConfig {
let tempdir = tempfile::tempdir().unwrap();
let home = tempdir.path().to_path_buf();
@ -394,8 +408,6 @@ mod tests {
max_block_size: bytesize::ByteSize::mib(1),
mempool_max_size: 10000,
block_create_timeout: Duration::from_secs(1),
initial_accounts,
initial_commitments: vec![],
signing_key: *sequencer_sign_key_for_testing().value(),
bedrock_config: BedrockConfig {
backoff: BackoffConfig {
@ -408,41 +420,17 @@ mod tests {
},
retry_pending_blocks_timeout: Duration::from_secs(60 * 4),
indexer_rpc_url: "ws://localhost:8779".parse().unwrap(),
initial_public_accounts: None,
initial_private_accounts: None,
}
}
fn setup_sequencer_config() -> SequencerConfig {
let acc1_account_id: Vec<u8> = vec![
148, 179, 206, 253, 199, 51, 82, 86, 232, 2, 152, 122, 80, 243, 54, 207, 237, 112, 83,
153, 44, 59, 204, 49, 128, 84, 160, 227, 216, 149, 97, 102,
];
let acc2_account_id: Vec<u8> = vec![
30, 145, 107, 3, 207, 73, 192, 230, 160, 63, 238, 207, 18, 69, 54, 216, 103, 244, 92,
94, 124, 248, 42, 16, 141, 19, 119, 18, 14, 226, 140, 204,
];
let initial_acc1 = AccountInitialData {
account_id: AccountId::from_str(&acc1_account_id.to_base58()).unwrap(),
balance: 10000,
};
let initial_acc2 = AccountInitialData {
account_id: AccountId::from_str(&acc2_account_id.to_base58()).unwrap(),
balance: 20000,
};
let initial_accounts = vec![initial_acc1, initial_acc2];
setup_sequencer_config_variable_initial_accounts(initial_accounts)
}
fn create_signing_key_for_account1() -> nssa::PrivateKey {
nssa::PrivateKey::try_new([1; 32]).unwrap()
initial_pub_accounts_private_keys()[0].pub_sign_key.clone()
}
fn create_signing_key_for_account2() -> nssa::PrivateKey {
nssa::PrivateKey::try_new([2; 32]).unwrap()
initial_pub_accounts_private_keys()[1].pub_sign_key.clone()
}
async fn common_setup() -> (SequencerCoreWithMockClients, MemPoolHandle<NSSATransaction>) {
@ -475,8 +463,8 @@ mod tests {
assert_eq!(sequencer.chain_height, config.genesis_id);
assert_eq!(sequencer.sequencer_config.max_num_tx_in_block, 10);
let acc1_account_id = config.initial_accounts[0].account_id;
let acc2_account_id = config.initial_accounts[1].account_id;
let acc1_account_id = initial_accounts()[0].account_id;
let acc2_account_id = initial_accounts()[1].account_id;
let balance_acc_1 = sequencer.state.get_account_by_id(acc1_account_id).balance;
let balance_acc_2 = sequencer.state.get_account_by_id(acc2_account_id).balance;
@ -485,47 +473,6 @@ mod tests {
assert_eq!(20000, balance_acc_2);
}
#[tokio::test]
async fn start_different_intial_accounts_balances() {
let acc1_account_id: Vec<u8> = vec![
27, 132, 197, 86, 123, 18, 100, 64, 153, 93, 62, 213, 170, 186, 5, 101, 215, 30, 24,
52, 96, 72, 25, 255, 156, 23, 245, 233, 213, 221, 7, 143,
];
let acc2_account_id: Vec<u8> = vec![
77, 75, 108, 209, 54, 16, 50, 202, 155, 210, 174, 185, 217, 0, 170, 77, 69, 217, 234,
216, 10, 201, 66, 51, 116, 196, 81, 167, 37, 77, 7, 102,
];
let initial_acc1 = AccountInitialData {
account_id: AccountId::from_str(&acc1_account_id.to_base58()).unwrap(),
balance: 10000,
};
let initial_acc2 = AccountInitialData {
account_id: AccountId::from_str(&acc2_account_id.to_base58()).unwrap(),
balance: 20000,
};
let initial_accounts = vec![initial_acc1, initial_acc2];
let config = setup_sequencer_config_variable_initial_accounts(initial_accounts);
let (sequencer, _mempool_handle) =
SequencerCoreWithMockClients::start_from_config(config.clone()).await;
let acc1_account_id = config.initial_accounts[0].account_id;
let acc2_account_id = config.initial_accounts[1].account_id;
assert_eq!(
10000,
sequencer.state.get_account_by_id(acc1_account_id).balance
);
assert_eq!(
20000,
sequencer.state.get_account_by_id(acc2_account_id).balance
);
}
#[test]
fn transaction_pre_check_pass() {
let tx = common::test_utils::produce_dummy_empty_transaction();
@ -536,10 +483,10 @@ mod tests {
#[tokio::test]
async fn transaction_pre_check_native_transfer_valid() {
let (sequencer, _mempool_handle) = common_setup().await;
let (_sequencer, _mempool_handle) = common_setup().await;
let acc1 = sequencer.sequencer_config.initial_accounts[0].account_id;
let acc2 = sequencer.sequencer_config.initial_accounts[1].account_id;
let acc1 = initial_accounts()[0].account_id;
let acc2 = initial_accounts()[1].account_id;
let sign_key1 = create_signing_key_for_account1();
@ -555,8 +502,8 @@ mod tests {
async fn transaction_pre_check_native_transfer_other_signature() {
let (mut sequencer, _mempool_handle) = common_setup().await;
let acc1 = sequencer.sequencer_config.initial_accounts[0].account_id;
let acc2 = sequencer.sequencer_config.initial_accounts[1].account_id;
let acc1 = initial_accounts()[0].account_id;
let acc2 = initial_accounts()[1].account_id;
let sign_key2 = create_signing_key_for_account2();
@ -580,8 +527,8 @@ mod tests {
async fn transaction_pre_check_native_transfer_sent_too_much() {
let (mut sequencer, _mempool_handle) = common_setup().await;
let acc1 = sequencer.sequencer_config.initial_accounts[0].account_id;
let acc2 = sequencer.sequencer_config.initial_accounts[1].account_id;
let acc1 = initial_accounts()[0].account_id;
let acc2 = initial_accounts()[1].account_id;
let sign_key1 = create_signing_key_for_account1();
@ -607,8 +554,8 @@ mod tests {
async fn transaction_execute_native_transfer() {
let (mut sequencer, _mempool_handle) = common_setup().await;
let acc1 = sequencer.sequencer_config.initial_accounts[0].account_id;
let acc2 = sequencer.sequencer_config.initial_accounts[1].account_id;
let acc1 = initial_accounts()[0].account_id;
let acc2 = initial_accounts()[1].account_id;
let sign_key1 = create_signing_key_for_account1();
@ -669,8 +616,8 @@ mod tests {
async fn replay_transactions_are_rejected_in_the_same_block() {
let (mut sequencer, mempool_handle) = common_setup().await;
let acc1 = sequencer.sequencer_config.initial_accounts[0].account_id;
let acc2 = sequencer.sequencer_config.initial_accounts[1].account_id;
let acc1 = initial_accounts()[0].account_id;
let acc2 = initial_accounts()[1].account_id;
let sign_key1 = create_signing_key_for_account1();
@ -702,8 +649,8 @@ mod tests {
async fn replay_transactions_are_rejected_in_different_blocks() {
let (mut sequencer, mempool_handle) = common_setup().await;
let acc1 = sequencer.sequencer_config.initial_accounts[0].account_id;
let acc2 = sequencer.sequencer_config.initial_accounts[1].account_id;
let acc1 = initial_accounts()[0].account_id;
let acc2 = initial_accounts()[1].account_id;
let sign_key1 = create_signing_key_for_account1();
@ -739,8 +686,8 @@ mod tests {
#[tokio::test]
async fn restart_from_storage() {
let config = setup_sequencer_config();
let acc1_account_id = config.initial_accounts[0].account_id;
let acc2_account_id = config.initial_accounts[1].account_id;
let acc1_account_id = initial_accounts()[0].account_id;
let acc2_account_id = initial_accounts()[1].account_id;
let balance_to_move = 13;
// In the following code block a transaction will be processed that moves `balance_to_move`
@ -749,7 +696,7 @@ mod tests {
{
let (mut sequencer, mempool_handle) =
SequencerCoreWithMockClients::start_from_config(config.clone()).await;
let signing_key = PrivateKey::try_new([1; 32]).unwrap();
let signing_key = create_signing_key_for_account1();
let tx = common::test_utils::create_transaction_native_token_transfer(
acc1_account_id,
@ -781,11 +728,11 @@ mod tests {
// Balances should be consistent with the stored block
assert_eq!(
balance_acc_1,
config.initial_accounts[0].balance - balance_to_move
initial_accounts()[0].balance - balance_to_move
);
assert_eq!(
balance_acc_2,
config.initial_accounts[1].balance + balance_to_move
initial_accounts()[1].balance + balance_to_move
);
}
@ -832,15 +779,15 @@ mod tests {
#[tokio::test]
async fn produce_block_with_correct_prev_meta_after_restart() {
let config = setup_sequencer_config();
let acc1_account_id = config.initial_accounts[0].account_id;
let acc2_account_id = config.initial_accounts[1].account_id;
let acc1_account_id = initial_accounts()[0].account_id;
let acc2_account_id = initial_accounts()[1].account_id;
// Step 1: Create initial database with some block metadata
let expected_prev_meta = {
let (mut sequencer, mempool_handle) =
SequencerCoreWithMockClients::start_from_config(config.clone()).await;
let signing_key = PrivateKey::try_new([1; 32]).unwrap();
let signing_key = create_signing_key_for_account1();
// Add a transaction and produce a block to set up block metadata
let tx = common::test_utils::create_transaction_native_token_transfer(
@ -865,7 +812,7 @@ mod tests {
SequencerCoreWithMockClients::start_from_config(config.clone()).await;
// Step 3: Submit a new transaction
let signing_key = PrivateKey::try_new([1; 32]).unwrap();
let signing_key = create_signing_key_for_account1();
let tx = common::test_utils::create_transaction_native_token_transfer(
acc1_account_id,
1, // Next nonce

View File

@ -0,0 +1,16 @@
[package]
name = "testnet_initial_state"
version = "0.1.0"
edition = "2024"
license.workspace = true
[dependencies]
key_protocol.workspace = true
nssa.workspace = true
nssa_core.workspace = true
common.workspace = true
serde.workspace = true
[lints]
workspace = true

View File

@ -0,0 +1,396 @@
use common::PINATA_BASE58;
use key_protocol::key_management::{
KeyChain,
secret_holders::{PrivateKeyHolder, SecretSpendingKey},
};
use nssa::{Account, AccountId, Data, PrivateKey, PublicKey, V03State};
use nssa_core::{NullifierPublicKey, encryption::shared_key_derivation::Secp256k1Point};
use serde::{Deserialize, Serialize};
const PRIVATE_KEY_PUB_ACC_A: [u8; 32] = [
16, 162, 106, 154, 236, 125, 52, 184, 35, 100, 238, 174, 69, 197, 41, 77, 187, 10, 118, 75, 0,
11, 148, 238, 185, 181, 133, 17, 220, 72, 124, 77,
];
const PRIVATE_KEY_PUB_ACC_B: [u8; 32] = [
113, 121, 64, 177, 204, 85, 229, 214, 178, 6, 109, 191, 29, 154, 63, 38, 242, 18, 244, 219, 8,
208, 35, 136, 23, 127, 207, 237, 216, 169, 190, 27,
];
const SSK_PRIV_ACC_A: [u8; 32] = [
93, 13, 190, 240, 250, 33, 108, 195, 176, 40, 144, 61, 4, 28, 58, 112, 53, 161, 42, 238, 155,
27, 23, 176, 208, 121, 15, 229, 165, 180, 99, 143,
];
const SSK_PRIV_ACC_B: [u8; 32] = [
48, 175, 124, 10, 230, 240, 166, 14, 249, 254, 157, 226, 208, 124, 122, 177, 203, 139, 192,
180, 43, 120, 55, 151, 50, 21, 113, 22, 254, 83, 148, 56,
];
const NSK_PRIV_ACC_A: [u8; 32] = [
25, 21, 186, 59, 180, 224, 101, 64, 163, 208, 228, 43, 13, 185, 100, 123, 156, 47, 80, 179, 72,
51, 115, 11, 180, 99, 21, 201, 48, 194, 118, 144,
];
const NSK_PRIV_ACC_B: [u8; 32] = [
99, 82, 190, 140, 234, 10, 61, 163, 15, 211, 179, 54, 70, 166, 87, 5, 182, 68, 117, 244, 217,
23, 99, 9, 4, 177, 230, 125, 109, 91, 160, 30,
];
const VSK_PRIV_ACC_A: [u8; 32] = [
5, 85, 114, 119, 141, 187, 202, 170, 122, 253, 198, 81, 150, 8, 155, 21, 192, 65, 24, 124, 116,
98, 110, 106, 137, 90, 165, 239, 80, 13, 222, 30,
];
const VSK_PRIV_ACC_B: [u8; 32] = [
205, 32, 76, 251, 255, 236, 96, 119, 61, 111, 65, 100, 75, 218, 12, 22, 17, 170, 55, 226, 21,
154, 161, 34, 208, 74, 27, 1, 119, 13, 88, 128,
];
const VPK_PRIV_ACC_A: [u8; 33] = [
2, 210, 206, 38, 213, 4, 182, 198, 220, 47, 93, 148, 61, 84, 148, 250, 158, 45, 8, 81, 48, 80,
46, 230, 87, 210, 47, 204, 76, 58, 214, 167, 81,
];
const VPK_PRIV_ACC_B: [u8; 33] = [
2, 79, 110, 46, 203, 29, 206, 205, 18, 86, 27, 189, 104, 103, 113, 181, 110, 53, 78, 172, 11,
171, 190, 18, 126, 214, 81, 77, 192, 154, 58, 195, 238,
];
const NPK_PRIV_ACC_A: [u8; 32] = [
167, 108, 50, 153, 74, 47, 151, 188, 140, 79, 195, 31, 181, 9, 40, 167, 201, 32, 175, 129, 45,
245, 223, 193, 210, 170, 247, 128, 167, 140, 155, 129,
];
const NPK_PRIV_ACC_B: [u8; 32] = [
32, 67, 72, 164, 106, 53, 66, 239, 141, 15, 52, 230, 136, 177, 2, 236, 207, 243, 134, 135, 210,
143, 87, 232, 215, 128, 194, 120, 113, 224, 4, 165,
];
const DEFAULT_PROGRAM_OWNER: [u32; 8] = [0, 0, 0, 0, 0, 0, 0, 0];
const PUB_ACC_A_INITIAL_BALANCE: u128 = 10000;
const PUB_ACC_B_INITIAL_BALANCE: u128 = 20000;
const PRIV_ACC_A_INITIAL_BALANCE: u128 = 10000;
const PRIV_ACC_B_INITIAL_BALANCE: u128 = 20000;
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct PublicAccountPublicInitialData {
pub account_id: AccountId,
pub balance: u128,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct PrivateAccountPublicInitialData {
pub npk: nssa_core::NullifierPublicKey,
pub account: nssa_core::account::Account,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct PublicAccountPrivateInitialData {
pub account_id: nssa::AccountId,
pub pub_sign_key: nssa::PrivateKey,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PrivateAccountPrivateInitialData {
pub account_id: nssa::AccountId,
pub account: nssa_core::account::Account,
pub key_chain: KeyChain,
}
#[must_use]
pub fn initial_pub_accounts_private_keys() -> Vec<PublicAccountPrivateInitialData> {
let acc1_pub_sign_key = PrivateKey::try_new(PRIVATE_KEY_PUB_ACC_A).unwrap();
let acc2_pub_sign_key = PrivateKey::try_new(PRIVATE_KEY_PUB_ACC_B).unwrap();
vec![
PublicAccountPrivateInitialData {
account_id: AccountId::from(&PublicKey::new_from_private_key(&acc1_pub_sign_key)),
pub_sign_key: acc1_pub_sign_key,
},
PublicAccountPrivateInitialData {
account_id: AccountId::from(&PublicKey::new_from_private_key(&acc2_pub_sign_key)),
pub_sign_key: acc2_pub_sign_key,
},
]
}
#[must_use]
pub fn initial_priv_accounts_private_keys() -> Vec<PrivateAccountPrivateInitialData> {
let key_chain_1 = KeyChain {
secret_spending_key: SecretSpendingKey(SSK_PRIV_ACC_A),
private_key_holder: PrivateKeyHolder {
nullifier_secret_key: NSK_PRIV_ACC_A,
viewing_secret_key: VSK_PRIV_ACC_A,
},
nullifier_public_key: NullifierPublicKey(NPK_PRIV_ACC_A),
viewing_public_key: Secp256k1Point(VPK_PRIV_ACC_A.to_vec()),
};
let key_chain_2 = KeyChain {
secret_spending_key: SecretSpendingKey(SSK_PRIV_ACC_B),
private_key_holder: PrivateKeyHolder {
nullifier_secret_key: NSK_PRIV_ACC_B,
viewing_secret_key: VSK_PRIV_ACC_B,
},
nullifier_public_key: NullifierPublicKey(NPK_PRIV_ACC_B),
viewing_public_key: Secp256k1Point(VPK_PRIV_ACC_B.to_vec()),
};
vec![
PrivateAccountPrivateInitialData {
account_id: AccountId::from(&key_chain_1.nullifier_public_key),
account: Account {
program_owner: DEFAULT_PROGRAM_OWNER,
balance: PRIV_ACC_A_INITIAL_BALANCE,
data: Data::default(),
nonce: 0.into(),
},
key_chain: key_chain_1,
},
PrivateAccountPrivateInitialData {
account_id: AccountId::from(&key_chain_2.nullifier_public_key),
account: Account {
program_owner: DEFAULT_PROGRAM_OWNER,
balance: PRIV_ACC_B_INITIAL_BALANCE,
data: Data::default(),
nonce: 0.into(),
},
key_chain: key_chain_2,
},
]
}
#[must_use]
pub fn initial_commitments() -> Vec<PrivateAccountPublicInitialData> {
initial_priv_accounts_private_keys()
.into_iter()
.map(|data| PrivateAccountPublicInitialData {
npk: data.key_chain.nullifier_public_key.clone(),
account: data.account,
})
.collect()
}
#[must_use]
pub fn initial_accounts() -> Vec<PublicAccountPublicInitialData> {
let initial_account_ids = initial_pub_accounts_private_keys()
.into_iter()
.map(|data| data.account_id)
.collect::<Vec<_>>();
vec![
PublicAccountPublicInitialData {
account_id: initial_account_ids[0],
balance: PUB_ACC_A_INITIAL_BALANCE,
},
PublicAccountPublicInitialData {
account_id: initial_account_ids[1],
balance: PUB_ACC_B_INITIAL_BALANCE,
},
]
}
#[must_use]
pub fn initial_state() -> V03State {
let initial_commitments: Vec<nssa_core::Commitment> = initial_commitments()
.iter()
.map(|init_comm_data| {
let npk = &init_comm_data.npk;
let mut acc = init_comm_data.account.clone();
acc.program_owner = nssa::program::Program::authenticated_transfer_program().id();
nssa_core::Commitment::new(npk, &acc)
})
.collect();
let init_accs: Vec<(nssa::AccountId, u128)> = initial_accounts()
.iter()
.map(|acc_data| (acc_data.account_id, acc_data.balance))
.collect();
nssa::V03State::new_with_genesis_accounts(&init_accs, &initial_commitments)
}
#[must_use]
pub fn initial_state_testnet() -> V03State {
let mut state = initial_state();
state.add_pinata_program(PINATA_BASE58.parse().unwrap());
state
}
#[cfg(test)]
mod tests {
use std::str::FromStr as _;
use super::*;
const PUB_ACC_A_TEXT_ADDR: &str = "6iArKUXxhUJqS7kCaPNhwMWt3ro71PDyBj7jwAyE2VQV";
const PUB_ACC_B_TEXT_ADDR: &str = "7wHg9sbJwc6h3NP1S9bekfAzB8CHifEcxKswCKUt3YQo";
const PRIV_ACC_A_TEXT_ADDR: &str = "5ya25h4Xc9GAmrGB2WrTEnEWtQKJwRwQx3Xfo2tucNcE";
const PRIV_ACC_B_TEXT_ADDR: &str = "E8HwiTyQe4H9HK7icTvn95HQMnzx49mP9A2ddtMLpNaN";
#[test]
fn pub_state_consistency() {
let init_accs_private_data = initial_pub_accounts_private_keys();
let init_accs_pub_data = initial_accounts();
assert_eq!(
init_accs_private_data[0].account_id,
init_accs_pub_data[0].account_id
);
assert_eq!(
init_accs_private_data[1].account_id,
init_accs_pub_data[1].account_id
);
assert_eq!(
init_accs_pub_data[0],
PublicAccountPublicInitialData {
account_id: AccountId::from_str(PUB_ACC_A_TEXT_ADDR).unwrap(),
balance: PUB_ACC_A_INITIAL_BALANCE,
}
);
assert_eq!(
init_accs_pub_data[1],
PublicAccountPublicInitialData {
account_id: AccountId::from_str(PUB_ACC_B_TEXT_ADDR).unwrap(),
balance: PUB_ACC_B_INITIAL_BALANCE,
}
);
}
#[test]
fn private_state_consistency() {
let init_private_accs_keys = initial_priv_accounts_private_keys();
let init_comms = initial_commitments();
assert_eq!(
init_private_accs_keys[0]
.key_chain
.secret_spending_key
.produce_private_key_holder(None)
.nullifier_secret_key,
init_private_accs_keys[0]
.key_chain
.private_key_holder
.nullifier_secret_key
);
assert_eq!(
init_private_accs_keys[0]
.key_chain
.secret_spending_key
.produce_private_key_holder(None)
.viewing_secret_key,
init_private_accs_keys[0]
.key_chain
.private_key_holder
.viewing_secret_key
);
assert_eq!(
init_private_accs_keys[0]
.key_chain
.private_key_holder
.generate_nullifier_public_key(),
init_private_accs_keys[0].key_chain.nullifier_public_key
);
assert_eq!(
init_private_accs_keys[0]
.key_chain
.private_key_holder
.generate_viewing_public_key(),
init_private_accs_keys[0].key_chain.viewing_public_key
);
assert_eq!(
init_private_accs_keys[1]
.key_chain
.secret_spending_key
.produce_private_key_holder(None)
.nullifier_secret_key,
init_private_accs_keys[1]
.key_chain
.private_key_holder
.nullifier_secret_key
);
assert_eq!(
init_private_accs_keys[1]
.key_chain
.secret_spending_key
.produce_private_key_holder(None)
.viewing_secret_key,
init_private_accs_keys[1]
.key_chain
.private_key_holder
.viewing_secret_key
);
assert_eq!(
init_private_accs_keys[1]
.key_chain
.private_key_holder
.generate_nullifier_public_key(),
init_private_accs_keys[1].key_chain.nullifier_public_key
);
assert_eq!(
init_private_accs_keys[1]
.key_chain
.private_key_holder
.generate_viewing_public_key(),
init_private_accs_keys[1].key_chain.viewing_public_key
);
assert_eq!(
init_private_accs_keys[0].account_id.to_string(),
PRIV_ACC_A_TEXT_ADDR
);
assert_eq!(
init_private_accs_keys[1].account_id.to_string(),
PRIV_ACC_B_TEXT_ADDR
);
assert_eq!(
init_private_accs_keys[0].key_chain.nullifier_public_key,
init_comms[0].npk
);
assert_eq!(
init_private_accs_keys[1].key_chain.nullifier_public_key,
init_comms[1].npk
);
assert_eq!(
init_comms[0],
PrivateAccountPublicInitialData {
npk: NullifierPublicKey(NPK_PRIV_ACC_A),
account: Account {
program_owner: DEFAULT_PROGRAM_OWNER,
balance: PRIV_ACC_A_INITIAL_BALANCE,
data: Data::default(),
nonce: 0.into(),
},
}
);
assert_eq!(
init_comms[1],
PrivateAccountPublicInitialData {
npk: NullifierPublicKey(NPK_PRIV_ACC_B),
account: Account {
program_owner: DEFAULT_PROGRAM_OWNER,
balance: PRIV_ACC_B_INITIAL_BALANCE,
data: Data::default(),
nonce: 0.into(),
},
}
);
}
}

View File

@ -15,6 +15,7 @@ key_protocol.workspace = true
sequencer_service_rpc = { workspace = true, features = ["client"] }
token_core.workspace = true
amm_core.workspace = true
testnet_initial_state.workspace = true
anyhow.workspace = true
thiserror.workspace = true

View File

@ -99,16 +99,22 @@ impl WalletChainStore {
let mut public_init_acc_map = BTreeMap::new();
let mut private_init_acc_map = BTreeMap::new();
for init_acc_data in config.initial_accounts.clone() {
let initial_accounts = config
.initial_accounts
.clone()
.unwrap_or_else(InitialAccountData::create_initial_accounts_data);
for init_acc_data in initial_accounts {
match init_acc_data {
InitialAccountData::Public(data) => {
public_init_acc_map.insert(data.account_id, data.pub_sign_key);
}
InitialAccountData::Private(data) => {
let mut account = data.account;
// TODO: Program owner is only known after code is compiled and can't be set in
// the config. Therefore we overwrite it here on startup. Fix this when program
// id can be fetched from the node and queried from the wallet.
// TODO: Program owner is only known after code is compiled and can't be set
// in the config. Therefore we overwrite it here on
// startup. Fix this when program id can be fetched
// from the node and queried from the wallet.
account.program_owner = Program::authenticated_transfer_program().id();
private_init_acc_map.insert(data.account_id, (data.key_chain, account));
}
@ -161,45 +167,12 @@ impl WalletChainStore {
#[cfg(test)]
mod tests {
use std::str::FromStr as _;
use key_protocol::key_management::key_tree::{
keys_private::ChildKeysPrivate, keys_public::ChildKeysPublic, traits::KeyNode as _,
};
use nssa::PrivateKey;
use super::*;
use crate::config::{
InitialAccountData, InitialAccountDataPublic, PersistentAccountDataPrivate,
PersistentAccountDataPublic,
};
fn create_initial_accounts() -> Vec<InitialAccountData> {
vec![
InitialAccountData::Public(InitialAccountDataPublic {
account_id: nssa::AccountId::from_str(
"CbgR6tj5kWx5oziiFptM7jMvrQeYY3Mzaao6ciuhSr2r",
)
.unwrap(),
pub_sign_key: PrivateKey::try_new([
127, 39, 48, 152, 242, 91, 113, 230, 192, 5, 169, 81, 159, 38, 120, 218, 141,
28, 127, 1, 246, 162, 119, 120, 226, 217, 148, 138, 189, 249, 1, 251,
])
.unwrap(),
}),
InitialAccountData::Public(InitialAccountDataPublic {
account_id: nssa::AccountId::from_str(
"2RHZhw9h534Zr3eq2RGhQete2Hh667foECzXPmSkGni2",
)
.unwrap(),
pub_sign_key: PrivateKey::try_new([
244, 52, 248, 116, 23, 32, 1, 69, 134, 174, 67, 53, 109, 42, 236, 98, 87, 218,
8, 98, 34, 246, 4, 221, 183, 93, 105, 115, 59, 134, 252, 76,
])
.unwrap(),
}),
]
}
use crate::config::{PersistentAccountDataPrivate, PersistentAccountDataPublic};
fn create_sample_wallet_config() -> WalletConfig {
WalletConfig {
@ -208,8 +181,8 @@ mod tests {
seq_tx_poll_max_blocks: 5,
seq_poll_max_retries: 10,
seq_block_poll_max_amount: 100,
initial_accounts: create_initial_accounts(),
basic_auth: None,
initial_accounts: None,
}
}

View File

@ -4,6 +4,7 @@ use clap::Subcommand;
use crate::{
WalletCore,
cli::{SubcommandReturnValue, WalletSubcommand},
config::InitialAccountData,
};
/// Represents generic config CLI subcommand.
@ -59,7 +60,17 @@ impl WalletSubcommand for ConfigSubcommand {
);
}
"initial_accounts" => {
println!("{:#?}", wallet_core.storage.wallet_config.initial_accounts);
println!(
"{:#?}",
wallet_core
.storage
.wallet_config
.initial_accounts
.clone()
.unwrap_or_else(
InitialAccountData::create_initial_accounts_data
)
);
}
"basic_auth" => {
if let Some(basic_auth) = &wallet_core.storage.wallet_config.basic_auth

View File

@ -8,22 +8,17 @@ use std::{
use anyhow::{Context as _, Result};
use common::config::BasicAuth;
use humantime_serde;
use key_protocol::key_management::{
KeyChain,
key_tree::{
chain_index::ChainIndex, keys_private::ChildKeysPrivate, keys_public::ChildKeysPublic,
},
use key_protocol::key_management::key_tree::{
chain_index::ChainIndex, keys_private::ChildKeysPrivate, keys_public::ChildKeysPublic,
};
use log::warn;
use serde::{Deserialize, Serialize};
use testnet_initial_state::{
PrivateAccountPrivateInitialData, PublicAccountPrivateInitialData,
initial_priv_accounts_private_keys, initial_pub_accounts_private_keys,
};
use url::Url;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct InitialAccountDataPublic {
pub account_id: nssa::AccountId,
pub pub_sign_key: nssa::PrivateKey,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PersistentAccountDataPublic {
pub account_id: nssa::AccountId,
@ -31,13 +26,6 @@ pub struct PersistentAccountDataPublic {
pub data: ChildKeysPublic,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct InitialAccountDataPrivate {
pub account_id: nssa::AccountId,
pub account: nssa_core::account::Account,
pub key_chain: KeyChain,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PersistentAccountDataPrivate {
pub account_id: nssa::AccountId,
@ -50,8 +38,29 @@ pub struct PersistentAccountDataPrivate {
// memory
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum InitialAccountData {
Public(InitialAccountDataPublic),
Private(Box<InitialAccountDataPrivate>),
Public(PublicAccountPrivateInitialData),
Private(Box<PrivateAccountPrivateInitialData>),
}
impl InitialAccountData {
#[must_use]
pub const fn account_id(&self) -> nssa::AccountId {
match &self {
Self::Public(acc) => acc.account_id,
Self::Private(acc) => acc.account_id,
}
}
pub(crate) fn create_initial_accounts_data() -> Vec<Self> {
let pub_data = initial_pub_accounts_private_keys();
let priv_data = initial_priv_accounts_private_keys();
pub_data
.into_iter()
.map(Into::into)
.chain(priv_data.into_iter().map(Into::into))
.collect()
}
}
// Big difference in enum variants sizes
@ -114,16 +123,6 @@ impl PersistentStorage {
}
}
impl InitialAccountData {
#[must_use]
pub fn account_id(&self) -> nssa::AccountId {
match &self {
Self::Public(acc) => acc.account_id,
Self::Private(acc) => acc.account_id,
}
}
}
impl PersistentAccountData {
#[must_use]
pub fn account_id(&self) -> nssa::AccountId {
@ -135,14 +134,14 @@ impl PersistentAccountData {
}
}
impl From<InitialAccountDataPublic> for InitialAccountData {
fn from(value: InitialAccountDataPublic) -> Self {
impl From<PublicAccountPrivateInitialData> for InitialAccountData {
fn from(value: PublicAccountPrivateInitialData) -> Self {
Self::Public(value)
}
}
impl From<InitialAccountDataPrivate> for InitialAccountData {
fn from(value: InitialAccountDataPrivate) -> Self {
impl From<PrivateAccountPrivateInitialData> for InitialAccountData {
fn from(value: PrivateAccountPrivateInitialData) -> Self {
Self::Private(Box::new(value))
}
}
@ -197,37 +196,15 @@ pub struct WalletConfig {
pub seq_poll_max_retries: u64,
/// Max amount of blocks to poll in one request.
pub seq_block_poll_max_amount: u64,
/// Initial accounts for wallet.
pub initial_accounts: Vec<InitialAccountData>,
/// Basic authentication credentials.
/// Basic authentication credentials
#[serde(skip_serializing_if = "Option::is_none")]
pub basic_auth: Option<BasicAuth>,
#[serde(skip_serializing_if = "Option::is_none")]
pub initial_accounts: Option<Vec<InitialAccountData>>,
}
impl Default for WalletConfig {
fn default() -> Self {
let pub_sign_key1 = nssa::PrivateKey::try_new([
127, 39, 48, 152, 242, 91, 113, 230, 192, 5, 169, 81, 159, 38, 120, 218, 141, 28, 127,
1, 246, 162, 119, 120, 226, 217, 148, 138, 189, 249, 1, 251,
])
.unwrap();
let public_key1 = nssa::PublicKey::new_from_private_key(&pub_sign_key1);
let public_account_id1 = nssa::AccountId::from(&public_key1);
let pub_sign_key2 = nssa::PrivateKey::try_new([
244, 52, 248, 116, 23, 32, 1, 69, 134, 174, 67, 53, 109, 42, 236, 98, 87, 218, 8, 98,
34, 246, 4, 221, 183, 93, 105, 115, 59, 134, 252, 76,
])
.unwrap();
let public_key2 = nssa::PublicKey::new_from_private_key(&pub_sign_key2);
let public_account_id2 = nssa::AccountId::from(&public_key2);
let key_chain1 = KeyChain::new_mnemonic("default_private_account_1".to_owned());
let private_account_id1 = nssa::AccountId::from(&key_chain1.nullifier_public_key);
let key_chain2 = KeyChain::new_mnemonic("default_private_account_2".to_owned());
let private_account_id2 = nssa::AccountId::from(&key_chain2.nullifier_public_key);
Self {
sequencer_addr: "http://127.0.0.1:3040".parse().unwrap(),
seq_poll_timeout: Duration::from_secs(12),
@ -235,32 +212,7 @@ impl Default for WalletConfig {
seq_poll_max_retries: 5,
seq_block_poll_max_amount: 100,
basic_auth: None,
initial_accounts: vec![
InitialAccountData::Public(InitialAccountDataPublic {
account_id: public_account_id1,
pub_sign_key: pub_sign_key1,
}),
InitialAccountData::Public(InitialAccountDataPublic {
account_id: public_account_id2,
pub_sign_key: pub_sign_key2,
}),
InitialAccountData::Private(Box::new(InitialAccountDataPrivate {
account_id: private_account_id1,
account: nssa::Account {
balance: 10_000,
..Default::default()
},
key_chain: key_chain1,
})),
InitialAccountData::Private(Box::new(InitialAccountDataPrivate {
account_id: private_account_id2,
account: nssa::Account {
balance: 20_000,
..Default::default()
},
key_chain: key_chain2,
})),
],
initial_accounts: None,
}
}
}
@ -310,8 +262,8 @@ impl WalletConfig {
seq_tx_poll_max_blocks,
seq_poll_max_retries,
seq_block_poll_max_amount,
initial_accounts,
basic_auth,
initial_accounts,
} = self;
let WalletConfigOverrides {
@ -320,8 +272,8 @@ impl WalletConfig {
seq_tx_poll_max_blocks: o_seq_tx_poll_max_blocks,
seq_poll_max_retries: o_seq_poll_max_retries,
seq_block_poll_max_amount: o_seq_block_poll_max_amount,
initial_accounts: o_initial_accounts,
basic_auth: o_basic_auth,
initial_accounts: o_initial_accounts,
} = overrides;
if let Some(v) = o_sequencer_addr {
@ -344,13 +296,13 @@ impl WalletConfig {
warn!("Overriding wallet config 'seq_block_poll_max_amount' to {v}");
*seq_block_poll_max_amount = v;
}
if let Some(v) = o_initial_accounts {
warn!("Overriding wallet config 'initial_accounts' to {v:#?}");
*initial_accounts = v;
}
if let Some(v) = o_basic_auth {
warn!("Overriding wallet config 'basic_auth' to {v:#?}");
*basic_auth = v;
}
if let Some(v) = o_initial_accounts {
warn!("Overriding wallet config 'initial_accounts' to {v:#?}");
*initial_accounts = v;
}
}
}

View File

@ -7,12 +7,13 @@ use nssa::Account;
use nssa_core::account::Nonce;
use rand::{RngCore as _, rngs::OsRng};
use serde::Serialize;
use testnet_initial_state::{PrivateAccountPrivateInitialData, PublicAccountPrivateInitialData};
use crate::{
HOME_DIR_ENV_VAR,
config::{
InitialAccountData, InitialAccountDataPrivate, InitialAccountDataPublic, Label,
PersistentAccountDataPrivate, PersistentAccountDataPublic, PersistentStorage,
InitialAccountData, Label, PersistentAccountDataPrivate, PersistentAccountDataPublic,
PersistentStorage,
},
};
@ -119,7 +120,7 @@ pub fn produce_data_for_storage(
for (account_id, key) in &user_data.default_pub_account_signing_keys {
vec_for_storage.push(
InitialAccountData::Public(InitialAccountDataPublic {
InitialAccountData::Public(PublicAccountPrivateInitialData {
account_id: *account_id,
pub_sign_key: key.clone(),
})
@ -129,7 +130,7 @@ pub fn produce_data_for_storage(
for (account_id, (key_chain, account)) in &user_data.default_user_private_accounts {
vec_for_storage.push(
InitialAccountData::Private(Box::new(InitialAccountDataPrivate {
InitialAccountData::Private(Box::new(PrivateAccountPrivateInitialData {
account_id: *account_id,
account: account.clone(),
key_chain: key_chain.clone(),