mirror of
https://github.com/logos-blockchain/logos-execution-zone.git
synced 2026-05-18 14:09:35 +00:00
Merge branch 'main' into schouhy/code-cleanup
This commit is contained in:
commit
d99fbde101
@ -13,8 +13,9 @@ use serde_json::Value;
|
|||||||
use crate::error::{SequencerClientError, SequencerRpcError};
|
use crate::error::{SequencerClientError, SequencerRpcError};
|
||||||
use crate::rpc_primitives::requests::{
|
use crate::rpc_primitives::requests::{
|
||||||
GetAccountRequest, GetAccountResponse, GetAccountsNoncesRequest, GetAccountsNoncesResponse,
|
GetAccountRequest, GetAccountResponse, GetAccountsNoncesRequest, GetAccountsNoncesResponse,
|
||||||
GetProgramIdsRequest, GetProgramIdsResponse, GetProofForCommitmentRequest,
|
GetLastBlockRequest, GetLastBlockResponse, GetProgramIdsRequest, GetProgramIdsResponse,
|
||||||
GetProofForCommitmentResponse, GetTransactionByHashRequest, GetTransactionByHashResponse,
|
GetProofForCommitmentRequest, GetProofForCommitmentResponse, GetTransactionByHashRequest,
|
||||||
|
GetTransactionByHashResponse,
|
||||||
};
|
};
|
||||||
use crate::sequencer_client::json::AccountInitialData;
|
use crate::sequencer_client::json::AccountInitialData;
|
||||||
use crate::transaction::{EncodedTransaction, NSSATransaction};
|
use crate::transaction::{EncodedTransaction, NSSATransaction};
|
||||||
@ -77,6 +78,19 @@ impl SequencerClient {
|
|||||||
Ok(resp_deser)
|
Ok(resp_deser)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///Get last known `blokc_id` from sequencer
|
||||||
|
pub async fn get_last_block(&self) -> Result<GetLastBlockResponse, SequencerClientError> {
|
||||||
|
let block_req = GetLastBlockRequest {};
|
||||||
|
|
||||||
|
let req = serde_json::to_value(block_req)?;
|
||||||
|
|
||||||
|
let resp = self.call_method_with_payload("get_last_block", req).await?;
|
||||||
|
|
||||||
|
let resp_deser = serde_json::from_value(resp)?;
|
||||||
|
|
||||||
|
Ok(resp_deser)
|
||||||
|
}
|
||||||
|
|
||||||
///Get account public balance for `address`. `address` must be a valid hex-string for 32 bytes.
|
///Get account public balance for `address`. `address` must be a valid hex-string for 32 bytes.
|
||||||
pub async fn get_account_balance(
|
pub async fn get_account_balance(
|
||||||
&self,
|
&self,
|
||||||
@ -241,7 +255,26 @@ impl SequencerClient {
|
|||||||
Ok(resp_deser)
|
Ok(resp_deser)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get Ids of the programs used by the node
|
pub async fn send_tx_program(
|
||||||
|
&self,
|
||||||
|
transaction: nssa::ProgramDeploymentTransaction,
|
||||||
|
) -> Result<SendTxResponse, SequencerClientError> {
|
||||||
|
let transaction = EncodedTransaction::from(NSSATransaction::ProgramDeployment(transaction));
|
||||||
|
|
||||||
|
let tx_req = SendTxRequest {
|
||||||
|
transaction: borsh::to_vec(&transaction).unwrap(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let req = serde_json::to_value(tx_req)?;
|
||||||
|
|
||||||
|
let resp = self.call_method_with_payload("send_tx", req).await?;
|
||||||
|
|
||||||
|
let resp_deser = serde_json::from_value(resp)?;
|
||||||
|
|
||||||
|
Ok(resp_deser)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get Ids of the programs used by the node
|
||||||
pub async fn get_program_ids(
|
pub async fn get_program_ids(
|
||||||
&self,
|
&self,
|
||||||
) -> Result<HashMap<String, ProgramId>, SequencerClientError> {
|
) -> Result<HashMap<String, ProgramId>, SequencerClientError> {
|
||||||
|
|||||||
@ -10,6 +10,7 @@ pub type HashType = [u8; 32];
|
|||||||
pub enum NSSATransaction {
|
pub enum NSSATransaction {
|
||||||
Public(nssa::PublicTransaction),
|
Public(nssa::PublicTransaction),
|
||||||
PrivacyPreserving(nssa::PrivacyPreservingTransaction),
|
PrivacyPreserving(nssa::PrivacyPreservingTransaction),
|
||||||
|
ProgramDeployment(nssa::ProgramDeploymentTransaction),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<nssa::PublicTransaction> for NSSATransaction {
|
impl From<nssa::PublicTransaction> for NSSATransaction {
|
||||||
@ -24,12 +25,19 @@ impl From<nssa::PrivacyPreservingTransaction> for NSSATransaction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<nssa::ProgramDeploymentTransaction> for NSSATransaction {
|
||||||
|
fn from(value: nssa::ProgramDeploymentTransaction) -> Self {
|
||||||
|
Self::ProgramDeployment(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(
|
#[derive(
|
||||||
Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, BorshSerialize, BorshDeserialize,
|
Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, BorshSerialize, BorshDeserialize,
|
||||||
)]
|
)]
|
||||||
pub enum TxKind {
|
pub enum TxKind {
|
||||||
Public,
|
Public,
|
||||||
PrivacyPreserving,
|
PrivacyPreserving,
|
||||||
|
ProgramDeployment,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
|
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
|
||||||
@ -51,6 +59,10 @@ impl From<NSSATransaction> for EncodedTransaction {
|
|||||||
tx_kind: TxKind::PrivacyPreserving,
|
tx_kind: TxKind::PrivacyPreserving,
|
||||||
encoded_transaction_data: tx.to_bytes(),
|
encoded_transaction_data: tx.to_bytes(),
|
||||||
},
|
},
|
||||||
|
NSSATransaction::ProgramDeployment(tx) => Self {
|
||||||
|
tx_kind: TxKind::ProgramDeployment,
|
||||||
|
encoded_transaction_data: tx.to_bytes(),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -66,6 +78,10 @@ impl TryFrom<&EncodedTransaction> for NSSATransaction {
|
|||||||
nssa::PrivacyPreservingTransaction::from_bytes(&value.encoded_transaction_data)
|
nssa::PrivacyPreservingTransaction::from_bytes(&value.encoded_transaction_data)
|
||||||
.map(|tx| tx.into())
|
.map(|tx| tx.into())
|
||||||
}
|
}
|
||||||
|
TxKind::ProgramDeployment => {
|
||||||
|
nssa::ProgramDeploymentTransaction::from_bytes(&value.encoded_transaction_data)
|
||||||
|
.map(|tx| tx.into())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,11 +8,11 @@
|
|||||||
"port": 3040,
|
"port": 3040,
|
||||||
"initial_accounts": [
|
"initial_accounts": [
|
||||||
{
|
{
|
||||||
"addr": "0eee24287296ba55278f1e5403be014754866366388730303c2889be17ada065",
|
"addr": "d07ad2e84b27fa00c262f0a1eea0ff35ca0973547e6a106f72f193c2dc838b44",
|
||||||
"balance": 10000
|
"balance": 10000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"addr": "9e3d8e654d440e95293aa2dceceb137899a59535e952f747068e7a0ee30965f2",
|
"addr": "e7ae77c5ef1a05999344af499fc78a1705398d62ed06cf2e1479f6def89a39bc",
|
||||||
"balance": 20000
|
"balance": 20000
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|||||||
@ -9,7 +9,7 @@
|
|||||||
"initial_accounts": [
|
"initial_accounts": [
|
||||||
{
|
{
|
||||||
"Public": {
|
"Public": {
|
||||||
"address": "0eee24287296ba55278f1e5403be014754866366388730303c2889be17ada065",
|
"address": "d07ad2e84b27fa00c262f0a1eea0ff35ca0973547e6a106f72f193c2dc838b44",
|
||||||
"pub_sign_key": [
|
"pub_sign_key": [
|
||||||
1,
|
1,
|
||||||
1,
|
1,
|
||||||
@ -48,7 +48,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Public": {
|
"Public": {
|
||||||
"address": "9e3d8e654d440e95293aa2dceceb137899a59535e952f747068e7a0ee30965f2",
|
"address": "e7ae77c5ef1a05999344af499fc78a1705398d62ed06cf2e1479f6def89a39bc",
|
||||||
"pub_sign_key": [
|
"pub_sign_key": [
|
||||||
2,
|
2,
|
||||||
2,
|
2,
|
||||||
@ -87,7 +87,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Private": {
|
"Private": {
|
||||||
"address": "9cb6b0035320266e430eac9d96745769e7efcf30d2b9cc21ff000b3f873dc2a8",
|
"address": "d360d6b5763f71ac6af56253687fd7d556d5c6c64312e53c0b92ef039a4375df",
|
||||||
"account": {
|
"account": {
|
||||||
"program_owner": [
|
"program_owner": [
|
||||||
0,
|
0,
|
||||||
@ -316,7 +316,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Private": {
|
"Private": {
|
||||||
"address": "a55f4f98d2f265c91d8a9868564242d8070b9bf7180a29363f52eb76988636fd",
|
"address": "f27087ffc29b99035303697dcf6c8e323b1847d4261e6afd49e0d71c6dfa31ea",
|
||||||
"account": {
|
"account": {
|
||||||
"program_owner": [
|
"program_owner": [
|
||||||
0,
|
0,
|
||||||
|
|||||||
BIN
integration_tests/src/data_changer.bin
Normal file
BIN
integration_tests/src/data_changer.bin
Normal file
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@ -14,6 +14,7 @@ secp256k1 = "0.31.1"
|
|||||||
rand = "0.8"
|
rand = "0.8"
|
||||||
borsh = "1.5.7"
|
borsh = "1.5.7"
|
||||||
hex = "0.4.3"
|
hex = "0.4.3"
|
||||||
|
risc0-binfmt = "3.0.2"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
risc0-build = "3.0.3"
|
risc0-build = "3.0.3"
|
||||||
|
|||||||
@ -54,7 +54,7 @@ impl EncryptionScheme {
|
|||||||
) -> [u8; 32] {
|
) -> [u8; 32] {
|
||||||
let mut bytes = Vec::new();
|
let mut bytes = Vec::new();
|
||||||
|
|
||||||
bytes.extend_from_slice(b"NSSA/v0.1/KDF-SHA256");
|
bytes.extend_from_slice(b"NSSA/v0.2/KDF-SHA256/");
|
||||||
bytes.extend_from_slice(&shared_secret.0);
|
bytes.extend_from_slice(&shared_secret.0);
|
||||||
bytes.extend_from_slice(&commitment.to_byte_array());
|
bytes.extend_from_slice(&commitment.to_byte_array());
|
||||||
bytes.extend_from_slice(&output_index.to_le_bytes());
|
bytes.extend_from_slice(&output_index.to_le_bytes());
|
||||||
|
|||||||
@ -9,7 +9,7 @@ pub struct NullifierPublicKey(pub [u8; 32]);
|
|||||||
|
|
||||||
impl From<&NullifierPublicKey> for AccountId {
|
impl From<&NullifierPublicKey> for AccountId {
|
||||||
fn from(value: &NullifierPublicKey) -> Self {
|
fn from(value: &NullifierPublicKey) -> Self {
|
||||||
const PRIVATE_ACCOUNT_ID_PREFIX: &[u8; 32] = b"/NSSA/v0.1/AccountId/Private/\x00\x00\x00";
|
const PRIVATE_ACCOUNT_ID_PREFIX: &[u8; 32] = b"/NSSA/v0.2/AccountId/Private/\x00\x00\x00";
|
||||||
|
|
||||||
let mut bytes = [0; 64];
|
let mut bytes = [0; 64];
|
||||||
bytes[0..32].copy_from_slice(PRIVATE_ACCOUNT_ID_PREFIX);
|
bytes[0..32].copy_from_slice(PRIVATE_ACCOUNT_ID_PREFIX);
|
||||||
@ -46,7 +46,7 @@ pub struct Nullifier(pub(super) [u8; 32]);
|
|||||||
|
|
||||||
impl Nullifier {
|
impl Nullifier {
|
||||||
pub fn for_account_update(commitment: &Commitment, nsk: &NullifierSecretKey) -> Self {
|
pub fn for_account_update(commitment: &Commitment, nsk: &NullifierSecretKey) -> Self {
|
||||||
const UPDATE_PREFIX: &[u8; 32] = b"/NSSA/v0.1/Nullifier/Update/\x00\x00\x00\x00";
|
const UPDATE_PREFIX: &[u8; 32] = b"/NSSA/v0.2/Nullifier/Update/\x00\x00\x00\x00";
|
||||||
let mut bytes = UPDATE_PREFIX.to_vec();
|
let mut bytes = UPDATE_PREFIX.to_vec();
|
||||||
bytes.extend_from_slice(&commitment.to_byte_array());
|
bytes.extend_from_slice(&commitment.to_byte_array());
|
||||||
bytes.extend_from_slice(nsk);
|
bytes.extend_from_slice(nsk);
|
||||||
@ -54,7 +54,7 @@ impl Nullifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn for_account_initialization(npk: &NullifierPublicKey) -> Self {
|
pub fn for_account_initialization(npk: &NullifierPublicKey) -> Self {
|
||||||
const INIT_PREFIX: &[u8; 32] = b"/NSSA/v0.1/Nullifier/Initialize/";
|
const INIT_PREFIX: &[u8; 32] = b"/NSSA/v0.2/Nullifier/Initialize/";
|
||||||
let mut bytes = INIT_PREFIX.to_vec();
|
let mut bytes = INIT_PREFIX.to_vec();
|
||||||
bytes.extend_from_slice(&npk.to_byte_array());
|
bytes.extend_from_slice(&npk.to_byte_array());
|
||||||
Self(Impl::hash_bytes(&bytes).as_bytes().try_into().unwrap())
|
Self(Impl::hash_bytes(&bytes).as_bytes().try_into().unwrap())
|
||||||
@ -70,8 +70,8 @@ mod tests {
|
|||||||
let commitment = Commitment((0..32u8).collect::<Vec<_>>().try_into().unwrap());
|
let commitment = Commitment((0..32u8).collect::<Vec<_>>().try_into().unwrap());
|
||||||
let nsk = [0x42; 32];
|
let nsk = [0x42; 32];
|
||||||
let expected_nullifier = Nullifier([
|
let expected_nullifier = Nullifier([
|
||||||
235, 128, 185, 229, 74, 74, 83, 13, 165, 48, 239, 24, 48, 101, 71, 251, 253, 92, 88,
|
148, 243, 116, 209, 140, 231, 211, 61, 35, 62, 114, 110, 143, 224, 82, 201, 221, 34,
|
||||||
201, 103, 43, 250, 135, 193, 54, 175, 82, 245, 171, 90, 135,
|
53, 80, 185, 48, 174, 28, 203, 43, 94, 187, 85, 199, 115, 81,
|
||||||
]);
|
]);
|
||||||
let nullifier = Nullifier::for_account_update(&commitment, &nsk);
|
let nullifier = Nullifier::for_account_update(&commitment, &nsk);
|
||||||
assert_eq!(nullifier, expected_nullifier);
|
assert_eq!(nullifier, expected_nullifier);
|
||||||
@ -84,8 +84,8 @@ mod tests {
|
|||||||
255, 29, 105, 42, 186, 43, 11, 157, 168, 132, 225, 17, 163,
|
255, 29, 105, 42, 186, 43, 11, 157, 168, 132, 225, 17, 163,
|
||||||
]);
|
]);
|
||||||
let expected_nullifier = Nullifier([
|
let expected_nullifier = Nullifier([
|
||||||
96, 99, 33, 1, 116, 84, 169, 18, 85, 201, 17, 243, 123, 240, 242, 34, 116, 233, 92,
|
1, 6, 59, 168, 16, 146, 65, 252, 255, 91, 48, 85, 116, 189, 110, 218, 110, 136, 163,
|
||||||
203, 247, 92, 161, 162, 135, 66, 127, 108, 230, 149, 105, 157,
|
193, 245, 103, 51, 27, 235, 170, 215, 115, 97, 144, 36, 238,
|
||||||
]);
|
]);
|
||||||
let nullifier = Nullifier::for_account_initialization(&npk);
|
let nullifier = Nullifier::for_account_initialization(&npk);
|
||||||
assert_eq!(nullifier, expected_nullifier);
|
assert_eq!(nullifier, expected_nullifier);
|
||||||
@ -113,8 +113,8 @@ mod tests {
|
|||||||
];
|
];
|
||||||
let npk = NullifierPublicKey::from(&nsk);
|
let npk = NullifierPublicKey::from(&nsk);
|
||||||
let expected_account_id = AccountId::new([
|
let expected_account_id = AccountId::new([
|
||||||
69, 160, 50, 67, 12, 56, 150, 116, 62, 145, 17, 161, 17, 45, 24, 53, 33, 167, 83, 178,
|
18, 153, 225, 78, 35, 214, 212, 205, 152, 83, 18, 246, 69, 41, 20, 217, 85, 1, 108, 7,
|
||||||
47, 114, 111, 233, 251, 30, 54, 244, 184, 22, 100, 236,
|
87, 133, 181, 53, 247, 221, 174, 12, 112, 194, 34, 121,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
let account_id = AccountId::from(&npk);
|
let account_id = AccountId::from(&npk);
|
||||||
|
|||||||
@ -21,9 +21,6 @@ fn main() {
|
|||||||
program_id,
|
program_id,
|
||||||
} = env::read();
|
} = env::read();
|
||||||
|
|
||||||
// TODO: Check that `program_execution_proof` is one of the allowed built-in programs
|
|
||||||
// assert_eq!(program_id, AUTHENTICATED_TRANSFER_PROGRAM_ID);
|
|
||||||
|
|
||||||
// Check that `program_output` is consistent with the execution of the corresponding program.
|
// Check that `program_output` is consistent with the execution of the corresponding program.
|
||||||
env::verify(program_id, &to_vec(&program_output).unwrap()).unwrap();
|
env::verify(program_id, &to_vec(&program_output).unwrap()).unwrap();
|
||||||
|
|
||||||
|
|||||||
@ -1,2 +1,3 @@
|
|||||||
pub mod privacy_preserving_transaction;
|
pub mod privacy_preserving_transaction;
|
||||||
|
pub mod program_deployment_transaction;
|
||||||
pub mod public_transaction;
|
pub mod public_transaction;
|
||||||
|
|||||||
@ -16,8 +16,9 @@ use crate::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const MESSAGE_ENCODING_PREFIX_LEN: usize = 22;
|
const MESSAGE_ENCODING_PREFIX_LEN: usize = 32;
|
||||||
const MESSAGE_ENCODING_PREFIX: &[u8; MESSAGE_ENCODING_PREFIX_LEN] = b"\x01/NSSA/v0.1/TxMessage/";
|
const MESSAGE_ENCODING_PREFIX: &[u8; MESSAGE_ENCODING_PREFIX_LEN] =
|
||||||
|
b"/NSSA/v0.2/TxMessage/Private/\x00\x00\x00";
|
||||||
|
|
||||||
impl EncryptedAccountData {
|
impl EncryptedAccountData {
|
||||||
pub fn to_bytes(&self) -> Vec<u8> {
|
pub fn to_bytes(&self) -> Vec<u8> {
|
||||||
|
|||||||
86
nssa/src/encoding/program_deployment_transaction.rs
Normal file
86
nssa/src/encoding/program_deployment_transaction.rs
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
// TODO: Consider switching to deriving Borsh
|
||||||
|
|
||||||
|
use std::io::{Cursor, Read};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
ProgramDeploymentTransaction, error::NssaError, program_deployment_transaction::Message,
|
||||||
|
};
|
||||||
|
|
||||||
|
const MESSAGE_ENCODING_PREFIX_LEN: usize = 32;
|
||||||
|
const MESSAGE_ENCODING_PREFIX: &[u8; MESSAGE_ENCODING_PREFIX_LEN] =
|
||||||
|
b"/NSSA/v0.2/TxMessage/Program/\x00\x00\x00";
|
||||||
|
|
||||||
|
impl Message {
|
||||||
|
/// Serializes a `Message` into bytes in the following layout:
|
||||||
|
/// PREFIX || bytecode_len (4 bytes LE) || <bytecode>
|
||||||
|
/// Integers are encoded in little-endian byte order, and fields appear in the above order.
|
||||||
|
pub(crate) fn to_bytes(&self) -> Vec<u8> {
|
||||||
|
let mut bytes = MESSAGE_ENCODING_PREFIX.to_vec();
|
||||||
|
let bytecode_len = self.bytecode.len() as u32;
|
||||||
|
bytes.extend(&bytecode_len.to_le_bytes());
|
||||||
|
bytes.extend(&self.bytecode);
|
||||||
|
bytes
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn from_cursor(cursor: &mut Cursor<&[u8]>) -> Result<Self, NssaError> {
|
||||||
|
let prefix = {
|
||||||
|
let mut this = [0u8; MESSAGE_ENCODING_PREFIX_LEN];
|
||||||
|
cursor.read_exact(&mut this)?;
|
||||||
|
this
|
||||||
|
};
|
||||||
|
if &prefix != MESSAGE_ENCODING_PREFIX {
|
||||||
|
return Err(NssaError::TransactionDeserializationError(
|
||||||
|
"Invalid public message prefix".to_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
let bytecode_len = u32_from_cursor(cursor)?;
|
||||||
|
let mut bytecode = vec![0; bytecode_len as usize];
|
||||||
|
let num_bytes = cursor.read(&mut bytecode)?;
|
||||||
|
if num_bytes != bytecode_len as usize {
|
||||||
|
println!("num bytes: {}", num_bytes);
|
||||||
|
return Err(NssaError::TransactionDeserializationError(
|
||||||
|
"Invalid number of bytes".to_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
Ok(Self { bytecode })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ProgramDeploymentTransaction {
|
||||||
|
pub fn to_bytes(&self) -> Vec<u8> {
|
||||||
|
self.message.to_bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_bytes(bytes: &[u8]) -> Result<Self, NssaError> {
|
||||||
|
let mut cursor = Cursor::new(bytes);
|
||||||
|
Self::from_cursor(&mut cursor)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_cursor(cursor: &mut Cursor<&[u8]>) -> Result<Self, NssaError> {
|
||||||
|
let message = Message::from_cursor(cursor)?;
|
||||||
|
Ok(Self::new(message))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn u32_from_cursor(cursor: &mut Cursor<&[u8]>) -> Result<u32, NssaError> {
|
||||||
|
let mut word_buf = [0u8; 4];
|
||||||
|
cursor.read_exact(&mut word_buf)?;
|
||||||
|
Ok(u32::from_le_bytes(word_buf))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use std::io::Cursor;
|
||||||
|
|
||||||
|
use crate::{ProgramDeploymentTransaction, program_deployment_transaction::Message};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_roundtrip() {
|
||||||
|
let message = Message::new(vec![0xca, 0xfe, 0xca, 0xfe, 0x01, 0x02, 0x03]);
|
||||||
|
let tx = ProgramDeploymentTransaction::new(message);
|
||||||
|
let bytes = tx.to_bytes();
|
||||||
|
let mut cursor = Cursor::new(bytes.as_ref());
|
||||||
|
let tx_from_cursor = ProgramDeploymentTransaction::from_cursor(&mut cursor).unwrap();
|
||||||
|
assert_eq!(tx, tx_from_cursor);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -10,8 +10,9 @@ use crate::{
|
|||||||
public_transaction::{Message, WitnessSet},
|
public_transaction::{Message, WitnessSet},
|
||||||
};
|
};
|
||||||
|
|
||||||
const MESSAGE_ENCODING_PREFIX_LEN: usize = 22;
|
const MESSAGE_ENCODING_PREFIX_LEN: usize = 32;
|
||||||
const MESSAGE_ENCODING_PREFIX: &[u8; MESSAGE_ENCODING_PREFIX_LEN] = b"\x00/NSSA/v0.1/TxMessage/";
|
const MESSAGE_ENCODING_PREFIX: &[u8; MESSAGE_ENCODING_PREFIX_LEN] =
|
||||||
|
b"/NSSA/v0.2/TxMessage/Public/\x00\x00\x00\x00";
|
||||||
|
|
||||||
impl Message {
|
impl Message {
|
||||||
/// Serializes a `Message` into bytes in the following layout:
|
/// Serializes a `Message` into bytes in the following layout:
|
||||||
|
|||||||
@ -48,4 +48,10 @@ pub enum NssaError {
|
|||||||
|
|
||||||
#[error("Circuit proving error")]
|
#[error("Circuit proving error")]
|
||||||
CircuitProvingError(String),
|
CircuitProvingError(String),
|
||||||
|
|
||||||
|
#[error("Invalid program bytecode")]
|
||||||
|
InvalidProgramBytecode,
|
||||||
|
|
||||||
|
#[error("Program already exists")]
|
||||||
|
ProgramAlreadyExists,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,6 +12,7 @@ pub mod error;
|
|||||||
mod merkle_tree;
|
mod merkle_tree;
|
||||||
pub mod privacy_preserving_transaction;
|
pub mod privacy_preserving_transaction;
|
||||||
pub mod program;
|
pub mod program;
|
||||||
|
pub mod program_deployment_transaction;
|
||||||
pub mod public_transaction;
|
pub mod public_transaction;
|
||||||
mod signature;
|
mod signature;
|
||||||
mod state;
|
mod state;
|
||||||
@ -21,9 +22,10 @@ pub use nssa_core::address::Address;
|
|||||||
pub use privacy_preserving_transaction::{
|
pub use privacy_preserving_transaction::{
|
||||||
PrivacyPreservingTransaction, circuit::execute_and_prove,
|
PrivacyPreservingTransaction, circuit::execute_and_prove,
|
||||||
};
|
};
|
||||||
|
pub use program_deployment_transaction::ProgramDeploymentTransaction;
|
||||||
pub use program_methods::PRIVACY_PRESERVING_CIRCUIT_ID;
|
pub use program_methods::PRIVACY_PRESERVING_CIRCUIT_ID;
|
||||||
pub use public_transaction::PublicTransaction;
|
pub use public_transaction::PublicTransaction;
|
||||||
pub use signature::PrivateKey;
|
pub use signature::PrivateKey;
|
||||||
pub use signature::PublicKey;
|
pub use signature::PublicKey;
|
||||||
pub use signature::Signature;
|
pub use signature::Signature;
|
||||||
pub use state::V01State;
|
pub use state::V02State;
|
||||||
|
|||||||
@ -31,10 +31,10 @@ impl EncryptedAccountData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Computes the tag as the first byte of SHA256("/NSSA/v0.1/ViewTag" || Npk || Ivk)
|
/// Computes the tag as the first byte of SHA256("/NSSA/v0.2/ViewTag/" || Npk || Ivk)
|
||||||
pub fn compute_view_tag(npk: NullifierPublicKey, ivk: IncomingViewingPublicKey) -> ViewTag {
|
pub fn compute_view_tag(npk: NullifierPublicKey, ivk: IncomingViewingPublicKey) -> ViewTag {
|
||||||
let mut hasher = Sha256::new();
|
let mut hasher = Sha256::new();
|
||||||
hasher.update(b"/NSSA/v0.1/ViewTag");
|
hasher.update(b"/NSSA/v0.2/ViewTag/");
|
||||||
hasher.update(npk.to_byte_array());
|
hasher.update(npk.to_byte_array());
|
||||||
hasher.update(ivk.to_bytes());
|
hasher.update(ivk.to_bytes());
|
||||||
let digest: [u8; 32] = hasher.finalize().into();
|
let digest: [u8; 32] = hasher.finalize().into();
|
||||||
@ -166,7 +166,7 @@ pub mod tests {
|
|||||||
|
|
||||||
let expected_view_tag = {
|
let expected_view_tag = {
|
||||||
let mut hasher = Sha256::new();
|
let mut hasher = Sha256::new();
|
||||||
hasher.update(b"/NSSA/v0.1/ViewTag");
|
hasher.update(b"/NSSA/v0.2/ViewTag/");
|
||||||
hasher.update(npk.to_byte_array());
|
hasher.update(npk.to_byte_array());
|
||||||
hasher.update(ivk.to_bytes());
|
hasher.update(ivk.to_bytes());
|
||||||
let digest: [u8; 32] = hasher.finalize().into();
|
let digest: [u8; 32] = hasher.finalize().into();
|
||||||
|
|||||||
@ -8,7 +8,7 @@ use nssa_core::{
|
|||||||
use crate::error::NssaError;
|
use crate::error::NssaError;
|
||||||
use crate::privacy_preserving_transaction::circuit::Proof;
|
use crate::privacy_preserving_transaction::circuit::Proof;
|
||||||
use crate::privacy_preserving_transaction::message::EncryptedAccountData;
|
use crate::privacy_preserving_transaction::message::EncryptedAccountData;
|
||||||
use crate::{Address, V01State};
|
use crate::{Address, V02State};
|
||||||
|
|
||||||
use super::message::Message;
|
use super::message::Message;
|
||||||
use super::witness_set::WitnessSet;
|
use super::witness_set::WitnessSet;
|
||||||
@ -29,7 +29,7 @@ impl PrivacyPreservingTransaction {
|
|||||||
|
|
||||||
pub(crate) fn validate_and_produce_public_state_diff(
|
pub(crate) fn validate_and_produce_public_state_diff(
|
||||||
&self,
|
&self,
|
||||||
state: &mut V01State,
|
state: &V02State,
|
||||||
) -> Result<HashMap<Address, Account>, NssaError> {
|
) -> Result<HashMap<Address, Account>, NssaError> {
|
||||||
let message = &self.message;
|
let message = &self.message;
|
||||||
let witness_set = &self.witness_set;
|
let witness_set = &self.witness_set;
|
||||||
|
|||||||
@ -1,29 +1,41 @@
|
|||||||
use crate::program_methods::{
|
use crate::program_methods::{AUTHENTICATED_TRANSFER_ELF, PINATA_ELF, TOKEN_ELF};
|
||||||
AUTHENTICATED_TRANSFER_ELF, AUTHENTICATED_TRANSFER_ID, PINATA_ELF, PINATA_ID, TOKEN_ELF,
|
|
||||||
TOKEN_ID,
|
|
||||||
};
|
|
||||||
use nssa_core::{
|
use nssa_core::{
|
||||||
account::{Account, AccountWithMetadata},
|
account::{Account, AccountWithMetadata},
|
||||||
program::{InstructionData, ProgramId, ProgramOutput},
|
program::{InstructionData, ProgramId, ProgramOutput},
|
||||||
};
|
};
|
||||||
|
|
||||||
use risc0_zkvm::{ExecutorEnv, ExecutorEnvBuilder, default_executor, serde::to_vec};
|
use risc0_zkvm::{ExecutorEnv, ExecutorEnvBuilder, default_executor, serde::to_vec};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use crate::error::NssaError;
|
use crate::error::NssaError;
|
||||||
|
|
||||||
|
/// Maximum number of cycles for a public execution.
|
||||||
|
/// TODO: Make this variable when fees are implemented
|
||||||
|
const MAX_NUM_CYCLES_PUBLIC_EXECUTION: u64 = 1024 * 1024 * 32; // 32M cycles
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
pub struct Program {
|
pub struct Program {
|
||||||
id: ProgramId,
|
id: ProgramId,
|
||||||
elf: &'static [u8],
|
elf: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Program {
|
impl Program {
|
||||||
|
pub fn new(bytecode: Vec<u8>) -> Result<Self, NssaError> {
|
||||||
|
let binary = risc0_binfmt::ProgramBinary::decode(&bytecode)
|
||||||
|
.map_err(|_| NssaError::InvalidProgramBytecode)?;
|
||||||
|
let id = binary
|
||||||
|
.compute_image_id()
|
||||||
|
.map_err(|_| NssaError::InvalidProgramBytecode)?
|
||||||
|
.into();
|
||||||
|
Ok(Self { elf: bytecode, id })
|
||||||
|
}
|
||||||
|
|
||||||
pub fn id(&self) -> ProgramId {
|
pub fn id(&self) -> ProgramId {
|
||||||
self.id
|
self.id
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn elf(&self) -> &'static [u8] {
|
pub fn elf(&self) -> &[u8] {
|
||||||
self.elf
|
&self.elf
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn serialize_instruction<T: Serialize>(
|
pub fn serialize_instruction<T: Serialize>(
|
||||||
@ -39,13 +51,14 @@ impl Program {
|
|||||||
) -> Result<Vec<Account>, NssaError> {
|
) -> Result<Vec<Account>, NssaError> {
|
||||||
// Write inputs to the program
|
// Write inputs to the program
|
||||||
let mut env_builder = ExecutorEnv::builder();
|
let mut env_builder = ExecutorEnv::builder();
|
||||||
|
env_builder.session_limit(Some(MAX_NUM_CYCLES_PUBLIC_EXECUTION));
|
||||||
Self::write_inputs(pre_states, instruction_data, &mut env_builder)?;
|
Self::write_inputs(pre_states, instruction_data, &mut env_builder)?;
|
||||||
let env = env_builder.build().unwrap();
|
let env = env_builder.build().unwrap();
|
||||||
|
|
||||||
// Execute the program (without proving)
|
// Execute the program (without proving)
|
||||||
let executor = default_executor();
|
let executor = default_executor();
|
||||||
let session_info = executor
|
let session_info = executor
|
||||||
.execute(env, self.elf)
|
.execute(env, self.elf())
|
||||||
.map_err(|e| NssaError::ProgramExecutionFailed(e.to_string()))?;
|
.map_err(|e| NssaError::ProgramExecutionFailed(e.to_string()))?;
|
||||||
|
|
||||||
// Get outputs
|
// Get outputs
|
||||||
@ -71,33 +84,34 @@ impl Program {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn authenticated_transfer_program() -> Self {
|
pub fn authenticated_transfer_program() -> Self {
|
||||||
Self {
|
// This unwrap won't panic since the `AUTHENTICATED_TRANSFER_ELF` comes from risc0 build of
|
||||||
id: AUTHENTICATED_TRANSFER_ID,
|
// `program_methods`
|
||||||
elf: AUTHENTICATED_TRANSFER_ELF,
|
Self::new(AUTHENTICATED_TRANSFER_ELF.to_vec()).unwrap()
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn token() -> Self {
|
pub fn token() -> Self {
|
||||||
Self {
|
// This unwrap won't panic since the `TOKEN_ELF` comes from risc0 build of
|
||||||
id: TOKEN_ID,
|
// `program_methods`
|
||||||
elf: TOKEN_ELF,
|
Self::new(TOKEN_ELF.to_vec()).unwrap()
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Testnet only. Refactor to prevent compilation on mainnet.
|
// TODO: Testnet only. Refactor to prevent compilation on mainnet.
|
||||||
impl Program {
|
impl Program {
|
||||||
pub fn pinata() -> Self {
|
pub fn pinata() -> Self {
|
||||||
Self {
|
// This unwrap won't panic since the `PINATA_ELF` comes from risc0 build of
|
||||||
id: PINATA_ID,
|
// `program_methods`
|
||||||
elf: PINATA_ELF,
|
Self::new(PINATA_ELF.to_vec()).unwrap()
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use nssa_core::account::{Account, AccountId, AccountWithMetadata};
|
use nssa_core::account::{Account, AccountId, AccountWithMetadata};
|
||||||
|
use program_methods::{
|
||||||
|
AUTHENTICATED_TRANSFER_ELF, AUTHENTICATED_TRANSFER_ID, PINATA_ELF, PINATA_ID, TOKEN_ELF,
|
||||||
|
TOKEN_ID,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::program::Program;
|
use crate::program::Program;
|
||||||
|
|
||||||
@ -108,7 +122,7 @@ mod tests {
|
|||||||
|
|
||||||
Program {
|
Program {
|
||||||
id: NONCE_CHANGER_ID,
|
id: NONCE_CHANGER_ID,
|
||||||
elf: NONCE_CHANGER_ELF,
|
elf: NONCE_CHANGER_ELF.to_vec(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,7 +132,7 @@ mod tests {
|
|||||||
|
|
||||||
Program {
|
Program {
|
||||||
id: EXTRA_OUTPUT_ID,
|
id: EXTRA_OUTPUT_ID,
|
||||||
elf: EXTRA_OUTPUT_ELF,
|
elf: EXTRA_OUTPUT_ELF.to_vec(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,7 +142,7 @@ mod tests {
|
|||||||
|
|
||||||
Program {
|
Program {
|
||||||
id: MISSING_OUTPUT_ID,
|
id: MISSING_OUTPUT_ID,
|
||||||
elf: MISSING_OUTPUT_ELF,
|
elf: MISSING_OUTPUT_ELF.to_vec(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,7 +152,7 @@ mod tests {
|
|||||||
|
|
||||||
Program {
|
Program {
|
||||||
id: PROGRAM_OWNER_CHANGER_ID,
|
id: PROGRAM_OWNER_CHANGER_ID,
|
||||||
elf: PROGRAM_OWNER_CHANGER_ELF,
|
elf: PROGRAM_OWNER_CHANGER_ELF.to_vec(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,7 +162,7 @@ mod tests {
|
|||||||
|
|
||||||
Program {
|
Program {
|
||||||
id: SIMPLE_BALANCE_TRANSFER_ID,
|
id: SIMPLE_BALANCE_TRANSFER_ID,
|
||||||
elf: SIMPLE_BALANCE_TRANSFER_ELF,
|
elf: SIMPLE_BALANCE_TRANSFER_ELF.to_vec(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -158,7 +172,7 @@ mod tests {
|
|||||||
|
|
||||||
Program {
|
Program {
|
||||||
id: DATA_CHANGER_ID,
|
id: DATA_CHANGER_ID,
|
||||||
elf: DATA_CHANGER_ELF,
|
elf: DATA_CHANGER_ELF.to_vec(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -168,7 +182,7 @@ mod tests {
|
|||||||
|
|
||||||
Program {
|
Program {
|
||||||
id: MINTER_ID,
|
id: MINTER_ID,
|
||||||
elf: MINTER_ELF,
|
elf: MINTER_ELF.to_vec(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,7 +192,7 @@ mod tests {
|
|||||||
|
|
||||||
Program {
|
Program {
|
||||||
id: BURNER_ID,
|
id: BURNER_ID,
|
||||||
elf: BURNER_ELF,
|
elf: BURNER_ELF.to_vec(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -216,4 +230,18 @@ mod tests {
|
|||||||
assert_eq!(sender_post, expected_sender_post);
|
assert_eq!(sender_post, expected_sender_post);
|
||||||
assert_eq!(recipient_post, expected_recipient_post);
|
assert_eq!(recipient_post, expected_recipient_post);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_builtin_programs() {
|
||||||
|
let auth_transfer_program = Program::authenticated_transfer_program();
|
||||||
|
let token_program = Program::token();
|
||||||
|
let pinata_program = Program::pinata();
|
||||||
|
|
||||||
|
assert_eq!(auth_transfer_program.id, AUTHENTICATED_TRANSFER_ID);
|
||||||
|
assert_eq!(auth_transfer_program.elf, AUTHENTICATED_TRANSFER_ELF);
|
||||||
|
assert_eq!(token_program.id, TOKEN_ID);
|
||||||
|
assert_eq!(token_program.elf, TOKEN_ELF);
|
||||||
|
assert_eq!(pinata_program.id, PINATA_ID);
|
||||||
|
assert_eq!(pinata_program.elf, PINATA_ELF);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
10
nssa/src/program_deployment_transaction/message.rs
Normal file
10
nssa/src/program_deployment_transaction/message.rs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct Message {
|
||||||
|
pub(crate) bytecode: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Message {
|
||||||
|
pub fn new(bytecode: Vec<u8>) -> Self {
|
||||||
|
Self { bytecode }
|
||||||
|
}
|
||||||
|
}
|
||||||
5
nssa/src/program_deployment_transaction/mod.rs
Normal file
5
nssa/src/program_deployment_transaction/mod.rs
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
mod message;
|
||||||
|
mod transaction;
|
||||||
|
|
||||||
|
pub use message::Message;
|
||||||
|
pub use transaction::ProgramDeploymentTransaction;
|
||||||
27
nssa/src/program_deployment_transaction/transaction.rs
Normal file
27
nssa/src/program_deployment_transaction/transaction.rs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
use crate::{
|
||||||
|
V02State, error::NssaError, program::Program, program_deployment_transaction::message::Message,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct ProgramDeploymentTransaction {
|
||||||
|
pub(crate) message: Message,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ProgramDeploymentTransaction {
|
||||||
|
pub fn new(message: Message) -> Self {
|
||||||
|
Self { message }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn validate_and_produce_public_state_diff(
|
||||||
|
&self,
|
||||||
|
state: &V02State,
|
||||||
|
) -> Result<Program, NssaError> {
|
||||||
|
// TODO: remove clone
|
||||||
|
let program = Program::new(self.message.bytecode.clone())?;
|
||||||
|
if state.programs().contains_key(&program.id()) {
|
||||||
|
Err(NssaError::ProgramAlreadyExists)
|
||||||
|
} else {
|
||||||
|
Ok(program)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -8,7 +8,7 @@ use nssa_core::{
|
|||||||
use sha2::{Digest, digest::FixedOutput};
|
use sha2::{Digest, digest::FixedOutput};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
V01State,
|
V02State,
|
||||||
error::NssaError,
|
error::NssaError,
|
||||||
public_transaction::{Message, WitnessSet},
|
public_transaction::{Message, WitnessSet},
|
||||||
};
|
};
|
||||||
@ -52,7 +52,7 @@ impl PublicTransaction {
|
|||||||
|
|
||||||
pub(crate) fn validate_and_produce_public_state_diff(
|
pub(crate) fn validate_and_produce_public_state_diff(
|
||||||
&self,
|
&self,
|
||||||
state: &V01State,
|
state: &V02State,
|
||||||
) -> Result<HashMap<Address, Account>, NssaError> {
|
) -> Result<HashMap<Address, Account>, NssaError> {
|
||||||
let message = self.message();
|
let message = self.message();
|
||||||
let witness_set = self.witness_set();
|
let witness_set = self.witness_set();
|
||||||
@ -100,9 +100,8 @@ impl PublicTransaction {
|
|||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
// Check the `program_id` corresponds to a built-in program
|
// Check the `program_id` corresponds to a deployed program
|
||||||
// Only allowed program so far is the authenticated transfer program
|
let Some(program) = state.programs().get(&message.program_id) else {
|
||||||
let Some(program) = state.builtin_programs().get(&message.program_id) else {
|
|
||||||
return Err(NssaError::InvalidInput("Unknown program".into()));
|
return Err(NssaError::InvalidInput("Unknown program".into()));
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -124,7 +123,7 @@ pub mod tests {
|
|||||||
use sha2::{Digest, digest::FixedOutput};
|
use sha2::{Digest, digest::FixedOutput};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
Address, PrivateKey, PublicKey, PublicTransaction, Signature, V01State,
|
Address, PrivateKey, PublicKey, PublicTransaction, Signature, V02State,
|
||||||
error::NssaError,
|
error::NssaError,
|
||||||
program::Program,
|
program::Program,
|
||||||
public_transaction::{Message, WitnessSet},
|
public_transaction::{Message, WitnessSet},
|
||||||
@ -138,10 +137,10 @@ pub mod tests {
|
|||||||
(key1, key2, addr1, addr2)
|
(key1, key2, addr1, addr2)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn state_for_tests() -> V01State {
|
fn state_for_tests() -> V02State {
|
||||||
let (_, _, addr1, addr2) = keys_for_tests();
|
let (_, _, addr1, addr2) = keys_for_tests();
|
||||||
let initial_data = [(addr1, 10000), (addr2, 20000)];
|
let initial_data = [(addr1, 10000), (addr2, 20000)];
|
||||||
V01State::new_with_genesis_accounts(&initial_data, &[])
|
V02State::new_with_genesis_accounts(&initial_data, &[])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn transaction_for_tests() -> PublicTransaction {
|
fn transaction_for_tests() -> PublicTransaction {
|
||||||
@ -187,12 +186,12 @@ pub mod tests {
|
|||||||
let tx = transaction_for_tests();
|
let tx = transaction_for_tests();
|
||||||
let expected_signer_addresses = vec![
|
let expected_signer_addresses = vec![
|
||||||
Address::new([
|
Address::new([
|
||||||
14, 238, 36, 40, 114, 150, 186, 85, 39, 143, 30, 84, 3, 190, 1, 71, 84, 134, 99,
|
208, 122, 210, 232, 75, 39, 250, 0, 194, 98, 240, 161, 238, 160, 255, 53, 202, 9,
|
||||||
102, 56, 135, 48, 48, 60, 40, 137, 190, 23, 173, 160, 101,
|
115, 84, 126, 106, 16, 111, 114, 241, 147, 194, 220, 131, 139, 68,
|
||||||
]),
|
]),
|
||||||
Address::new([
|
Address::new([
|
||||||
158, 61, 142, 101, 77, 68, 14, 149, 41, 58, 162, 220, 236, 235, 19, 120, 153, 165,
|
231, 174, 119, 197, 239, 26, 5, 153, 147, 68, 175, 73, 159, 199, 138, 23, 5, 57,
|
||||||
149, 53, 233, 82, 247, 71, 6, 142, 122, 14, 227, 9, 101, 242,
|
141, 98, 237, 6, 207, 46, 20, 121, 246, 222, 248, 154, 57, 188,
|
||||||
]),
|
]),
|
||||||
];
|
];
|
||||||
let signer_addresses = tx.signer_addresses();
|
let signer_addresses = tx.signer_addresses();
|
||||||
|
|||||||
@ -33,7 +33,7 @@ impl PublicKey {
|
|||||||
|
|
||||||
impl From<&PublicKey> for Address {
|
impl From<&PublicKey> for Address {
|
||||||
fn from(key: &PublicKey) -> Self {
|
fn from(key: &PublicKey) -> Self {
|
||||||
const PUBLIC_ACCOUNT_ID_PREFIX: &[u8; 32] = b"/NSSA/v0.1/AccountId/Public/\x00\x00\x00\x00";
|
const PUBLIC_ACCOUNT_ID_PREFIX: &[u8; 32] = b"/NSSA/v0.2/AccountId/Public/\x00\x00\x00\x00";
|
||||||
|
|
||||||
let mut hasher = Sha256::new();
|
let mut hasher = Sha256::new();
|
||||||
hasher.update(PUBLIC_ACCOUNT_ID_PREFIX);
|
hasher.update(PUBLIC_ACCOUNT_ID_PREFIX);
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
error::NssaError, merkle_tree::MerkleTree,
|
error::NssaError, merkle_tree::MerkleTree,
|
||||||
privacy_preserving_transaction::PrivacyPreservingTransaction, program::Program,
|
privacy_preserving_transaction::PrivacyPreservingTransaction, program::Program,
|
||||||
|
program_deployment_transaction::ProgramDeploymentTransaction,
|
||||||
public_transaction::PublicTransaction,
|
public_transaction::PublicTransaction,
|
||||||
};
|
};
|
||||||
use nssa_core::{
|
use nssa_core::{
|
||||||
@ -58,13 +59,13 @@ impl CommitmentSet {
|
|||||||
|
|
||||||
type NullifierSet = HashSet<Nullifier>;
|
type NullifierSet = HashSet<Nullifier>;
|
||||||
|
|
||||||
pub struct V01State {
|
pub struct V02State {
|
||||||
public_state: HashMap<Address, Account>,
|
public_state: HashMap<Address, Account>,
|
||||||
private_state: (CommitmentSet, NullifierSet),
|
private_state: (CommitmentSet, NullifierSet),
|
||||||
builtin_programs: HashMap<ProgramId, Program>,
|
programs: HashMap<ProgramId, Program>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl V01State {
|
impl V02State {
|
||||||
pub fn new_with_genesis_accounts(
|
pub fn new_with_genesis_accounts(
|
||||||
initial_data: &[(Address, u128)],
|
initial_data: &[(Address, u128)],
|
||||||
initial_commitments: &[nssa_core::Commitment],
|
initial_commitments: &[nssa_core::Commitment],
|
||||||
@ -90,7 +91,7 @@ impl V01State {
|
|||||||
let mut this = Self {
|
let mut this = Self {
|
||||||
public_state,
|
public_state,
|
||||||
private_state: (private_state, NullifierSet::new()),
|
private_state: (private_state, NullifierSet::new()),
|
||||||
builtin_programs: HashMap::new(),
|
programs: HashMap::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
this.insert_program(Program::authenticated_transfer_program());
|
this.insert_program(Program::authenticated_transfer_program());
|
||||||
@ -100,7 +101,7 @@ impl V01State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn insert_program(&mut self, program: Program) {
|
pub(crate) fn insert_program(&mut self, program: Program) {
|
||||||
self.builtin_programs.insert(program.id(), program);
|
self.programs.insert(program.id(), program);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn transition_from_public_transaction(
|
pub fn transition_from_public_transaction(
|
||||||
@ -157,6 +158,15 @@ impl V01State {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn transition_from_program_deployment_transaction(
|
||||||
|
&mut self,
|
||||||
|
tx: &ProgramDeploymentTransaction,
|
||||||
|
) -> Result<(), NssaError> {
|
||||||
|
let program = tx.validate_and_produce_public_state_diff(self)?;
|
||||||
|
self.insert_program(program);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn get_account_by_address_mut(&mut self, address: Address) -> &mut Account {
|
fn get_account_by_address_mut(&mut self, address: Address) -> &mut Account {
|
||||||
self.public_state.entry(address).or_default()
|
self.public_state.entry(address).or_default()
|
||||||
}
|
}
|
||||||
@ -172,8 +182,8 @@ impl V01State {
|
|||||||
self.private_state.0.get_proof_for(commitment)
|
self.private_state.0.get_proof_for(commitment)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn builtin_programs(&self) -> &HashMap<ProgramId, Program> {
|
pub(crate) fn programs(&self) -> &HashMap<ProgramId, Program> {
|
||||||
&self.builtin_programs
|
&self.programs
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn commitment_set_digest(&self) -> CommitmentSetDigest {
|
pub fn commitment_set_digest(&self) -> CommitmentSetDigest {
|
||||||
@ -215,7 +225,7 @@ impl V01State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Testnet only. Refactor to prevent compilation on mainnet.
|
// TODO: Testnet only. Refactor to prevent compilation on mainnet.
|
||||||
impl V01State {
|
impl V02State {
|
||||||
pub fn add_pinata_program(&mut self, address: Address) {
|
pub fn add_pinata_program(&mut self, address: Address) {
|
||||||
self.insert_program(Program::pinata());
|
self.insert_program(Program::pinata());
|
||||||
|
|
||||||
@ -238,7 +248,7 @@ pub mod tests {
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
Address, PublicKey, PublicTransaction, V01State,
|
Address, PublicKey, PublicTransaction, V02State,
|
||||||
error::NssaError,
|
error::NssaError,
|
||||||
execute_and_prove,
|
execute_and_prove,
|
||||||
privacy_preserving_transaction::{
|
privacy_preserving_transaction::{
|
||||||
@ -309,22 +319,22 @@ pub mod tests {
|
|||||||
this
|
this
|
||||||
};
|
};
|
||||||
|
|
||||||
let state = V01State::new_with_genesis_accounts(&initial_data, &[]);
|
let state = V02State::new_with_genesis_accounts(&initial_data, &[]);
|
||||||
|
|
||||||
assert_eq!(state.public_state, expected_public_state);
|
assert_eq!(state.public_state, expected_public_state);
|
||||||
assert_eq!(state.builtin_programs, expected_builtin_programs);
|
assert_eq!(state.programs, expected_builtin_programs);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_insert_program() {
|
fn test_insert_program() {
|
||||||
let mut state = V01State::new_with_genesis_accounts(&[], &[]);
|
let mut state = V02State::new_with_genesis_accounts(&[], &[]);
|
||||||
let program_to_insert = Program::simple_balance_transfer();
|
let program_to_insert = Program::simple_balance_transfer();
|
||||||
let program_id = program_to_insert.id();
|
let program_id = program_to_insert.id();
|
||||||
assert!(!state.builtin_programs.contains_key(&program_id));
|
assert!(!state.programs.contains_key(&program_id));
|
||||||
|
|
||||||
state.insert_program(program_to_insert);
|
state.insert_program(program_to_insert);
|
||||||
|
|
||||||
assert!(state.builtin_programs.contains_key(&program_id));
|
assert!(state.programs.contains_key(&program_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -332,7 +342,7 @@ pub mod tests {
|
|||||||
let key = PrivateKey::try_new([1; 32]).unwrap();
|
let key = PrivateKey::try_new([1; 32]).unwrap();
|
||||||
let addr = Address::from(&PublicKey::new_from_private_key(&key));
|
let addr = Address::from(&PublicKey::new_from_private_key(&key));
|
||||||
let initial_data = [(addr, 100u128)];
|
let initial_data = [(addr, 100u128)];
|
||||||
let state = V01State::new_with_genesis_accounts(&initial_data, &[]);
|
let state = V02State::new_with_genesis_accounts(&initial_data, &[]);
|
||||||
let expected_account = state.public_state.get(&addr).unwrap();
|
let expected_account = state.public_state.get(&addr).unwrap();
|
||||||
|
|
||||||
let account = state.get_account_by_address(&addr);
|
let account = state.get_account_by_address(&addr);
|
||||||
@ -343,7 +353,7 @@ pub mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_get_account_by_address_default_account() {
|
fn test_get_account_by_address_default_account() {
|
||||||
let addr2 = Address::new([0; 32]);
|
let addr2 = Address::new([0; 32]);
|
||||||
let state = V01State::new_with_genesis_accounts(&[], &[]);
|
let state = V02State::new_with_genesis_accounts(&[], &[]);
|
||||||
let expected_account = Account::default();
|
let expected_account = Account::default();
|
||||||
|
|
||||||
let account = state.get_account_by_address(&addr2);
|
let account = state.get_account_by_address(&addr2);
|
||||||
@ -353,11 +363,11 @@ pub mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_builtin_programs_getter() {
|
fn test_builtin_programs_getter() {
|
||||||
let state = V01State::new_with_genesis_accounts(&[], &[]);
|
let state = V02State::new_with_genesis_accounts(&[], &[]);
|
||||||
|
|
||||||
let builtin_programs = state.builtin_programs();
|
let builtin_programs = state.programs();
|
||||||
|
|
||||||
assert_eq!(builtin_programs, &state.builtin_programs);
|
assert_eq!(builtin_programs, &state.programs);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -365,7 +375,7 @@ pub mod tests {
|
|||||||
let key = PrivateKey::try_new([1; 32]).unwrap();
|
let key = PrivateKey::try_new([1; 32]).unwrap();
|
||||||
let address = Address::from(&PublicKey::new_from_private_key(&key));
|
let address = Address::from(&PublicKey::new_from_private_key(&key));
|
||||||
let initial_data = [(address, 100)];
|
let initial_data = [(address, 100)];
|
||||||
let mut state = V01State::new_with_genesis_accounts(&initial_data, &[]);
|
let mut state = V02State::new_with_genesis_accounts(&initial_data, &[]);
|
||||||
let from = address;
|
let from = address;
|
||||||
let to = Address::new([2; 32]);
|
let to = Address::new([2; 32]);
|
||||||
assert_eq!(state.get_account_by_address(&to), Account::default());
|
assert_eq!(state.get_account_by_address(&to), Account::default());
|
||||||
@ -385,7 +395,7 @@ pub mod tests {
|
|||||||
let key = PrivateKey::try_new([1; 32]).unwrap();
|
let key = PrivateKey::try_new([1; 32]).unwrap();
|
||||||
let address = Address::from(&PublicKey::new_from_private_key(&key));
|
let address = Address::from(&PublicKey::new_from_private_key(&key));
|
||||||
let initial_data = [(address, 100)];
|
let initial_data = [(address, 100)];
|
||||||
let mut state = V01State::new_with_genesis_accounts(&initial_data, &[]);
|
let mut state = V02State::new_with_genesis_accounts(&initial_data, &[]);
|
||||||
let from = address;
|
let from = address;
|
||||||
let from_key = key;
|
let from_key = key;
|
||||||
let to = Address::new([2; 32]);
|
let to = Address::new([2; 32]);
|
||||||
@ -409,7 +419,7 @@ pub mod tests {
|
|||||||
let address1 = Address::from(&PublicKey::new_from_private_key(&key1));
|
let address1 = Address::from(&PublicKey::new_from_private_key(&key1));
|
||||||
let address2 = Address::from(&PublicKey::new_from_private_key(&key2));
|
let address2 = Address::from(&PublicKey::new_from_private_key(&key2));
|
||||||
let initial_data = [(address1, 100), (address2, 200)];
|
let initial_data = [(address1, 100), (address2, 200)];
|
||||||
let mut state = V01State::new_with_genesis_accounts(&initial_data, &[]);
|
let mut state = V02State::new_with_genesis_accounts(&initial_data, &[]);
|
||||||
let from = address2;
|
let from = address2;
|
||||||
let from_key = key2;
|
let from_key = key2;
|
||||||
let to = address1;
|
let to = address1;
|
||||||
@ -432,7 +442,7 @@ pub mod tests {
|
|||||||
let key2 = PrivateKey::try_new([2; 32]).unwrap();
|
let key2 = PrivateKey::try_new([2; 32]).unwrap();
|
||||||
let address2 = Address::from(&PublicKey::new_from_private_key(&key2));
|
let address2 = Address::from(&PublicKey::new_from_private_key(&key2));
|
||||||
let initial_data = [(address1, 100)];
|
let initial_data = [(address1, 100)];
|
||||||
let mut state = V01State::new_with_genesis_accounts(&initial_data, &[]);
|
let mut state = V02State::new_with_genesis_accounts(&initial_data, &[]);
|
||||||
let address3 = Address::new([3; 32]);
|
let address3 = Address::new([3; 32]);
|
||||||
let balance_to_move = 5;
|
let balance_to_move = 5;
|
||||||
|
|
||||||
@ -450,7 +460,7 @@ pub mod tests {
|
|||||||
assert_eq!(state.get_account_by_address(&address3).nonce, 0);
|
assert_eq!(state.get_account_by_address(&address3).nonce, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl V01State {
|
impl V02State {
|
||||||
pub fn force_insert_account(&mut self, address: Address, account: Account) {
|
pub fn force_insert_account(&mut self, address: Address, account: Account) {
|
||||||
self.public_state.insert(address, account);
|
self.public_state.insert(address, account);
|
||||||
}
|
}
|
||||||
@ -517,7 +527,7 @@ pub mod tests {
|
|||||||
fn test_program_should_fail_if_modifies_nonces() {
|
fn test_program_should_fail_if_modifies_nonces() {
|
||||||
let initial_data = [(Address::new([1; 32]), 100)];
|
let initial_data = [(Address::new([1; 32]), 100)];
|
||||||
let mut state =
|
let mut state =
|
||||||
V01State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs();
|
V02State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs();
|
||||||
let addresses = vec![Address::new([1; 32])];
|
let addresses = vec![Address::new([1; 32])];
|
||||||
let program_id = Program::nonce_changer_program().id();
|
let program_id = Program::nonce_changer_program().id();
|
||||||
let message =
|
let message =
|
||||||
@ -534,7 +544,7 @@ pub mod tests {
|
|||||||
fn test_program_should_fail_if_output_accounts_exceed_inputs() {
|
fn test_program_should_fail_if_output_accounts_exceed_inputs() {
|
||||||
let initial_data = [(Address::new([1; 32]), 100)];
|
let initial_data = [(Address::new([1; 32]), 100)];
|
||||||
let mut state =
|
let mut state =
|
||||||
V01State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs();
|
V02State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs();
|
||||||
let addresses = vec![Address::new([1; 32])];
|
let addresses = vec![Address::new([1; 32])];
|
||||||
let program_id = Program::extra_output_program().id();
|
let program_id = Program::extra_output_program().id();
|
||||||
let message =
|
let message =
|
||||||
@ -551,7 +561,7 @@ pub mod tests {
|
|||||||
fn test_program_should_fail_with_missing_output_accounts() {
|
fn test_program_should_fail_with_missing_output_accounts() {
|
||||||
let initial_data = [(Address::new([1; 32]), 100)];
|
let initial_data = [(Address::new([1; 32]), 100)];
|
||||||
let mut state =
|
let mut state =
|
||||||
V01State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs();
|
V02State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs();
|
||||||
let addresses = vec![Address::new([1; 32]), Address::new([2; 32])];
|
let addresses = vec![Address::new([1; 32]), Address::new([2; 32])];
|
||||||
let program_id = Program::missing_output_program().id();
|
let program_id = Program::missing_output_program().id();
|
||||||
let message =
|
let message =
|
||||||
@ -568,7 +578,7 @@ pub mod tests {
|
|||||||
fn test_program_should_fail_if_modifies_program_owner_with_only_non_default_program_owner() {
|
fn test_program_should_fail_if_modifies_program_owner_with_only_non_default_program_owner() {
|
||||||
let initial_data = [(Address::new([1; 32]), 0)];
|
let initial_data = [(Address::new([1; 32]), 0)];
|
||||||
let mut state =
|
let mut state =
|
||||||
V01State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs();
|
V02State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs();
|
||||||
let address = Address::new([1; 32]);
|
let address = Address::new([1; 32]);
|
||||||
let account = state.get_account_by_address(&address);
|
let account = state.get_account_by_address(&address);
|
||||||
// Assert the target account only differs from the default account in the program owner field
|
// Assert the target account only differs from the default account in the program owner field
|
||||||
@ -590,7 +600,7 @@ pub mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_program_should_fail_if_modifies_program_owner_with_only_non_default_balance() {
|
fn test_program_should_fail_if_modifies_program_owner_with_only_non_default_balance() {
|
||||||
let initial_data = [];
|
let initial_data = [];
|
||||||
let mut state = V01State::new_with_genesis_accounts(&initial_data, &[])
|
let mut state = V02State::new_with_genesis_accounts(&initial_data, &[])
|
||||||
.with_test_programs()
|
.with_test_programs()
|
||||||
.with_non_default_accounts_but_default_program_owners();
|
.with_non_default_accounts_but_default_program_owners();
|
||||||
let address = Address::new([255; 32]);
|
let address = Address::new([255; 32]);
|
||||||
@ -614,7 +624,7 @@ pub mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_program_should_fail_if_modifies_program_owner_with_only_non_default_nonce() {
|
fn test_program_should_fail_if_modifies_program_owner_with_only_non_default_nonce() {
|
||||||
let initial_data = [];
|
let initial_data = [];
|
||||||
let mut state = V01State::new_with_genesis_accounts(&initial_data, &[])
|
let mut state = V02State::new_with_genesis_accounts(&initial_data, &[])
|
||||||
.with_test_programs()
|
.with_test_programs()
|
||||||
.with_non_default_accounts_but_default_program_owners();
|
.with_non_default_accounts_but_default_program_owners();
|
||||||
let address = Address::new([254; 32]);
|
let address = Address::new([254; 32]);
|
||||||
@ -638,7 +648,7 @@ pub mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_program_should_fail_if_modifies_program_owner_with_only_non_default_data() {
|
fn test_program_should_fail_if_modifies_program_owner_with_only_non_default_data() {
|
||||||
let initial_data = [];
|
let initial_data = [];
|
||||||
let mut state = V01State::new_with_genesis_accounts(&initial_data, &[])
|
let mut state = V02State::new_with_genesis_accounts(&initial_data, &[])
|
||||||
.with_test_programs()
|
.with_test_programs()
|
||||||
.with_non_default_accounts_but_default_program_owners();
|
.with_non_default_accounts_but_default_program_owners();
|
||||||
let address = Address::new([253; 32]);
|
let address = Address::new([253; 32]);
|
||||||
@ -663,7 +673,7 @@ pub mod tests {
|
|||||||
fn test_program_should_fail_if_transfers_balance_from_non_owned_account() {
|
fn test_program_should_fail_if_transfers_balance_from_non_owned_account() {
|
||||||
let initial_data = [(Address::new([1; 32]), 100)];
|
let initial_data = [(Address::new([1; 32]), 100)];
|
||||||
let mut state =
|
let mut state =
|
||||||
V01State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs();
|
V02State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs();
|
||||||
let sender_address = Address::new([1; 32]);
|
let sender_address = Address::new([1; 32]);
|
||||||
let receiver_address = Address::new([2; 32]);
|
let receiver_address = Address::new([2; 32]);
|
||||||
let balance_to_move: u128 = 1;
|
let balance_to_move: u128 = 1;
|
||||||
@ -690,7 +700,7 @@ pub mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_program_should_fail_if_modifies_data_of_non_owned_account() {
|
fn test_program_should_fail_if_modifies_data_of_non_owned_account() {
|
||||||
let initial_data = [];
|
let initial_data = [];
|
||||||
let mut state = V01State::new_with_genesis_accounts(&initial_data, &[])
|
let mut state = V02State::new_with_genesis_accounts(&initial_data, &[])
|
||||||
.with_test_programs()
|
.with_test_programs()
|
||||||
.with_non_default_accounts_but_default_program_owners();
|
.with_non_default_accounts_but_default_program_owners();
|
||||||
let address = Address::new([255; 32]);
|
let address = Address::new([255; 32]);
|
||||||
@ -715,7 +725,7 @@ pub mod tests {
|
|||||||
fn test_program_should_fail_if_does_not_preserve_total_balance_by_minting() {
|
fn test_program_should_fail_if_does_not_preserve_total_balance_by_minting() {
|
||||||
let initial_data = [];
|
let initial_data = [];
|
||||||
let mut state =
|
let mut state =
|
||||||
V01State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs();
|
V02State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs();
|
||||||
let address = Address::new([1; 32]);
|
let address = Address::new([1; 32]);
|
||||||
let program_id = Program::minter().id();
|
let program_id = Program::minter().id();
|
||||||
|
|
||||||
@ -732,7 +742,7 @@ pub mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_program_should_fail_if_does_not_preserve_total_balance_by_burning() {
|
fn test_program_should_fail_if_does_not_preserve_total_balance_by_burning() {
|
||||||
let initial_data = [];
|
let initial_data = [];
|
||||||
let mut state = V01State::new_with_genesis_accounts(&initial_data, &[])
|
let mut state = V02State::new_with_genesis_accounts(&initial_data, &[])
|
||||||
.with_test_programs()
|
.with_test_programs()
|
||||||
.with_account_owned_by_burner_program();
|
.with_account_owned_by_burner_program();
|
||||||
let program_id = Program::burner().id();
|
let program_id = Program::burner().id();
|
||||||
@ -807,7 +817,7 @@ pub mod tests {
|
|||||||
sender_keys: &TestPublicKeys,
|
sender_keys: &TestPublicKeys,
|
||||||
recipient_keys: &TestPrivateKeys,
|
recipient_keys: &TestPrivateKeys,
|
||||||
balance_to_move: u128,
|
balance_to_move: u128,
|
||||||
state: &V01State,
|
state: &V02State,
|
||||||
) -> PrivacyPreservingTransaction {
|
) -> PrivacyPreservingTransaction {
|
||||||
let sender = AccountWithMetadata::new(
|
let sender = AccountWithMetadata::new(
|
||||||
state.get_account_by_address(&sender_keys.address()),
|
state.get_account_by_address(&sender_keys.address()),
|
||||||
@ -852,7 +862,7 @@ pub mod tests {
|
|||||||
recipient_keys: &TestPrivateKeys,
|
recipient_keys: &TestPrivateKeys,
|
||||||
balance_to_move: u128,
|
balance_to_move: u128,
|
||||||
new_nonces: [Nonce; 2],
|
new_nonces: [Nonce; 2],
|
||||||
state: &V01State,
|
state: &V02State,
|
||||||
) -> PrivacyPreservingTransaction {
|
) -> PrivacyPreservingTransaction {
|
||||||
let program = Program::authenticated_transfer_program();
|
let program = Program::authenticated_transfer_program();
|
||||||
let sender_commitment = Commitment::new(&sender_keys.npk(), sender_private_account);
|
let sender_commitment = Commitment::new(&sender_keys.npk(), sender_private_account);
|
||||||
@ -908,7 +918,7 @@ pub mod tests {
|
|||||||
recipient_address: &Address,
|
recipient_address: &Address,
|
||||||
balance_to_move: u128,
|
balance_to_move: u128,
|
||||||
new_nonce: Nonce,
|
new_nonce: Nonce,
|
||||||
state: &V01State,
|
state: &V02State,
|
||||||
) -> PrivacyPreservingTransaction {
|
) -> PrivacyPreservingTransaction {
|
||||||
let program = Program::authenticated_transfer_program();
|
let program = Program::authenticated_transfer_program();
|
||||||
let sender_commitment = Commitment::new(&sender_keys.npk(), sender_private_account);
|
let sender_commitment = Commitment::new(&sender_keys.npk(), sender_private_account);
|
||||||
@ -956,7 +966,7 @@ pub mod tests {
|
|||||||
let sender_keys = test_public_account_keys_1();
|
let sender_keys = test_public_account_keys_1();
|
||||||
let recipient_keys = test_private_account_keys_1();
|
let recipient_keys = test_private_account_keys_1();
|
||||||
|
|
||||||
let mut state = V01State::new_with_genesis_accounts(&[(sender_keys.address(), 200)], &[]);
|
let mut state = V02State::new_with_genesis_accounts(&[(sender_keys.address(), 200)], &[]);
|
||||||
|
|
||||||
let balance_to_move = 37;
|
let balance_to_move = 37;
|
||||||
|
|
||||||
@ -1002,7 +1012,7 @@ pub mod tests {
|
|||||||
};
|
};
|
||||||
let recipient_keys = test_private_account_keys_2();
|
let recipient_keys = test_private_account_keys_2();
|
||||||
|
|
||||||
let mut state = V01State::new_with_genesis_accounts(&[], &[])
|
let mut state = V02State::new_with_genesis_accounts(&[], &[])
|
||||||
.with_private_account(&sender_keys, &sender_private_account);
|
.with_private_account(&sender_keys, &sender_private_account);
|
||||||
|
|
||||||
let balance_to_move = 37;
|
let balance_to_move = 37;
|
||||||
@ -1068,7 +1078,7 @@ pub mod tests {
|
|||||||
};
|
};
|
||||||
let recipient_keys = test_public_account_keys_1();
|
let recipient_keys = test_public_account_keys_1();
|
||||||
let recipient_initial_balance = 400;
|
let recipient_initial_balance = 400;
|
||||||
let mut state = V01State::new_with_genesis_accounts(
|
let mut state = V02State::new_with_genesis_accounts(
|
||||||
&[(recipient_keys.address(), recipient_initial_balance)],
|
&[(recipient_keys.address(), recipient_initial_balance)],
|
||||||
&[],
|
&[],
|
||||||
)
|
)
|
||||||
@ -1956,7 +1966,7 @@ pub mod tests {
|
|||||||
};
|
};
|
||||||
let recipient_keys = test_private_account_keys_2();
|
let recipient_keys = test_private_account_keys_2();
|
||||||
|
|
||||||
let mut state = V01State::new_with_genesis_accounts(&[], &[])
|
let mut state = V02State::new_with_genesis_accounts(&[], &[])
|
||||||
.with_private_account(&sender_keys, &sender_private_account);
|
.with_private_account(&sender_keys, &sender_private_account);
|
||||||
|
|
||||||
let balance_to_move = 37;
|
let balance_to_move = 37;
|
||||||
|
|||||||
@ -88,6 +88,7 @@ impl SequencerCore {
|
|||||||
Err(TransactionMalformationError::InvalidSignature)
|
Err(TransactionMalformationError::InvalidSignature)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
NSSATransaction::ProgramDeployment(tx) => Ok(NSSATransaction::ProgramDeployment(tx)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,6 +133,12 @@ impl SequencerCore {
|
|||||||
.transition_from_privacy_preserving_transaction(tx)
|
.transition_from_privacy_preserving_transaction(tx)
|
||||||
.inspect_err(|err| warn!("Error at transition {err:#?}"))?;
|
.inspect_err(|err| warn!("Error at transition {err:#?}"))?;
|
||||||
}
|
}
|
||||||
|
NSSATransaction::ProgramDeployment(tx) => {
|
||||||
|
self.store
|
||||||
|
.state
|
||||||
|
.transition_from_program_deployment_transaction(tx)
|
||||||
|
.inspect_err(|err| warn!("Error at transition {err:#?}"))?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(tx)
|
Ok(tx)
|
||||||
@ -221,13 +228,13 @@ mod tests {
|
|||||||
|
|
||||||
fn setup_sequencer_config() -> SequencerConfig {
|
fn setup_sequencer_config() -> SequencerConfig {
|
||||||
let acc1_addr = vec![
|
let acc1_addr = vec![
|
||||||
14, 238, 36, 40, 114, 150, 186, 85, 39, 143, 30, 84, 3, 190, 1, 71, 84, 134, 99, 102,
|
208, 122, 210, 232, 75, 39, 250, 0, 194, 98, 240, 161, 238, 160, 255, 53, 202, 9, 115,
|
||||||
56, 135, 48, 48, 60, 40, 137, 190, 23, 173, 160, 101,
|
84, 126, 106, 16, 111, 114, 241, 147, 194, 220, 131, 139, 68,
|
||||||
];
|
];
|
||||||
|
|
||||||
let acc2_addr = vec![
|
let acc2_addr = vec![
|
||||||
158, 61, 142, 101, 77, 68, 14, 149, 41, 58, 162, 220, 236, 235, 19, 120, 153, 165, 149,
|
231, 174, 119, 197, 239, 26, 5, 153, 147, 68, 175, 73, 159, 199, 138, 23, 5, 57, 141,
|
||||||
53, 233, 82, 247, 71, 6, 142, 122, 14, 227, 9, 101, 242,
|
98, 237, 6, 207, 46, 20, 121, 246, 222, 248, 154, 57, 188,
|
||||||
];
|
];
|
||||||
|
|
||||||
let initial_acc1 = AccountInitialData {
|
let initial_acc1 = AccountInitialData {
|
||||||
|
|||||||
@ -10,7 +10,7 @@ use crate::config::AccountInitialData;
|
|||||||
pub mod block_store;
|
pub mod block_store;
|
||||||
|
|
||||||
pub struct SequecerChainStore {
|
pub struct SequecerChainStore {
|
||||||
pub state: nssa::V01State,
|
pub state: nssa::V02State,
|
||||||
pub block_store: SequecerBlockStore,
|
pub block_store: SequecerBlockStore,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29,12 +29,12 @@ impl SequecerChainStore {
|
|||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
#[cfg(not(feature = "testnet"))]
|
#[cfg(not(feature = "testnet"))]
|
||||||
let state = nssa::V01State::new_with_genesis_accounts(&init_accs, initial_commitments);
|
let state = nssa::V02State::new_with_genesis_accounts(&init_accs, initial_commitments);
|
||||||
|
|
||||||
#[cfg(feature = "testnet")]
|
#[cfg(feature = "testnet")]
|
||||||
let state = {
|
let state = {
|
||||||
let mut this =
|
let mut this =
|
||||||
nssa::V01State::new_with_genesis_accounts(&init_accs, initial_commitments);
|
nssa::V02State::new_with_genesis_accounts(&init_accs, initial_commitments);
|
||||||
this.add_pinata_program("cafe".repeat(16).parse().unwrap());
|
this.add_pinata_program("cafe".repeat(16).parse().unwrap());
|
||||||
this
|
this
|
||||||
};
|
};
|
||||||
|
|||||||
@ -330,13 +330,13 @@ mod tests {
|
|||||||
let tempdir = tempdir().unwrap();
|
let tempdir = tempdir().unwrap();
|
||||||
let home = tempdir.path().to_path_buf();
|
let home = tempdir.path().to_path_buf();
|
||||||
let acc1_addr = vec![
|
let acc1_addr = vec![
|
||||||
14, 238, 36, 40, 114, 150, 186, 85, 39, 143, 30, 84, 3, 190, 1, 71, 84, 134, 99, 102,
|
208, 122, 210, 232, 75, 39, 250, 0, 194, 98, 240, 161, 238, 160, 255, 53, 202, 9, 115,
|
||||||
56, 135, 48, 48, 60, 40, 137, 190, 23, 173, 160, 101,
|
84, 126, 106, 16, 111, 114, 241, 147, 194, 220, 131, 139, 68,
|
||||||
];
|
];
|
||||||
|
|
||||||
let acc2_addr = vec![
|
let acc2_addr = vec![
|
||||||
158, 61, 142, 101, 77, 68, 14, 149, 41, 58, 162, 220, 236, 235, 19, 120, 153, 165, 149,
|
231, 174, 119, 197, 239, 26, 5, 153, 147, 68, 175, 73, 159, 199, 138, 23, 5, 57, 141,
|
||||||
53, 233, 82, 247, 71, 6, 142, 122, 14, 227, 9, 101, 242,
|
98, 237, 6, 207, 46, 20, 121, 246, 222, 248, 154, 57, 188,
|
||||||
];
|
];
|
||||||
|
|
||||||
let initial_acc1 = AccountInitialData {
|
let initial_acc1 = AccountInitialData {
|
||||||
@ -374,8 +374,8 @@ mod tests {
|
|||||||
let balance_to_move = 10;
|
let balance_to_move = 10;
|
||||||
let tx = common::test_utils::create_transaction_native_token_transfer(
|
let tx = common::test_utils::create_transaction_native_token_transfer(
|
||||||
[
|
[
|
||||||
14, 238, 36, 40, 114, 150, 186, 85, 39, 143, 30, 84, 3, 190, 1, 71, 84, 134, 99,
|
208, 122, 210, 232, 75, 39, 250, 0, 194, 98, 240, 161, 238, 160, 255, 53, 202, 9,
|
||||||
102, 56, 135, 48, 48, 60, 40, 137, 190, 23, 173, 160, 101,
|
115, 84, 126, 106, 16, 111, 114, 241, 147, 194, 220, 131, 139, 68,
|
||||||
],
|
],
|
||||||
0,
|
0,
|
||||||
[2; 32],
|
[2; 32],
|
||||||
|
|||||||
@ -8,11 +8,11 @@
|
|||||||
"port": 3040,
|
"port": 3040,
|
||||||
"initial_accounts": [
|
"initial_accounts": [
|
||||||
{
|
{
|
||||||
"addr": "0eee24287296ba55278f1e5403be014754866366388730303c2889be17ada065",
|
"addr": "d07ad2e84b27fa00c262f0a1eea0ff35ca0973547e6a106f72f193c2dc838b44",
|
||||||
"balance": 10000
|
"balance": 10000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"addr": "9e3d8e654d440e95293aa2dceceb137899a59535e952f747068e7a0ee30965f2",
|
"addr": "e7ae77c5ef1a05999344af499fc78a1705398d62ed06cf2e1479f6def89a39bc",
|
||||||
"balance": 20000
|
"balance": 20000
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|||||||
@ -77,14 +77,14 @@ mod tests {
|
|||||||
fn create_initial_accounts() -> Vec<InitialAccountData> {
|
fn create_initial_accounts() -> Vec<InitialAccountData> {
|
||||||
let initial_acc1 = serde_json::from_str(r#"{
|
let initial_acc1 = serde_json::from_str(r#"{
|
||||||
"Public": {
|
"Public": {
|
||||||
"address": "0eee24287296ba55278f1e5403be014754866366388730303c2889be17ada065",
|
"address": "d07ad2e84b27fa00c262f0a1eea0ff35ca0973547e6a106f72f193c2dc838b44",
|
||||||
"pub_sign_key": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
|
"pub_sign_key": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
|
||||||
}
|
}
|
||||||
}"#).unwrap();
|
}"#).unwrap();
|
||||||
|
|
||||||
let initial_acc2 = serde_json::from_str(r#"{
|
let initial_acc2 = serde_json::from_str(r#"{
|
||||||
"Public": {
|
"Public": {
|
||||||
"address": "9e3d8e654d440e95293aa2dceceb137899a59535e952f747068e7a0ee30965f2",
|
"address": "e7ae77c5ef1a05999344af499fc78a1705398d62ed06cf2e1479f6def89a39bc",
|
||||||
"pub_sign_key": [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]
|
"pub_sign_key": [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]
|
||||||
}
|
}
|
||||||
}"#).unwrap();
|
}"#).unwrap();
|
||||||
|
|||||||
253
wallet/src/cli/account.rs
Normal file
253
wallet/src/cli/account.rs
Normal file
@ -0,0 +1,253 @@
|
|||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
|
use clap::Subcommand;
|
||||||
|
use common::transaction::NSSATransaction;
|
||||||
|
use nssa::Address;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
SubcommandReturnValue, WalletCore, cli::WalletSubcommand, helperfunctions::HumanReadableAccount,
|
||||||
|
};
|
||||||
|
|
||||||
|
///Represents generic chain CLI subcommand
|
||||||
|
#[derive(Subcommand, Debug, Clone)]
|
||||||
|
pub enum AccountSubcommand {
|
||||||
|
///Get
|
||||||
|
#[command(subcommand)]
|
||||||
|
Get(GetSubcommand),
|
||||||
|
///Fetch
|
||||||
|
#[command(subcommand)]
|
||||||
|
Fetch(FetchSubcommand),
|
||||||
|
///Register
|
||||||
|
#[command(subcommand)]
|
||||||
|
Register(RegisterSubcommand),
|
||||||
|
}
|
||||||
|
|
||||||
|
///Represents generic getter CLI subcommand
|
||||||
|
#[derive(Subcommand, Debug, Clone)]
|
||||||
|
pub enum GetSubcommand {
|
||||||
|
///Get account `addr` balance
|
||||||
|
PublicAccountBalance {
|
||||||
|
#[arg(short, long)]
|
||||||
|
addr: String,
|
||||||
|
},
|
||||||
|
///Get account `addr` nonce
|
||||||
|
PublicAccountNonce {
|
||||||
|
#[arg(short, long)]
|
||||||
|
addr: String,
|
||||||
|
},
|
||||||
|
///Get account at address `addr`
|
||||||
|
PublicAccount {
|
||||||
|
#[arg(short, long)]
|
||||||
|
addr: String,
|
||||||
|
},
|
||||||
|
///Get private account with `addr` from storage
|
||||||
|
PrivateAccount {
|
||||||
|
#[arg(short, long)]
|
||||||
|
addr: String,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
///Represents generic getter CLI subcommand
|
||||||
|
#[derive(Subcommand, Debug, Clone)]
|
||||||
|
pub enum FetchSubcommand {
|
||||||
|
///Fetch transaction by `hash`
|
||||||
|
Tx {
|
||||||
|
#[arg(short, long)]
|
||||||
|
tx_hash: String,
|
||||||
|
},
|
||||||
|
///Claim account `acc_addr` generated in transaction `tx_hash`, using secret `sh_secret` at ciphertext id `ciph_id`
|
||||||
|
PrivateAccount {
|
||||||
|
///tx_hash - valid 32 byte hex string
|
||||||
|
#[arg(long)]
|
||||||
|
tx_hash: String,
|
||||||
|
///acc_addr - valid 32 byte hex string
|
||||||
|
#[arg(long)]
|
||||||
|
acc_addr: String,
|
||||||
|
///output_id - id of the output in the transaction
|
||||||
|
#[arg(long)]
|
||||||
|
output_id: usize,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
///Represents generic register CLI subcommand
|
||||||
|
#[derive(Subcommand, Debug, Clone)]
|
||||||
|
pub enum RegisterSubcommand {
|
||||||
|
///Register new public account
|
||||||
|
Public {},
|
||||||
|
///Register new private account
|
||||||
|
Private {},
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WalletSubcommand for GetSubcommand {
|
||||||
|
async fn handle_subcommand(
|
||||||
|
self,
|
||||||
|
wallet_core: &mut WalletCore,
|
||||||
|
) -> Result<SubcommandReturnValue> {
|
||||||
|
match self {
|
||||||
|
GetSubcommand::PublicAccountBalance { addr } => {
|
||||||
|
let addr = Address::from_str(&addr)?;
|
||||||
|
|
||||||
|
let balance = wallet_core.get_account_balance(addr).await?;
|
||||||
|
println!("Accounts {addr} balance is {balance}");
|
||||||
|
|
||||||
|
Ok(SubcommandReturnValue::Empty)
|
||||||
|
}
|
||||||
|
GetSubcommand::PublicAccountNonce { addr } => {
|
||||||
|
let addr = Address::from_str(&addr)?;
|
||||||
|
|
||||||
|
let nonce = wallet_core.get_accounts_nonces(vec![addr]).await?[0];
|
||||||
|
println!("Accounts {addr} nonce is {nonce}");
|
||||||
|
|
||||||
|
Ok(SubcommandReturnValue::Empty)
|
||||||
|
}
|
||||||
|
GetSubcommand::PublicAccount { addr } => {
|
||||||
|
let addr: Address = addr.parse()?;
|
||||||
|
let account = wallet_core.get_account_public(addr).await?;
|
||||||
|
let account_hr: HumanReadableAccount = account.clone().into();
|
||||||
|
println!("{}", serde_json::to_string(&account_hr).unwrap());
|
||||||
|
|
||||||
|
Ok(SubcommandReturnValue::Account(account))
|
||||||
|
}
|
||||||
|
GetSubcommand::PrivateAccount { addr } => {
|
||||||
|
let addr: Address = addr.parse()?;
|
||||||
|
if let Some(account) = wallet_core.get_account_private(&addr) {
|
||||||
|
println!("{}", serde_json::to_string(&account).unwrap());
|
||||||
|
} else {
|
||||||
|
println!("Private account not found.");
|
||||||
|
}
|
||||||
|
Ok(SubcommandReturnValue::Empty)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WalletSubcommand for FetchSubcommand {
|
||||||
|
async fn handle_subcommand(
|
||||||
|
self,
|
||||||
|
wallet_core: &mut WalletCore,
|
||||||
|
) -> Result<SubcommandReturnValue> {
|
||||||
|
match self {
|
||||||
|
FetchSubcommand::Tx { tx_hash } => {
|
||||||
|
let tx_obj = wallet_core
|
||||||
|
.sequencer_client
|
||||||
|
.get_transaction_by_hash(tx_hash)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
println!("Transaction object {tx_obj:#?}");
|
||||||
|
|
||||||
|
Ok(SubcommandReturnValue::Empty)
|
||||||
|
}
|
||||||
|
FetchSubcommand::PrivateAccount {
|
||||||
|
tx_hash,
|
||||||
|
acc_addr,
|
||||||
|
output_id: ciph_id,
|
||||||
|
} => {
|
||||||
|
let acc_addr: Address = acc_addr.parse().unwrap();
|
||||||
|
|
||||||
|
let account_key_chain = wallet_core
|
||||||
|
.storage
|
||||||
|
.user_data
|
||||||
|
.user_private_accounts
|
||||||
|
.get(&acc_addr);
|
||||||
|
|
||||||
|
let Some((account_key_chain, _)) = account_key_chain else {
|
||||||
|
anyhow::bail!("Account not found");
|
||||||
|
};
|
||||||
|
|
||||||
|
let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?;
|
||||||
|
|
||||||
|
if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx {
|
||||||
|
let to_ebc = tx.message.encrypted_private_post_states[ciph_id].clone();
|
||||||
|
let to_comm = tx.message.new_commitments[ciph_id].clone();
|
||||||
|
let shared_secret =
|
||||||
|
account_key_chain.calculate_shared_secret_receiver(to_ebc.epk);
|
||||||
|
|
||||||
|
let res_acc_to = nssa_core::EncryptionScheme::decrypt(
|
||||||
|
&to_ebc.ciphertext,
|
||||||
|
&shared_secret,
|
||||||
|
&to_comm,
|
||||||
|
ciph_id as u32,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
println!("RES acc to {res_acc_to:#?}");
|
||||||
|
|
||||||
|
println!("Transaction data is {:?}", tx.message);
|
||||||
|
|
||||||
|
wallet_core
|
||||||
|
.storage
|
||||||
|
.insert_private_account_data(acc_addr, res_acc_to);
|
||||||
|
}
|
||||||
|
|
||||||
|
let path = wallet_core.store_persistent_accounts().await?;
|
||||||
|
|
||||||
|
println!("Stored persistent accounts at {path:#?}");
|
||||||
|
|
||||||
|
Ok(SubcommandReturnValue::Empty)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WalletSubcommand for RegisterSubcommand {
|
||||||
|
async fn handle_subcommand(
|
||||||
|
self,
|
||||||
|
wallet_core: &mut WalletCore,
|
||||||
|
) -> Result<SubcommandReturnValue> {
|
||||||
|
match self {
|
||||||
|
RegisterSubcommand::Public {} => {
|
||||||
|
let addr = wallet_core.create_new_account_public();
|
||||||
|
|
||||||
|
println!("Generated new account with addr {addr}");
|
||||||
|
|
||||||
|
let path = wallet_core.store_persistent_accounts().await?;
|
||||||
|
|
||||||
|
println!("Stored persistent accounts at {path:#?}");
|
||||||
|
|
||||||
|
Ok(SubcommandReturnValue::RegisterAccount { addr })
|
||||||
|
}
|
||||||
|
RegisterSubcommand::Private {} => {
|
||||||
|
let addr = wallet_core.create_new_account_private();
|
||||||
|
|
||||||
|
let (key, _) = wallet_core
|
||||||
|
.storage
|
||||||
|
.user_data
|
||||||
|
.get_private_account(&addr)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
println!("Generated new account with addr {addr}");
|
||||||
|
println!("With npk {}", hex::encode(&key.nullifer_public_key));
|
||||||
|
println!(
|
||||||
|
"With ipk {}",
|
||||||
|
hex::encode(key.incoming_viewing_public_key.to_bytes())
|
||||||
|
);
|
||||||
|
|
||||||
|
let path = wallet_core.store_persistent_accounts().await?;
|
||||||
|
|
||||||
|
println!("Stored persistent accounts at {path:#?}");
|
||||||
|
|
||||||
|
Ok(SubcommandReturnValue::RegisterAccount { addr })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WalletSubcommand for AccountSubcommand {
|
||||||
|
async fn handle_subcommand(
|
||||||
|
self,
|
||||||
|
wallet_core: &mut WalletCore,
|
||||||
|
) -> Result<SubcommandReturnValue> {
|
||||||
|
match self {
|
||||||
|
AccountSubcommand::Get(get_subcommand) => {
|
||||||
|
get_subcommand.handle_subcommand(wallet_core).await
|
||||||
|
}
|
||||||
|
AccountSubcommand::Fetch(fetch_subcommand) => {
|
||||||
|
fetch_subcommand.handle_subcommand(wallet_core).await
|
||||||
|
}
|
||||||
|
AccountSubcommand::Register(register_subcommand) => {
|
||||||
|
register_subcommand.handle_subcommand(wallet_core).await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
47
wallet/src/cli/chain.rs
Normal file
47
wallet/src/cli/chain.rs
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
use anyhow::Result;
|
||||||
|
use clap::Subcommand;
|
||||||
|
|
||||||
|
use crate::{SubcommandReturnValue, WalletCore, cli::WalletSubcommand};
|
||||||
|
|
||||||
|
///Represents generic chain CLI subcommand
|
||||||
|
#[derive(Subcommand, Debug, Clone)]
|
||||||
|
pub enum ChainSubcommand {
|
||||||
|
GetLatestBlockId {},
|
||||||
|
GetBlockAtId {
|
||||||
|
#[arg(short, long)]
|
||||||
|
id: u64,
|
||||||
|
},
|
||||||
|
GetTransactionAtHash {
|
||||||
|
#[arg(short, long)]
|
||||||
|
hash: String,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WalletSubcommand for ChainSubcommand {
|
||||||
|
async fn handle_subcommand(
|
||||||
|
self,
|
||||||
|
wallet_core: &mut WalletCore,
|
||||||
|
) -> Result<SubcommandReturnValue> {
|
||||||
|
match self {
|
||||||
|
ChainSubcommand::GetLatestBlockId {} => {
|
||||||
|
let latest_block_res = wallet_core.sequencer_client.get_last_block().await?;
|
||||||
|
|
||||||
|
println!("Last block id is {}", latest_block_res.last_block);
|
||||||
|
}
|
||||||
|
ChainSubcommand::GetBlockAtId { id } => {
|
||||||
|
let block_res = wallet_core.sequencer_client.get_block(id).await?;
|
||||||
|
|
||||||
|
println!("Last block id is {:#?}", block_res.block);
|
||||||
|
}
|
||||||
|
ChainSubcommand::GetTransactionAtHash { hash } => {
|
||||||
|
let tx_res = wallet_core
|
||||||
|
.sequencer_client
|
||||||
|
.get_transaction_by_hash(hash)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
println!("Last block id is {:#?}", tx_res.transaction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(SubcommandReturnValue::Empty)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,6 +2,10 @@ use anyhow::Result;
|
|||||||
|
|
||||||
use crate::{SubcommandReturnValue, WalletCore};
|
use crate::{SubcommandReturnValue, WalletCore};
|
||||||
|
|
||||||
|
pub mod account;
|
||||||
|
pub mod chain;
|
||||||
|
pub mod native_token_transfer_program;
|
||||||
|
pub mod pinata_program;
|
||||||
pub mod token_program;
|
pub mod token_program;
|
||||||
|
|
||||||
pub(crate) trait WalletSubcommand {
|
pub(crate) trait WalletSubcommand {
|
||||||
|
|||||||
362
wallet/src/cli/native_token_transfer_program.rs
Normal file
362
wallet/src/cli/native_token_transfer_program.rs
Normal file
@ -0,0 +1,362 @@
|
|||||||
|
use anyhow::Result;
|
||||||
|
use clap::Subcommand;
|
||||||
|
use common::transaction::NSSATransaction;
|
||||||
|
use nssa::Address;
|
||||||
|
|
||||||
|
use crate::{SubcommandReturnValue, WalletCore, cli::WalletSubcommand};
|
||||||
|
|
||||||
|
///Represents generic CLI subcommand for a wallet working with native token transfer program
|
||||||
|
#[derive(Subcommand, Debug, Clone)]
|
||||||
|
pub enum NativeTokenTransferProgramSubcommand {
|
||||||
|
///Send native token transfer from `from` to `to` for `amount`
|
||||||
|
///
|
||||||
|
/// Public operation
|
||||||
|
Public {
|
||||||
|
///from - valid 32 byte hex string
|
||||||
|
#[arg(long)]
|
||||||
|
from: String,
|
||||||
|
///to - valid 32 byte hex string
|
||||||
|
#[arg(long)]
|
||||||
|
to: String,
|
||||||
|
///amount - amount of balance to move
|
||||||
|
#[arg(long)]
|
||||||
|
amount: u128,
|
||||||
|
},
|
||||||
|
///Private execution
|
||||||
|
#[command(subcommand)]
|
||||||
|
Private(NativeTokenTransferProgramSubcommandPrivate),
|
||||||
|
///Send native token transfer from `from` to `to` for `amount`
|
||||||
|
///
|
||||||
|
/// Deshielded operation
|
||||||
|
Deshielded {
|
||||||
|
///from - valid 32 byte hex string
|
||||||
|
#[arg(long)]
|
||||||
|
from: String,
|
||||||
|
///to - valid 32 byte hex string
|
||||||
|
#[arg(long)]
|
||||||
|
to: String,
|
||||||
|
///amount - amount of balance to move
|
||||||
|
#[arg(long)]
|
||||||
|
amount: u128,
|
||||||
|
},
|
||||||
|
///Shielded execution
|
||||||
|
#[command(subcommand)]
|
||||||
|
Shielded(NativeTokenTransferProgramSubcommandShielded),
|
||||||
|
}
|
||||||
|
|
||||||
|
///Represents generic shielded CLI subcommand for a wallet working with native token transfer program
|
||||||
|
#[derive(Subcommand, Debug, Clone)]
|
||||||
|
pub enum NativeTokenTransferProgramSubcommandShielded {
|
||||||
|
///Send native token transfer from `from` to `to` for `amount`
|
||||||
|
///
|
||||||
|
/// Shielded operation
|
||||||
|
ShieldedOwned {
|
||||||
|
///from - valid 32 byte hex string
|
||||||
|
#[arg(long)]
|
||||||
|
from: String,
|
||||||
|
///to - valid 32 byte hex string
|
||||||
|
#[arg(long)]
|
||||||
|
to: String,
|
||||||
|
///amount - amount of balance to move
|
||||||
|
#[arg(long)]
|
||||||
|
amount: u128,
|
||||||
|
},
|
||||||
|
///Send native token transfer from `from` to `to` for `amount`
|
||||||
|
///
|
||||||
|
/// Shielded operation
|
||||||
|
ShieldedForeign {
|
||||||
|
///from - valid 32 byte hex string
|
||||||
|
#[arg(long)]
|
||||||
|
from: String,
|
||||||
|
///to_npk - valid 32 byte hex string
|
||||||
|
#[arg(long)]
|
||||||
|
to_npk: String,
|
||||||
|
///to_ipk - valid 33 byte hex string
|
||||||
|
#[arg(long)]
|
||||||
|
to_ipk: String,
|
||||||
|
///amount - amount of balance to move
|
||||||
|
#[arg(long)]
|
||||||
|
amount: u128,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
///Represents generic private CLI subcommand for a wallet working with native token transfer program
|
||||||
|
#[derive(Subcommand, Debug, Clone)]
|
||||||
|
pub enum NativeTokenTransferProgramSubcommandPrivate {
|
||||||
|
///Send native token transfer from `from` to `to` for `amount`
|
||||||
|
///
|
||||||
|
/// Private operation
|
||||||
|
PrivateOwned {
|
||||||
|
///from - valid 32 byte hex string
|
||||||
|
#[arg(long)]
|
||||||
|
from: String,
|
||||||
|
///to - valid 32 byte hex string
|
||||||
|
#[arg(long)]
|
||||||
|
to: String,
|
||||||
|
///amount - amount of balance to move
|
||||||
|
#[arg(long)]
|
||||||
|
amount: u128,
|
||||||
|
},
|
||||||
|
///Send native token transfer from `from` to `to` for `amount`
|
||||||
|
///
|
||||||
|
/// Private operation
|
||||||
|
PrivateForeign {
|
||||||
|
///from - valid 32 byte hex string
|
||||||
|
#[arg(long)]
|
||||||
|
from: String,
|
||||||
|
///to_npk - valid 32 byte hex string
|
||||||
|
#[arg(long)]
|
||||||
|
to_npk: String,
|
||||||
|
///to_ipk - valid 33 byte hex string
|
||||||
|
#[arg(long)]
|
||||||
|
to_ipk: String,
|
||||||
|
///amount - amount of balance to move
|
||||||
|
#[arg(long)]
|
||||||
|
amount: u128,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WalletSubcommand for NativeTokenTransferProgramSubcommandPrivate {
|
||||||
|
async fn handle_subcommand(
|
||||||
|
self,
|
||||||
|
wallet_core: &mut WalletCore,
|
||||||
|
) -> Result<SubcommandReturnValue> {
|
||||||
|
match self {
|
||||||
|
NativeTokenTransferProgramSubcommandPrivate::PrivateOwned { from, to, amount } => {
|
||||||
|
let from: Address = from.parse().unwrap();
|
||||||
|
let to: Address = to.parse().unwrap();
|
||||||
|
|
||||||
|
let to_initialization = wallet_core.check_private_account_initialized(&to).await?;
|
||||||
|
|
||||||
|
let (res, [secret_from, secret_to]) = if let Some(to_proof) = to_initialization {
|
||||||
|
wallet_core
|
||||||
|
.send_private_native_token_transfer_owned_account_already_initialized(
|
||||||
|
from, to, amount, to_proof,
|
||||||
|
)
|
||||||
|
.await?
|
||||||
|
} else {
|
||||||
|
wallet_core
|
||||||
|
.send_private_native_token_transfer_owned_account_not_initialized(
|
||||||
|
from, to, amount,
|
||||||
|
)
|
||||||
|
.await?
|
||||||
|
};
|
||||||
|
|
||||||
|
println!("Results of tx send is {res:#?}");
|
||||||
|
|
||||||
|
let tx_hash = res.tx_hash;
|
||||||
|
let transfer_tx = wallet_core
|
||||||
|
.poll_native_token_transfer(tx_hash.clone())
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx {
|
||||||
|
let acc_decode_data = vec![(secret_from, from), (secret_to, to)];
|
||||||
|
|
||||||
|
wallet_core.decode_insert_privacy_preserving_transaction_results(
|
||||||
|
tx,
|
||||||
|
&acc_decode_data,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let path = wallet_core.store_persistent_accounts().await?;
|
||||||
|
|
||||||
|
println!("Stored persistent accounts at {path:#?}");
|
||||||
|
|
||||||
|
Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash })
|
||||||
|
}
|
||||||
|
NativeTokenTransferProgramSubcommandPrivate::PrivateForeign {
|
||||||
|
from,
|
||||||
|
to_npk,
|
||||||
|
to_ipk,
|
||||||
|
amount,
|
||||||
|
} => {
|
||||||
|
let from: Address = from.parse().unwrap();
|
||||||
|
let to_npk_res = hex::decode(to_npk)?;
|
||||||
|
let mut to_npk = [0; 32];
|
||||||
|
to_npk.copy_from_slice(&to_npk_res);
|
||||||
|
let to_npk = nssa_core::NullifierPublicKey(to_npk);
|
||||||
|
|
||||||
|
let to_ipk_res = hex::decode(to_ipk)?;
|
||||||
|
let mut to_ipk = [0u8; 33];
|
||||||
|
to_ipk.copy_from_slice(&to_ipk_res);
|
||||||
|
let to_ipk =
|
||||||
|
nssa_core::encryption::shared_key_derivation::Secp256k1Point(to_ipk.to_vec());
|
||||||
|
|
||||||
|
let (res, [secret_from, _]) = wallet_core
|
||||||
|
.send_private_native_token_transfer_outer_account(from, to_npk, to_ipk, amount)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
println!("Results of tx send is {res:#?}");
|
||||||
|
|
||||||
|
let tx_hash = res.tx_hash;
|
||||||
|
let transfer_tx = wallet_core
|
||||||
|
.poll_native_token_transfer(tx_hash.clone())
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx {
|
||||||
|
let acc_decode_data = vec![(secret_from, from)];
|
||||||
|
|
||||||
|
wallet_core.decode_insert_privacy_preserving_transaction_results(
|
||||||
|
tx,
|
||||||
|
&acc_decode_data,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let path = wallet_core.store_persistent_accounts().await?;
|
||||||
|
|
||||||
|
println!("Stored persistent accounts at {path:#?}");
|
||||||
|
|
||||||
|
Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WalletSubcommand for NativeTokenTransferProgramSubcommandShielded {
|
||||||
|
async fn handle_subcommand(
|
||||||
|
self,
|
||||||
|
wallet_core: &mut WalletCore,
|
||||||
|
) -> Result<SubcommandReturnValue> {
|
||||||
|
match self {
|
||||||
|
NativeTokenTransferProgramSubcommandShielded::ShieldedOwned { from, to, amount } => {
|
||||||
|
let from: Address = from.parse().unwrap();
|
||||||
|
let to: Address = to.parse().unwrap();
|
||||||
|
|
||||||
|
let to_initialization = wallet_core.check_private_account_initialized(&to).await?;
|
||||||
|
|
||||||
|
let (res, secret) = if let Some(to_proof) = to_initialization {
|
||||||
|
wallet_core
|
||||||
|
.send_shielded_native_token_transfer_already_initialized(
|
||||||
|
from, to, amount, to_proof,
|
||||||
|
)
|
||||||
|
.await?
|
||||||
|
} else {
|
||||||
|
wallet_core
|
||||||
|
.send_shielded_native_token_transfer_not_initialized(from, to, amount)
|
||||||
|
.await?
|
||||||
|
};
|
||||||
|
|
||||||
|
println!("Results of tx send is {res:#?}");
|
||||||
|
|
||||||
|
let tx_hash = res.tx_hash;
|
||||||
|
let transfer_tx = wallet_core
|
||||||
|
.poll_native_token_transfer(tx_hash.clone())
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx {
|
||||||
|
let acc_decode_data = vec![(secret, to)];
|
||||||
|
|
||||||
|
wallet_core.decode_insert_privacy_preserving_transaction_results(
|
||||||
|
tx,
|
||||||
|
&acc_decode_data,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let path = wallet_core.store_persistent_accounts().await?;
|
||||||
|
|
||||||
|
println!("Stored persistent accounts at {path:#?}");
|
||||||
|
|
||||||
|
Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash })
|
||||||
|
}
|
||||||
|
NativeTokenTransferProgramSubcommandShielded::ShieldedForeign {
|
||||||
|
from,
|
||||||
|
to_npk,
|
||||||
|
to_ipk,
|
||||||
|
amount,
|
||||||
|
} => {
|
||||||
|
let from: Address = from.parse().unwrap();
|
||||||
|
|
||||||
|
let to_npk_res = hex::decode(to_npk)?;
|
||||||
|
let mut to_npk = [0; 32];
|
||||||
|
to_npk.copy_from_slice(&to_npk_res);
|
||||||
|
let to_npk = nssa_core::NullifierPublicKey(to_npk);
|
||||||
|
|
||||||
|
let to_ipk_res = hex::decode(to_ipk)?;
|
||||||
|
let mut to_ipk = [0u8; 33];
|
||||||
|
to_ipk.copy_from_slice(&to_ipk_res);
|
||||||
|
let to_ipk =
|
||||||
|
nssa_core::encryption::shared_key_derivation::Secp256k1Point(to_ipk.to_vec());
|
||||||
|
|
||||||
|
let (res, _) = wallet_core
|
||||||
|
.send_shielded_native_token_transfer_outer_account(from, to_npk, to_ipk, amount)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
println!("Results of tx send is {res:#?}");
|
||||||
|
|
||||||
|
let tx_hash = res.tx_hash;
|
||||||
|
|
||||||
|
let path = wallet_core.store_persistent_accounts().await?;
|
||||||
|
|
||||||
|
println!("Stored persistent accounts at {path:#?}");
|
||||||
|
|
||||||
|
Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WalletSubcommand for NativeTokenTransferProgramSubcommand {
|
||||||
|
async fn handle_subcommand(
|
||||||
|
self,
|
||||||
|
wallet_core: &mut WalletCore,
|
||||||
|
) -> Result<SubcommandReturnValue> {
|
||||||
|
match self {
|
||||||
|
NativeTokenTransferProgramSubcommand::Private(private_subcommand) => {
|
||||||
|
private_subcommand.handle_subcommand(wallet_core).await
|
||||||
|
}
|
||||||
|
NativeTokenTransferProgramSubcommand::Shielded(shielded_subcommand) => {
|
||||||
|
shielded_subcommand.handle_subcommand(wallet_core).await
|
||||||
|
}
|
||||||
|
NativeTokenTransferProgramSubcommand::Deshielded { from, to, amount } => {
|
||||||
|
let from: Address = from.parse().unwrap();
|
||||||
|
let to: Address = to.parse().unwrap();
|
||||||
|
|
||||||
|
let (res, secret) = wallet_core
|
||||||
|
.send_deshielded_native_token_transfer(from, to, amount)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
println!("Results of tx send is {res:#?}");
|
||||||
|
|
||||||
|
let tx_hash = res.tx_hash;
|
||||||
|
let transfer_tx = wallet_core
|
||||||
|
.poll_native_token_transfer(tx_hash.clone())
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx {
|
||||||
|
let acc_decode_data = vec![(secret, from)];
|
||||||
|
|
||||||
|
wallet_core.decode_insert_privacy_preserving_transaction_results(
|
||||||
|
tx,
|
||||||
|
&acc_decode_data,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let path = wallet_core.store_persistent_accounts().await?;
|
||||||
|
|
||||||
|
println!("Stored persistent accounts at {path:#?}");
|
||||||
|
|
||||||
|
Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash })
|
||||||
|
}
|
||||||
|
NativeTokenTransferProgramSubcommand::Public { from, to, amount } => {
|
||||||
|
let from: Address = from.parse().unwrap();
|
||||||
|
let to: Address = to.parse().unwrap();
|
||||||
|
|
||||||
|
let res = wallet_core
|
||||||
|
.send_public_native_token_transfer(from, to, amount)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
println!("Results of tx send is {res:#?}");
|
||||||
|
|
||||||
|
let transfer_tx = wallet_core.poll_native_token_transfer(res.tx_hash).await?;
|
||||||
|
|
||||||
|
println!("Transaction data is {transfer_tx:?}");
|
||||||
|
|
||||||
|
let path = wallet_core.store_persistent_accounts().await?;
|
||||||
|
|
||||||
|
println!("Stored persistent accounts at {path:#?}");
|
||||||
|
|
||||||
|
Ok(SubcommandReturnValue::Empty)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
158
wallet/src/cli/pinata_program.rs
Normal file
158
wallet/src/cli/pinata_program.rs
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
use anyhow::Result;
|
||||||
|
use clap::Subcommand;
|
||||||
|
use common::transaction::NSSATransaction;
|
||||||
|
use log::info;
|
||||||
|
|
||||||
|
use crate::{SubcommandReturnValue, WalletCore, cli::WalletSubcommand};
|
||||||
|
|
||||||
|
///Represents generic CLI subcommand for a wallet working with pinata program
|
||||||
|
#[derive(Subcommand, Debug, Clone)]
|
||||||
|
pub enum PinataProgramSubcommand {
|
||||||
|
///Public execution
|
||||||
|
#[command(subcommand)]
|
||||||
|
Public(PinataProgramSubcommandPublic),
|
||||||
|
///Private execution
|
||||||
|
#[command(subcommand)]
|
||||||
|
Private(PinataProgramSubcommandPrivate),
|
||||||
|
}
|
||||||
|
|
||||||
|
///Represents generic public CLI subcommand for a wallet working with pinata program
|
||||||
|
#[derive(Subcommand, Debug, Clone)]
|
||||||
|
pub enum PinataProgramSubcommandPublic {
|
||||||
|
// TODO: Testnet only. Refactor to prevent compilation on mainnet.
|
||||||
|
// Claim piñata prize
|
||||||
|
Claim {
|
||||||
|
///pinata_addr - valid 32 byte hex string
|
||||||
|
#[arg(long)]
|
||||||
|
pinata_addr: String,
|
||||||
|
///winner_addr - valid 32 byte hex string
|
||||||
|
#[arg(long)]
|
||||||
|
winner_addr: String,
|
||||||
|
///solution - solution to pinata challenge
|
||||||
|
#[arg(long)]
|
||||||
|
solution: u128,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
///Represents generic private CLI subcommand for a wallet working with pinata program
|
||||||
|
#[derive(Subcommand, Debug, Clone)]
|
||||||
|
pub enum PinataProgramSubcommandPrivate {
|
||||||
|
// TODO: Testnet only. Refactor to prevent compilation on mainnet.
|
||||||
|
// Claim piñata prize
|
||||||
|
ClaimPrivateOwned {
|
||||||
|
///pinata_addr - valid 32 byte hex string
|
||||||
|
#[arg(long)]
|
||||||
|
pinata_addr: String,
|
||||||
|
///winner_addr - valid 32 byte hex string
|
||||||
|
#[arg(long)]
|
||||||
|
winner_addr: String,
|
||||||
|
///solution - solution to pinata challenge
|
||||||
|
#[arg(long)]
|
||||||
|
solution: u128,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WalletSubcommand for PinataProgramSubcommandPublic {
|
||||||
|
async fn handle_subcommand(
|
||||||
|
self,
|
||||||
|
wallet_core: &mut WalletCore,
|
||||||
|
) -> Result<SubcommandReturnValue> {
|
||||||
|
match self {
|
||||||
|
PinataProgramSubcommandPublic::Claim {
|
||||||
|
pinata_addr,
|
||||||
|
winner_addr,
|
||||||
|
solution,
|
||||||
|
} => {
|
||||||
|
let res = wallet_core
|
||||||
|
.claim_pinata(
|
||||||
|
pinata_addr.parse().unwrap(),
|
||||||
|
winner_addr.parse().unwrap(),
|
||||||
|
solution,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
info!("Results of tx send is {res:#?}");
|
||||||
|
|
||||||
|
Ok(SubcommandReturnValue::Empty)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WalletSubcommand for PinataProgramSubcommandPrivate {
|
||||||
|
async fn handle_subcommand(
|
||||||
|
self,
|
||||||
|
wallet_core: &mut WalletCore,
|
||||||
|
) -> Result<SubcommandReturnValue> {
|
||||||
|
match self {
|
||||||
|
PinataProgramSubcommandPrivate::ClaimPrivateOwned {
|
||||||
|
pinata_addr,
|
||||||
|
winner_addr,
|
||||||
|
solution,
|
||||||
|
} => {
|
||||||
|
let pinata_addr = pinata_addr.parse().unwrap();
|
||||||
|
let winner_addr = winner_addr.parse().unwrap();
|
||||||
|
|
||||||
|
let winner_initialization = wallet_core
|
||||||
|
.check_private_account_initialized(&winner_addr)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
let (res, [secret_winner]) = if let Some(winner_proof) = winner_initialization {
|
||||||
|
wallet_core
|
||||||
|
.claim_pinata_private_owned_account_already_initialized(
|
||||||
|
pinata_addr,
|
||||||
|
winner_addr,
|
||||||
|
solution,
|
||||||
|
winner_proof,
|
||||||
|
)
|
||||||
|
.await?
|
||||||
|
} else {
|
||||||
|
wallet_core
|
||||||
|
.claim_pinata_private_owned_account_not_initialized(
|
||||||
|
pinata_addr,
|
||||||
|
winner_addr,
|
||||||
|
solution,
|
||||||
|
)
|
||||||
|
.await?
|
||||||
|
};
|
||||||
|
|
||||||
|
info!("Results of tx send is {res:#?}");
|
||||||
|
|
||||||
|
let tx_hash = res.tx_hash;
|
||||||
|
let transfer_tx = wallet_core
|
||||||
|
.poll_native_token_transfer(tx_hash.clone())
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx {
|
||||||
|
let acc_decode_data = vec![(secret_winner, winner_addr)];
|
||||||
|
|
||||||
|
wallet_core.decode_insert_privacy_preserving_transaction_results(
|
||||||
|
tx,
|
||||||
|
&acc_decode_data,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let path = wallet_core.store_persistent_accounts().await?;
|
||||||
|
|
||||||
|
println!("Stored persistent accounts at {path:#?}");
|
||||||
|
|
||||||
|
Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WalletSubcommand for PinataProgramSubcommand {
|
||||||
|
async fn handle_subcommand(
|
||||||
|
self,
|
||||||
|
wallet_core: &mut WalletCore,
|
||||||
|
) -> Result<SubcommandReturnValue> {
|
||||||
|
match self {
|
||||||
|
PinataProgramSubcommand::Private(private_subcommand) => {
|
||||||
|
private_subcommand.handle_subcommand(wallet_core).await
|
||||||
|
}
|
||||||
|
PinataProgramSubcommand::Public(public_subcommand) => {
|
||||||
|
public_subcommand.handle_subcommand(wallet_core).await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -221,7 +221,7 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate {
|
|||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let path = wallet_core.store_persistent_accounts()?;
|
let path = wallet_core.store_persistent_accounts().await?;
|
||||||
|
|
||||||
println!("Stored persistent accounts at {path:#?}");
|
println!("Stored persistent accounts at {path:#?}");
|
||||||
|
|
||||||
@ -278,7 +278,7 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate {
|
|||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let path = wallet_core.store_persistent_accounts()?;
|
let path = wallet_core.store_persistent_accounts().await?;
|
||||||
|
|
||||||
println!("Stored persistent accounts at {path:#?}");
|
println!("Stored persistent accounts at {path:#?}");
|
||||||
|
|
||||||
@ -328,7 +328,7 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate {
|
|||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let path = wallet_core.store_persistent_accounts()?;
|
let path = wallet_core.store_persistent_accounts().await?;
|
||||||
|
|
||||||
println!("Stored persistent accounts at {path:#?}");
|
println!("Stored persistent accounts at {path:#?}");
|
||||||
|
|
||||||
@ -376,7 +376,7 @@ impl WalletSubcommand for TokenProgramSubcommandDeshielded {
|
|||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let path = wallet_core.store_persistent_accounts()?;
|
let path = wallet_core.store_persistent_accounts().await?;
|
||||||
|
|
||||||
println!("Stored persistent accounts at {path:#?}");
|
println!("Stored persistent accounts at {path:#?}");
|
||||||
|
|
||||||
@ -431,7 +431,7 @@ impl WalletSubcommand for TokenProgramSubcommandShielded {
|
|||||||
println!("Transaction data is {:?}", tx.message);
|
println!("Transaction data is {:?}", tx.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
let path = wallet_core.store_persistent_accounts()?;
|
let path = wallet_core.store_persistent_accounts().await?;
|
||||||
|
|
||||||
println!("Stored persistent accounts at {path:#?}");
|
println!("Stored persistent accounts at {path:#?}");
|
||||||
|
|
||||||
@ -485,7 +485,7 @@ impl WalletSubcommand for TokenProgramSubcommandShielded {
|
|||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let path = wallet_core.store_persistent_accounts()?;
|
let path = wallet_core.store_persistent_accounts().await?;
|
||||||
|
|
||||||
println!("Stored persistent accounts at {path:#?}");
|
println!("Stored persistent accounts at {path:#?}");
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
use base64::{Engine, engine::general_purpose::STANDARD as BASE64};
|
use base64::{Engine, engine::general_purpose::STANDARD as BASE64};
|
||||||
use nssa_core::account::Nonce;
|
use nssa_core::account::Nonce;
|
||||||
use rand::{RngCore, rngs::OsRng};
|
use rand::{RngCore, rngs::OsRng};
|
||||||
use std::{fs::File, io::BufReader, path::PathBuf, str::FromStr};
|
use std::{path::PathBuf, str::FromStr};
|
||||||
|
use tokio::io::AsyncReadExt;
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use key_protocol::key_protocol_core::NSSAUserData;
|
use key_protocol::key_protocol_core::NSSAUserData;
|
||||||
@ -22,25 +23,25 @@ pub fn get_home() -> Result<PathBuf> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Fetch config from `NSSA_WALLET_HOME_DIR`
|
/// Fetch config from `NSSA_WALLET_HOME_DIR`
|
||||||
pub fn fetch_config() -> Result<WalletConfig> {
|
pub async fn fetch_config() -> Result<WalletConfig> {
|
||||||
let config_home = get_home()?;
|
let config_home = get_home()?;
|
||||||
let file = File::open(config_home.join("wallet_config.json"))?;
|
let config_contents = tokio::fs::read(config_home.join("wallet_config.json")).await?;
|
||||||
let reader = BufReader::new(file);
|
|
||||||
|
|
||||||
Ok(serde_json::from_reader(reader)?)
|
Ok(serde_json::from_slice(&config_contents)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fetch list of accounts stored at `NSSA_WALLET_HOME_DIR/curr_accounts.json`
|
/// Fetch list of accounts stored at `NSSA_WALLET_HOME_DIR/curr_accounts.json`
|
||||||
///
|
///
|
||||||
/// If file not present, it is considered as empty list of persistent accounts
|
/// If file not present, it is considered as empty list of persistent accounts
|
||||||
pub fn fetch_persistent_accounts() -> Result<Vec<PersistentAccountData>> {
|
pub async fn fetch_persistent_accounts() -> Result<Vec<PersistentAccountData>> {
|
||||||
let home = get_home()?;
|
let home = get_home()?;
|
||||||
let accs_path = home.join("curr_accounts.json");
|
let accs_path = home.join("curr_accounts.json");
|
||||||
|
let mut persistent_accounts_content = vec![];
|
||||||
|
|
||||||
match File::open(accs_path) {
|
match tokio::fs::File::open(accs_path).await {
|
||||||
Ok(file) => {
|
Ok(mut file) => {
|
||||||
let reader = BufReader::new(file);
|
file.read_to_end(&mut persistent_accounts_content).await?;
|
||||||
Ok(serde_json::from_reader(reader)?)
|
Ok(serde_json::from_slice(&persistent_accounts_content)?)
|
||||||
}
|
}
|
||||||
Err(err) => match err.kind() {
|
Err(err) => match err.kind() {
|
||||||
std::io::ErrorKind::NotFound => Ok(vec![]),
|
std::io::ErrorKind::NotFound => Ok(vec![]),
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
use std::{fs::File, io::Write, path::PathBuf, str::FromStr, sync::Arc};
|
use std::{path::PathBuf, sync::Arc};
|
||||||
|
|
||||||
use base64::{Engine, engine::general_purpose::STANDARD as BASE64};
|
use base64::{Engine, engine::general_purpose::STANDARD as BASE64};
|
||||||
use common::{
|
use common::{
|
||||||
|
block::HashableBlockData,
|
||||||
sequencer_client::SequencerClient,
|
sequencer_client::SequencerClient,
|
||||||
transaction::{EncodedTransaction, NSSATransaction},
|
transaction::{EncodedTransaction, NSSATransaction},
|
||||||
};
|
};
|
||||||
@ -10,17 +11,24 @@ use anyhow::Result;
|
|||||||
use chain_storage::WalletChainStore;
|
use chain_storage::WalletChainStore;
|
||||||
use config::WalletConfig;
|
use config::WalletConfig;
|
||||||
use log::info;
|
use log::info;
|
||||||
use nssa::{Account, Address, program::Program};
|
use nssa::{
|
||||||
|
Account, Address, privacy_preserving_transaction::message::EncryptedAccountData,
|
||||||
|
program::Program,
|
||||||
|
};
|
||||||
|
|
||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
use nssa_core::{Commitment, MembershipProof};
|
use nssa_core::{Commitment, MembershipProof};
|
||||||
|
use tokio::io::AsyncWriteExt;
|
||||||
|
|
||||||
use crate::cli::WalletSubcommand;
|
use crate::cli::{
|
||||||
|
WalletSubcommand, account::AccountSubcommand, chain::ChainSubcommand,
|
||||||
|
native_token_transfer_program::NativeTokenTransferProgramSubcommand,
|
||||||
|
pinata_program::PinataProgramSubcommand,
|
||||||
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
cli::token_program::TokenProgramSubcommand,
|
cli::token_program::TokenProgramSubcommand,
|
||||||
helperfunctions::{
|
helperfunctions::{
|
||||||
HumanReadableAccount, fetch_config, fetch_persistent_accounts, get_home,
|
fetch_config, fetch_persistent_accounts, get_home, produce_data_for_storage,
|
||||||
produce_data_for_storage,
|
|
||||||
},
|
},
|
||||||
poller::TxPoller,
|
poller::TxPoller,
|
||||||
};
|
};
|
||||||
@ -43,13 +51,13 @@ pub struct WalletCore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl WalletCore {
|
impl WalletCore {
|
||||||
pub fn start_from_config_update_chain(config: WalletConfig) -> Result<Self> {
|
pub async fn start_from_config_update_chain(config: WalletConfig) -> Result<Self> {
|
||||||
let client = Arc::new(SequencerClient::new(config.sequencer_addr.clone())?);
|
let client = Arc::new(SequencerClient::new(config.sequencer_addr.clone())?);
|
||||||
let tx_poller = TxPoller::new(config.clone(), client.clone());
|
let tx_poller = TxPoller::new(config.clone(), client.clone());
|
||||||
|
|
||||||
let mut storage = WalletChainStore::new(config)?;
|
let mut storage = WalletChainStore::new(config)?;
|
||||||
|
|
||||||
let persistent_accounts = fetch_persistent_accounts()?;
|
let persistent_accounts = fetch_persistent_accounts().await?;
|
||||||
for pers_acc_data in persistent_accounts {
|
for pers_acc_data in persistent_accounts {
|
||||||
storage.insert_account_data(pers_acc_data);
|
storage.insert_account_data(pers_acc_data);
|
||||||
}
|
}
|
||||||
@ -62,15 +70,15 @@ impl WalletCore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
///Store persistent accounts at home
|
///Store persistent accounts at home
|
||||||
pub fn store_persistent_accounts(&self) -> Result<PathBuf> {
|
pub async fn store_persistent_accounts(&self) -> Result<PathBuf> {
|
||||||
let home = get_home()?;
|
let home = get_home()?;
|
||||||
let accs_path = home.join("curr_accounts.json");
|
let accs_path = home.join("curr_accounts.json");
|
||||||
|
|
||||||
let data = produce_data_for_storage(&self.storage.user_data);
|
let data = produce_data_for_storage(&self.storage.user_data);
|
||||||
let accs = serde_json::to_vec_pretty(&data)?;
|
let accs = serde_json::to_vec_pretty(&data)?;
|
||||||
|
|
||||||
let mut accs_file = File::create(accs_path.as_path())?;
|
let mut accs_file = tokio::fs::File::create(accs_path.as_path()).await?;
|
||||||
accs_file.write_all(&accs)?;
|
accs_file.write_all(&accs).await?;
|
||||||
|
|
||||||
info!("Stored accounts data at {accs_path:#?}");
|
info!("Stored accounts data at {accs_path:#?}");
|
||||||
|
|
||||||
@ -182,179 +190,37 @@ impl WalletCore {
|
|||||||
#[derive(Subcommand, Debug, Clone)]
|
#[derive(Subcommand, Debug, Clone)]
|
||||||
#[clap(about)]
|
#[clap(about)]
|
||||||
pub enum Command {
|
pub enum Command {
|
||||||
///Send native token transfer from `from` to `to` for `amount`
|
///Transfer command
|
||||||
///
|
#[command(subcommand)]
|
||||||
/// Public operation
|
Transfer(NativeTokenTransferProgramSubcommand),
|
||||||
SendNativeTokenTransferPublic {
|
///Chain command
|
||||||
///from - valid 32 byte hex string
|
#[command(subcommand)]
|
||||||
#[arg(long)]
|
Chain(ChainSubcommand),
|
||||||
from: String,
|
///Chain command
|
||||||
///to - valid 32 byte hex string
|
#[command(subcommand)]
|
||||||
#[arg(long)]
|
Account(AccountSubcommand),
|
||||||
to: String,
|
///Pinata command
|
||||||
///amount - amount of balance to move
|
#[command(subcommand)]
|
||||||
#[arg(long)]
|
PinataProgram(PinataProgramSubcommand),
|
||||||
amount: u128,
|
///Token command
|
||||||
},
|
#[command(subcommand)]
|
||||||
///Send native token transfer from `from` to `to` for `amount`
|
TokenProgram(TokenProgramSubcommand),
|
||||||
///
|
|
||||||
/// Private operation
|
|
||||||
SendNativeTokenTransferPrivateOwnedAccount {
|
|
||||||
///from - valid 32 byte hex string
|
|
||||||
#[arg(long)]
|
|
||||||
from: String,
|
|
||||||
///to - valid 32 byte hex string
|
|
||||||
#[arg(long)]
|
|
||||||
to: String,
|
|
||||||
///amount - amount of balance to move
|
|
||||||
#[arg(long)]
|
|
||||||
amount: u128,
|
|
||||||
},
|
|
||||||
///Send native token transfer from `from` to `to` for `amount`
|
|
||||||
///
|
|
||||||
/// Private operation
|
|
||||||
SendNativeTokenTransferPrivateForeignAccount {
|
|
||||||
///from - valid 32 byte hex string
|
|
||||||
#[arg(long)]
|
|
||||||
from: String,
|
|
||||||
///to_npk - valid 32 byte hex string
|
|
||||||
#[arg(long)]
|
|
||||||
to_npk: String,
|
|
||||||
///to_ipk - valid 33 byte hex string
|
|
||||||
#[arg(long)]
|
|
||||||
to_ipk: String,
|
|
||||||
///amount - amount of balance to move
|
|
||||||
#[arg(long)]
|
|
||||||
amount: u128,
|
|
||||||
},
|
|
||||||
///Send native token transfer from `from` to `to` for `amount`
|
|
||||||
///
|
|
||||||
/// Deshielded operation
|
|
||||||
SendNativeTokenTransferDeshielded {
|
|
||||||
///from - valid 32 byte hex string
|
|
||||||
#[arg(long)]
|
|
||||||
from: String,
|
|
||||||
///to - valid 32 byte hex string
|
|
||||||
#[arg(long)]
|
|
||||||
to: String,
|
|
||||||
///amount - amount of balance to move
|
|
||||||
#[arg(long)]
|
|
||||||
amount: u128,
|
|
||||||
},
|
|
||||||
///Send native token transfer from `from` to `to` for `amount`
|
|
||||||
///
|
|
||||||
/// Shielded operation
|
|
||||||
SendNativeTokenTransferShielded {
|
|
||||||
///from - valid 32 byte hex string
|
|
||||||
#[arg(long)]
|
|
||||||
from: String,
|
|
||||||
///to - valid 32 byte hex string
|
|
||||||
#[arg(long)]
|
|
||||||
to: String,
|
|
||||||
///amount - amount of balance to move
|
|
||||||
#[arg(long)]
|
|
||||||
amount: u128,
|
|
||||||
},
|
|
||||||
///Send native token transfer from `from` to `to` for `amount`
|
|
||||||
///
|
|
||||||
/// Shielded operation
|
|
||||||
SendNativeTokenTransferShieldedForeignAccount {
|
|
||||||
///from - valid 32 byte hex string
|
|
||||||
#[arg(long)]
|
|
||||||
from: String,
|
|
||||||
///to_npk - valid 32 byte hex string
|
|
||||||
#[arg(long)]
|
|
||||||
to_npk: String,
|
|
||||||
///to_ipk - valid 33 byte hex string
|
|
||||||
#[arg(long)]
|
|
||||||
to_ipk: String,
|
|
||||||
///amount - amount of balance to move
|
|
||||||
#[arg(long)]
|
|
||||||
amount: u128,
|
|
||||||
},
|
|
||||||
///Claim account `acc_addr` generated in transaction `tx_hash`, using secret `sh_secret` at ciphertext id `ciph_id`
|
|
||||||
FetchPrivateAccount {
|
|
||||||
///tx_hash - valid 32 byte hex string
|
|
||||||
#[arg(long)]
|
|
||||||
tx_hash: String,
|
|
||||||
///acc_addr - valid 32 byte hex string
|
|
||||||
#[arg(long)]
|
|
||||||
acc_addr: String,
|
|
||||||
///output_id - id of the output in the transaction
|
|
||||||
#[arg(long)]
|
|
||||||
output_id: usize,
|
|
||||||
},
|
|
||||||
///Get private account with `addr` from storage
|
|
||||||
GetPrivateAccount {
|
|
||||||
#[arg(short, long)]
|
|
||||||
addr: String,
|
|
||||||
},
|
|
||||||
///Register new public account
|
|
||||||
RegisterAccountPublic {},
|
|
||||||
///Register new private account
|
|
||||||
RegisterAccountPrivate {},
|
|
||||||
///Fetch transaction by `hash`
|
|
||||||
FetchTx {
|
|
||||||
#[arg(short, long)]
|
|
||||||
tx_hash: String,
|
|
||||||
},
|
|
||||||
///Get account `addr` balance
|
|
||||||
GetPublicAccountBalance {
|
|
||||||
#[arg(short, long)]
|
|
||||||
addr: String,
|
|
||||||
},
|
|
||||||
///Get account `addr` nonce
|
|
||||||
GetPublicAccountNonce {
|
|
||||||
#[arg(short, long)]
|
|
||||||
addr: String,
|
|
||||||
},
|
|
||||||
///Get account at address `addr`
|
|
||||||
GetPublicAccount {
|
|
||||||
#[arg(short, long)]
|
|
||||||
addr: String,
|
|
||||||
},
|
|
||||||
// TODO: Testnet only. Refactor to prevent compilation on mainnet.
|
|
||||||
// Claim piñata prize
|
|
||||||
ClaimPinata {
|
|
||||||
///pinata_addr - valid 32 byte hex string
|
|
||||||
#[arg(long)]
|
|
||||||
pinata_addr: String,
|
|
||||||
///winner_addr - valid 32 byte hex string
|
|
||||||
#[arg(long)]
|
|
||||||
winner_addr: String,
|
|
||||||
///solution - solution to pinata challenge
|
|
||||||
#[arg(long)]
|
|
||||||
solution: u128,
|
|
||||||
},
|
|
||||||
AuthenticatedTransferInitializePublicAccount {},
|
AuthenticatedTransferInitializePublicAccount {},
|
||||||
// Check the wallet can connect to the node and builtin local programs
|
// Check the wallet can connect to the node and builtin local programs
|
||||||
// match the remote versions
|
// match the remote versions
|
||||||
CheckHealth {},
|
CheckHealth {},
|
||||||
// TODO: Testnet only. Refactor to prevent compilation on mainnet.
|
|
||||||
// Claim piñata prize
|
|
||||||
ClaimPinataPrivateReceiverOwned {
|
|
||||||
///pinata_addr - valid 32 byte hex string
|
|
||||||
#[arg(long)]
|
|
||||||
pinata_addr: String,
|
|
||||||
///winner_addr - valid 32 byte hex string
|
|
||||||
#[arg(long)]
|
|
||||||
winner_addr: String,
|
|
||||||
///solution - solution to pinata challenge
|
|
||||||
#[arg(long)]
|
|
||||||
solution: u128,
|
|
||||||
},
|
|
||||||
///Token command
|
|
||||||
#[command(subcommand)]
|
|
||||||
TokenProgram(TokenProgramSubcommand),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
///To execute commands, env var NSSA_WALLET_HOME_DIR must be set into directory with config
|
///To execute commands, env var NSSA_WALLET_HOME_DIR must be set into directory with config
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
#[clap(version, about)]
|
#[clap(version, about)]
|
||||||
pub struct Args {
|
pub struct Args {
|
||||||
|
/// Continious run flag
|
||||||
|
#[arg(short, long)]
|
||||||
|
pub continious_run: bool,
|
||||||
/// Wallet command
|
/// Wallet command
|
||||||
#[command(subcommand)]
|
#[command(subcommand)]
|
||||||
pub command: Command,
|
pub command: Option<Command>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@ -366,328 +232,27 @@ pub enum SubcommandReturnValue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn execute_subcommand(command: Command) -> Result<SubcommandReturnValue> {
|
pub async fn execute_subcommand(command: Command) -> Result<SubcommandReturnValue> {
|
||||||
let wallet_config = fetch_config()?;
|
let wallet_config = fetch_config().await?;
|
||||||
let mut wallet_core = WalletCore::start_from_config_update_chain(wallet_config)?;
|
let mut wallet_core = WalletCore::start_from_config_update_chain(wallet_config).await?;
|
||||||
|
|
||||||
let subcommand_ret = match command {
|
let subcommand_ret = match command {
|
||||||
Command::SendNativeTokenTransferPublic { from, to, amount } => {
|
Command::Transfer(transfer_subcommand) => {
|
||||||
let from: Address = from.parse().unwrap();
|
transfer_subcommand
|
||||||
let to: Address = to.parse().unwrap();
|
.handle_subcommand(&mut wallet_core)
|
||||||
|
.await?
|
||||||
let res = wallet_core
|
|
||||||
.send_public_native_token_transfer(from, to, amount)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
println!("Results of tx send is {res:#?}");
|
|
||||||
|
|
||||||
let transfer_tx = wallet_core.poll_native_token_transfer(res.tx_hash).await?;
|
|
||||||
|
|
||||||
println!("Transaction data is {transfer_tx:?}");
|
|
||||||
|
|
||||||
let path = wallet_core.store_persistent_accounts()?;
|
|
||||||
|
|
||||||
println!("Stored persistent accounts at {path:#?}");
|
|
||||||
|
|
||||||
SubcommandReturnValue::Empty
|
|
||||||
}
|
}
|
||||||
Command::SendNativeTokenTransferPrivateOwnedAccount { from, to, amount } => {
|
Command::Chain(chain_subcommand) => {
|
||||||
let from: Address = from.parse().unwrap();
|
chain_subcommand.handle_subcommand(&mut wallet_core).await?
|
||||||
let to: Address = to.parse().unwrap();
|
|
||||||
|
|
||||||
let (res, [secret_from, secret_to]) = wallet_core
|
|
||||||
.send_private_native_token_transfer_owned_account(from, to, amount)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
println!("Results of tx send is {res:#?}");
|
|
||||||
|
|
||||||
let tx_hash = res.tx_hash;
|
|
||||||
let transfer_tx = wallet_core
|
|
||||||
.poll_native_token_transfer(tx_hash.clone())
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx {
|
|
||||||
let acc_decode_data = vec![(secret_from, from), (secret_to, to)];
|
|
||||||
|
|
||||||
wallet_core
|
|
||||||
.decode_insert_privacy_preserving_transaction_results(tx, &acc_decode_data)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
let path = wallet_core.store_persistent_accounts()?;
|
|
||||||
|
|
||||||
println!("Stored persistent accounts at {path:#?}");
|
|
||||||
|
|
||||||
SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash }
|
|
||||||
}
|
}
|
||||||
Command::SendNativeTokenTransferPrivateForeignAccount {
|
Command::Account(account_subcommand) => {
|
||||||
from,
|
account_subcommand
|
||||||
to_npk,
|
.handle_subcommand(&mut wallet_core)
|
||||||
to_ipk,
|
.await?
|
||||||
amount,
|
|
||||||
} => {
|
|
||||||
let from: Address = from.parse().unwrap();
|
|
||||||
let to_npk_res = hex::decode(to_npk)?;
|
|
||||||
let mut to_npk = [0; 32];
|
|
||||||
to_npk.copy_from_slice(&to_npk_res);
|
|
||||||
let to_npk = nssa_core::NullifierPublicKey(to_npk);
|
|
||||||
|
|
||||||
let to_ipk_res = hex::decode(to_ipk)?;
|
|
||||||
let mut to_ipk = [0u8; 33];
|
|
||||||
to_ipk.copy_from_slice(&to_ipk_res);
|
|
||||||
let to_ipk =
|
|
||||||
nssa_core::encryption::shared_key_derivation::Secp256k1Point(to_ipk.to_vec());
|
|
||||||
|
|
||||||
let (res, [secret_from, _]) = wallet_core
|
|
||||||
.send_private_native_token_transfer_outer_account(from, to_npk, to_ipk, amount)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
println!("Results of tx send is {res:#?}");
|
|
||||||
|
|
||||||
let tx_hash = res.tx_hash;
|
|
||||||
let transfer_tx = wallet_core
|
|
||||||
.poll_native_token_transfer(tx_hash.clone())
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx {
|
|
||||||
let acc_decode_data = vec![(secret_from, from)];
|
|
||||||
|
|
||||||
wallet_core
|
|
||||||
.decode_insert_privacy_preserving_transaction_results(tx, &acc_decode_data)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
let path = wallet_core.store_persistent_accounts()?;
|
|
||||||
|
|
||||||
println!("Stored persistent accounts at {path:#?}");
|
|
||||||
|
|
||||||
SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash }
|
|
||||||
}
|
}
|
||||||
Command::SendNativeTokenTransferDeshielded { from, to, amount } => {
|
Command::PinataProgram(pinata_subcommand) => {
|
||||||
let from: Address = from.parse().unwrap();
|
pinata_subcommand
|
||||||
let to: Address = to.parse().unwrap();
|
.handle_subcommand(&mut wallet_core)
|
||||||
|
.await?
|
||||||
let (res, secret) = wallet_core
|
|
||||||
.send_deshielded_native_token_transfer(from, to, amount)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
println!("Results of tx send is {res:#?}");
|
|
||||||
|
|
||||||
let tx_hash = res.tx_hash;
|
|
||||||
let transfer_tx = wallet_core
|
|
||||||
.poll_native_token_transfer(tx_hash.clone())
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx {
|
|
||||||
let acc_decode_data = vec![(secret, from)];
|
|
||||||
|
|
||||||
wallet_core
|
|
||||||
.decode_insert_privacy_preserving_transaction_results(tx, &acc_decode_data)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
let path = wallet_core.store_persistent_accounts()?;
|
|
||||||
|
|
||||||
println!("Stored persistent accounts at {path:#?}");
|
|
||||||
|
|
||||||
SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash }
|
|
||||||
}
|
|
||||||
Command::SendNativeTokenTransferShielded { from, to, amount } => {
|
|
||||||
let from: Address = from.parse().unwrap();
|
|
||||||
let to: Address = to.parse().unwrap();
|
|
||||||
|
|
||||||
let (res, secret) = wallet_core
|
|
||||||
.send_shielded_native_token_transfer(from, to, amount)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
println!("Results of tx send is {res:#?}");
|
|
||||||
|
|
||||||
let tx_hash = res.tx_hash;
|
|
||||||
let transfer_tx = wallet_core
|
|
||||||
.poll_native_token_transfer(tx_hash.clone())
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx {
|
|
||||||
let acc_decode_data = vec![(secret, to)];
|
|
||||||
|
|
||||||
wallet_core
|
|
||||||
.decode_insert_privacy_preserving_transaction_results(tx, &acc_decode_data)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
let path = wallet_core.store_persistent_accounts()?;
|
|
||||||
|
|
||||||
println!("Stored persistent accounts at {path:#?}");
|
|
||||||
|
|
||||||
SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash }
|
|
||||||
}
|
|
||||||
Command::SendNativeTokenTransferShieldedForeignAccount {
|
|
||||||
from,
|
|
||||||
to_npk,
|
|
||||||
to_ipk,
|
|
||||||
amount,
|
|
||||||
} => {
|
|
||||||
let from: Address = from.parse().unwrap();
|
|
||||||
|
|
||||||
let to_npk_res = hex::decode(to_npk)?;
|
|
||||||
let mut to_npk = [0; 32];
|
|
||||||
to_npk.copy_from_slice(&to_npk_res);
|
|
||||||
let to_npk = nssa_core::NullifierPublicKey(to_npk);
|
|
||||||
|
|
||||||
let to_ipk_res = hex::decode(to_ipk)?;
|
|
||||||
let mut to_ipk = [0u8; 33];
|
|
||||||
to_ipk.copy_from_slice(&to_ipk_res);
|
|
||||||
let to_ipk =
|
|
||||||
nssa_core::encryption::shared_key_derivation::Secp256k1Point(to_ipk.to_vec());
|
|
||||||
|
|
||||||
let (res, _) = wallet_core
|
|
||||||
.send_shielded_native_token_transfer_outer_account(from, to_npk, to_ipk, amount)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
println!("Results of tx send is {res:#?}");
|
|
||||||
|
|
||||||
let tx_hash = res.tx_hash;
|
|
||||||
|
|
||||||
let path = wallet_core.store_persistent_accounts()?;
|
|
||||||
|
|
||||||
println!("Stored persistent accounts at {path:#?}");
|
|
||||||
|
|
||||||
SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash }
|
|
||||||
}
|
|
||||||
Command::FetchPrivateAccount {
|
|
||||||
tx_hash,
|
|
||||||
acc_addr,
|
|
||||||
output_id: ciph_id,
|
|
||||||
} => {
|
|
||||||
let acc_addr: Address = acc_addr.parse().unwrap();
|
|
||||||
|
|
||||||
let account_key_chain = wallet_core
|
|
||||||
.storage
|
|
||||||
.user_data
|
|
||||||
.user_private_accounts
|
|
||||||
.get(&acc_addr);
|
|
||||||
|
|
||||||
let Some((account_key_chain, _)) = account_key_chain else {
|
|
||||||
anyhow::bail!("Account not found");
|
|
||||||
};
|
|
||||||
|
|
||||||
let transfer_tx = wallet_core.poll_native_token_transfer(tx_hash).await?;
|
|
||||||
|
|
||||||
if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx {
|
|
||||||
let to_ebc = tx.message.encrypted_private_post_states[ciph_id].clone();
|
|
||||||
let to_comm = tx.message.new_commitments[ciph_id].clone();
|
|
||||||
let shared_secret = account_key_chain.calculate_shared_secret_receiver(to_ebc.epk);
|
|
||||||
|
|
||||||
let res_acc_to = nssa_core::EncryptionScheme::decrypt(
|
|
||||||
&to_ebc.ciphertext,
|
|
||||||
&shared_secret,
|
|
||||||
&to_comm,
|
|
||||||
ciph_id as u32,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
println!("RES acc to {res_acc_to:#?}");
|
|
||||||
|
|
||||||
println!("Transaction data is {:?}", tx.message);
|
|
||||||
|
|
||||||
wallet_core
|
|
||||||
.storage
|
|
||||||
.insert_private_account_data(acc_addr, res_acc_to);
|
|
||||||
}
|
|
||||||
|
|
||||||
let path = wallet_core.store_persistent_accounts()?;
|
|
||||||
|
|
||||||
println!("Stored persistent accounts at {path:#?}");
|
|
||||||
|
|
||||||
SubcommandReturnValue::Empty
|
|
||||||
}
|
|
||||||
Command::RegisterAccountPublic {} => {
|
|
||||||
let addr = wallet_core.create_new_account_public();
|
|
||||||
|
|
||||||
println!("Generated new account with addr {addr}");
|
|
||||||
|
|
||||||
let path = wallet_core.store_persistent_accounts()?;
|
|
||||||
|
|
||||||
println!("Stored persistent accounts at {path:#?}");
|
|
||||||
|
|
||||||
SubcommandReturnValue::RegisterAccount { addr }
|
|
||||||
}
|
|
||||||
Command::RegisterAccountPrivate {} => {
|
|
||||||
let addr = wallet_core.create_new_account_private();
|
|
||||||
|
|
||||||
let (key, _) = wallet_core
|
|
||||||
.storage
|
|
||||||
.user_data
|
|
||||||
.get_private_account(&addr)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
println!("Generated new account with addr {addr}");
|
|
||||||
println!("With npk {}", hex::encode(&key.nullifer_public_key));
|
|
||||||
println!(
|
|
||||||
"With ipk {}",
|
|
||||||
hex::encode(key.incoming_viewing_public_key.to_bytes())
|
|
||||||
);
|
|
||||||
|
|
||||||
let path = wallet_core.store_persistent_accounts()?;
|
|
||||||
|
|
||||||
println!("Stored persistent accounts at {path:#?}");
|
|
||||||
|
|
||||||
SubcommandReturnValue::RegisterAccount { addr }
|
|
||||||
}
|
|
||||||
Command::FetchTx { tx_hash } => {
|
|
||||||
let tx_obj = wallet_core
|
|
||||||
.sequencer_client
|
|
||||||
.get_transaction_by_hash(tx_hash)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
println!("Transaction object {tx_obj:#?}");
|
|
||||||
|
|
||||||
SubcommandReturnValue::Empty
|
|
||||||
}
|
|
||||||
Command::GetPublicAccountBalance { addr } => {
|
|
||||||
let addr = Address::from_str(&addr)?;
|
|
||||||
|
|
||||||
let balance = wallet_core.get_account_balance(addr).await?;
|
|
||||||
println!("Accounts {addr} balance is {balance}");
|
|
||||||
|
|
||||||
SubcommandReturnValue::Empty
|
|
||||||
}
|
|
||||||
Command::GetPublicAccountNonce { addr } => {
|
|
||||||
let addr = Address::from_str(&addr)?;
|
|
||||||
|
|
||||||
let nonce = wallet_core.get_accounts_nonces(vec![addr]).await?[0];
|
|
||||||
println!("Accounts {addr} nonce is {nonce}");
|
|
||||||
|
|
||||||
SubcommandReturnValue::Empty
|
|
||||||
}
|
|
||||||
Command::GetPublicAccount { addr } => {
|
|
||||||
let addr: Address = addr.parse()?;
|
|
||||||
let account = wallet_core.get_account_public(addr).await?;
|
|
||||||
let account_hr: HumanReadableAccount = account.clone().into();
|
|
||||||
println!("{}", serde_json::to_string(&account_hr).unwrap());
|
|
||||||
|
|
||||||
SubcommandReturnValue::Account(account)
|
|
||||||
}
|
|
||||||
Command::GetPrivateAccount { addr } => {
|
|
||||||
let addr: Address = addr.parse()?;
|
|
||||||
if let Some(account) = wallet_core.get_account_private(&addr) {
|
|
||||||
let account_hr: HumanReadableAccount = account.into();
|
|
||||||
println!("{}", serde_json::to_string(&account_hr).unwrap());
|
|
||||||
} else {
|
|
||||||
println!("Private account not found.");
|
|
||||||
}
|
|
||||||
SubcommandReturnValue::Empty
|
|
||||||
}
|
|
||||||
Command::ClaimPinata {
|
|
||||||
pinata_addr,
|
|
||||||
winner_addr,
|
|
||||||
solution,
|
|
||||||
} => {
|
|
||||||
let res = wallet_core
|
|
||||||
.claim_pinata(
|
|
||||||
pinata_addr.parse().unwrap(),
|
|
||||||
winner_addr.parse().unwrap(),
|
|
||||||
solution,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
info!("Results of tx send is {res:#?}");
|
|
||||||
|
|
||||||
SubcommandReturnValue::Empty
|
|
||||||
}
|
}
|
||||||
Command::CheckHealth {} => {
|
Command::CheckHealth {} => {
|
||||||
let remote_program_ids = wallet_core
|
let remote_program_ids = wallet_core
|
||||||
@ -719,63 +284,12 @@ pub async fn execute_subcommand(command: Command) -> Result<SubcommandReturnValu
|
|||||||
|
|
||||||
SubcommandReturnValue::Empty
|
SubcommandReturnValue::Empty
|
||||||
}
|
}
|
||||||
Command::ClaimPinataPrivateReceiverOwned {
|
|
||||||
pinata_addr,
|
|
||||||
winner_addr,
|
|
||||||
solution,
|
|
||||||
} => {
|
|
||||||
let pinata_addr = pinata_addr.parse().unwrap();
|
|
||||||
let winner_addr = winner_addr.parse().unwrap();
|
|
||||||
|
|
||||||
let winner_initialization = wallet_core
|
|
||||||
.check_private_account_initialized(&winner_addr)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
let (res, [secret_winner]) = if let Some(winner_proof) = winner_initialization {
|
|
||||||
wallet_core
|
|
||||||
.claim_pinata_private_owned_account_already_initialized(
|
|
||||||
pinata_addr,
|
|
||||||
winner_addr,
|
|
||||||
solution,
|
|
||||||
winner_proof,
|
|
||||||
)
|
|
||||||
.await?
|
|
||||||
} else {
|
|
||||||
wallet_core
|
|
||||||
.claim_pinata_private_owned_account_not_initialized(
|
|
||||||
pinata_addr,
|
|
||||||
winner_addr,
|
|
||||||
solution,
|
|
||||||
)
|
|
||||||
.await?
|
|
||||||
};
|
|
||||||
|
|
||||||
info!("Results of tx send is {res:#?}");
|
|
||||||
|
|
||||||
let tx_hash = res.tx_hash;
|
|
||||||
let transfer_tx = wallet_core
|
|
||||||
.poll_native_token_transfer(tx_hash.clone())
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx {
|
|
||||||
let acc_decode_data = vec![(secret_winner, winner_addr)];
|
|
||||||
|
|
||||||
wallet_core
|
|
||||||
.decode_insert_privacy_preserving_transaction_results(tx, &acc_decode_data)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
let path = wallet_core.store_persistent_accounts()?;
|
|
||||||
|
|
||||||
println!("Stored persistent accounts at {path:#?}");
|
|
||||||
|
|
||||||
SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash }
|
|
||||||
}
|
|
||||||
Command::AuthenticatedTransferInitializePublicAccount {} => {
|
Command::AuthenticatedTransferInitializePublicAccount {} => {
|
||||||
let addr = wallet_core.create_new_account_public();
|
let addr = wallet_core.create_new_account_public();
|
||||||
|
|
||||||
println!("Generated new account with addr {addr}");
|
println!("Generated new account with addr {addr}");
|
||||||
|
|
||||||
let path = wallet_core.store_persistent_accounts()?;
|
let path = wallet_core.store_persistent_accounts().await?;
|
||||||
|
|
||||||
println!("Stored persistent accounts at {path:#?}");
|
println!("Stored persistent accounts at {path:#?}");
|
||||||
|
|
||||||
@ -796,3 +310,88 @@ pub async fn execute_subcommand(command: Command) -> Result<SubcommandReturnValu
|
|||||||
|
|
||||||
Ok(subcommand_ret)
|
Ok(subcommand_ret)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn execute_continious_run() -> Result<()> {
|
||||||
|
let config = fetch_config().await?;
|
||||||
|
let seq_client = Arc::new(SequencerClient::new(config.sequencer_addr.clone())?);
|
||||||
|
let mut wallet_core = WalletCore::start_from_config_update_chain(config.clone()).await?;
|
||||||
|
|
||||||
|
let mut latest_block_num = seq_client.get_last_block().await?.last_block;
|
||||||
|
let mut curr_last_block = latest_block_num;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
for block_id in curr_last_block..(latest_block_num + 1) {
|
||||||
|
let block = borsh::from_slice::<HashableBlockData>(
|
||||||
|
&seq_client.get_block(block_id).await?.block,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
for tx in block.transactions {
|
||||||
|
let nssa_tx = NSSATransaction::try_from(&tx)?;
|
||||||
|
|
||||||
|
if let NSSATransaction::PrivacyPreserving(tx) = nssa_tx {
|
||||||
|
let mut affected_accounts = vec![];
|
||||||
|
|
||||||
|
for (acc_addr, (key_chain, _)) in
|
||||||
|
&wallet_core.storage.user_data.user_private_accounts
|
||||||
|
{
|
||||||
|
let view_tag = EncryptedAccountData::compute_view_tag(
|
||||||
|
key_chain.nullifer_public_key.clone(),
|
||||||
|
key_chain.incoming_viewing_public_key.clone(),
|
||||||
|
);
|
||||||
|
|
||||||
|
for (ciph_id, encrypted_data) in tx
|
||||||
|
.message()
|
||||||
|
.encrypted_private_post_states
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
{
|
||||||
|
if encrypted_data.view_tag == view_tag {
|
||||||
|
let ciphertext = &encrypted_data.ciphertext;
|
||||||
|
let commitment = &tx.message.new_commitments[ciph_id];
|
||||||
|
let shared_secret = key_chain
|
||||||
|
.calculate_shared_secret_receiver(encrypted_data.epk.clone());
|
||||||
|
|
||||||
|
let res_acc = nssa_core::EncryptionScheme::decrypt(
|
||||||
|
ciphertext,
|
||||||
|
&shared_secret,
|
||||||
|
commitment,
|
||||||
|
ciph_id as u32,
|
||||||
|
);
|
||||||
|
|
||||||
|
if let Some(res_acc) = res_acc {
|
||||||
|
println!(
|
||||||
|
"Received new account for addr {acc_addr:#?} with account object {res_acc:#?}"
|
||||||
|
);
|
||||||
|
|
||||||
|
affected_accounts.push((*acc_addr, res_acc));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (affected_addr, new_acc) in affected_accounts {
|
||||||
|
wallet_core
|
||||||
|
.storage
|
||||||
|
.insert_private_account_data(affected_addr, new_acc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wallet_core.store_persistent_accounts().await?;
|
||||||
|
|
||||||
|
println!(
|
||||||
|
"Block at id {block_id} with timestamp {} parsed",
|
||||||
|
block.timestamp
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
curr_last_block = latest_block_num + 1;
|
||||||
|
|
||||||
|
tokio::time::sleep(std::time::Duration::from_millis(
|
||||||
|
config.seq_poll_timeout_millis,
|
||||||
|
))
|
||||||
|
.await;
|
||||||
|
|
||||||
|
latest_block_num = seq_client.get_last_block().await?.last_block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use clap::Parser;
|
use clap::{CommandFactory, Parser};
|
||||||
use tokio::runtime::Builder;
|
use tokio::runtime::Builder;
|
||||||
use wallet::{Args, execute_subcommand};
|
use wallet::{Args, execute_continious_run, execute_subcommand};
|
||||||
|
|
||||||
pub const NUM_THREADS: usize = 2;
|
pub const NUM_THREADS: usize = 2;
|
||||||
|
|
||||||
@ -17,7 +17,14 @@ fn main() -> Result<()> {
|
|||||||
env_logger::init();
|
env_logger::init();
|
||||||
|
|
||||||
runtime.block_on(async move {
|
runtime.block_on(async move {
|
||||||
execute_subcommand(args.command).await.unwrap();
|
if let Some(command) = args.command {
|
||||||
|
execute_subcommand(command).await.unwrap();
|
||||||
|
} else if args.continious_run {
|
||||||
|
execute_continious_run().await.unwrap();
|
||||||
|
} else {
|
||||||
|
let help = Args::command().render_long_help();
|
||||||
|
println!("{help}");
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@ -6,7 +6,7 @@ use nssa::{
|
|||||||
program::Program,
|
program::Program,
|
||||||
};
|
};
|
||||||
use nssa_core::{
|
use nssa_core::{
|
||||||
Commitment, NullifierPublicKey, SharedSecretKey, account::AccountWithMetadata,
|
Commitment, MembershipProof, NullifierPublicKey, SharedSecretKey, account::AccountWithMetadata,
|
||||||
encryption::IncomingViewingPublicKey,
|
encryption::IncomingViewingPublicKey,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -98,11 +98,12 @@ impl WalletCore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn send_private_native_token_transfer_owned_account(
|
pub async fn send_private_native_token_transfer_owned_account_already_initialized(
|
||||||
&self,
|
&self,
|
||||||
from: Address,
|
from: Address,
|
||||||
to: Address,
|
to: Address,
|
||||||
balance_to_move: u128,
|
balance_to_move: u128,
|
||||||
|
to_proof: MembershipProof,
|
||||||
) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> {
|
) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> {
|
||||||
let Some((from_keys, from_acc)) =
|
let Some((from_keys, from_acc)) =
|
||||||
self.storage.user_data.get_private_account(&from).cloned()
|
self.storage.user_data.get_private_account(&from).cloned()
|
||||||
@ -124,7 +125,6 @@ impl WalletCore {
|
|||||||
let program = Program::authenticated_transfer_program();
|
let program = Program::authenticated_transfer_program();
|
||||||
|
|
||||||
let sender_commitment = Commitment::new(&from_npk, &from_acc);
|
let sender_commitment = Commitment::new(&from_npk, &from_acc);
|
||||||
let receiver_commitment = Commitment::new(&to_npk, &to_acc);
|
|
||||||
|
|
||||||
let sender_pre = AccountWithMetadata::new(from_acc.clone(), true, &from_npk);
|
let sender_pre = AccountWithMetadata::new(from_acc.clone(), true, &from_npk);
|
||||||
let recipient_pre = AccountWithMetadata::new(to_acc.clone(), true, &to_npk);
|
let recipient_pre = AccountWithMetadata::new(to_acc.clone(), true, &to_npk);
|
||||||
@ -153,14 +153,7 @@ impl WalletCore {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
),
|
),
|
||||||
(
|
(to_keys.private_key_holder.nullifier_secret_key, to_proof),
|
||||||
to_keys.private_key_holder.nullifier_secret_key,
|
|
||||||
self.sequencer_client
|
|
||||||
.get_proof_for_commitment(receiver_commitment)
|
|
||||||
.await
|
|
||||||
.unwrap()
|
|
||||||
.unwrap(),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
&program,
|
&program,
|
||||||
)
|
)
|
||||||
@ -196,4 +189,92 @@ impl WalletCore {
|
|||||||
Err(ExecutionFailureKind::InsufficientFundsError)
|
Err(ExecutionFailureKind::InsufficientFundsError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn send_private_native_token_transfer_owned_account_not_initialized(
|
||||||
|
&self,
|
||||||
|
from: Address,
|
||||||
|
to: Address,
|
||||||
|
balance_to_move: u128,
|
||||||
|
) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> {
|
||||||
|
let Some((from_keys, from_acc)) =
|
||||||
|
self.storage.user_data.get_private_account(&from).cloned()
|
||||||
|
else {
|
||||||
|
return Err(ExecutionFailureKind::KeyNotFoundError);
|
||||||
|
};
|
||||||
|
|
||||||
|
let Some((to_keys, to_acc)) = self.storage.user_data.get_private_account(&to).cloned()
|
||||||
|
else {
|
||||||
|
return Err(ExecutionFailureKind::KeyNotFoundError);
|
||||||
|
};
|
||||||
|
|
||||||
|
let from_npk = from_keys.nullifer_public_key;
|
||||||
|
let from_ipk = from_keys.incoming_viewing_public_key;
|
||||||
|
let to_npk = to_keys.nullifer_public_key.clone();
|
||||||
|
let to_ipk = to_keys.incoming_viewing_public_key.clone();
|
||||||
|
|
||||||
|
if from_acc.balance >= balance_to_move {
|
||||||
|
let program = Program::authenticated_transfer_program();
|
||||||
|
|
||||||
|
let sender_commitment = Commitment::new(&from_npk, &from_acc);
|
||||||
|
|
||||||
|
let sender_pre = AccountWithMetadata::new(from_acc.clone(), true, &from_npk);
|
||||||
|
let recipient_pre = AccountWithMetadata::new(to_acc.clone(), false, &to_npk);
|
||||||
|
|
||||||
|
let eph_holder_from = EphemeralKeyHolder::new(&from_npk);
|
||||||
|
let shared_secret_from = eph_holder_from.calculate_shared_secret_sender(&from_ipk);
|
||||||
|
|
||||||
|
let eph_holder_to = EphemeralKeyHolder::new(&to_npk);
|
||||||
|
let shared_secret_to = eph_holder_to.calculate_shared_secret_sender(&to_ipk);
|
||||||
|
|
||||||
|
let (output, proof) = circuit::execute_and_prove(
|
||||||
|
&[sender_pre, recipient_pre],
|
||||||
|
&Program::serialize_instruction(balance_to_move).unwrap(),
|
||||||
|
&[1, 2],
|
||||||
|
&produce_random_nonces(2),
|
||||||
|
&[
|
||||||
|
(from_npk.clone(), shared_secret_from.clone()),
|
||||||
|
(to_npk.clone(), shared_secret_to.clone()),
|
||||||
|
],
|
||||||
|
&[(
|
||||||
|
from_keys.private_key_holder.nullifier_secret_key,
|
||||||
|
self.sequencer_client
|
||||||
|
.get_proof_for_commitment(sender_commitment)
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.unwrap(),
|
||||||
|
)],
|
||||||
|
&program,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let message = Message::try_from_circuit_output(
|
||||||
|
vec![],
|
||||||
|
vec![],
|
||||||
|
vec![
|
||||||
|
(
|
||||||
|
from_npk.clone(),
|
||||||
|
from_ipk.clone(),
|
||||||
|
eph_holder_from.generate_ephemeral_public_key(),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
to_npk.clone(),
|
||||||
|
to_ipk.clone(),
|
||||||
|
eph_holder_to.generate_ephemeral_public_key(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
output,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let witness_set = WitnessSet::for_message(&message, proof, &[]);
|
||||||
|
let tx = PrivacyPreservingTransaction::new(message, witness_set);
|
||||||
|
|
||||||
|
Ok((
|
||||||
|
self.sequencer_client.send_tx_private(tx).await?,
|
||||||
|
[shared_secret_from, shared_secret_to],
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
Err(ExecutionFailureKind::InsufficientFundsError)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,14 +6,84 @@ use nssa::{
|
|||||||
program::Program,
|
program::Program,
|
||||||
};
|
};
|
||||||
use nssa_core::{
|
use nssa_core::{
|
||||||
Commitment, NullifierPublicKey, SharedSecretKey, account::AccountWithMetadata,
|
MembershipProof, NullifierPublicKey, SharedSecretKey, account::AccountWithMetadata,
|
||||||
encryption::IncomingViewingPublicKey,
|
encryption::IncomingViewingPublicKey,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{WalletCore, helperfunctions::produce_random_nonces};
|
use crate::{WalletCore, helperfunctions::produce_random_nonces};
|
||||||
|
|
||||||
impl WalletCore {
|
impl WalletCore {
|
||||||
pub async fn send_shielded_native_token_transfer(
|
pub async fn send_shielded_native_token_transfer_already_initialized(
|
||||||
|
&self,
|
||||||
|
from: Address,
|
||||||
|
to: Address,
|
||||||
|
balance_to_move: u128,
|
||||||
|
to_proof: MembershipProof,
|
||||||
|
) -> Result<(SendTxResponse, SharedSecretKey), ExecutionFailureKind> {
|
||||||
|
let Ok(from_acc) = self.get_account_public(from).await else {
|
||||||
|
return Err(ExecutionFailureKind::KeyNotFoundError);
|
||||||
|
};
|
||||||
|
|
||||||
|
let Some((to_keys, to_acc)) = self.storage.user_data.get_private_account(&to).cloned()
|
||||||
|
else {
|
||||||
|
return Err(ExecutionFailureKind::KeyNotFoundError);
|
||||||
|
};
|
||||||
|
|
||||||
|
let to_npk = to_keys.nullifer_public_key.clone();
|
||||||
|
let to_ipk = to_keys.incoming_viewing_public_key.clone();
|
||||||
|
|
||||||
|
if from_acc.balance >= balance_to_move {
|
||||||
|
let program = Program::authenticated_transfer_program();
|
||||||
|
|
||||||
|
let sender_pre = AccountWithMetadata::new(from_acc.clone(), true, from);
|
||||||
|
let recipient_pre = AccountWithMetadata::new(to_acc.clone(), true, &to_npk);
|
||||||
|
|
||||||
|
let eph_holder = EphemeralKeyHolder::new(&to_npk);
|
||||||
|
let shared_secret = eph_holder.calculate_shared_secret_sender(&to_ipk);
|
||||||
|
|
||||||
|
let (output, proof) = circuit::execute_and_prove(
|
||||||
|
&[sender_pre, recipient_pre],
|
||||||
|
&nssa::program::Program::serialize_instruction(balance_to_move).unwrap(),
|
||||||
|
&[0, 1],
|
||||||
|
&produce_random_nonces(1),
|
||||||
|
&[(to_npk.clone(), shared_secret.clone())],
|
||||||
|
&[(to_keys.private_key_holder.nullifier_secret_key, to_proof)],
|
||||||
|
&program,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let message = Message::try_from_circuit_output(
|
||||||
|
vec![from],
|
||||||
|
vec![from_acc.nonce],
|
||||||
|
vec![(
|
||||||
|
to_npk.clone(),
|
||||||
|
to_ipk.clone(),
|
||||||
|
eph_holder.generate_ephemeral_public_key(),
|
||||||
|
)],
|
||||||
|
output,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let signing_key = self.storage.user_data.get_pub_account_signing_key(&from);
|
||||||
|
|
||||||
|
let Some(signing_key) = signing_key else {
|
||||||
|
return Err(ExecutionFailureKind::KeyNotFoundError);
|
||||||
|
};
|
||||||
|
|
||||||
|
let witness_set = WitnessSet::for_message(&message, proof, &[signing_key]);
|
||||||
|
|
||||||
|
let tx = PrivacyPreservingTransaction::new(message, witness_set);
|
||||||
|
|
||||||
|
Ok((
|
||||||
|
self.sequencer_client.send_tx_private(tx).await?,
|
||||||
|
shared_secret,
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
Err(ExecutionFailureKind::InsufficientFundsError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn send_shielded_native_token_transfer_not_initialized(
|
||||||
&self,
|
&self,
|
||||||
from: Address,
|
from: Address,
|
||||||
to: Address,
|
to: Address,
|
||||||
@ -34,10 +104,8 @@ impl WalletCore {
|
|||||||
if from_acc.balance >= balance_to_move {
|
if from_acc.balance >= balance_to_move {
|
||||||
let program = Program::authenticated_transfer_program();
|
let program = Program::authenticated_transfer_program();
|
||||||
|
|
||||||
let receiver_commitment = Commitment::new(&to_npk, &to_acc);
|
|
||||||
|
|
||||||
let sender_pre = AccountWithMetadata::new(from_acc.clone(), true, from);
|
let sender_pre = AccountWithMetadata::new(from_acc.clone(), true, from);
|
||||||
let recipient_pre = AccountWithMetadata::new(to_acc.clone(), true, &to_npk);
|
let recipient_pre = AccountWithMetadata::new(to_acc.clone(), false, &to_npk);
|
||||||
|
|
||||||
let eph_holder = EphemeralKeyHolder::new(&to_npk);
|
let eph_holder = EphemeralKeyHolder::new(&to_npk);
|
||||||
let shared_secret = eph_holder.calculate_shared_secret_sender(&to_ipk);
|
let shared_secret = eph_holder.calculate_shared_secret_sender(&to_ipk);
|
||||||
@ -45,17 +113,10 @@ impl WalletCore {
|
|||||||
let (output, proof) = circuit::execute_and_prove(
|
let (output, proof) = circuit::execute_and_prove(
|
||||||
&[sender_pre, recipient_pre],
|
&[sender_pre, recipient_pre],
|
||||||
&nssa::program::Program::serialize_instruction(balance_to_move).unwrap(),
|
&nssa::program::Program::serialize_instruction(balance_to_move).unwrap(),
|
||||||
&[0, 1],
|
&[0, 2],
|
||||||
&produce_random_nonces(1),
|
&produce_random_nonces(1),
|
||||||
&[(to_npk.clone(), shared_secret.clone())],
|
&[(to_npk.clone(), shared_secret.clone())],
|
||||||
&[(
|
&[],
|
||||||
to_keys.private_key_holder.nullifier_secret_key,
|
|
||||||
self.sequencer_client
|
|
||||||
.get_proof_for_commitment(receiver_commitment)
|
|
||||||
.await
|
|
||||||
.unwrap()
|
|
||||||
.unwrap(),
|
|
||||||
)],
|
|
||||||
&program,
|
&program,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user