breaking: initial cuts

This commit is contained in:
Oleksandr Pravdyvyi 2025-08-04 15:09:28 +03:00
parent ebec84b3c0
commit 6565e0af18
No known key found for this signature in database
GPG Key ID: 9F8955C63C443871
4 changed files with 22 additions and 2394 deletions

View File

@ -2,24 +2,18 @@ use std::collections::{BTreeMap, HashMap, HashSet};
use accounts::account_core::{address::AccountAddress, Account};
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,
};
use k256::AffinePoint;
use log::{info, warn};
use sc_core::public_context::PublicSCContext;
use serde::{Deserialize, Serialize};
use utxo::utxo_core::UTXO;
use crate::{config::NodeConfig, ActionData};
use crate::config::NodeConfig;
pub mod accounts_store;
pub mod block_store;
//pub mod block_store;
#[derive(Deserialize, Serialize)]
pub struct AccMap {
@ -49,7 +43,6 @@ impl From<AccMap> for HashMap<[u8; 32], Account> {
pub struct NodeChainStore {
pub acc_map: HashMap<AccountAddress, Account>,
pub block_store: NodeBlockStore,
pub nullifier_store: HashSet<UTXONullifier>,
pub utxo_commitments_store: UTXOCommitmentsMerkleTree,
pub pub_tx_store: PublicTransactionMerkleTree,
@ -58,30 +51,15 @@ pub struct NodeChainStore {
impl NodeChainStore {
pub fn new(config: NodeConfig, genesis_block: Block) -> Result<(Self, u64)> {
let mut acc_map = HashMap::new();
let mut nullifier_store = HashSet::new();
let mut utxo_commitments_store = UTXOCommitmentsMerkleTree::new(vec![]);
let mut pub_tx_store = PublicTransactionMerkleTree::new(vec![]);
let mut block_id = genesis_block.block_id;
//Sequencer should panic if unable to open db,
//as fixing this issue may require actions non-native to program scope
let block_store =
NodeBlockStore::open_db_with_genesis(&config.home.join("rocksdb"), Some(genesis_block))
.unwrap();
if let Ok(temp_block_id) = block_store.get_snapshot_block_id() {
utxo_commitments_store = block_store.get_snapshot_commitment()?;
nullifier_store = block_store.get_snapshot_nullifier()?;
acc_map = block_store.get_snapshot_account()?;
pub_tx_store = block_store.get_snapshot_transaction()?;
block_id = temp_block_id;
}
let acc_map = HashMap::new();
let nullifier_store = HashSet::new();
let utxo_commitments_store = UTXOCommitmentsMerkleTree::new(vec![]);
let pub_tx_store = PublicTransactionMerkleTree::new(vec![]);
let block_id = genesis_block.block_id;
Ok((
Self {
acc_map,
block_store,
nullifier_store,
utxo_commitments_store,
pub_tx_store,
@ -91,184 +69,6 @@ impl NodeChainStore {
))
}
pub fn new_after_restart(config: NodeConfig, genesis_block: Block) -> Result<(Self, u64)> {
let mut acc_map = HashMap::new();
let mut nullifier_store = HashSet::new();
let mut utxo_commitments_store = UTXOCommitmentsMerkleTree::new(vec![]);
let mut pub_tx_store = PublicTransactionMerkleTree::new(vec![]);
let mut block_id = genesis_block.block_id;
//Sequencer should panic if unable to open db,
//as fixing this issue may require actions non-native to program scope
let block_store = NodeBlockStore::open_db_reload(&config.home.join("rocksdb")).unwrap();
if let Ok(temp_block_id) = block_store.get_snapshot_block_id() {
utxo_commitments_store = block_store.get_snapshot_commitment()?;
nullifier_store = block_store.get_snapshot_nullifier()?;
acc_map = block_store.get_snapshot_account()?;
pub_tx_store = block_store.get_snapshot_transaction()?;
block_id = temp_block_id;
}
Ok((
Self {
acc_map,
block_store,
nullifier_store,
utxo_commitments_store,
pub_tx_store,
node_config: config,
},
block_id,
))
}
pub fn dissect_insert_block(&mut self, block: Block) -> Result<()> {
let block_id = block.block_id;
for tx in &block.transactions {
if !tx.body().execution_input.is_empty() {
let public_action =
serde_json::from_slice::<ActionData>(&tx.body().execution_input);
if let Ok(public_action) = public_action {
match public_action {
ActionData::MintMoneyPublicTx(action) => {
let acc_mut = self.acc_map.get_mut(&action.acc);
if let Some(acc_mut) = acc_mut {
acc_mut.balance += action.amount as u64;
}
}
ActionData::SendMoneyDeshieldedTx(action) => {
for (balance, acc_addr) in action.receiver_data {
let acc_mut = self.acc_map.get_mut(&acc_addr);
if let Some(acc_mut) = acc_mut {
acc_mut.balance += balance as u64;
}
}
}
ActionData::SendMoneyShieldedTx(action) => {
let acc_mut = self.acc_map.get_mut(&action.acc_sender);
if let Some(acc_mut) = acc_mut {
acc_mut.balance =
acc_mut.balance.saturating_sub(action.amount as u64);
}
}
_ => {}
}
} else {
let native_transfer =
serde_json::from_slice::<PublicNativeTokenSend>(&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;
}
}
}
}
}
self.utxo_commitments_store.add_tx_multiple(
tx.body()
.utxo_commitments_created_hashes
.clone()
.into_iter()
.map(|hash| UTXOCommitment { hash })
.collect(),
);
for nullifier in tx.body().nullifier_created_hashes.iter() {
self.nullifier_store.insert(UTXONullifier {
utxo_hash: *nullifier,
});
}
if !tx.body().encoded_data.is_empty() {
let ephemeral_public_key_sender =
serde_json::from_slice::<AffinePoint>(&tx.body().ephemeral_pub_key)?;
for (ciphertext, nonce, tag) in tx.body().encoded_data.clone() {
let slice = nonce.as_slice();
let nonce =
accounts::key_management::constants_types::Nonce::clone_from_slice(slice);
for (acc_id, acc) in self.acc_map.iter_mut() {
if hex::decode(acc_id).unwrap()[0] == tag {
let decoded_data_curr_acc = acc.decrypt_data(
ephemeral_public_key_sender,
ciphertext.clone(),
nonce,
);
if let Ok(decoded_data_curr_acc) = decoded_data_curr_acc {
let decoded_utxo_try =
serde_json::from_slice::<UTXO>(&decoded_data_curr_acc);
if let Ok(utxo) = decoded_utxo_try {
if &utxo.owner == acc_id {
acc.utxos.insert(utxo.hash, utxo);
}
}
}
}
}
}
}
self.pub_tx_store.add_tx(tx);
}
self.block_store.put_block_at_id(block)?;
//Snapshot
if block_id.is_multiple_of(self.node_config.shapshot_frequency_in_blocks) {
//Serializing all important data structures
//If we fail serialization, it is not the reason to stop running
//Logging on warn level in this cases
let acc_map: AccMap = self.acc_map.clone().into();
if let Ok(accounts_ser) = serde_json::to_vec(&acc_map).inspect_err(|err| {
warn!("Failed to serialize accounts data {err:#?}");
}) {
if let Ok(comm_ser) =
serde_json::to_vec(&self.utxo_commitments_store).inspect_err(|err| {
warn!("Failed to serialize commitments {err:#?}");
})
{
if let Ok(txs_ser) = serde_json::to_vec(&self.pub_tx_store).inspect_err(|err| {
warn!("Failed to serialize transactions {err:#?}");
}) {
if let Ok(nullifiers_ser) = serde_json::to_vec(&self.nullifier_store)
.inspect_err(|err| {
warn!("Failed to serialize nullifiers {err:#?}");
})
{
let snapshot_trace = self.block_store.put_snapshot_at_block_id(
block_id,
accounts_ser,
comm_ser,
txs_ser,
nullifiers_ser,
);
info!(
"Snapshot executed at {block_id:?} with results {snapshot_trace:#?}"
);
}
}
}
}
}
Ok(())
}
pub fn produce_context(&self, caller: AccountAddress) -> PublicSCContext {
let mut account_masks = BTreeMap::new();
@ -298,7 +98,6 @@ mod tests {
use crate::config::GasConfig;
use accounts::account_core::Account;
use common::block::{Block, Data};
use common::merkle_tree_public::TreeHashType;
use common::transaction::{SignaturePrivateKey, Transaction, TransactionBody, TxKind};
use secp256k1_zkp::Tweak;
use std::path::PathBuf;
@ -489,6 +288,7 @@ mod tests {
}
}
//ToDo: Continue refactor
fn create_dummy_transaction(
nullifier_created_hashes: Vec<[u8; 32]>,
utxo_commitments_spent_hashes: Vec<[u8; 32]>,
@ -515,6 +315,7 @@ mod tests {
Transaction::new(body, SignaturePrivateKey::random(&mut rng))
}
//ToDo: Continue refactor
fn create_sample_block(block_id: u64, prev_block_id: u64) -> Block {
Block {
block_id,
@ -551,10 +352,6 @@ mod tests {
}
}
fn generate_dummy_utxo(address: TreeHashType, amount: u128) -> UTXO {
UTXO::new(address, vec![], amount, false)
}
#[test]
fn test_new_initializes_correctly() {
let temp_dir = tempdir().unwrap();
@ -574,59 +371,4 @@ mod tests {
[0; 32]
);
}
#[test]
fn test_new_recovers_from_snapshot() {
let temp_dir = tempdir().unwrap();
let path = temp_dir.path().to_path_buf();
let config = create_sample_node_config(path);
let nullifier_secret_const =
"261d61d294ac4bdc24f91b6f490efa263757a4a95f65871cd4f16b2ea23c3b5d";
std::env::set_var("NULLIFIER_SECRET_CONST", nullifier_secret_const);
let viewing_secret_const =
"6117af750b30d7a296672ec3b3b25d3489beca3cfe5770fa39f275cec395d5ce";
std::env::set_var("VIEWING_SECRET_CONST", viewing_secret_const);
let genesis_block = create_genesis_block();
// Initialize once to create DB and store fake snapshot
{
let (mut store, _) =
NodeChainStore::new(config.clone(), genesis_block.clone()).unwrap();
// Insert state
let mut account = Account::new();
account
.add_new_utxo_outputs(vec![generate_dummy_utxo(account.address, 100)])
.unwrap();
store.acc_map.insert(account.address, account);
store.nullifier_store.insert(UTXONullifier {
utxo_hash: [2u8; 32],
});
store
.utxo_commitments_store
.add_tx_multiple(vec![UTXOCommitment { hash: [3u8; 32] }]);
store.pub_tx_store.add_tx(&create_dummy_transaction(
vec![[9; 32]],
vec![[7; 32]],
vec![[8; 32]],
));
// Put block snapshot to trigger snapshot recovery on next load
let dummy_block = create_sample_block(1, 0);
store.dissect_insert_block(dummy_block).unwrap();
}
// Now reload and verify snapshot is used
let (recovered_store, block_id) =
NodeChainStore::new_after_restart(config.clone(), genesis_block).unwrap();
assert_eq!(block_id, 1);
assert_eq!(recovered_store.acc_map.len(), 1);
assert!(recovered_store.utxo_commitments_store.get_root().is_some());
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,71 +0,0 @@
use anyhow::Result;
use log::info;
use crate::chain_storage::NodeChainStore;
///Addres of public fund transfer account, as no such binary exists for zkVM
pub const PUBLIC_DEPOSIT_ID: [u8; 32] = [0; 32];
///Setups public states of default smart conracts as empty
pub async fn setup_empty_sc_states(node: &NodeChainStore) -> Result<()> {
info!("Filling up public states of default smart contracts");
let empty_state = vec![];
let public_deposit_addr = hex::encode(PUBLIC_DEPOSIT_ID);
node.block_store.put_sc_sc_state(
&public_deposit_addr,
empty_state.len(),
empty_state.clone(),
)?;
info!("Public transfer state set");
let mint_utxo_addr_bytes: Vec<u8> = zkvm::test_methods::MINT_UTXO_ID
.iter()
.flat_map(|num| num.to_le_bytes())
.collect();
let mint_utxo_addr = hex::encode(mint_utxo_addr_bytes);
node.block_store
.put_sc_sc_state(&mint_utxo_addr, empty_state.len(), empty_state.clone())?;
info!("Mint UTXO state set");
let single_utxo_transfer_addr_bytes: Vec<u8> = zkvm::test_methods::SEND_UTXO_ID
.iter()
.flat_map(|num| num.to_le_bytes())
.collect();
let single_utxo_transfer_addr = hex::encode(single_utxo_transfer_addr_bytes);
node.block_store.put_sc_sc_state(
&single_utxo_transfer_addr,
empty_state.len(),
empty_state.clone(),
)?;
info!("Single UTXO transfer state set");
let mint_utxo_multiple_assets_addr_bytes: Vec<u8> =
zkvm::test_methods::MINT_UTXO_MULTIPLE_ASSETS_ID
.iter()
.flat_map(|num| num.to_le_bytes())
.collect();
let mint_utxo_multiple_assets_addr = hex::encode(mint_utxo_multiple_assets_addr_bytes);
node.block_store.put_sc_sc_state(
&mint_utxo_multiple_assets_addr,
empty_state.len(),
empty_state.clone(),
)?;
info!("Mint UTXO multiple assets state set");
let multiple_assets_utxo_transfer_addr_bytes: Vec<u8> =
zkvm::test_methods::SEND_UTXO_MULTIPLE_ASSETS_ID
.iter()
.flat_map(|num| num.to_le_bytes())
.collect();
let multiple_assets_utxo_transfer_addr = hex::encode(multiple_assets_utxo_transfer_addr_bytes);
node.block_store.put_sc_sc_state(
&multiple_assets_utxo_transfer_addr,
empty_state.len(),
empty_state.clone(),
)?;
info!("Multiple_assets UTXO transfer state set");
Ok(())
}

View File

@ -1,7 +1,6 @@
use std::sync::atomic::Ordering;
use actix_web::Error as HttpError;
use node_core::generate_commitments_helper;
use serde_json::Value;
use common::rpc_primitives::{
@ -11,25 +10,12 @@ use common::rpc_primitives::{
};
use common::transaction::ActionData;
use common::rpc_primitives::requests::{
GetBlockDataRequest, GetBlockDataResponse, GetLastBlockRequest, GetLastBlockResponse,
};
use common::rpc_primitives::requests::{GetLastBlockRequest, GetLastBlockResponse};
use crate::types::{
err_rpc::cast_common_execution_error_into_rpc_error,
rpc_structs::{
CreateAccountRequest, CreateAccountResponse, ExecuteScenarioMultipleSendRequest,
ExecuteScenarioMultipleSendResponse, ExecuteScenarioSplitRequest,
ExecuteScenarioSplitResponse, ExecuteSubscenarioRequest, ExecuteSubscenarioResponse,
ShowAccountPublicBalanceRequest, ShowAccountPublicBalanceResponse, ShowAccountUTXORequest,
ShowAccountUTXOResponse, ShowTransactionRequest, ShowTransactionResponse,
UTXOShortEssentialStruct, WriteMintPrivateUTXOMultipleAssetsRequest,
WriteMintPrivateUTXOMultipleAssetsResponse, WriteMintPrivateUTXORequest,
WriteMintPrivateUTXOResponse, WriteSendDeshieldedBalanceRequest,
WriteSendDeshieldedUTXOResponse, WriteSendPrivateUTXORequest, WriteSendPrivateUTXOResponse,
WriteSendShieldedUTXORequest, WriteSendShieldedUTXOResponse, WriteSendSplitUTXOResponse,
WriteSplitUTXORequest,
},
use crate::types::rpc_structs::{
CreateAccountRequest, CreateAccountResponse, ShowAccountPublicBalanceRequest,
ShowAccountPublicBalanceResponse, ShowAccountUTXORequest, ShowAccountUTXOResponse,
ShowTransactionRequest, ShowTransactionResponse,
};
pub const CREATE_ACCOUNT: &str = "create_account";
@ -71,80 +57,6 @@ impl JsonHandler {
}
}
async fn process_request_execute_subscenario(&self, request: Request) -> Result<Value, RpcErr> {
let req = ExecuteSubscenarioRequest::parse(Some(request.params))?;
{
let mut store = self.node_chain_store.lock().await;
match req.scenario_id {
1 => store
.subscenario_1()
.await
.map_err(cast_common_execution_error_into_rpc_error)?,
2 => store
.subscenario_2()
.await
.map_err(cast_common_execution_error_into_rpc_error)?,
3 => store
.subscenario_3()
.await
.map_err(cast_common_execution_error_into_rpc_error)?,
_ => return Err(RpcErr(RpcError::invalid_params("Scenario id not found"))),
}
}
let helperstruct = ExecuteSubscenarioResponse {
scenario_result: SUCCESS.to_string(),
};
respond(helperstruct)
}
async fn process_request_execute_scenario_split(
&self,
request: Request,
) -> Result<Value, RpcErr> {
let req = ExecuteScenarioSplitRequest::parse(Some(request.params))?;
{
let mut store = self.node_chain_store.lock().await;
store
.scenario_1(req.visibility_list, req.publication_index)
.await
.map_err(cast_common_execution_error_into_rpc_error)?;
}
let helperstruct = ExecuteScenarioSplitResponse {
scenario_result: SUCCESS.to_string(),
};
respond(helperstruct)
}
async fn process_request_execute_scenario_multiple_send(
&self,
request: Request,
) -> Result<Value, RpcErr> {
let req = ExecuteScenarioMultipleSendRequest::parse(Some(request.params))?;
{
let mut store = self.node_chain_store.lock().await;
store
.scenario_2(req.number_of_assets, req.number_to_send)
.await
.map_err(cast_common_execution_error_into_rpc_error)?;
}
let helperstruct = ExecuteScenarioMultipleSendResponse {
scenario_result: SUCCESS.to_string(),
};
respond(helperstruct)
}
async fn process_create_account(&self, request: Request) -> Result<Value, RpcErr> {
let _req = CreateAccountRequest::parse(Some(request.params))?;
@ -161,24 +73,6 @@ impl JsonHandler {
respond(helperstruct)
}
async fn process_get_block_data(&self, request: Request) -> Result<Value, RpcErr> {
let req = GetBlockDataRequest::parse(Some(request.params))?;
let block = {
let guard = self.node_chain_store.lock().await;
{
let read_guard = guard.storage.read().await;
read_guard.block_store.get_block_at_id(req.block_id)?
}
};
let helperstruct = GetBlockDataResponse { block };
respond(helperstruct)
}
async fn process_get_last_block(&self, request: Request) -> Result<Value, RpcErr> {
let _req = GetLastBlockRequest::parse(Some(request.params))?;
@ -349,406 +243,14 @@ impl JsonHandler {
respond(helperstruct)
}
pub async fn process_write_mint_utxo(&self, request: Request) -> Result<Value, RpcErr> {
let req = WriteMintPrivateUTXORequest::parse(Some(request.params))?;
let acc_addr_hex_dec = hex::decode(req.account_addr.clone()).map_err(|_| {
RpcError::parse_error("Failed to decode account address from hex string".to_string())
})?;
let acc_addr: [u8; 32] = acc_addr_hex_dec.try_into().map_err(|_| {
RpcError::parse_error("Failed to parse account address from bytes".to_string())
})?;
let (utxo, commitment_hash) = {
let mut cover_guard = self.node_chain_store.lock().await;
cover_guard
.operate_account_mint_private(acc_addr, req.amount as u128)
.await
.map_err(cast_common_execution_error_into_rpc_error)?
};
let helperstruct = WriteMintPrivateUTXOResponse {
status: SUCCESS.to_string(),
utxo: UTXOShortEssentialStruct {
hash: hex::encode(utxo.hash),
commitment_hash: hex::encode(commitment_hash),
asset: utxo.asset,
},
};
respond(helperstruct)
}
pub async fn process_write_mint_utxo_multiple_assets(
&self,
request: Request,
) -> Result<Value, RpcErr> {
let req = WriteMintPrivateUTXOMultipleAssetsRequest::parse(Some(request.params))?;
let acc_addr_hex_dec = hex::decode(req.account_addr.clone()).map_err(|_| {
RpcError::parse_error("Failed to decode account address from hex string".to_string())
})?;
let acc_addr: [u8; 32] = acc_addr_hex_dec.try_into().map_err(|_| {
RpcError::parse_error("Failed to parse account address from bytes".to_string())
})?;
let (utxos, commitment_hashes) = {
let mut cover_guard = self.node_chain_store.lock().await;
cover_guard
.operate_account_mint_multiple_assets_private(
acc_addr,
req.amount as u128,
req.num_of_assets,
)
.await
.map_err(cast_common_execution_error_into_rpc_error)?
};
let helperstruct = WriteMintPrivateUTXOMultipleAssetsResponse {
status: SUCCESS.to_string(),
utxos: utxos
.into_iter()
.zip(commitment_hashes)
.map(|(utxo, comm_hash)| UTXOShortEssentialStruct {
hash: hex::encode(utxo.hash),
commitment_hash: hex::encode(comm_hash),
asset: utxo.asset,
})
.collect(),
};
respond(helperstruct)
}
pub async fn process_write_send_private_utxo(&self, request: Request) -> Result<Value, RpcErr> {
let req = WriteSendPrivateUTXORequest::parse(Some(request.params))?;
let acc_addr_hex_dec_sender =
hex::decode(req.account_addr_sender.clone()).map_err(|_| {
RpcError::parse_error(
"Failed to decode account address from hex string".to_string(),
)
})?;
let acc_addr_sender: [u8; 32] = acc_addr_hex_dec_sender.try_into().map_err(|_| {
RpcError::parse_error("Failed to parse account address from bytes".to_string())
})?;
let acc_addr_hex_dec = hex::decode(req.account_addr_receiver.clone()).map_err(|_| {
RpcError::parse_error("Failed to decode account address from hex string".to_string())
})?;
let acc_addr: [u8; 32] = acc_addr_hex_dec.try_into().map_err(|_| {
RpcError::parse_error("Failed to parse account address from bytes".to_string())
})?;
let utxo_hash_hex_dec = hex::decode(req.utxo_hash.clone()).map_err(|_| {
RpcError::parse_error("Failed to decode utxo hash from hex string".to_string())
})?;
let utxo_hash: [u8; 32] = utxo_hash_hex_dec.try_into().map_err(|_| {
RpcError::parse_error("Failed to parse utxo hash from bytes".to_string())
})?;
let comm_hash_hex_dec = hex::decode(req.utxo_commitment.clone()).map_err(|_| {
RpcError::parse_error("Failed to decode commitment hash from hex string".to_string())
})?;
let comm_hash: [u8; 32] = comm_hash_hex_dec.try_into().map_err(|_| {
RpcError::parse_error("Failed to parse commitment hash from bytes".to_string())
})?;
let new_utxo_rec = {
let mut cover_guard = self.node_chain_store.lock().await;
let utxo_to_send = {
let mut under_guard = cover_guard.storage.write().await;
let acc = under_guard
.acc_map
.get_mut(&acc_addr_sender)
.ok_or(RpcError::new_internal_error(None, ACCOUNT_NOT_FOUND))?;
acc.utxos
.get(&utxo_hash)
.ok_or(RpcError::new_internal_error(
None,
"UTXO does not exist in tree",
))?
.clone()
};
cover_guard
.operate_account_send_private_one_receiver(acc_addr, utxo_to_send, comm_hash)
.await
.map_err(cast_common_execution_error_into_rpc_error)?
};
let helperstruct = WriteSendPrivateUTXOResponse {
status: SUCCESS.to_string(),
utxo_result: UTXOShortEssentialStruct {
hash: hex::encode(new_utxo_rec.hash),
asset: new_utxo_rec.asset.clone(),
commitment_hash: hex::encode(generate_commitments_helper(&[new_utxo_rec])[0]),
},
};
respond(helperstruct)
}
pub async fn process_write_send_shielded_utxo(
&self,
request: Request,
) -> Result<Value, RpcErr> {
let req = WriteSendShieldedUTXORequest::parse(Some(request.params))?;
let acc_addr_hex_dec_sender =
hex::decode(req.account_addr_sender.clone()).map_err(|_| {
RpcError::parse_error(
"Failed to decode account address sender from hex string".to_string(),
)
})?;
let acc_addr_sender: [u8; 32] = acc_addr_hex_dec_sender.try_into().map_err(|_| {
RpcError::parse_error("Failed to parse account address sender from bytes".to_string())
})?;
let acc_addr_hex_dec_rec =
hex::decode(req.account_addr_receiver.clone()).map_err(|_| {
RpcError::parse_error(
"Failed to decode account address receiver from hex string".to_string(),
)
})?;
let acc_addr_rec: [u8; 32] = acc_addr_hex_dec_rec.try_into().map_err(|_| {
RpcError::parse_error("Failed to parse account address receiver from bytes".to_string())
})?;
let new_utxo_rec = {
let mut cover_guard = self.node_chain_store.lock().await;
cover_guard
.operate_account_send_shielded_one_receiver(
acc_addr_sender,
acc_addr_rec,
req.amount as u128,
)
.await
.map_err(cast_common_execution_error_into_rpc_error)?
};
let helperstruct = WriteSendShieldedUTXOResponse {
status: SUCCESS.to_string(),
utxo_result: UTXOShortEssentialStruct {
hash: hex::encode(new_utxo_rec.hash),
asset: new_utxo_rec.asset.clone(),
commitment_hash: hex::encode(generate_commitments_helper(&[new_utxo_rec])[0]),
},
};
respond(helperstruct)
}
pub async fn process_write_send_deshielded_utxo(
&self,
request: Request,
) -> Result<Value, RpcErr> {
let req = WriteSendDeshieldedBalanceRequest::parse(Some(request.params))?;
let acc_addr_hex_dec_sender =
hex::decode(req.account_addr_sender.clone()).map_err(|_| {
RpcError::parse_error(
"Failed to decode account address from hex string".to_string(),
)
})?;
let acc_addr_sender: [u8; 32] = acc_addr_hex_dec_sender.try_into().map_err(|_| {
RpcError::parse_error("Failed to parse account address from bytes".to_string())
})?;
let acc_addr_hex_dec = hex::decode(req.account_addr_receiver.clone()).map_err(|_| {
RpcError::parse_error("Failed to decode account address from hex string".to_string())
})?;
let acc_addr: [u8; 32] = acc_addr_hex_dec.try_into().map_err(|_| {
RpcError::parse_error("Failed to parse account address from bytes".to_string())
})?;
let utxo_hash_hex_dec = hex::decode(req.utxo_hash.clone()).map_err(|_| {
RpcError::parse_error("Failed to decode utxo hash from hex string".to_string())
})?;
let utxo_hash: [u8; 32] = utxo_hash_hex_dec.try_into().map_err(|_| {
RpcError::parse_error("Failed to parse utxo hash from bytes".to_string())
})?;
let comm_hash_hex_dec = hex::decode(req.utxo_commitment.clone()).map_err(|_| {
RpcError::parse_error("Failed to decode commitment hash from hex string".to_string())
})?;
let comm_hash: [u8; 32] = comm_hash_hex_dec.try_into().map_err(|_| {
RpcError::parse_error("Failed to parse commitment hash from bytes".to_string())
})?;
{
let mut cover_guard = self.node_chain_store.lock().await;
let utxo_to_send = {
let mut under_guard = cover_guard.storage.write().await;
let acc = under_guard
.acc_map
.get_mut(&acc_addr_sender)
.ok_or(RpcError::new_internal_error(None, ACCOUNT_NOT_FOUND))?;
acc.utxos
.get(&utxo_hash)
.ok_or(RpcError::new_internal_error(
None,
"UTXO does not exist in tree",
))?
.clone()
};
cover_guard
.operate_account_send_deshielded_one_receiver(acc_addr, utxo_to_send, comm_hash)
.await
.map_err(cast_common_execution_error_into_rpc_error)?
};
let helperstruct = WriteSendDeshieldedUTXOResponse {
status: SUCCESS.to_string(),
};
respond(helperstruct)
}
pub async fn process_write_send_split_utxo(&self, request: Request) -> Result<Value, RpcErr> {
let req = WriteSplitUTXORequest::parse(Some(request.params))?;
let acc_addr_hex_dec_sender =
hex::decode(req.account_addr_sender.clone()).map_err(|_| {
RpcError::parse_error(
"Failed to decode account address from hex string".to_string(),
)
})?;
let acc_addr_sender: [u8; 32] = acc_addr_hex_dec_sender.try_into().map_err(|_| {
RpcError::parse_error("Failed to parse account address from bytes".to_string())
})?;
let acc_addresses = {
let mut res_addrs = vec![];
for item in req.account_addr_receivers {
let hex_dec_item = hex::decode(item).map_err(|_| {
RpcError::parse_error(
"Failed to decode account address from hex string".to_string(),
)
})?;
let dec_item = hex_dec_item.try_into().map_err(|_| {
RpcError::parse_error(
"Failed to decode account address from hex string".to_string(),
)
})?;
res_addrs.push(dec_item);
}
res_addrs.try_into().unwrap()
};
let utxo_hash_hex_dec = hex::decode(req.utxo_hash.clone()).map_err(|_| {
RpcError::parse_error("Failed to decode utxo hash from hex string".to_string())
})?;
let utxo_hash: [u8; 32] = utxo_hash_hex_dec.try_into().map_err(|_| {
RpcError::parse_error("Failed to parse utxo hash from bytes".to_string())
})?;
let comm_hash_hex_dec = hex::decode(req.utxo_commitment.clone()).map_err(|_| {
RpcError::parse_error("Failed to decode commitment hash from hex string".to_string())
})?;
let comm_hash: [u8; 32] = comm_hash_hex_dec.try_into().map_err(|_| {
RpcError::parse_error("Failed to parse commitment hash from bytes".to_string())
})?;
let (new_utxos, commitment_hashes) = {
let mut cover_guard = self.node_chain_store.lock().await;
let utxo_to_send = {
let mut under_guard = cover_guard.storage.write().await;
let acc = under_guard
.acc_map
.get_mut(&acc_addr_sender)
.ok_or(RpcError::new_internal_error(None, ACCOUNT_NOT_FOUND))?;
acc.utxos
.get(&utxo_hash)
.ok_or(RpcError::new_internal_error(
None,
"UTXO does not exist in tree",
))?
.clone()
};
cover_guard
.operate_account_send_split_utxo(
acc_addresses,
utxo_to_send,
comm_hash,
req.visibility_list,
)
.await
.map_err(cast_common_execution_error_into_rpc_error)?
};
let helperstruct = WriteSendSplitUTXOResponse {
status: SUCCESS.to_string(),
utxo_results: new_utxos
.into_iter()
.zip(commitment_hashes)
.map(|(utxo, comm_hash)| UTXOShortEssentialStruct {
hash: hex::encode(utxo.hash),
commitment_hash: hex::encode(comm_hash),
asset: utxo.asset,
})
.collect(),
};
respond(helperstruct)
}
pub async fn process_request_internal(&self, request: Request) -> Result<Value, RpcErr> {
match request.method.as_ref() {
//Todo : Add handling of more JSON RPC methods
CREATE_ACCOUNT => self.process_create_account(request).await,
EXECUTE_SUBSCENARIO => self.process_request_execute_subscenario(request).await,
GET_BLOCK => self.process_get_block_data(request).await,
GET_LAST_BLOCK => self.process_get_last_block(request).await,
EXECUTE_SCENARIO_SPLIT => self.process_request_execute_scenario_split(request).await,
EXECUTE_SCENARIO_MULTIPLE_SEND => {
self.process_request_execute_scenario_multiple_send(request)
.await
}
SHOW_ACCOUNT_PUBLIC_BALANCE => self.process_show_account_public_balance(request).await,
SHOW_ACCOUNT_UTXO => self.process_show_account_utxo_request(request).await,
SHOW_TRANSACTION => self.process_show_transaction(request).await,
WRITE_MINT_UTXO => self.process_write_mint_utxo(request).await,
WRITE_MINT_UTXO_MULTIPLE_ASSETS => {
self.process_write_mint_utxo_multiple_assets(request).await
}
WRITE_SEND_UTXO_PRIVATE => self.process_write_send_private_utxo(request).await,
WRITE_SEND_UTXO_SHIELDED => self.process_write_send_shielded_utxo(request).await,
WRITE_SEND_UTXO_DESHIELDED => self.process_write_send_deshielded_utxo(request).await,
WRITE_SPLIT_UTXO => self.process_write_send_split_utxo(request).await,
_ => Err(RpcErr(RpcError::method_not_found(request.method))),
}
}