fix: second complex scenario added

This commit is contained in:
Oleksandr Pravdyvyi 2025-01-03 12:43:05 +02:00
parent 31f782f214
commit 90d1a9bb9b
8 changed files with 659 additions and 24 deletions

View File

@ -54,6 +54,9 @@ impl EphemeralKeyHolder {
}
pub fn log(&self) {
info!("Ephemeral private key is {:?}", hex::encode(self.ephemeral_secret_key.to_bytes()));
info!(
"Ephemeral private key is {:?}",
hex::encode(self.ephemeral_secret_key.to_bytes())
);
}
}

View File

@ -5,7 +5,10 @@ use std::sync::{
use k256::elliptic_curve::group::GroupEncoding;
use ::storage::{nullifier::UTXONullifier, transaction::{Transaction, TransactionPayload, TxKind}};
use ::storage::{
nullifier::UTXONullifier,
transaction::{Transaction, TransactionPayload, TxKind},
};
use accounts::account_core::{Account, AccountAddress};
use anyhow::Result;
use config::NodeConfig;
@ -22,7 +25,8 @@ use storage::NodeChainStore;
use tokio::{sync::RwLock, task::JoinHandle};
use utxo::utxo_core::{Asset, UTXO};
use zkvm::{
prove_mint_utxo, prove_send_utxo, prove_send_utxo_deshielded, prove_send_utxo_shielded,
prove_mint_utxo, prove_mint_utxo_multiple_assets, prove_send_utxo, prove_send_utxo_deshielded,
prove_send_utxo_multiple_assets_one_receiver, prove_send_utxo_shielded,
};
pub const BLOCK_GEN_DELAY_SECS: u64 = 20;
@ -202,6 +206,58 @@ impl NodeCore {
)
}
pub async fn mint_utxo_multiple_assets_private(
&self,
acc: AccountAddress,
amount: u128,
number_of_assets: usize,
) -> (Transaction, Vec<[u8; 32]>) {
let (utxos, receipt) = prove_mint_utxo_multiple_assets(amount, number_of_assets, acc);
let result_hashes = utxos.iter().map(|utxo| utxo.hash).collect();
let acc_map_read_guard = self.storage.read().await;
let accout = acc_map_read_guard.acc_map.get(&acc).unwrap();
let ephm_key_holder = &accout.produce_ephemeral_key_holder();
ephm_key_holder.log();
let eph_pub_key = ephm_key_holder.generate_ephemeral_public_key().to_bytes();
let encoded_data = utxos
.iter()
.map(|utxo| {
Account::encrypt_data(
&ephm_key_holder,
accout.key_holder.viewing_public_key,
&serde_json::to_vec(&utxo).unwrap(),
)
})
.map(|(ciphertext, nonce)| (ciphertext, nonce.to_vec()))
.collect();
let comm = generate_commitments(&utxos);
(
TransactionPayload {
tx_kind: TxKind::Private,
execution_input: vec![],
execution_output: vec![],
utxo_commitments_spent_hashes: vec![],
utxo_commitments_created_hashes: comm
.into_iter()
.map(|hash_data| hash_data.try_into().unwrap())
.collect(),
nullifier_created_hashes: vec![],
execution_proof_private: hex::encode(serde_json::to_vec(&receipt).unwrap()),
encoded_data,
ephemeral_pub_key: eph_pub_key.to_vec(),
}
.into(),
result_hashes,
)
}
pub fn deposit_money_public(&self, acc: AccountAddress, amount: u128) -> Transaction {
TransactionPayload {
tx_kind: TxKind::Public,
@ -293,6 +349,106 @@ impl NodeCore {
)
}
pub async fn transfer_utxo_multiple_assets_private(
&self,
utxos: Vec<UTXO>,
commitments_in: Vec<[u8; 32]>,
number_to_send: usize,
receiver: AccountAddress,
) -> (Transaction, Vec<[u8; 32]>, Vec<[u8; 32]>) {
let acc_map_read_guard = self.storage.read().await;
let accout = acc_map_read_guard.acc_map.get(&utxos[0].owner).unwrap();
let nsk = accout
.key_holder
.utxo_secret_key_holder
.nullifier_secret_key
.to_bytes()
.to_vec();
let nullifiers = utxos
.iter()
.map(|utxo| generate_nullifiers(utxo, &nsk))
.map(|vecc| vecc.try_into().unwrap())
.collect();
let (resulting_utxos_receiver, resulting_utxos_not_spent, receipt) =
prove_send_utxo_multiple_assets_one_receiver(utxos, number_to_send, receiver);
let utxo_hashes_receiver = resulting_utxos_receiver
.iter()
.map(|utxo| utxo.hash)
.collect();
let utxo_hashes_not_spent = resulting_utxos_not_spent
.iter()
.map(|utxo| utxo.hash)
.collect();
let ephm_key_holder = &accout.produce_ephemeral_key_holder();
ephm_key_holder.log();
let eph_pub_key = ephm_key_holder.generate_ephemeral_public_key().to_bytes();
let mut encoded_data: Vec<(Vec<u8>, Vec<u8>)> = resulting_utxos_receiver
.iter()
.map(|utxo_enc| {
let accout_enc = acc_map_read_guard.acc_map.get(&utxo_enc.owner).unwrap();
let (ciphertext, nonce) = Account::encrypt_data(
&ephm_key_holder,
accout_enc.key_holder.viewing_public_key,
&serde_json::to_vec(&utxo_enc).unwrap(),
);
(ciphertext, nonce.to_vec())
})
.collect();
let encoded_data_1: Vec<(Vec<u8>, Vec<u8>)> = resulting_utxos_not_spent
.iter()
.map(|utxo_enc| {
let accout_enc = acc_map_read_guard.acc_map.get(&utxo_enc.owner).unwrap();
let (ciphertext, nonce) = Account::encrypt_data(
&ephm_key_holder,
accout_enc.key_holder.viewing_public_key,
&serde_json::to_vec(&utxo_enc).unwrap(),
);
(ciphertext, nonce.to_vec())
})
.collect();
encoded_data.extend(encoded_data_1);
let mut commitments = generate_commitments(&resulting_utxos_receiver);
let commitments_1 = generate_commitments(&resulting_utxos_not_spent);
commitments.extend(commitments_1);
(
TransactionPayload {
tx_kind: TxKind::Private,
execution_input: vec![],
execution_output: vec![],
utxo_commitments_spent_hashes: commitments_in,
utxo_commitments_created_hashes: commitments
.into_iter()
.map(|hash_data| hash_data.try_into().unwrap())
.collect(),
nullifier_created_hashes: nullifiers,
execution_proof_private: hex::encode(serde_json::to_vec(&receipt).unwrap()),
encoded_data,
ephemeral_pub_key: eph_pub_key.to_vec(),
}
.into(),
utxo_hashes_receiver,
utxo_hashes_not_spent,
)
}
pub async fn transfer_balance_shielded(
&self,
acc: AccountAddress,
@ -458,6 +614,31 @@ impl NodeCore {
))
}
pub async fn send_private_mint_multiple_assets_tx(
&self,
acc: AccountAddress,
amount: u128,
number_of_assets: usize,
) -> Result<(SendTxResponse, Vec<[u8; 32]>, Vec<[u8; 32]>)> {
let point_before_prove = std::time::Instant::now();
let (tx, utxo_hashes) = self
.mint_utxo_multiple_assets_private(acc, amount, number_of_assets)
.await;
tx.log();
let point_after_prove = std::time::Instant::now();
let commitment_generated_hashes = tx.utxo_commitments_created_hashes.clone();
let timedelta = (point_after_prove - point_before_prove).as_millis();
info!("Mint utxo proof spent {timedelta:?} milliseconds");
Ok((
self.sequencer_client.send_tx(tx).await?,
utxo_hashes,
commitment_generated_hashes,
))
}
pub async fn send_public_deposit(
&self,
acc: AccountAddress,
@ -486,6 +667,30 @@ impl NodeCore {
Ok((self.sequencer_client.send_tx(tx).await?, utxo_hashes))
}
pub async fn send_private_multiple_assets_send_tx(
&self,
utxos: Vec<UTXO>,
comm_hashes: Vec<[u8; 32]>,
number_to_send: usize,
receiver: AccountAddress,
) -> Result<(SendTxResponse, Vec<[u8; 32]>, Vec<[u8; 32]>)> {
let point_before_prove = std::time::Instant::now();
let (tx, utxo_hashes_received, utxo_hashes_not_spent) = self
.transfer_utxo_multiple_assets_private(utxos, comm_hashes, number_to_send, receiver)
.await;
tx.log();
let point_after_prove = std::time::Instant::now();
let timedelta = (point_after_prove - point_before_prove).as_millis();
info!("Send private utxo proof spent {timedelta:?} milliseconds");
Ok((
self.sequencer_client.send_tx(tx).await?,
utxo_hashes_received,
utxo_hashes_not_spent,
))
}
pub async fn send_shielded_send_tx(
&self,
acc: AccountAddress,
@ -560,6 +765,56 @@ impl NodeCore {
(new_utxo, comm_gen_hash)
}
async fn operate_account_mint_multiple_assets_private(
&mut self,
acc_addr: AccountAddress,
amount: u128,
number_of_assets: usize,
) -> (Vec<UTXO>, Vec<[u8; 32]>) {
let (resp, new_utxo_hashes, comm_gen_hashes) = self
.send_private_mint_multiple_assets_tx(acc_addr, amount, number_of_assets)
.await
.unwrap();
info!("Response for mint multiple assets private is {resp:?}");
info!("Awaiting new blocks");
tokio::time::sleep(std::time::Duration::from_secs(BLOCK_GEN_DELAY_SECS)).await;
let new_utxos = {
let mut write_guard = self.storage.write().await;
new_utxo_hashes
.into_iter()
.map(|new_utxo_hash| {
let acc = write_guard.acc_map.get_mut(&acc_addr).unwrap();
let new_utxo = acc
.utxo_tree
.get_item(new_utxo_hash)
.unwrap()
.unwrap()
.clone();
new_utxo.log();
info!(
"Account address is {:?} ,new utxo owner address is {:?}",
hex::encode(acc_addr),
hex::encode(new_utxo.owner)
);
info!(
"Account {:?} got new utxo with amount {amount:?} and asset {:?}",
hex::encode(acc_addr),
new_utxo.asset
);
new_utxo
})
.collect()
};
(new_utxos, comm_gen_hashes)
}
async fn operate_account_send_deshielded_one_receiver(
&mut self,
acc_addr_sender: AccountAddress,
@ -727,6 +982,83 @@ impl NodeCore {
);
}
async fn operate_account_send_private_multiple_assets_one_receiver(
&mut self,
acc_addr: AccountAddress,
acc_addr_rec: AccountAddress,
utxos: Vec<UTXO>,
comm_gen_hashes: Vec<[u8; 32]>,
number_to_send: usize,
) {
let (resp, new_utxo_hashes_rec, new_utxo_hashes_not_sp) = self
.send_private_multiple_assets_send_tx(
utxos,
comm_gen_hashes,
number_to_send,
acc_addr_rec,
)
.await
.unwrap();
info!("Response for send private multiple assets is {resp:?}");
info!("Awaiting new blocks");
tokio::time::sleep(std::time::Duration::from_secs(BLOCK_GEN_DELAY_SECS)).await;
{
let mut write_guard = self.storage.write().await;
for new_utxo_hash in new_utxo_hashes_rec {
let acc = write_guard.acc_map.get_mut(&acc_addr_rec).unwrap();
acc.log();
let new_utxo = acc
.utxo_tree
.get_item(new_utxo_hash)
.unwrap()
.unwrap()
.clone();
new_utxo.log();
info!(
"Account address is {:?} ,new utxo owner address is {:?}",
hex::encode(acc_addr_rec),
hex::encode(new_utxo.owner)
);
info!(
"Account {:?} got new utxo with amount {:?} and asset {:?}",
hex::encode(acc_addr_rec),
new_utxo.amount,
new_utxo.asset,
);
}
for new_utxo_hash in new_utxo_hashes_not_sp {
let acc = write_guard.acc_map.get_mut(&acc_addr).unwrap();
acc.log();
let new_utxo = acc
.utxo_tree
.get_item(new_utxo_hash)
.unwrap()
.unwrap()
.clone();
new_utxo.log();
info!(
"Account address is {:?} ,new utxo owner address is {:?}",
hex::encode(acc_addr),
hex::encode(new_utxo.owner)
);
info!(
"Account {:?} got new utxo with amount {:?} and asset {:?}",
hex::encode(acc_addr),
new_utxo.amount,
new_utxo.asset,
);
}
}
}
pub async fn split_utxo(
&self,
utxo: UTXO,
@ -999,4 +1331,23 @@ impl NodeCore {
)
.await;
}
///Mint number of different assets with same amount for account
pub async fn scenario_2(&mut self, number_of_assets: usize, number_to_send: usize) {
let acc_addr_sender = self.create_new_account().await;
let acc_addr_receiver = self.create_new_account().await;
let (utxos, comm_gen_hashes) = self
.operate_account_mint_multiple_assets_private(acc_addr_sender, 100, number_of_assets)
.await;
self.operate_account_send_private_multiple_assets_one_receiver(
acc_addr_sender,
acc_addr_receiver,
utxos,
comm_gen_hashes,
number_to_send,
)
.await;
}
}

View File

@ -14,7 +14,11 @@ use crate::{
types::{
err_rpc::cast_seq_client_error_into_rpc_error,
rpc_structs::{
ExecuteScenarioSplitRequest, ExecuteScenarioSplitResponse, ExecuteSubscenarioRequest, ExecuteSubscenarioResponse, GetBlockDataRequest, GetBlockDataResponse, GetLastBlockRequest, GetLastBlockResponse, RegisterAccountRequest, RegisterAccountResponse, SendTxRequest
ExecuteScenarioMultipleSendRequest, ExecuteScenarioMultipleSendResponse,
ExecuteScenarioSplitRequest, ExecuteScenarioSplitResponse, ExecuteSubscenarioRequest,
ExecuteSubscenarioResponse, GetBlockDataRequest, GetBlockDataResponse,
GetLastBlockRequest, GetLastBlockResponse, RegisterAccountRequest,
RegisterAccountResponse, SendTxRequest,
},
},
};
@ -61,13 +65,18 @@ impl JsonHandler {
respond(helperstruct)
}
async fn process_request_execute_scenario_split(&self, request: Request) -> Result<Value, RpcErr> {
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;
store
.scenario_1(req.visibility_list, req.publication_index)
.await;
}
let helperstruct = ExecuteScenarioSplitResponse {
@ -77,6 +86,27 @@ impl JsonHandler {
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;
}
let helperstruct = ExecuteScenarioMultipleSendResponse {
scenario_result: "success".to_string(),
};
respond(helperstruct)
}
async fn process_register_account(&self, request: Request) -> Result<Value, RpcErr> {
let _req = RegisterAccountRequest::parse(Some(request.params))?;
@ -154,6 +184,10 @@ impl JsonHandler {
"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
}
_ => Err(RpcErr(RpcError::method_not_found(request.method))),
}
}

View File

@ -31,6 +31,12 @@ pub struct ExecuteScenarioSplitRequest {
pub publication_index: usize,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct ExecuteScenarioMultipleSendRequest {
pub number_of_assets: usize,
pub number_to_send: usize,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct GetGenesisIdRequest {}
@ -43,6 +49,7 @@ parse_request!(GetBlockDataRequest);
parse_request!(GetGenesisIdRequest);
parse_request!(ExecuteSubscenarioRequest);
parse_request!(ExecuteScenarioSplitRequest);
parse_request!(ExecuteScenarioMultipleSendRequest);
parse_request!(GetLastBlockRequest);
#[derive(Serialize, Deserialize, Debug)]
@ -75,6 +82,11 @@ pub struct ExecuteScenarioSplitResponse {
pub scenario_result: String,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct ExecuteScenarioMultipleSendResponse {
pub scenario_result: String,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct GetGenesisIdResponse {
pub genesis_id: u64,

View File

@ -91,30 +91,117 @@ impl From<TransactionPayload> for Transaction {
}
}
#[derive(Debug, Serialize, Deserialize)]
pub struct MintMoneyPublicTx {
pub acc: [u8; 32],
pub amount: u128,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct SendMoneyShieldedTx {
pub acc_sender: [u8; 32],
pub amount: u128,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct SendMoneyDeshieldedTx {
pub receiver_data: Vec<(u128, [u8; 32])>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct OwnedUTXO {
pub hash: [u8; 32],
pub owner: [u8; 32],
pub amount: u128,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct OwnedUTXOForPublication {
pub hash: String,
pub owner: String,
pub amount: u128,
}
impl From<OwnedUTXO> for OwnedUTXOForPublication {
fn from(value: OwnedUTXO) -> Self {
Self {
hash: hex::encode(value.hash),
owner: hex::encode(value.owner),
amount: value.amount,
}
}
}
#[derive(Debug, Serialize, Deserialize)]
pub struct UTXOPublication {
pub utxos: Vec<OwnedUTXO>,
}
#[derive(Debug, Serialize, Deserialize)]
pub enum ActionData {
MintMoneyPublicTx(MintMoneyPublicTx),
SendMoneyShieldedTx(SendMoneyShieldedTx),
SendMoneyDeshieldedTx(SendMoneyDeshieldedTx),
UTXOPublication(UTXOPublication),
}
impl ActionData {
pub fn into_hexed_print(self) -> String {
match self {
ActionData::MintMoneyPublicTx(action) => {
format!(
"Account {:?} minted {:?} balance",
hex::encode(action.acc),
action.amount
)
}
ActionData::SendMoneyDeshieldedTx(action) => {
format!(
"Receivers receipt {:?}",
action
.receiver_data
.into_iter()
.map(|(amount, rec)| (amount, hex::encode(rec)))
.collect::<Vec<_>>()
)
}
ActionData::SendMoneyShieldedTx(action) => {
format!(
"Shielded send from {:?} for {:?} balance",
hex::encode(action.acc_sender),
action.amount
)
}
ActionData::UTXOPublication(action) => {
let pub_own_utxo: Vec<OwnedUTXOForPublication> = action
.utxos
.into_iter()
.map(|owned_utxo| owned_utxo.into())
.collect();
format!("Published utxos {:?}", pub_own_utxo)
}
}
}
}
impl Transaction {
pub fn log(&self) {
info!("Transaction hash is {:?}", hex::encode(self.hash));
info!("Transaction tx_kind is {:?}", self.tx_kind);
info!(
"Transaction execution_input is {:?}",
{
if let Ok(vall) = serde_json::from_slice::<serde_json::Value>(&self.execution_input) {
vall
} else {
serde_json::Value::Null
}
info!("Transaction execution_input is {:?}", {
if let Ok(action) = serde_json::from_slice::<ActionData>(&self.execution_input) {
action.into_hexed_print()
} else {
"".to_string()
}
);
info!(
"Transaction execution_output is {:?}",
{
if let Ok(vall) = serde_json::from_slice::<serde_json::Value>(&self.execution_output) {
vall
} else {
serde_json::Value::Null
}
});
info!("Transaction execution_output is {:?}", {
if let Ok(action) = serde_json::from_slice::<ActionData>(&self.execution_output) {
action.into_hexed_print()
} else {
"".to_string()
}
);
});
info!(
"Transaction utxo_commitments_spent_hashes is {:?}",
self.utxo_commitments_spent_hashes

View File

@ -52,6 +52,47 @@ pub fn prove_send_utxo(
)
}
pub fn prove_send_utxo_multiple_assets_one_receiver(
spent_utxos: Vec<UTXO>,
number_to_send: usize,
receiver: AccountAddress,
) -> (Vec<UTXO>, Vec<UTXO>, Receipt) {
let mut builder = ExecutorEnv::builder();
let utxo_payload: Vec<UTXOPayload> = spent_utxos
.into_iter()
.map(|spent_utxo| spent_utxo.into_payload())
.collect();
builder.write(&utxo_payload).unwrap();
builder.write(&number_to_send).unwrap();
builder.write(&receiver).unwrap();
let env = builder.build().unwrap();
let prover = default_prover();
let receipt = prover
.prove(env, test_methods::SEND_UTXO_MULTIPLE_ASSETS_ELF)
.unwrap()
.receipt;
let digest: (Vec<UTXOPayload>, Vec<UTXOPayload>) = receipt.journal.decode().unwrap();
(
digest
.0
.into_iter()
.map(|payload| UTXO::create_utxo_from_payload(payload))
.collect(),
digest
.1
.into_iter()
.map(|payload| UTXO::create_utxo_from_payload(payload))
.collect(),
receipt,
)
}
pub fn prove_send_utxo_shielded(
owner: AccountAddress,
amount: u128,
@ -120,6 +161,37 @@ pub fn prove_send_utxo_deshielded(
)
}
pub fn prove_mint_utxo_multiple_assets(
amount_to_mint: u128,
number_of_assets: usize,
owner: AccountAddress,
) -> (Vec<UTXO>, Receipt) {
let mut builder = ExecutorEnv::builder();
builder.write(&amount_to_mint).unwrap();
builder.write(&number_of_assets).unwrap();
builder.write(&owner).unwrap();
let env = builder.build().unwrap();
let prover = default_prover();
let receipt = prover
.prove(env, test_methods::MINT_UTXO_MULTIPLE_ASSETS_ELF)
.unwrap()
.receipt;
let digest: Vec<UTXOPayload> = receipt.journal.decode().unwrap();
(
digest
.into_iter()
.map(UTXO::create_utxo_from_payload)
.collect(),
receipt,
)
}
pub fn execute_mint_utxo(amount_to_mint: u128, owner: AccountAddress) -> UTXO {
let mut builder = ExecutorEnv::builder();

View File

@ -0,0 +1,36 @@
use risc0_zkvm::{
guest::env,
};
use serde::{Deserialize, Serialize};
type AccountAddr = [u8; 32];
#[derive(Serialize, Deserialize)]
pub struct UTXOPayload {
pub owner: AccountAddr,
pub asset: Vec<u8>,
// TODO: change to u256
pub amount: u128,
pub privacy_flag: bool,
}
fn main() {
let amount_to_mint: u128 = env::read();
let number_of_assets: usize = env::read();
let owner: AccountAddr = env::read();
let mut asseted_utxos = vec![];
for i in 0..number_of_assets {
let payload = UTXOPayload {
owner,
asset: vec![i as u8],
amount: amount_to_mint,
privacy_flag: true,
};
asseted_utxos.push(payload);
}
env::commit(&(asseted_utxos));
}

View File

@ -0,0 +1,40 @@
use risc0_zkvm::{
guest::env,
};
use serde::{Deserialize, Serialize};
type AccountAddr = [u8; 32];
#[derive(Clone, Serialize, Deserialize)]
pub struct UTXOPayload {
pub owner: AccountAddr,
pub asset: Vec<u8>,
// TODO: change to u256
pub amount: u128,
pub privacy_flag: bool,
}
fn main() {
let utxo_spent: Vec<UTXOPayload> = env::read();
let number_to_send = env::read();
let receiver: AccountAddr = env::read();
let mut utxo_received = vec![];
let mut utxo_not_spent = vec![];
for i in 0..utxo_spent.len() {
let mut utxo_payload = utxo_spent[i].clone();
if i < number_to_send {
utxo_payload.owner = receiver;
utxo_received.push(utxo_payload);
} else {
utxo_payload.asset.push(0);
utxo_not_spent.push(utxo_payload);
}
}
env::commit(&(utxo_received, utxo_not_spent));
}