diff --git a/Cargo.lock b/Cargo.lock index 18c27a3..bf0838b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,6 +19,7 @@ dependencies = [ "serde", "serde_json", "sha2", + "tiny-keccak", "utxo", ] @@ -1141,6 +1142,12 @@ version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + [[package]] name = "crypto-bigint" version = "0.5.5" @@ -4396,12 +4403,14 @@ dependencies = [ "serde_json", "storage", "tempfile", + "tiny-keccak", ] [[package]] name = "sequencer_rpc" version = "0.1.0" dependencies = [ + "accounts", "actix", "actix-cors", "actix-web", @@ -4883,6 +4892,15 @@ dependencies = [ "time-core", ] +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + [[package]] name = "tinystr" version = "0.8.1" diff --git a/Cargo.toml b/Cargo.toml index 47fcb98..4ce7c9a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,6 +46,7 @@ tempfile = "3.14.0" light-poseidon = "0.3.0" ark-bn254 = "0.5.0" ark-ff = "0.5.0" +tiny-keccak = { version = "2.0.2", features = ["keccak"] } rocksdb = { version = "0.21.0", default-features = false, features = [ "snappy", diff --git a/accounts/Cargo.toml b/accounts/Cargo.toml index 682d8ac..ffd500a 100644 --- a/accounts/Cargo.toml +++ b/accounts/Cargo.toml @@ -16,6 +16,7 @@ elliptic-curve.workspace = true hex.workspace = true aes-gcm.workspace = true lazy_static.workspace = true +tiny-keccak.workspace = true [dependencies.utxo] path = "../utxo" diff --git a/accounts/src/account_core/mod.rs b/accounts/src/account_core/mod.rs index b1b4a91..e698b49 100644 --- a/accounts/src/account_core/mod.rs +++ b/accounts/src/account_core/mod.rs @@ -16,7 +16,7 @@ use crate::key_management::{ pub type PublicKey = AffinePoint; pub type AccountAddress = TreeHashType; -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct Account { pub key_holder: AddressKeyHolder, pub address: AccountAddress, @@ -24,7 +24,7 @@ pub struct Account { pub utxos: HashMap, } -#[derive(Serialize, Deserialize, Clone)] +#[derive(Serialize, Deserialize, Clone, Debug)] pub struct AccountForSerialization { pub key_holder: AddressKeyHolder, pub address: AccountAddress, diff --git a/accounts/src/key_management/mod.rs b/accounts/src/key_management/mod.rs index 6fa1462..a5a3e4b 100644 --- a/accounts/src/key_management/mod.rs +++ b/accounts/src/key_management/mod.rs @@ -7,6 +7,7 @@ use log::info; use rand::{rngs::OsRng, RngCore}; use secret_holders::{SeedHolder, TopSecretKeyHolder, UTXOSecretKeyHolder}; use serde::{Deserialize, Serialize}; +use tiny_keccak::{Hasher, Keccak}; use crate::account_core::PublicKey; pub type PublicAccountSigningKey = [u8; 32]; @@ -15,7 +16,7 @@ pub mod constants_types; pub mod ephemeral_key_holder; pub mod secret_holders; -#[derive(Serialize, Deserialize, Clone)] +#[derive(Serialize, Deserialize, Clone, Debug)] ///Entrypoint to key management pub struct AddressKeyHolder { //Will be useful in future @@ -37,7 +38,6 @@ impl AddressKeyHolder { let utxo_secret_key_holder = top_secret_key_holder.produce_utxo_secret_holder(); - let address = utxo_secret_key_holder.generate_address(); let nullifer_public_key = utxo_secret_key_holder.generate_nullifier_public_key(); let viewing_public_key = utxo_secret_key_holder.generate_viewing_public_key(); @@ -47,6 +47,17 @@ impl AddressKeyHolder { bytes }; + //Address is a Keccak(verification_key) + let field_bytes = FieldBytes::from_slice(&pub_account_signing_key); + let signing_key = SigningKey::from_bytes(field_bytes).unwrap(); + + let verifying_key = signing_key.verifying_key(); + + let mut address = [0; 32]; + let mut keccak_hasher = Keccak::v256(); + keccak_hasher.update(&verifying_key.to_sec1_bytes()); + keccak_hasher.finalize(&mut address); + Self { top_secret_key_holder, utxo_secret_key_holder, @@ -332,6 +343,21 @@ mod tests { ); } + #[test] + fn test_address_key_equal_keccak_pub_sign_key() { + let address_key_holder = AddressKeyHolder::new_os_random(); + let signing_key = address_key_holder.get_pub_account_signing_key(); + + let verifying_key = signing_key.verifying_key(); + + let mut address = [0; 32]; + let mut keccak_hasher = Keccak::v256(); + keccak_hasher.update(&verifying_key.to_sec1_bytes()); + keccak_hasher.finalize(&mut address); + + assert_eq!(address, address_key_holder.address); + } + #[test] fn key_generation_test() { let seed_holder = SeedHolder::new_os_random(); @@ -339,10 +365,26 @@ mod tests { let utxo_secret_key_holder = top_secret_key_holder.produce_utxo_secret_holder(); - let address = utxo_secret_key_holder.generate_address(); let nullifer_public_key = utxo_secret_key_holder.generate_nullifier_public_key(); let viewing_public_key = utxo_secret_key_holder.generate_viewing_public_key(); + let pub_account_signing_key = { + let mut bytes = [0; 32]; + OsRng.fill_bytes(&mut bytes); + bytes + }; + + //Address is a Keccak(verification_key) + let field_bytes = FieldBytes::from_slice(&pub_account_signing_key); + let signing_key = SigningKey::from_bytes(field_bytes).unwrap(); + + let verifying_key = signing_key.verifying_key(); + + let mut address = [0; 32]; + let mut keccak_hasher = Keccak::v256(); + keccak_hasher.update(&verifying_key.to_sec1_bytes()); + keccak_hasher.finalize(&mut address); + println!("======Prerequisites======"); println!(); diff --git a/accounts/src/key_management/secret_holders.rs b/accounts/src/key_management/secret_holders.rs index 45fd792..47342ec 100644 --- a/accounts/src/key_management/secret_holders.rs +++ b/accounts/src/key_management/secret_holders.rs @@ -98,16 +98,4 @@ impl UTXOSecretKeyHolder { pub fn generate_viewing_public_key(&self) -> AffinePoint { (AffinePoint::GENERATOR * self.viewing_secret_key).into() } - - pub fn generate_address(&self) -> TreeHashType { - let npk = self.generate_nullifier_public_key(); - let vpk = self.generate_viewing_public_key(); - - let mut hasher = sha2::Sha256::new(); - - hasher.update(serde_json::to_vec(&npk).unwrap()); - hasher.update(serde_json::to_vec(&vpk).unwrap()); - - ::from(hasher.finalize_fixed()) - } } diff --git a/common/src/execution_input.rs b/common/src/execution_input.rs new file mode 100644 index 0000000..d1f282a --- /dev/null +++ b/common/src/execution_input.rs @@ -0,0 +1,10 @@ +use serde::{Deserialize, Serialize}; + +use crate::merkle_tree_public::TreeHashType; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct PublicNativeTokenSend { + pub from: TreeHashType, + pub to: TreeHashType, + pub balance_to_move: u64, +} diff --git a/common/src/lib.rs b/common/src/lib.rs index 96a7b55..1722218 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -3,6 +3,7 @@ use serde::Deserialize; pub mod block; pub mod commitment; +pub mod execution_input; pub mod merkle_tree_public; pub mod nullifier; pub mod rpc_primitives; diff --git a/common/src/rpc_primitives/requests.rs b/common/src/rpc_primitives/requests.rs index 48e41ea..29612c5 100644 --- a/common/src/rpc_primitives/requests.rs +++ b/common/src/rpc_primitives/requests.rs @@ -34,6 +34,9 @@ pub struct GetGenesisIdRequest {} #[derive(Serialize, Deserialize, Debug)] pub struct GetLastBlockRequest {} +#[derive(Serialize, Deserialize, Debug)] +pub struct GetInitialTestnetAccountsRequest {} + #[derive(Serialize, Deserialize, Debug)] pub struct GetAccountBalanceRequest { pub address: String, @@ -50,6 +53,7 @@ parse_request!(SendTxRequest); parse_request!(GetBlockDataRequest); parse_request!(GetGenesisIdRequest); parse_request!(GetLastBlockRequest); +parse_request!(GetInitialTestnetAccountsRequest); parse_request!(GetAccountBalanceRequest); parse_request!(GetTransactionByHashRequest); diff --git a/common/src/transaction.rs b/common/src/transaction.rs index 26dc670..78e1930 100644 --- a/common/src/transaction.rs +++ b/common/src/transaction.rs @@ -235,8 +235,8 @@ pub type SignaturePrivateKey = SigningKey; #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] pub struct Transaction { body: TransactionBody, - signature: TransactionSignature, - public_key: VerifyingKey, + pub signature: TransactionSignature, + pub public_key: VerifyingKey, } impl Transaction { diff --git a/node_core/src/chain_storage/mod.rs b/node_core/src/chain_storage/mod.rs index c470a0a..985014b 100644 --- a/node_core/src/chain_storage/mod.rs +++ b/node_core/src/chain_storage/mod.rs @@ -5,6 +5,7 @@ use anyhow::Result; use block_store::NodeBlockStore; use common::{ block::Block, + execution_input::PublicNativeTokenSend, merkle_tree_public::merkle_tree::{PublicTransactionMerkleTree, UTXOCommitmentsMerkleTree}, nullifier::UTXONullifier, utxo_commitment::UTXOCommitment, @@ -158,6 +159,20 @@ impl NodeChainStore { } _ => {} } + } else { + let native_transfer = + serde_json::from_slice::(&tx.body().execution_input); + + if let Ok(transfer) = native_transfer { + if let Some(acc_sender) = self.acc_map.get_mut(&transfer.from) { + //Can panic, we depend on sequencer maintaining chain consistency here + acc_sender.balance -= transfer.balance_to_move; + + if let Some(acc_rec) = self.acc_map.get_mut(&transfer.to) { + acc_rec.balance += transfer.balance_to_move; + } + } + } } } @@ -289,6 +304,248 @@ mod tests { use std::path::PathBuf; use tempfile::tempdir; + fn create_initial_accounts() -> Vec { + let initial_acc1 = serde_json::from_str(r#"{ + "address": [ + 244, + 55, + 238, + 205, + 74, + 115, + 179, + 192, + 65, + 186, + 166, + 169, + 221, + 45, + 6, + 57, + 200, + 65, + 195, + 70, + 118, + 252, + 206, + 100, + 215, + 250, + 72, + 230, + 19, + 71, + 217, + 249 + ], + "balance": 100, + "key_holder": { + "address": [ + 244, + 55, + 238, + 205, + 74, + 115, + 179, + 192, + 65, + 186, + 166, + 169, + 221, + 45, + 6, + 57, + 200, + 65, + 195, + 70, + 118, + 252, + 206, + 100, + 215, + 250, + 72, + 230, + 19, + 71, + 217, + 249 + ], + "nullifer_public_key": "03A340BECA9FAAB444CED0140681D72EA1318B5C611704FEE017DA9836B17DB718", + "pub_account_signing_key": [ + 244, + 88, + 134, + 61, + 35, + 209, + 229, + 101, + 85, + 35, + 140, + 140, + 192, + 226, + 83, + 83, + 190, + 189, + 110, + 8, + 89, + 127, + 147, + 142, + 157, + 204, + 51, + 109, + 189, + 92, + 144, + 68 + ], + "top_secret_key_holder": { + "secret_spending_key": "7BC46784DB1BC67825D8F029436846712BFDF9B5D79EA3AB11D39A52B9B229D4" + }, + "utxo_secret_key_holder": { + "nullifier_secret_key": "BB54A8D3C9C51B82C431082D1845A74677B0EF829A11B517E1D9885DE3139506", + "viewing_secret_key": "AD923E92F6A5683E30140CEAB2702AFB665330C1EE4EFA70FAF29767B6B52BAF" + }, + "viewing_public_key": "0361220C5D277E7A1709340FD31A52600C1432B9C45B9BCF88A43581D58824A8B6" + }, + "utxos": {} + }"#).unwrap(); + + let initial_acc2 = serde_json::from_str(r#"{ + "address": [ + 72, + 169, + 70, + 237, + 1, + 96, + 35, + 157, + 25, + 15, + 83, + 18, + 52, + 206, + 202, + 63, + 48, + 59, + 173, + 76, + 78, + 7, + 254, + 229, + 28, + 45, + 194, + 79, + 6, + 89, + 58, + 85 + ], + "balance": 200, + "key_holder": { + "address": [ + 72, + 169, + 70, + 237, + 1, + 96, + 35, + 157, + 25, + 15, + 83, + 18, + 52, + 206, + 202, + 63, + 48, + 59, + 173, + 76, + 78, + 7, + 254, + 229, + 28, + 45, + 194, + 79, + 6, + 89, + 58, + 85 + ], + "nullifer_public_key": "02172F50274DE67C4087C344F5D58E11DF761D90285B095060E0994FAA6BCDE271", + "pub_account_signing_key": [ + 136, + 105, + 9, + 53, + 180, + 145, + 64, + 5, + 235, + 174, + 62, + 211, + 206, + 116, + 185, + 24, + 214, + 62, + 244, + 64, + 224, + 59, + 120, + 150, + 30, + 249, + 160, + 46, + 189, + 254, + 47, + 244 + ], + "top_secret_key_holder": { + "secret_spending_key": "80A186737C8D38B4288A03F0F589957D9C040D79C19F3E0CC4BA80F8494E5179" + }, + "utxo_secret_key_holder": { + "nullifier_secret_key": "746928E63F0984F6F4818933493CE9C067562D9CB932FDC06D82C86CDF6D7122", + "viewing_secret_key": "89176CF4BC9E673807643FD52110EF99D4894335AFB10D881AC0B5041FE1FCB7" + }, + "viewing_public_key": "026072A8F83FEC3472E30CDD4767683F30B91661D25B1040AD9A5FC2E01D659F99" + }, + "utxos": {} + }"#).unwrap(); + + let initial_accounts = vec![initial_acc1, initial_acc2]; + + initial_accounts + } + fn create_genesis_block() -> Block { Block { block_id: 0, @@ -346,6 +603,7 @@ mod tests { port: 8000, gas_config: create_sample_gas_config(), shapshot_frequency_in_blocks: 1, + initial_accounts: create_initial_accounts(), } } diff --git a/node_core/src/config.rs b/node_core/src/config.rs index 935a803..e2ddf83 100644 --- a/node_core/src/config.rs +++ b/node_core/src/config.rs @@ -1,5 +1,6 @@ use std::path::PathBuf; +use accounts::account_core::Account; use serde::{Deserialize, Serialize}; use zkvm::gas_calculator::GasCalculator; @@ -51,4 +52,6 @@ pub struct NodeConfig { pub gas_config: GasConfig, ///Frequency of snapshots pub shapshot_frequency_in_blocks: u64, + ///Initial accounts for wallet + pub initial_accounts: Vec, } diff --git a/node_core/src/lib.rs b/node_core/src/lib.rs index e2c31c5..a8ca0b9 100644 --- a/node_core/src/lib.rs +++ b/node_core/src/lib.rs @@ -3,7 +3,9 @@ use std::sync::{ Arc, }; -use common::{transaction::Transaction, ExecutionFailureKind}; +use common::{ + execution_input::PublicNativeTokenSend, transaction::Transaction, ExecutionFailureKind, +}; use accounts::{ account_core::{Account, AccountAddress}, @@ -101,7 +103,14 @@ impl NodeCore { let genesis_block = client.get_block(genesis_id.genesis_id).await?.block; + let initial_accounts_ser = client.get_initial_testnet_accounts().await?; + let initial_accounts: Vec = + initial_accounts_ser.into_iter().map(Into::into).collect(); + let (mut storage, mut chain_height) = NodeChainStore::new(config.clone(), genesis_block)?; + for acc in initial_accounts { + storage.acc_map.insert(acc.address, acc); + } pre_start::setup_empty_sc_states(&storage).await?; @@ -942,6 +951,70 @@ impl NodeCore { // Ok(self.sequencer_client.send_tx(tx, tx_roots).await?) // } + // ToDo: Currently untested due to need for end-to-end integration tests. + // Add integration tests to cover this functionality + pub async fn send_public_native_token_transfer( + &self, + from: AccountAddress, + to: AccountAddress, + balance_to_move: u64, + ) -> Result { + let tx_roots = self.get_roots().await; + + let public_context = { + let read_guard = self.storage.read().await; + + read_guard.produce_context(from) + }; + + let (tweak, secret_r, commitment) = pedersen_commitment_vec( + //Will not panic, as public context is serializable + public_context.produce_u64_list_from_context().unwrap(), + ); + + let sc_addr = hex::encode([0; 32]); + + //Native contract does not change its state + let state_changes: Vec = vec![]; + let new_len = 0; + let state_changes = (serde_json::to_value(state_changes).unwrap(), new_len); + + let tx: TransactionBody = + sc_core::transaction_payloads_tools::create_public_transaction_payload( + serde_json::to_vec(&PublicNativeTokenSend { + from, + to, + balance_to_move, + }) + .unwrap(), + commitment, + tweak, + secret_r, + sc_addr, + state_changes, + ); + tx.log(); + + { + let read_guard = self.storage.read().await; + + let account = read_guard.acc_map.get(&from); + + if let Some(account) = account { + let key_to_sign_transaction = account.key_holder.get_pub_account_signing_key(); + + let signed_transaction = Transaction::new(tx, key_to_sign_transaction); + + Ok(self + .sequencer_client + .send_tx(signed_transaction, tx_roots) + .await?) + } else { + Err(ExecutionFailureKind::AmountMismatchError) + } + } + } + pub async fn send_private_send_tx( &self, utxo: UTXO, diff --git a/node_core/src/sequencer_client/mod.rs b/node_core/src/sequencer_client/mod.rs index c348395..e24b840 100644 --- a/node_core/src/sequencer_client/mod.rs +++ b/node_core/src/sequencer_client/mod.rs @@ -1,8 +1,8 @@ -use accounts::account_core::Account; +use accounts::account_core::{Account, AccountForSerialization}; use anyhow::Result; use common::rpc_primitives::requests::{ GetBlockDataRequest, GetBlockDataResponse, GetGenesisIdRequest, GetGenesisIdResponse, - RegisterAccountRequest, RegisterAccountResponse, + GetInitialTestnetAccountsRequest, RegisterAccountRequest, RegisterAccountResponse, }; use common::transaction::Transaction; use common::{SequencerClientError, SequencerRpcError}; @@ -121,4 +121,21 @@ impl SequencerClient { Ok(resp_deser) } + + pub async fn get_initial_testnet_accounts( + &self, + ) -> Result, SequencerClientError> { + let acc_req = GetInitialTestnetAccountsRequest {}; + + let req = serde_json::to_value(acc_req).unwrap(); + + let resp = self + .call_method_with_payload("get_initial_testnet_accounts", req) + .await + .unwrap(); + + let resp_deser = serde_json::from_value(resp).unwrap(); + + Ok(resp_deser) + } } diff --git a/node_runner/configs/debug/node_config.json b/node_runner/configs/debug/node_config.json index c948b82..6c39f15 100644 --- a/node_runner/configs/debug/node_config.json +++ b/node_runner/configs/debug/node_config.json @@ -13,5 +13,241 @@ "gas_limit_deploy": 30000000, "gas_limit_runtime": 30000000 }, - "shapshot_frequency_in_blocks": 10 + "shapshot_frequency_in_blocks": 10, + "initial_accounts": [ + { + "address": [ + 13, + 150, + 223, + 204, + 65, + 64, + 25, + 56, + 12, + 157, + 222, + 12, + 211, + 220, + 229, + 170, + 201, + 15, + 181, + 68, + 59, + 248, + 113, + 16, + 135, + 65, + 174, + 175, + 222, + 85, + 42, + 215 + ], + "balance": 10000, + "key_holder": { + "address": [ + 13, + 150, + 223, + 204, + 65, + 64, + 25, + 56, + 12, + 157, + 222, + 12, + 211, + 220, + 229, + 170, + 201, + 15, + 181, + 68, + 59, + 248, + 113, + 16, + 135, + 65, + 174, + 175, + 222, + 85, + 42, + 215 + ], + "nullifer_public_key": "03A340BECA9FAAB444CED0140681D72EA1318B5C611704FEE017DA9836B17DB718", + "pub_account_signing_key": [ + 133, + 143, + 177, + 187, + 252, + 66, + 237, + 236, + 234, + 252, + 244, + 138, + 5, + 151, + 3, + 99, + 217, + 231, + 112, + 217, + 77, + 211, + 58, + 218, + 176, + 68, + 99, + 53, + 152, + 228, + 198, + 190 + ], + "top_secret_key_holder": { + "secret_spending_key": "7BC46784DB1BC67825D8F029436846712BFDF9B5D79EA3AB11D39A52B9B229D4" + }, + "utxo_secret_key_holder": { + "nullifier_secret_key": "BB54A8D3C9C51B82C431082D1845A74677B0EF829A11B517E1D9885DE3139506", + "viewing_secret_key": "AD923E92F6A5683E30140CEAB2702AFB665330C1EE4EFA70FAF29767B6B52BAF" + }, + "viewing_public_key": "0361220C5D277E7A1709340FD31A52600C1432B9C45B9BCF88A43581D58824A8B6" + }, + "utxos": {} + }, + { + "address": [ + 151, + 72, + 112, + 233, + 190, + 141, + 10, + 192, + 138, + 168, + 59, + 63, + 199, + 167, + 166, + 134, + 41, + 29, + 135, + 50, + 80, + 138, + 186, + 152, + 179, + 96, + 128, + 243, + 156, + 44, + 243, + 100 + ], + "balance": 20000, + "key_holder": { + "address": [ + 151, + 72, + 112, + 233, + 190, + 141, + 10, + 192, + 138, + 168, + 59, + 63, + 199, + 167, + 166, + 134, + 41, + 29, + 135, + 50, + 80, + 138, + 186, + 152, + 179, + 96, + 128, + 243, + 156, + 44, + 243, + 100 + ], + "nullifer_public_key": "02172F50274DE67C4087C344F5D58E11DF761D90285B095060E0994FAA6BCDE271", + "pub_account_signing_key": [ + 54, + 90, + 62, + 225, + 71, + 225, + 228, + 148, + 143, + 53, + 210, + 23, + 137, + 158, + 171, + 156, + 48, + 7, + 139, + 52, + 117, + 242, + 214, + 7, + 99, + 29, + 122, + 184, + 59, + 116, + 144, + 107 + ], + "top_secret_key_holder": { + "secret_spending_key": "80A186737C8D38B4288A03F0F589957D9C040D79C19F3E0CC4BA80F8494E5179" + }, + "utxo_secret_key_holder": { + "nullifier_secret_key": "746928E63F0984F6F4818933493CE9C067562D9CB932FDC06D82C86CDF6D7122", + "viewing_secret_key": "89176CF4BC9E673807643FD52110EF99D4894335AFB10D881AC0B5041FE1FCB7" + }, + "viewing_public_key": "026072A8F83FEC3472E30CDD4767683F30B91661D25B1040AD9A5FC2E01D659F99" + }, + "utxos": {} + } + ] } \ No newline at end of file diff --git a/sequencer_core/Cargo.toml b/sequencer_core/Cargo.toml index ebe3984..f148655 100644 --- a/sequencer_core/Cargo.toml +++ b/sequencer_core/Cargo.toml @@ -13,6 +13,7 @@ serde.workspace = true rand.workspace = true elliptic-curve.workspace = true k256.workspace = true +tiny-keccak.workspace = true tempfile.workspace = true [dependencies.storage] diff --git a/sequencer_core/src/config.rs b/sequencer_core/src/config.rs index 95ed7bc..2dda687 100644 --- a/sequencer_core/src/config.rs +++ b/sequencer_core/src/config.rs @@ -1,8 +1,6 @@ use serde::{Deserialize, Serialize}; use std::path::PathBuf; -// - #[derive(Debug, Serialize, Deserialize, Clone)] ///Helperstruct for account serialization pub struct AccountInitialData { @@ -11,7 +9,7 @@ pub struct AccountInitialData { pub balance: u64, } -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Clone, Serialize, Deserialize)] pub struct SequencerConfig { ///Home dir of sequencer storage pub home: PathBuf, @@ -27,6 +25,6 @@ pub struct SequencerConfig { pub block_create_timeout_millis: u64, ///Port to listen pub port: u16, - ///List of pairs (account_address, initial_balance) + ///List of initial accounts data pub initial_accounts: Vec, } diff --git a/sequencer_core/src/lib.rs b/sequencer_core/src/lib.rs index bfde1f6..3786a2b 100644 --- a/sequencer_core/src/lib.rs +++ b/sequencer_core/src/lib.rs @@ -4,6 +4,7 @@ use accounts::account_core::AccountAddress; use anyhow::Result; use common::{ block::{Block, HashableBlockData}, + execution_input::PublicNativeTokenSend, merkle_tree_public::TreeHashType, nullifier::UTXONullifier, transaction::{AuthenticatedTransaction, Transaction, TransactionBody, TxKind}, @@ -14,6 +15,7 @@ use mempool::MemPool; use mempool_transaction::MempoolTransaction; use sequencer_store::SequecerChainStore; use serde::{Deserialize, Serialize}; +use tiny_keccak::{Hasher, Keccak}; pub mod config; pub mod mempool_transaction; @@ -26,7 +28,7 @@ pub struct SequencerCore { pub chain_height: u64, } -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] pub enum TransactionMalformationErrorKind { PublicTransactionChangedPrivateData { tx: TreeHashType }, PrivateTransactionChangedPublicData { tx: TreeHashType }, @@ -37,6 +39,9 @@ pub enum TransactionMalformationErrorKind { ChainStateFurtherThanTransactionState { tx: TreeHashType }, FailedToInsert { tx: TreeHashType, details: String }, InvalidSignature, + IncorrectSender, + BalanceMismatch { tx: TreeHashType }, + FailedToDecode { tx: TreeHashType }, } impl Display for TransactionMalformationErrorKind { @@ -137,6 +142,21 @@ impl SequencerCore { _ => {} }; + //Native transfers checks + if let Ok(native_transfer_action) = + serde_json::from_slice::(execution_input) + { + let mut output = [0; 32]; + let mut keccak_hasher = Keccak::v256(); + keccak_hasher.update(&tx.transaction().public_key.to_sec1_bytes()); + keccak_hasher.finalize(&mut output); + + //Correct sender check + if native_transfer_action.from != output { + return Err(TransactionMalformationErrorKind::IncorrectSender); + } + } + //Tree checks let tx_tree_check = self.store.pub_tx_store.get_tx(tx_hash).is_some(); let nullifier_tree_check = nullifier_created_hashes.iter().any(|nullifier_hash| { @@ -203,9 +223,40 @@ impl SequencerCore { let TransactionBody { ref utxo_commitments_created_hashes, ref nullifier_created_hashes, + execution_input, .. } = mempool_tx.auth_tx.transaction().body(); + let tx_hash = *mempool_tx.auth_tx.hash(); + + //Balance move + if let Ok(native_transfer_action) = + serde_json::from_slice::(execution_input) + { + let from_balance = self + .store + .acc_store + .get_account_balance(&native_transfer_action.from); + let to_balance = self + .store + .acc_store + .get_account_balance(&native_transfer_action.to); + + //Balance check + if from_balance < native_transfer_action.balance_to_move { + return Err(TransactionMalformationErrorKind::BalanceMismatch { tx: tx_hash }); + } + + self.store.acc_store.set_account_balance( + &native_transfer_action.from, + from_balance - native_transfer_action.balance_to_move, + ); + self.store.acc_store.set_account_balance( + &native_transfer_action.to, + to_balance + native_transfer_action.balance_to_move, + ); + } + for utxo_comm in utxo_commitments_created_hashes { self.store .utxo_commitments_store @@ -276,6 +327,7 @@ mod tests { use std::path::PathBuf; use common::transaction::{SignaturePrivateKey, Transaction, TransactionBody, TxKind}; + use k256::{ecdsa::SigningKey, FieldBytes}; use mempool_transaction::MempoolTransaction; use rand::Rng; use secp256k1_zkp::Tweak; @@ -301,19 +353,28 @@ mod tests { } fn setup_sequencer_config() -> SequencerConfig { - let initial_accounts = vec![ - AccountInitialData { - addr: "bfd91e6703273a115ad7f099ef32f621243be69369d00ddef5d3a25117d09a8c" - .to_string(), - balance: 10, - }, - AccountInitialData { - addr: "20573479053979b98d2ad09ef31a0750f22c77709bed51c4e64946bd1e376f31" - .to_string(), - balance: 100, - }, + let acc1_addr = vec![ + 13, 150, 223, 204, 65, 64, 25, 56, 12, 157, 222, 12, 211, 220, 229, 170, 201, 15, 181, + 68, 59, 248, 113, 16, 135, 65, 174, 175, 222, 85, 42, 215, ]; + let acc2_addr = vec![ + 151, 72, 112, 233, 190, 141, 10, 192, 138, 168, 59, 63, 199, 167, 166, 134, 41, 29, + 135, 50, 80, 138, 186, 152, 179, 96, 128, 243, 156, 44, 243, 100, + ]; + + let initial_acc1 = AccountInitialData { + addr: hex::encode(acc1_addr), + balance: 10000, + }; + + let initial_acc2 = AccountInitialData { + addr: hex::encode(acc2_addr), + balance: 20000, + }; + + let initial_accounts = vec![initial_acc1, initial_acc2]; + setup_sequencer_config_variable_initial_accounts(initial_accounts) } @@ -343,6 +404,59 @@ mod tests { Transaction::new(body, SignaturePrivateKey::random(&mut rng)) } + fn create_dummy_transaction_native_token_transfer( + from: [u8; 32], + to: [u8; 32], + balance_to_move: u64, + signing_key: SigningKey, + ) -> Transaction { + let mut rng = rand::thread_rng(); + + let native_token_transfer = PublicNativeTokenSend { + from, + to, + balance_to_move, + }; + + let body = TransactionBody { + tx_kind: TxKind::Public, + execution_input: serde_json::to_vec(&native_token_transfer).unwrap(), + execution_output: vec![], + utxo_commitments_spent_hashes: vec![], + utxo_commitments_created_hashes: vec![], + nullifier_created_hashes: vec![], + execution_proof_private: "".to_string(), + encoded_data: vec![], + ephemeral_pub_key: vec![10, 11, 12], + commitment: vec![], + tweak: Tweak::new(&mut rng), + secret_r: [0; 32], + sc_addr: "sc_addr".to_string(), + state_changes: (serde_json::Value::Null, 0), + }; + Transaction::new(body, signing_key) + } + + fn create_signing_key_for_account1() -> SigningKey { + let pub_sign_key_acc1 = [ + 133, 143, 177, 187, 252, 66, 237, 236, 234, 252, 244, 138, 5, 151, 3, 99, 217, 231, + 112, 217, 77, 211, 58, 218, 176, 68, 99, 53, 152, 228, 198, 190, + ]; + + let field_bytes = FieldBytes::from_slice(&pub_sign_key_acc1); + SigningKey::from_bytes(field_bytes).unwrap() + } + + fn create_signing_key_for_account2() -> SigningKey { + let pub_sign_key_acc2 = [ + 54, 90, 62, 225, 71, 225, 228, 148, 143, 53, 210, 23, 137, 158, 171, 156, 48, 7, 139, + 52, 117, 242, 214, 7, 99, 29, 122, 184, 59, 116, 144, 107, + ]; + + let field_bytes = FieldBytes::from_slice(&pub_sign_key_acc2); + SigningKey::from_bytes(field_bytes).unwrap() + } + fn common_setup(sequencer: &mut SequencerCore) { let tx = create_dummy_transaction(vec![[9; 32]], vec![[7; 32]], vec![[8; 32]]); let mempool_tx = MempoolTransaction { @@ -364,68 +478,65 @@ mod tests { assert_eq!(sequencer.sequencer_config.max_num_tx_in_block, 10); assert_eq!(sequencer.sequencer_config.port, 8080); - let acc1_addr: [u8; 32] = - hex::decode("bfd91e6703273a115ad7f099ef32f621243be69369d00ddef5d3a25117d09a8c") - .unwrap() - .try_into() - .unwrap(); - let acc2_addr: [u8; 32] = - hex::decode("20573479053979b98d2ad09ef31a0750f22c77709bed51c4e64946bd1e376f31") - .unwrap() - .try_into() - .unwrap(); + let acc1_addr = hex::decode(config.initial_accounts[0].addr.clone()) + .unwrap() + .try_into() + .unwrap(); + let acc2_addr = hex::decode(config.initial_accounts[1].addr.clone()) + .unwrap() + .try_into() + .unwrap(); assert!(sequencer.store.acc_store.contains_account(&acc1_addr)); assert!(sequencer.store.acc_store.contains_account(&acc2_addr)); assert_eq!( - 10, - sequencer - .store - .acc_store - .get_account_balance(&acc1_addr) - .unwrap() + 10000, + sequencer.store.acc_store.get_account_balance(&acc1_addr) ); assert_eq!( - 100, - sequencer - .store - .acc_store - .get_account_balance(&acc2_addr) - .unwrap() + 20000, + sequencer.store.acc_store.get_account_balance(&acc2_addr) ); } #[test] - fn test_start_different_intial_accounts() { - let initial_accounts = vec![ - AccountInitialData { - addr: "bfd91e6703273a115ad7f099ef32f621243be69369d00ddef5d3a25117ffffff" - .to_string(), - balance: 1000, - }, - AccountInitialData { - addr: "20573479053979b98d2ad09ef31a0750f22c77709bed51c4e64946bd1effffff" - .to_string(), - balance: 1000, - }, + fn test_start_different_intial_accounts_balances() { + let acc1_addr = vec![ + 13, 150, 223, 204, 65, 64, 25, 56, 12, 157, 222, 12, 211, 220, 229, 170, 201, 15, 181, + 68, 59, 248, 113, 16, 135, 65, 174, 175, 222, 42, 42, 42, ]; + let acc2_addr = vec![ + 151, 72, 112, 233, 190, 141, 10, 192, 138, 168, 59, 63, 199, 167, 166, 134, 41, 29, + 135, 50, 80, 138, 186, 152, 179, 96, 128, 243, 156, 42, 42, 42, + ]; + + let initial_acc1 = AccountInitialData { + addr: hex::encode(acc1_addr), + balance: 10000, + }; + + let initial_acc2 = AccountInitialData { + addr: hex::encode(acc2_addr), + balance: 20000, + }; + + let initial_accounts = vec![initial_acc1, initial_acc2]; + let intial_accounts_len = initial_accounts.len(); let config = setup_sequencer_config_variable_initial_accounts(initial_accounts); let sequencer = SequencerCore::start_from_config(config.clone()); - let acc1_addr: [u8; 32] = - hex::decode("bfd91e6703273a115ad7f099ef32f621243be69369d00ddef5d3a25117ffffff") - .unwrap() - .try_into() - .unwrap(); - let acc2_addr: [u8; 32] = - hex::decode("20573479053979b98d2ad09ef31a0750f22c77709bed51c4e64946bd1effffff") - .unwrap() - .try_into() - .unwrap(); + let acc1_addr = hex::decode(config.initial_accounts[0].addr.clone()) + .unwrap() + .try_into() + .unwrap(); + let acc2_addr = hex::decode(config.initial_accounts[1].addr.clone()) + .unwrap() + .try_into() + .unwrap(); assert!(sequencer.store.acc_store.contains_account(&acc1_addr)); assert!(sequencer.store.acc_store.contains_account(&acc2_addr)); @@ -433,20 +544,12 @@ mod tests { assert_eq!(sequencer.store.acc_store.len(), intial_accounts_len); assert_eq!( - 1000, - sequencer - .store - .acc_store - .get_account_balance(&acc1_addr) - .unwrap() + 10000, + sequencer.store.acc_store.get_account_balance(&acc1_addr) ); assert_eq!( - 1000, - sequencer - .store - .acc_store - .get_account_balance(&acc2_addr) - .unwrap() + 20000, + sequencer.store.acc_store.get_account_balance(&acc2_addr) ); } @@ -475,6 +578,124 @@ mod tests { assert!(result.is_ok()); } + #[test] + fn test_transaction_pre_check_native_transfer_valid() { + let config = setup_sequencer_config(); + let mut sequencer = SequencerCore::start_from_config(config); + + common_setup(&mut sequencer); + + let acc1 = hex::decode(sequencer.sequencer_config.initial_accounts[0].addr.clone()) + .unwrap() + .try_into() + .unwrap(); + let acc2 = hex::decode(sequencer.sequencer_config.initial_accounts[1].addr.clone()) + .unwrap() + .try_into() + .unwrap(); + + let sign_key1 = create_signing_key_for_account1(); + + let tx = create_dummy_transaction_native_token_transfer(acc1, acc2, 10, sign_key1); + let tx_roots = sequencer.get_tree_roots(); + let result = sequencer.transaction_pre_check(tx, tx_roots); + + assert!(result.is_ok()); + } + + #[test] + fn test_transaction_pre_check_native_transfer_other_signature() { + let config = setup_sequencer_config(); + let mut sequencer = SequencerCore::start_from_config(config); + + common_setup(&mut sequencer); + + let acc1 = hex::decode(sequencer.sequencer_config.initial_accounts[0].addr.clone()) + .unwrap() + .try_into() + .unwrap(); + let acc2 = hex::decode(sequencer.sequencer_config.initial_accounts[1].addr.clone()) + .unwrap() + .try_into() + .unwrap(); + + let sign_key2 = create_signing_key_for_account2(); + + let tx = create_dummy_transaction_native_token_transfer(acc1, acc2, 10, sign_key2); + let tx_roots = sequencer.get_tree_roots(); + let result = sequencer.transaction_pre_check(tx, tx_roots); + + assert_eq!( + result.err().unwrap(), + TransactionMalformationErrorKind::IncorrectSender + ); + } + + #[test] + fn test_transaction_pre_check_native_transfer_sent_too_much() { + let config = setup_sequencer_config(); + let mut sequencer = SequencerCore::start_from_config(config); + + common_setup(&mut sequencer); + + let acc1 = hex::decode(sequencer.sequencer_config.initial_accounts[0].addr.clone()) + .unwrap() + .try_into() + .unwrap(); + let acc2 = hex::decode(sequencer.sequencer_config.initial_accounts[1].addr.clone()) + .unwrap() + .try_into() + .unwrap(); + + let sign_key1 = create_signing_key_for_account1(); + + let tx = create_dummy_transaction_native_token_transfer(acc1, acc2, 10000000, sign_key1); + let tx_roots = sequencer.get_tree_roots(); + let result = sequencer.transaction_pre_check(tx, tx_roots); + + //Passed pre-check + assert!(result.is_ok()); + + let result = sequencer.execute_check_transaction_on_state(&result.unwrap().into()); + let is_failed_at_balance_mismatch = matches!( + result.err().unwrap(), + TransactionMalformationErrorKind::BalanceMismatch { tx: _ } + ); + + assert!(is_failed_at_balance_mismatch); + } + + #[test] + fn test_transaction_execute_native_transfer() { + let config = setup_sequencer_config(); + let mut sequencer = SequencerCore::start_from_config(config); + + common_setup(&mut sequencer); + + let acc1 = hex::decode(sequencer.sequencer_config.initial_accounts[0].addr.clone()) + .unwrap() + .try_into() + .unwrap(); + let acc2 = hex::decode(sequencer.sequencer_config.initial_accounts[1].addr.clone()) + .unwrap() + .try_into() + .unwrap(); + + let sign_key1 = create_signing_key_for_account1(); + + let tx = create_dummy_transaction_native_token_transfer(acc1, acc2, 100, sign_key1); + + sequencer + .execute_check_transaction_on_state(&tx.into_authenticated().unwrap().into()) + .unwrap(); + + let bal_from = sequencer.store.acc_store.get_account_balance(&acc1); + let bal_to = sequencer.store.acc_store.get_account_balance(&acc2); + + assert_eq!(bal_from, 9900); + assert_eq!(bal_to, 20100); + } + #[test] fn test_push_tx_into_mempool_fails_mempool_full() { let config = SequencerConfig { diff --git a/sequencer_core/src/sequencer_store/accounts_store.rs b/sequencer_core/src/sequencer_store/accounts_store.rs index 7d64491..8dd2070 100644 --- a/sequencer_core/src/sequencer_store/accounts_store.rs +++ b/sequencer_core/src/sequencer_store/accounts_store.rs @@ -56,9 +56,33 @@ impl SequencerAccountsStore { ///Check `account_addr` balance, /// - ///returns `None`, if account address not found - pub fn get_account_balance(&self, account_addr: &AccountAddress) -> Option { - self.accounts.get(account_addr).map(|acc| acc.balance) + ///returns 0, if account address not found + pub fn get_account_balance(&self, account_addr: &AccountAddress) -> u64 { + self.accounts + .get(account_addr) + .map(|acc| acc.balance) + .unwrap_or(0) + } + + ///Update `account_addr` balance, + /// + /// returns 0, if account address not found, otherwise returns previous balance + /// + /// Also, if account was not previously found, sets it with zero balance + pub fn set_account_balance(&mut self, account_addr: &AccountAddress, new_balance: u64) -> u64 { + let acc_data = self.accounts.get_mut(account_addr); + + if let Some(acc_data) = acc_data { + let old_balance = acc_data.balance; + + acc_data.balance = new_balance; + + old_balance + } else { + self.register_account(*account_addr); + + 0 + } } ///Remove account from storage @@ -70,14 +94,10 @@ impl SequencerAccountsStore { &mut self, account_addr: AccountAddress, ) -> Result> { - if let Some(account_balance) = self.get_account_balance(&account_addr) { - if account_balance == 0 { - Ok(self.accounts.remove(&account_addr).map(|data| data.address)) - } else { - anyhow::bail!("Chain consistency violation: It is forbidden to remove account with nonzero balance"); - } + if self.get_account_balance(&account_addr) == 0 { + Ok(self.accounts.remove(&account_addr).map(|data| data.address)) } else { - Ok(None) + anyhow::bail!("Chain consistency violation: It is forbidden to remove account with nonzero balance"); } } @@ -133,7 +153,7 @@ mod tests { assert!(seq_acc_store.contains_account(&[1; 32])); - let acc_balance = seq_acc_store.get_account_balance(&[1; 32]).unwrap(); + let acc_balance = seq_acc_store.get_account_balance(&[1; 32]); assert_eq!(acc_balance, 0); } @@ -178,11 +198,11 @@ mod tests { assert!(seq_acc_store.contains_account(&[1; 32])); assert!(seq_acc_store.contains_account(&[2; 32])); - let acc_balance = seq_acc_store.get_account_balance(&[1; 32]).unwrap(); + let acc_balance = seq_acc_store.get_account_balance(&[1; 32]); assert_eq!(acc_balance, 12); - let acc_balance = seq_acc_store.get_account_balance(&[2; 32]).unwrap(); + let acc_balance = seq_acc_store.get_account_balance(&[2; 32]); assert_eq!(acc_balance, 100); } @@ -196,15 +216,15 @@ mod tests { assert!(seq_acc_store.contains_account(&[7; 32])); assert!(seq_acc_store.contains_account(&[8; 32])); - let acc_balance = seq_acc_store.get_account_balance(&[6; 32]).unwrap(); + let acc_balance = seq_acc_store.get_account_balance(&[6; 32]); assert_eq!(acc_balance, 120); - let acc_balance = seq_acc_store.get_account_balance(&[7; 32]).unwrap(); + let acc_balance = seq_acc_store.get_account_balance(&[7; 32]); assert_eq!(acc_balance, 15); - let acc_balance = seq_acc_store.get_account_balance(&[8; 32]).unwrap(); + let acc_balance = seq_acc_store.get_account_balance(&[8; 32]); assert_eq!(acc_balance, 10); } @@ -216,7 +236,7 @@ mod tests { let acc_balance = seq_acc_store.get_account_balance(&[9; 32]); - assert!(acc_balance.is_none()); + assert_eq!(acc_balance, 0); } #[test] @@ -225,4 +245,15 @@ mod tests { assert!(seq_acc_store.is_empty()); } + + #[test] + fn account_sequencer_store_set_balance_to_unknown_account() { + let mut seq_acc_store = SequencerAccountsStore::default(); + + let ret = seq_acc_store.set_account_balance(&[1; 32], 100); + + assert_eq!(ret, 0); + assert!(seq_acc_store.contains_account(&[1; 32])); + assert_eq!(seq_acc_store.get_account_balance(&[1; 32]), 0); + } } diff --git a/sequencer_core/src/sequencer_store/mod.rs b/sequencer_core/src/sequencer_store/mod.rs index daffc91..a85fd23 100644 --- a/sequencer_core/src/sequencer_store/mod.rs +++ b/sequencer_core/src/sequencer_store/mod.rs @@ -29,12 +29,10 @@ impl SequecerChainStore { is_genesis_random: bool, initial_accounts: &[AccountInitialData], ) -> Self { - let acc_data_decoded: Vec<([u8; 32], u64)> = initial_accounts + let init_accs: Vec<_> = initial_accounts .iter() .map(|acc_data| { ( - //ToDo: Handle this error for direct error message - //Failure to produce account address is critical, so error handling is needed only for clarity hex::decode(acc_data.addr.clone()) .unwrap() .try_into() @@ -44,7 +42,7 @@ impl SequecerChainStore { }) .collect(); - let acc_store = SequencerAccountsStore::new(&acc_data_decoded); + let acc_store = SequencerAccountsStore::new(&init_accs); let nullifier_store = HashSet::new(); let utxo_commitments_store = UTXOCommitmentsMerkleTree::new(vec![]); let pub_tx_store = PublicTransactionMerkleTree::new(vec![]); diff --git a/sequencer_rpc/Cargo.toml b/sequencer_rpc/Cargo.toml index 5da9521..fb33c2d 100644 --- a/sequencer_rpc/Cargo.toml +++ b/sequencer_rpc/Cargo.toml @@ -21,6 +21,9 @@ tokio.workspace = true [dependencies.mempool] path = "../mempool" +[dependencies.accounts] +path = "../accounts" + [dependencies.consensus] path = "../consensus" diff --git a/sequencer_rpc/src/process.rs b/sequencer_rpc/src/process.rs index 98dcaae..d606f4c 100644 --- a/sequencer_rpc/src/process.rs +++ b/sequencer_rpc/src/process.rs @@ -1,4 +1,5 @@ use actix_web::Error as HttpError; +use sequencer_core::config::AccountInitialData; use serde_json::Value; use common::{ @@ -8,8 +9,8 @@ use common::{ message::{Message, Request}, parser::RpcRequest, requests::{ - GetAccountBalanceRequest, GetAccountBalanceResponse, GetTransactionByHashRequest, - GetTransactionByHashResponse, + GetAccountBalanceRequest, GetAccountBalanceResponse, GetInitialTestnetAccountsRequest, + GetTransactionByHashRequest, GetTransactionByHashResponse, }, }, }; @@ -35,6 +36,8 @@ pub const HELLO_FROM_SEQUENCER: &str = "HELLO_FROM_SEQUENCER"; pub const SUCCESS: &str = "Success"; +pub const GET_INITIAL_TESTNET_ACCOUNTS: &str = "get_initial_testnet_accounts"; + impl JsonHandler { pub async fn process(&self, message: Message) -> Result { let id = message.id(); @@ -140,6 +143,21 @@ impl JsonHandler { respond(helperstruct) } + /// Returns the initial accounts for testnet + /// ToDo: Useful only for testnet and needs to be removed later + async fn get_initial_testnet_accounts(&self, request: Request) -> Result { + let _get_initial_testnet_accounts_request = + GetInitialTestnetAccountsRequest::parse(Some(request.params))?; + + let initial_accounts: Vec = { + let state = self.sequencer_state.lock().await; + + state.sequencer_config.initial_accounts.clone() + }; + + respond(initial_accounts) + } + /// Returns the balance of the account at the given address. /// The address must be a valid hex string of the correct length. async fn process_get_account_balance(&self, request: Request) -> Result { @@ -153,8 +171,7 @@ impl JsonHandler { let balance = { let state = self.sequencer_state.lock().await; state.store.acc_store.get_account_balance(&address) - } - .unwrap_or(0); + }; let helperstruct = GetAccountBalanceResponse { balance }; @@ -187,6 +204,7 @@ impl JsonHandler { GET_BLOCK => self.process_get_block_data(request).await, GET_GENESIS => self.process_get_genesis(request).await, GET_LAST_BLOCK => self.process_get_last_block(request).await, + GET_INITIAL_TESTNET_ACCOUNTS => self.get_initial_testnet_accounts(request).await, GET_ACCOUNT_BALANCE => self.process_get_account_balance(request).await, GET_TRANSACTION_BY_HASH => self.process_get_transaction_by_hash(request).await, _ => Err(RpcErr(RpcError::method_not_found(request.method))), @@ -214,17 +232,28 @@ mod tests { fn sequencer_config_for_tests() -> SequencerConfig { let tempdir = tempdir().unwrap(); let home = tempdir.path().to_path_buf(); - let initial_accounts = vec![ - AccountInitialData { - addr: "cafe".repeat(16).to_string(), - balance: 100, - }, - AccountInitialData { - addr: "feca".repeat(16).to_string(), - balance: 200, - }, + let acc1_addr = vec![ + 13, 150, 223, 204, 65, 64, 25, 56, 12, 157, 222, 12, 211, 220, 229, 170, 201, 15, 181, + 68, 59, 248, 113, 16, 135, 65, 174, 175, 222, 85, 42, 215, ]; + let acc2_addr = vec![ + 151, 72, 112, 233, 190, 141, 10, 192, 138, 168, 59, 63, 199, 167, 166, 134, 41, 29, + 135, 50, 80, 138, 186, 152, 179, 96, 128, 243, 156, 44, 243, 100, + ]; + + let initial_acc1 = AccountInitialData { + addr: hex::encode(acc1_addr), + balance: 10000, + }; + + let initial_acc2 = AccountInitialData { + addr: hex::encode(acc2_addr), + balance: 20000, + }; + + let initial_accounts = vec![initial_acc1, initial_acc2]; + SequencerConfig { home, override_rust_log: Some("info".to_string()), @@ -237,9 +266,13 @@ mod tests { } } - fn json_handler_for_tests() -> JsonHandler { + fn json_handler_for_tests() -> (JsonHandler, Vec) { let config = sequencer_config_for_tests(); + let mut sequencer_core = SequencerCore::start_from_config(config); + + let initial_accounts = sequencer_core.sequencer_config.initial_accounts.clone(); + let tx_body = TransactionBody { tx_kind: common::transaction::TxKind::Public, execution_input: Default::default(), @@ -265,10 +298,15 @@ mod tests { .produce_new_block_with_mempool_transactions() .unwrap(); - JsonHandler { - polling_config: RpcPollingConfig::default(), - sequencer_state: Arc::new(Mutex::new(sequencer_core)), - } + let sequencer_core = Arc::new(Mutex::new(sequencer_core)); + + ( + JsonHandler { + polling_config: RpcPollingConfig::default(), + sequencer_state: sequencer_core, + }, + initial_accounts, + ) } async fn call_rpc_handler_with_json(handler: JsonHandler, request_json: Value) -> Value { @@ -294,7 +332,7 @@ mod tests { #[actix_web::test] async fn test_get_account_balance_for_non_existent_account() { - let json_handler = json_handler_for_tests(); + let (json_handler, _) = json_handler_for_tests(); let request = serde_json::json!({ "jsonrpc": "2.0", "method": "get_account_balance", @@ -316,7 +354,7 @@ mod tests { #[actix_web::test] async fn test_get_account_balance_for_invalid_hex() { - let json_handler = json_handler_for_tests(); + let (json_handler, _) = json_handler_for_tests(); let request = serde_json::json!({ "jsonrpc": "2.0", "method": "get_account_balance", @@ -339,7 +377,7 @@ mod tests { #[actix_web::test] async fn test_get_account_balance_for_invalid_length() { - let json_handler = json_handler_for_tests(); + let (json_handler, _) = json_handler_for_tests(); let request = serde_json::json!({ "jsonrpc": "2.0", "method": "get_account_balance", @@ -362,18 +400,21 @@ mod tests { #[actix_web::test] async fn test_get_account_balance_for_existing_account() { - let json_handler = json_handler_for_tests(); + let (json_handler, initial_accounts) = json_handler_for_tests(); + + let acc1_addr = initial_accounts[0].addr.clone(); + let request = serde_json::json!({ "jsonrpc": "2.0", "method": "get_account_balance", - "params": { "address": "cafe".repeat(16) }, + "params": { "address": acc1_addr }, "id": 1 }); let expected_response = serde_json::json!({ "id": 1, "jsonrpc": "2.0", "result": { - "balance": 100 + "balance": 10000 } }); @@ -384,7 +425,7 @@ mod tests { #[actix_web::test] async fn test_get_transaction_by_hash_for_non_existent_hash() { - let json_handler = json_handler_for_tests(); + let (json_handler, _) = json_handler_for_tests(); let request = serde_json::json!({ "jsonrpc": "2.0", "method": "get_transaction_by_hash", @@ -406,7 +447,7 @@ mod tests { #[actix_web::test] async fn test_get_transaction_by_hash_for_invalid_hex() { - let json_handler = json_handler_for_tests(); + let (json_handler, _) = json_handler_for_tests(); let request = serde_json::json!({ "jsonrpc": "2.0", "method": "get_transaction_by_hash", @@ -430,7 +471,7 @@ mod tests { #[actix_web::test] async fn test_get_transaction_by_hash_for_invalid_length() { - let json_handler = json_handler_for_tests(); + let (json_handler, _) = json_handler_for_tests(); let request = serde_json::json!({ "jsonrpc": "2.0", "method": "get_transaction_by_hash", @@ -454,7 +495,7 @@ mod tests { #[actix_web::test] async fn test_get_transaction_by_hash_for_existing_transaction() { - let json_handler = json_handler_for_tests(); + let (json_handler, _) = json_handler_for_tests(); let request = serde_json::json!({ "jsonrpc": "2.0", "method": "get_transaction_by_hash", diff --git a/sequencer_runner/configs/debug/sequencer_config.json b/sequencer_runner/configs/debug/sequencer_config.json index 18d1b72..010a9ba 100644 --- a/sequencer_runner/configs/debug/sequencer_config.json +++ b/sequencer_runner/configs/debug/sequencer_config.json @@ -7,13 +7,6 @@ "block_create_timeout_millis": 10000, "port": 3040, "initial_accounts": [ - { - "addr": "bfd91e6703273a115ad7f099ef32f621243be69369d00ddef5d3a25117d09a8c", - "balance": 10 - }, - { - "addr": "20573479053979b98d2ad09ef31a0750f22c77709bed51c4e64946bd1e376f31", - "balance": 100 - } + ] } \ No newline at end of file