mirror of
https://github.com/logos-blockchain/lssa.git
synced 2026-01-05 23:03:06 +00:00
Merge branch 'Pravdyvy/structural-upgrades' into Pravdyvy/structural-improvements
This commit is contained in:
commit
494cc7fb1e
1
.gitignore
vendored
1
.gitignore
vendored
@ -6,3 +6,4 @@ data/
|
|||||||
.idea/
|
.idea/
|
||||||
.vscode/
|
.vscode/
|
||||||
rocksdb
|
rocksdb
|
||||||
|
Cargo.lock
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
[workspace]
|
[workspace]
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
members = [
|
members = [
|
||||||
|
"integration_tests",
|
||||||
"sequencer_runner",
|
"sequencer_runner",
|
||||||
"storage",
|
"storage",
|
||||||
"accounts",
|
"accounts",
|
||||||
@ -12,11 +13,11 @@ members = [
|
|||||||
"sequencer_core",
|
"sequencer_core",
|
||||||
"common",
|
"common",
|
||||||
"sc_core",
|
"sc_core",
|
||||||
"integration_tests",
|
"nssa",
|
||||||
]
|
]
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
anyhow = "1.0"
|
anyhow = "1.0.98"
|
||||||
num_cpus = "1.13.1"
|
num_cpus = "1.13.1"
|
||||||
openssl = { version = "0.10", features = ["vendored"] }
|
openssl = { version = "0.10", features = ["vendored"] }
|
||||||
openssl-probe = { version = "0.1.2" }
|
openssl-probe = { version = "0.1.2" }
|
||||||
@ -29,7 +30,7 @@ lazy_static = "1.5.0"
|
|||||||
env_logger = "0.10"
|
env_logger = "0.10"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
lru = "0.7.8"
|
lru = "0.7.8"
|
||||||
thiserror = "1.0"
|
thiserror = "2.0.12"
|
||||||
rs_merkle = "1.4"
|
rs_merkle = "1.4"
|
||||||
sha2 = "0.10.8"
|
sha2 = "0.10.8"
|
||||||
hex = "0.4.3"
|
hex = "0.4.3"
|
||||||
@ -42,6 +43,7 @@ light-poseidon = "0.3.0"
|
|||||||
ark-bn254 = "0.5.0"
|
ark-bn254 = "0.5.0"
|
||||||
ark-ff = "0.5.0"
|
ark-ff = "0.5.0"
|
||||||
tiny-keccak = { version = "2.0.2", features = ["keccak"] }
|
tiny-keccak = { version = "2.0.2", features = ["keccak"] }
|
||||||
|
base64 = "0.22.1"
|
||||||
|
|
||||||
rocksdb = { version = "0.21.0", default-features = false, features = [
|
rocksdb = { version = "0.21.0", default-features = false, features = [
|
||||||
"snappy",
|
"snappy",
|
||||||
|
|||||||
@ -23,3 +23,6 @@ path = "../utxo"
|
|||||||
|
|
||||||
[dependencies.common]
|
[dependencies.common]
|
||||||
path = "../common"
|
path = "../common"
|
||||||
|
|
||||||
|
[dependencies.nssa]
|
||||||
|
path = "../nssa"
|
||||||
|
|||||||
@ -1,36 +1,3 @@
|
|||||||
use common::transaction::SignaturePublicKey;
|
|
||||||
use tiny_keccak::{Hasher, Keccak};
|
|
||||||
|
|
||||||
// TODO: Consider wrapping `AccountAddress` in a struct.
|
// TODO: Consider wrapping `AccountAddress` in a struct.
|
||||||
|
|
||||||
pub type AccountAddress = [u8; 32];
|
pub type AccountAddress = [u8; 32];
|
||||||
|
|
||||||
/// Returns the address associated with a public key
|
|
||||||
pub fn from_public_key(public_key: &SignaturePublicKey) -> AccountAddress {
|
|
||||||
let mut address = [0; 32];
|
|
||||||
let mut keccak_hasher = Keccak::v256();
|
|
||||||
keccak_hasher.update(&public_key.to_sec1_bytes());
|
|
||||||
keccak_hasher.finalize(&mut address);
|
|
||||||
address
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use common::transaction::SignaturePrivateKey;
|
|
||||||
|
|
||||||
use super::*;
|
|
||||||
use crate::account_core::address;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_address_key_equal_keccak_pub_sign_key() {
|
|
||||||
let signing_key = SignaturePrivateKey::from_slice(&[1; 32]).unwrap();
|
|
||||||
let public_key = signing_key.verifying_key();
|
|
||||||
|
|
||||||
let mut expected_address = [0; 32];
|
|
||||||
let mut keccak_hasher = Keccak::v256();
|
|
||||||
keccak_hasher.update(&public_key.to_sec1_bytes());
|
|
||||||
keccak_hasher.finalize(&mut expected_address);
|
|
||||||
|
|
||||||
assert_eq!(expected_address, address::from_public_key(public_key));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -4,18 +4,14 @@ use anyhow::Result;
|
|||||||
use common::{merkle_tree_public::TreeHashType, transaction::Tag};
|
use common::{merkle_tree_public::TreeHashType, transaction::Tag};
|
||||||
use k256::AffinePoint;
|
use k256::AffinePoint;
|
||||||
use log::info;
|
use log::info;
|
||||||
|
use nssa::Address;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use utxo::utxo_core::UTXO;
|
use utxo::utxo_core::UTXO;
|
||||||
|
|
||||||
pub mod address;
|
use crate::key_management::{
|
||||||
|
constants_types::{CipherText, Nonce},
|
||||||
use crate::{
|
ephemeral_key_holder::EphemeralKeyHolder,
|
||||||
account_core::address::AccountAddress,
|
AddressKeyHolder,
|
||||||
key_management::{
|
|
||||||
constants_types::{CipherText, Nonce},
|
|
||||||
ephemeral_key_holder::EphemeralKeyHolder,
|
|
||||||
AddressKeyHolder,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub type PublicKey = AffinePoint;
|
pub type PublicKey = AffinePoint;
|
||||||
@ -23,7 +19,7 @@ pub type PublicKey = AffinePoint;
|
|||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Account {
|
pub struct Account {
|
||||||
pub key_holder: AddressKeyHolder,
|
pub key_holder: AddressKeyHolder,
|
||||||
pub address: AccountAddress,
|
pub address: Address,
|
||||||
pub balance: u64,
|
pub balance: u64,
|
||||||
pub nonce: u64,
|
pub nonce: u64,
|
||||||
pub utxos: HashMap<TreeHashType, UTXO>,
|
pub utxos: HashMap<TreeHashType, UTXO>,
|
||||||
@ -32,7 +28,7 @@ pub struct Account {
|
|||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
pub struct AccountForSerialization {
|
pub struct AccountForSerialization {
|
||||||
pub key_holder: AddressKeyHolder,
|
pub key_holder: AddressKeyHolder,
|
||||||
pub address: AccountAddress,
|
pub address: Address,
|
||||||
pub balance: u64,
|
pub balance: u64,
|
||||||
pub nonce: u64,
|
pub nonce: u64,
|
||||||
pub utxos: HashMap<String, UTXO>,
|
pub utxos: HashMap<String, UTXO>,
|
||||||
@ -99,7 +95,7 @@ impl<'de> Deserialize<'de> for Account {
|
|||||||
pub struct AccountPublicMask {
|
pub struct AccountPublicMask {
|
||||||
pub nullifier_public_key: AffinePoint,
|
pub nullifier_public_key: AffinePoint,
|
||||||
pub viewing_public_key: AffinePoint,
|
pub viewing_public_key: AffinePoint,
|
||||||
pub address: AccountAddress,
|
pub address: Address,
|
||||||
pub balance: u64,
|
pub balance: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,15 +110,16 @@ impl AccountPublicMask {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn make_tag(&self) -> Tag {
|
pub fn make_tag(&self) -> Tag {
|
||||||
self.address[0]
|
self.address.tag()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Account {
|
impl Account {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let key_holder = AddressKeyHolder::new_os_random();
|
let key_holder = AddressKeyHolder::new_os_random();
|
||||||
let public_key = *key_holder.get_pub_account_signing_key().verifying_key();
|
let public_key =
|
||||||
let address = address::from_public_key(&public_key);
|
nssa::PublicKey::new_from_private_key(key_holder.get_pub_account_signing_key());
|
||||||
|
let address = nssa::Address::from(&public_key);
|
||||||
let balance = 0;
|
let balance = 0;
|
||||||
let nonce = 0;
|
let nonce = 0;
|
||||||
let utxos = HashMap::new();
|
let utxos = HashMap::new();
|
||||||
@ -138,9 +135,9 @@ impl Account {
|
|||||||
|
|
||||||
pub fn new_with_balance(balance: u64) -> Self {
|
pub fn new_with_balance(balance: u64) -> Self {
|
||||||
let key_holder = AddressKeyHolder::new_os_random();
|
let key_holder = AddressKeyHolder::new_os_random();
|
||||||
let public_key = *key_holder.get_pub_account_signing_key().verifying_key();
|
let public_key =
|
||||||
let address = address::from_public_key(&public_key);
|
nssa::PublicKey::new_from_private_key(key_holder.get_pub_account_signing_key());
|
||||||
let nonce = 0;
|
let address = nssa::Address::from(&public_key);
|
||||||
let utxos = HashMap::new();
|
let utxos = HashMap::new();
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
@ -191,7 +188,7 @@ impl Account {
|
|||||||
privacy_flag: bool,
|
privacy_flag: bool,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let asset_utxo = UTXO::new(
|
let asset_utxo = UTXO::new(
|
||||||
self.address,
|
*self.address.value(),
|
||||||
serde_json::to_vec(&asset)?,
|
serde_json::to_vec(&asset)?,
|
||||||
amount,
|
amount,
|
||||||
privacy_flag,
|
privacy_flag,
|
||||||
@ -209,7 +206,7 @@ impl Account {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn make_tag(&self) -> Tag {
|
pub fn make_tag(&self) -> Tag {
|
||||||
self.address[0]
|
self.address.tag()
|
||||||
}
|
}
|
||||||
|
|
||||||
///Produce account public mask
|
///Produce account public mask
|
||||||
@ -247,8 +244,8 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_add_new_utxo_outputs() {
|
fn test_add_new_utxo_outputs() {
|
||||||
let mut account = Account::new();
|
let mut account = Account::new();
|
||||||
let utxo1 = generate_dummy_utxo(account.address, 100);
|
let utxo1 = generate_dummy_utxo(*account.address.value(), 100);
|
||||||
let utxo2 = generate_dummy_utxo(account.address, 200);
|
let utxo2 = generate_dummy_utxo(*account.address.value(), 200);
|
||||||
|
|
||||||
let result = account.add_new_utxo_outputs(vec![utxo1.clone(), utxo2.clone()]);
|
let result = account.add_new_utxo_outputs(vec![utxo1.clone(), utxo2.clone()]);
|
||||||
|
|
||||||
|
|||||||
@ -1,14 +1,15 @@
|
|||||||
use aes_gcm::{aead::Aead, Aes256Gcm, KeyInit};
|
use aes_gcm::{aead::Aead, Aes256Gcm, KeyInit};
|
||||||
use constants_types::{CipherText, Nonce};
|
use constants_types::{CipherText, Nonce};
|
||||||
use elliptic_curve::point::AffineCoordinates;
|
use elliptic_curve::point::AffineCoordinates;
|
||||||
use k256::{ecdsa::SigningKey, AffinePoint, FieldBytes};
|
use k256::AffinePoint;
|
||||||
use log::info;
|
use log::info;
|
||||||
use rand::{rngs::OsRng, RngCore};
|
use rand::{rngs::OsRng, Rng};
|
||||||
use secret_holders::{SeedHolder, TopSecretKeyHolder, UTXOSecretKeyHolder};
|
use secret_holders::{SeedHolder, TopSecretKeyHolder, UTXOSecretKeyHolder};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::account_core::PublicKey;
|
use crate::account_core::PublicKey;
|
||||||
pub type PublicAccountSigningKey = [u8; 32];
|
pub type PublicAccountSigningKey = [u8; 32];
|
||||||
|
use nssa::{self};
|
||||||
|
|
||||||
pub mod constants_types;
|
pub mod constants_types;
|
||||||
pub mod ephemeral_key_holder;
|
pub mod ephemeral_key_holder;
|
||||||
@ -19,7 +20,7 @@ pub mod secret_holders;
|
|||||||
pub struct AddressKeyHolder {
|
pub struct AddressKeyHolder {
|
||||||
top_secret_key_holder: TopSecretKeyHolder,
|
top_secret_key_holder: TopSecretKeyHolder,
|
||||||
pub utxo_secret_key_holder: UTXOSecretKeyHolder,
|
pub utxo_secret_key_holder: UTXOSecretKeyHolder,
|
||||||
pub_account_signing_key: PublicAccountSigningKey,
|
pub_account_signing_key: nssa::PrivateKey,
|
||||||
pub nullifer_public_key: PublicKey,
|
pub nullifer_public_key: PublicKey,
|
||||||
pub viewing_public_key: PublicKey,
|
pub viewing_public_key: PublicKey,
|
||||||
}
|
}
|
||||||
@ -36,10 +37,12 @@ impl AddressKeyHolder {
|
|||||||
let nullifer_public_key = utxo_secret_key_holder.generate_nullifier_public_key();
|
let nullifer_public_key = utxo_secret_key_holder.generate_nullifier_public_key();
|
||||||
let viewing_public_key = utxo_secret_key_holder.generate_viewing_public_key();
|
let viewing_public_key = utxo_secret_key_holder.generate_viewing_public_key();
|
||||||
|
|
||||||
let pub_account_signing_key = {
|
let mut rng = OsRng;
|
||||||
let mut bytes = [0; 32];
|
let pub_account_signing_key = loop {
|
||||||
OsRng.fill_bytes(&mut bytes);
|
match nssa::PrivateKey::try_new(rng.gen()) {
|
||||||
bytes
|
Ok(key) => break key,
|
||||||
|
Err(_) => continue,
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
@ -52,10 +55,8 @@ impl AddressKeyHolder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the signing key for public transaction signatures
|
/// Returns the signing key for public transaction signatures
|
||||||
pub fn get_pub_account_signing_key(&self) -> SigningKey {
|
pub fn get_pub_account_signing_key(&self) -> &nssa::PrivateKey {
|
||||||
let field_bytes = FieldBytes::from_slice(&self.pub_account_signing_key);
|
&self.pub_account_signing_key
|
||||||
// TODO: remove unwrap
|
|
||||||
SigningKey::from_bytes(field_bytes).unwrap()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn calculate_shared_secret_receiver(
|
pub fn calculate_shared_secret_receiver(
|
||||||
@ -120,7 +121,7 @@ mod tests {
|
|||||||
use elliptic_curve::point::AffineCoordinates;
|
use elliptic_curve::point::AffineCoordinates;
|
||||||
use k256::{AffinePoint, ProjectivePoint, Scalar};
|
use k256::{AffinePoint, ProjectivePoint, Scalar};
|
||||||
|
|
||||||
use crate::{account_core::address, key_management::ephemeral_key_holder::EphemeralKeyHolder};
|
use crate::key_management::ephemeral_key_holder::EphemeralKeyHolder;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
@ -319,10 +320,7 @@ mod tests {
|
|||||||
fn test_get_public_account_signing_key() {
|
fn test_get_public_account_signing_key() {
|
||||||
let address_key_holder = AddressKeyHolder::new_os_random();
|
let address_key_holder = AddressKeyHolder::new_os_random();
|
||||||
let signing_key = address_key_holder.get_pub_account_signing_key();
|
let signing_key = address_key_holder.get_pub_account_signing_key();
|
||||||
assert_eq!(
|
assert_eq!(signing_key, &address_key_holder.pub_account_signing_key);
|
||||||
signing_key.to_bytes().as_slice(),
|
|
||||||
address_key_holder.pub_account_signing_key
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -335,19 +333,17 @@ mod tests {
|
|||||||
let nullifer_public_key = utxo_secret_key_holder.generate_nullifier_public_key();
|
let nullifer_public_key = utxo_secret_key_holder.generate_nullifier_public_key();
|
||||||
let viewing_public_key = utxo_secret_key_holder.generate_viewing_public_key();
|
let viewing_public_key = utxo_secret_key_holder.generate_viewing_public_key();
|
||||||
|
|
||||||
let pub_account_signing_key = {
|
let mut rng = OsRng;
|
||||||
let mut bytes = [0; 32];
|
let pub_account_signing_key = loop {
|
||||||
OsRng.fill_bytes(&mut bytes);
|
match nssa::PrivateKey::try_new(rng.gen()) {
|
||||||
bytes
|
Ok(key) => break key,
|
||||||
|
Err(_) => continue,
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
//Address is a Keccak(verification_key)
|
let public_key = nssa::PublicKey::new_from_private_key(&pub_account_signing_key);
|
||||||
let field_bytes = FieldBytes::from_slice(&pub_account_signing_key);
|
|
||||||
let signing_key = SigningKey::from_bytes(field_bytes).unwrap();
|
|
||||||
|
|
||||||
let verifying_key = signing_key.verifying_key();
|
let address = nssa::Address::from(&public_key);
|
||||||
|
|
||||||
let address = address::from_public_key(verifying_key);
|
|
||||||
|
|
||||||
println!("======Prerequisites======");
|
println!("======Prerequisites======");
|
||||||
println!();
|
println!();
|
||||||
@ -373,7 +369,7 @@ mod tests {
|
|||||||
|
|
||||||
println!("======Public data======");
|
println!("======Public data======");
|
||||||
println!();
|
println!();
|
||||||
println!("Address{:?}", hex::encode(address));
|
println!("Address{:?}", hex::encode(address.value()));
|
||||||
println!(
|
println!(
|
||||||
"Nulifier public key {:?}",
|
"Nulifier public key {:?}",
|
||||||
hex::encode(serde_json::to_vec(&nullifer_public_key).unwrap())
|
hex::encode(serde_json::to_vec(&nullifer_public_key).unwrap())
|
||||||
|
|||||||
@ -9,7 +9,6 @@ thiserror.workspace = true
|
|||||||
serde_json.workspace = true
|
serde_json.workspace = true
|
||||||
serde.workspace = true
|
serde.workspace = true
|
||||||
reqwest.workspace = true
|
reqwest.workspace = true
|
||||||
risc0-zkvm = { git = "https://github.com/risc0/risc0.git", branch = "release-2.3" }
|
|
||||||
k256.workspace = true
|
k256.workspace = true
|
||||||
rand.workspace = true
|
rand.workspace = true
|
||||||
|
|
||||||
@ -22,3 +21,6 @@ hex.workspace = true
|
|||||||
[dependencies.secp256k1-zkp]
|
[dependencies.secp256k1-zkp]
|
||||||
workspace = true
|
workspace = true
|
||||||
features = ["std", "rand-std", "rand", "serde", "global-context"]
|
features = ["std", "rand-std", "rand", "serde", "global-context"]
|
||||||
|
|
||||||
|
[dependencies.nssa]
|
||||||
|
path = "../nssa"
|
||||||
|
|||||||
@ -1,35 +1,33 @@
|
|||||||
use rs_merkle::Hasher;
|
use std::io::{Cursor, Read};
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
use crate::{merkle_tree_public::hasher::OwnHasher, transaction::Transaction};
|
use rs_merkle::Hasher;
|
||||||
|
|
||||||
|
use crate::merkle_tree_public::hasher::OwnHasher;
|
||||||
|
use nssa;
|
||||||
|
|
||||||
pub type BlockHash = [u8; 32];
|
pub type BlockHash = [u8; 32];
|
||||||
pub type Data = Vec<u8>;
|
|
||||||
pub type BlockId = u64;
|
pub type BlockId = u64;
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Block {
|
pub struct Block {
|
||||||
pub block_id: BlockId,
|
pub block_id: BlockId,
|
||||||
pub prev_block_id: BlockId,
|
pub prev_block_id: BlockId,
|
||||||
pub prev_block_hash: BlockHash,
|
pub prev_block_hash: BlockHash,
|
||||||
pub hash: BlockHash,
|
pub hash: BlockHash,
|
||||||
pub transactions: Vec<Transaction>,
|
pub transactions: Vec<nssa::PublicTransaction>,
|
||||||
pub data: Data,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
pub struct HashableBlockData {
|
pub struct HashableBlockData {
|
||||||
pub block_id: BlockId,
|
pub block_id: BlockId,
|
||||||
pub prev_block_id: BlockId,
|
pub prev_block_id: BlockId,
|
||||||
pub prev_block_hash: BlockHash,
|
pub prev_block_hash: BlockHash,
|
||||||
pub transactions: Vec<Transaction>,
|
pub transactions: Vec<nssa::PublicTransaction>,
|
||||||
pub data: Data,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<HashableBlockData> for Block {
|
impl From<HashableBlockData> for Block {
|
||||||
fn from(value: HashableBlockData) -> Self {
|
fn from(value: HashableBlockData) -> Self {
|
||||||
let data = serde_json::to_vec(&value).unwrap();
|
let data = value.to_bytes();
|
||||||
|
|
||||||
let hash = OwnHasher::hash(&data);
|
let hash = OwnHasher::hash(&data);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
@ -37,8 +35,88 @@ impl From<HashableBlockData> for Block {
|
|||||||
prev_block_id: value.prev_block_id,
|
prev_block_id: value.prev_block_id,
|
||||||
hash,
|
hash,
|
||||||
transactions: value.transactions,
|
transactions: value.transactions,
|
||||||
data: value.data,
|
|
||||||
prev_block_hash: value.prev_block_hash,
|
prev_block_hash: value.prev_block_hash,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<Block> for HashableBlockData {
|
||||||
|
fn from(value: Block) -> Self {
|
||||||
|
Self {
|
||||||
|
block_id: value.block_id,
|
||||||
|
prev_block_id: value.prev_block_id,
|
||||||
|
prev_block_hash: value.prev_block_hash,
|
||||||
|
transactions: value.transactions,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HashableBlockData {
|
||||||
|
pub fn to_bytes(&self) -> Vec<u8> {
|
||||||
|
let mut bytes = Vec::new();
|
||||||
|
bytes.extend_from_slice(&self.block_id.to_le_bytes());
|
||||||
|
bytes.extend_from_slice(&self.prev_block_id.to_le_bytes());
|
||||||
|
bytes.extend_from_slice(&self.prev_block_hash);
|
||||||
|
let num_transactions: u32 = self.transactions.len() as u32;
|
||||||
|
bytes.extend_from_slice(&num_transactions.to_le_bytes());
|
||||||
|
for tx in &self.transactions {
|
||||||
|
bytes.extend_from_slice(&tx.to_bytes());
|
||||||
|
}
|
||||||
|
bytes
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Improve error handling. Remove unwraps.
|
||||||
|
pub fn from_bytes(data: &[u8]) -> Self {
|
||||||
|
let mut cursor = Cursor::new(data);
|
||||||
|
|
||||||
|
let block_id = u64_from_cursor(&mut cursor);
|
||||||
|
let prev_block_id = u64_from_cursor(&mut cursor);
|
||||||
|
|
||||||
|
let mut prev_block_hash = [0u8; 32];
|
||||||
|
cursor.read_exact(&mut prev_block_hash).unwrap();
|
||||||
|
|
||||||
|
let num_transactions = u32_from_cursor(&mut cursor) as usize;
|
||||||
|
|
||||||
|
let mut transactions = Vec::with_capacity(num_transactions);
|
||||||
|
for _ in 0..num_transactions {
|
||||||
|
let tx = nssa::PublicTransaction::from_cursor(&mut cursor).unwrap();
|
||||||
|
transactions.push(tx);
|
||||||
|
}
|
||||||
|
|
||||||
|
Self {
|
||||||
|
block_id,
|
||||||
|
prev_block_id,
|
||||||
|
prev_block_hash,
|
||||||
|
transactions,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Improve error handling. Remove unwraps.
|
||||||
|
fn u32_from_cursor(cursor: &mut Cursor<&[u8]>) -> u32 {
|
||||||
|
let mut word_buf = [0u8; 4];
|
||||||
|
cursor.read_exact(&mut word_buf).unwrap();
|
||||||
|
u32::from_le_bytes(word_buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Improve error handling. Remove unwraps.
|
||||||
|
fn u64_from_cursor(cursor: &mut Cursor<&[u8]>) -> u64 {
|
||||||
|
let mut word_buf = [0u8; 8];
|
||||||
|
cursor.read_exact(&mut word_buf).unwrap();
|
||||||
|
u64::from_le_bytes(word_buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::{block::HashableBlockData, test_utils};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_encoding_roundtrip() {
|
||||||
|
let transactions = vec![test_utils::produce_dummy_empty_transaction()];
|
||||||
|
let block = test_utils::produce_dummy_block(1, Some([1; 32]), transactions);
|
||||||
|
let hashable = HashableBlockData::from(block);
|
||||||
|
let bytes = hashable.to_bytes();
|
||||||
|
let block_from_bytes = HashableBlockData::from_bytes(&bytes);
|
||||||
|
assert_eq!(hashable, block_from_bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -65,7 +65,7 @@ pub enum ExecutionFailureKind {
|
|||||||
#[error("Failed prove execution err: {0:?}")]
|
#[error("Failed prove execution err: {0:?}")]
|
||||||
ProveError(anyhow::Error),
|
ProveError(anyhow::Error),
|
||||||
#[error("Failed to decode data from VM: {0:?}")]
|
#[error("Failed to decode data from VM: {0:?}")]
|
||||||
DecodeError(#[from] risc0_zkvm::serde::Error),
|
DecodeError(String),
|
||||||
#[error("Inputs amounts does not match outputs")]
|
#[error("Inputs amounts does not match outputs")]
|
||||||
AmountMismatchError,
|
AmountMismatchError,
|
||||||
#[error("Sequencer client error: {0:?}")]
|
#[error("Sequencer client error: {0:?}")]
|
||||||
|
|||||||
@ -1,6 +1,4 @@
|
|||||||
use crate::block::Block;
|
|
||||||
use crate::parse_request;
|
use crate::parse_request;
|
||||||
use crate::transaction::Transaction;
|
|
||||||
|
|
||||||
use super::errors::RpcParseError;
|
use super::errors::RpcParseError;
|
||||||
use super::parser::parse_params;
|
use super::parser::parse_params;
|
||||||
@ -18,7 +16,7 @@ pub struct RegisterAccountRequest {
|
|||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
pub struct SendTxRequest {
|
pub struct SendTxRequest {
|
||||||
pub transaction: Transaction,
|
pub transaction: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
@ -72,7 +70,7 @@ pub struct SendTxResponse {
|
|||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
pub struct GetBlockDataResponse {
|
pub struct GetBlockDataResponse {
|
||||||
pub block: Block,
|
pub block: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
@ -87,10 +85,10 @@ pub struct GetLastBlockResponse {
|
|||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
pub struct GetAccountBalanceResponse {
|
pub struct GetAccountBalanceResponse {
|
||||||
pub balance: u64,
|
pub balance: u128,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
pub struct GetTransactionByHashResponse {
|
pub struct GetTransactionByHashResponse {
|
||||||
pub transaction: Option<Transaction>,
|
pub transaction: Option<String>,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,12 +1,10 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::transaction::Transaction;
|
|
||||||
|
|
||||||
//Requests
|
//Requests
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
pub struct SendTxRequest {
|
pub struct SendTxRequest {
|
||||||
pub transaction: Transaction,
|
pub transaction: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
//Responses
|
//Responses
|
||||||
|
|||||||
@ -8,7 +8,6 @@ use reqwest::Client;
|
|||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
|
||||||
use crate::sequencer_client::json::AccountInitialData;
|
use crate::sequencer_client::json::AccountInitialData;
|
||||||
use crate::transaction::Transaction;
|
|
||||||
use crate::{SequencerClientError, SequencerRpcError};
|
use crate::{SequencerClientError, SequencerRpcError};
|
||||||
|
|
||||||
pub mod json;
|
pub mod json;
|
||||||
@ -90,9 +89,11 @@ impl SequencerClient {
|
|||||||
///Send transaction to sequencer
|
///Send transaction to sequencer
|
||||||
pub async fn send_tx(
|
pub async fn send_tx(
|
||||||
&self,
|
&self,
|
||||||
transaction: Transaction,
|
transaction: nssa::PublicTransaction,
|
||||||
) -> Result<SendTxResponse, SequencerClientError> {
|
) -> Result<SendTxResponse, SequencerClientError> {
|
||||||
let tx_req = SendTxRequest { transaction };
|
let tx_req = SendTxRequest {
|
||||||
|
transaction: transaction.to_bytes(),
|
||||||
|
};
|
||||||
|
|
||||||
let req = serde_json::to_value(tx_req)?;
|
let req = serde_json::to_value(tx_req)?;
|
||||||
|
|
||||||
|
|||||||
@ -1,11 +1,6 @@
|
|||||||
use k256::ecdsa::SigningKey;
|
use nssa;
|
||||||
use secp256k1_zkp::Tweak;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::block::{Block, HashableBlockData};
|
||||||
block::{Block, HashableBlockData},
|
|
||||||
execution_input::PublicNativeTokenSend,
|
|
||||||
transaction::{SignaturePrivateKey, Transaction, TransactionBody, TxKind},
|
|
||||||
};
|
|
||||||
|
|
||||||
//Dummy producers
|
//Dummy producers
|
||||||
|
|
||||||
@ -16,100 +11,47 @@ use crate::{
|
|||||||
/// `prev_hash` - hash of previous block, provide None for genesis
|
/// `prev_hash` - hash of previous block, provide None for genesis
|
||||||
///
|
///
|
||||||
/// `transactions` - vector of `Transaction` objects
|
/// `transactions` - vector of `Transaction` objects
|
||||||
///
|
|
||||||
/// `additional_data` - vector with additional data
|
|
||||||
pub fn produce_dummy_block(
|
pub fn produce_dummy_block(
|
||||||
id: u64,
|
id: u64,
|
||||||
prev_hash: Option<[u8; 32]>,
|
prev_hash: Option<[u8; 32]>,
|
||||||
transactions: Vec<Transaction>,
|
transactions: Vec<nssa::PublicTransaction>,
|
||||||
additional_data: Vec<u8>,
|
|
||||||
) -> Block {
|
) -> Block {
|
||||||
let block_data = HashableBlockData {
|
let block_data = HashableBlockData {
|
||||||
block_id: id,
|
block_id: id,
|
||||||
prev_block_id: id.saturating_sub(1),
|
prev_block_id: id.saturating_sub(1),
|
||||||
prev_block_hash: prev_hash.unwrap_or_default(),
|
prev_block_hash: prev_hash.unwrap_or_default(),
|
||||||
transactions,
|
transactions,
|
||||||
data: additional_data,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
block_data.into()
|
block_data.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn produce_dummy_empty_transaction() -> Transaction {
|
pub fn produce_dummy_empty_transaction() -> nssa::PublicTransaction {
|
||||||
let body = TransactionBody {
|
let program_id = nssa::program::Program::authenticated_transfer_program().id();
|
||||||
tx_kind: TxKind::Public,
|
let addresses = vec![];
|
||||||
execution_input: Default::default(),
|
let nonces = vec![];
|
||||||
execution_output: Default::default(),
|
let instruction_data: u128 = 0;
|
||||||
utxo_commitments_spent_hashes: Default::default(),
|
let message =
|
||||||
utxo_commitments_created_hashes: Default::default(),
|
nssa::public_transaction::Message::try_new(program_id, addresses, nonces, instruction_data)
|
||||||
nullifier_created_hashes: Default::default(),
|
.unwrap();
|
||||||
execution_proof_private: Default::default(),
|
let private_key = nssa::PrivateKey::try_new([1; 32]).unwrap();
|
||||||
encoded_data: Default::default(),
|
let witness_set = nssa::public_transaction::WitnessSet::for_message(&message, &[&private_key]);
|
||||||
ephemeral_pub_key: Default::default(),
|
nssa::PublicTransaction::new(message, witness_set)
|
||||||
commitment: Default::default(),
|
|
||||||
tweak: Default::default(),
|
|
||||||
secret_r: Default::default(),
|
|
||||||
sc_addr: Default::default(),
|
|
||||||
};
|
|
||||||
|
|
||||||
Transaction::new(body, SignaturePrivateKey::from_slice(&[1; 32]).unwrap())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_dummy_private_transaction_random_signer(
|
pub fn create_transaction_native_token_transfer(
|
||||||
nullifier_created_hashes: Vec<[u8; 32]>,
|
|
||||||
utxo_commitments_spent_hashes: Vec<[u8; 32]>,
|
|
||||||
utxo_commitments_created_hashes: Vec<[u8; 32]>,
|
|
||||||
) -> Transaction {
|
|
||||||
let mut rng = rand::thread_rng();
|
|
||||||
|
|
||||||
let body = TransactionBody {
|
|
||||||
tx_kind: TxKind::Private,
|
|
||||||
execution_input: vec![],
|
|
||||||
execution_output: vec![],
|
|
||||||
utxo_commitments_spent_hashes,
|
|
||||||
utxo_commitments_created_hashes,
|
|
||||||
nullifier_created_hashes,
|
|
||||||
execution_proof_private: "dummy_proof".to_string(),
|
|
||||||
encoded_data: vec![],
|
|
||||||
ephemeral_pub_key: vec![10, 11, 12],
|
|
||||||
commitment: vec![],
|
|
||||||
tweak: Tweak::new(&mut rng),
|
|
||||||
secret_r: [0; 32],
|
|
||||||
sc_addr: "sc_addr".to_string(),
|
|
||||||
};
|
|
||||||
Transaction::new(body, SignaturePrivateKey::random(&mut rng))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn create_dummy_transaction_native_token_transfer(
|
|
||||||
from: [u8; 32],
|
from: [u8; 32],
|
||||||
nonce: u64,
|
nonce: u128,
|
||||||
to: [u8; 32],
|
to: [u8; 32],
|
||||||
balance_to_move: u64,
|
balance_to_move: u128,
|
||||||
signing_key: SigningKey,
|
signing_key: nssa::PrivateKey,
|
||||||
) -> Transaction {
|
) -> nssa::PublicTransaction {
|
||||||
let mut rng = rand::thread_rng();
|
let addresses = vec![nssa::Address::new(from), nssa::Address::new(to)];
|
||||||
|
let nonces = vec![nonce];
|
||||||
let native_token_transfer = PublicNativeTokenSend {
|
let program_id = nssa::program::Program::authenticated_transfer_program().id();
|
||||||
from,
|
let message =
|
||||||
nonce,
|
nssa::public_transaction::Message::try_new(program_id, addresses, nonces, balance_to_move)
|
||||||
to,
|
.unwrap();
|
||||||
balance_to_move,
|
let witness_set = nssa::public_transaction::WitnessSet::for_message(&message, &[&signing_key]);
|
||||||
};
|
nssa::PublicTransaction::new(message, witness_set)
|
||||||
|
|
||||||
let body = TransactionBody {
|
|
||||||
tx_kind: TxKind::Public,
|
|
||||||
execution_input: serde_json::to_vec(&native_token_transfer).unwrap(),
|
|
||||||
execution_output: vec![],
|
|
||||||
utxo_commitments_spent_hashes: vec![],
|
|
||||||
utxo_commitments_created_hashes: vec![],
|
|
||||||
nullifier_created_hashes: vec![],
|
|
||||||
execution_proof_private: "".to_string(),
|
|
||||||
encoded_data: vec![],
|
|
||||||
ephemeral_pub_key: vec![10, 11, 12],
|
|
||||||
commitment: vec![],
|
|
||||||
tweak: Tweak::new(&mut rng),
|
|
||||||
secret_r: [0; 32],
|
|
||||||
sc_addr: "sc_addr".to_string(),
|
|
||||||
};
|
|
||||||
Transaction::new(body, signing_key)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,12 +8,12 @@
|
|||||||
"port": 3040,
|
"port": 3040,
|
||||||
"initial_accounts": [
|
"initial_accounts": [
|
||||||
{
|
{
|
||||||
"addr": "0d96dfcc414019380c9dde0cd3dce5aac90fb5443bf871108741aeafde552ad7",
|
"addr": "1b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f",
|
||||||
"balance": 10000
|
"balance": 10000
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"addr": "974870e9be8d0ac08aa83b3fc7a7a686291d8732508aba98b36080f39c2cf364",
|
"addr": "4d4b6cd1361032ca9bd2aeb9d900aa4d45d9ead80ac9423374c451a7254d0766",
|
||||||
"balance": 20000
|
"balance": 20000
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,244 +1,45 @@
|
|||||||
{
|
{
|
||||||
"home": "./wallet",
|
"home": "./node",
|
||||||
"override_rust_log": null,
|
"override_rust_log": null,
|
||||||
"sequencer_addr": "http://127.0.0.1:3040",
|
"sequencer_addr": "http://127.0.0.1:3040",
|
||||||
"seq_poll_timeout_secs": 10,
|
"seq_poll_timeout_secs": 10,
|
||||||
"initial_accounts": [
|
"initial_accounts": [
|
||||||
{
|
{
|
||||||
"address": [
|
"address": "1b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f",
|
||||||
13,
|
"balance": 10000,
|
||||||
150,
|
"key_holder": {
|
||||||
223,
|
"address": "1b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f",
|
||||||
204,
|
"nullifer_public_key": "03A340BECA9FAAB444CED0140681D72EA1318B5C611704FEE017DA9836B17DB718",
|
||||||
65,
|
"pub_account_signing_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],
|
||||||
64,
|
"top_secret_key_holder": {
|
||||||
25,
|
"secret_spending_key": "7BC46784DB1BC67825D8F029436846712BFDF9B5D79EA3AB11D39A52B9B229D4"
|
||||||
56,
|
|
||||||
12,
|
|
||||||
157,
|
|
||||||
222,
|
|
||||||
12,
|
|
||||||
211,
|
|
||||||
220,
|
|
||||||
229,
|
|
||||||
170,
|
|
||||||
201,
|
|
||||||
15,
|
|
||||||
181,
|
|
||||||
68,
|
|
||||||
59,
|
|
||||||
248,
|
|
||||||
113,
|
|
||||||
16,
|
|
||||||
135,
|
|
||||||
65,
|
|
||||||
174,
|
|
||||||
175,
|
|
||||||
222,
|
|
||||||
85,
|
|
||||||
42,
|
|
||||||
215
|
|
||||||
],
|
|
||||||
"balance": 10000,
|
|
||||||
"nonce": 0,
|
|
||||||
"key_holder": {
|
|
||||||
"address": [
|
|
||||||
13,
|
|
||||||
150,
|
|
||||||
223,
|
|
||||||
204,
|
|
||||||
65,
|
|
||||||
64,
|
|
||||||
25,
|
|
||||||
56,
|
|
||||||
12,
|
|
||||||
157,
|
|
||||||
222,
|
|
||||||
12,
|
|
||||||
211,
|
|
||||||
220,
|
|
||||||
229,
|
|
||||||
170,
|
|
||||||
201,
|
|
||||||
15,
|
|
||||||
181,
|
|
||||||
68,
|
|
||||||
59,
|
|
||||||
248,
|
|
||||||
113,
|
|
||||||
16,
|
|
||||||
135,
|
|
||||||
65,
|
|
||||||
174,
|
|
||||||
175,
|
|
||||||
222,
|
|
||||||
85,
|
|
||||||
42,
|
|
||||||
215
|
|
||||||
],
|
|
||||||
"nullifer_public_key": "03A340BECA9FAAB444CED0140681D72EA1318B5C611704FEE017DA9836B17DB718",
|
|
||||||
"pub_account_signing_key": [
|
|
||||||
133,
|
|
||||||
143,
|
|
||||||
177,
|
|
||||||
187,
|
|
||||||
252,
|
|
||||||
66,
|
|
||||||
237,
|
|
||||||
236,
|
|
||||||
234,
|
|
||||||
252,
|
|
||||||
244,
|
|
||||||
138,
|
|
||||||
5,
|
|
||||||
151,
|
|
||||||
3,
|
|
||||||
99,
|
|
||||||
217,
|
|
||||||
231,
|
|
||||||
112,
|
|
||||||
217,
|
|
||||||
77,
|
|
||||||
211,
|
|
||||||
58,
|
|
||||||
218,
|
|
||||||
176,
|
|
||||||
68,
|
|
||||||
99,
|
|
||||||
53,
|
|
||||||
152,
|
|
||||||
228,
|
|
||||||
198,
|
|
||||||
190
|
|
||||||
],
|
|
||||||
"top_secret_key_holder": {
|
|
||||||
"secret_spending_key": "7BC46784DB1BC67825D8F029436846712BFDF9B5D79EA3AB11D39A52B9B229D4"
|
|
||||||
},
|
|
||||||
"utxo_secret_key_holder": {
|
|
||||||
"nullifier_secret_key": "BB54A8D3C9C51B82C431082D1845A74677B0EF829A11B517E1D9885DE3139506",
|
|
||||||
"viewing_secret_key": "AD923E92F6A5683E30140CEAB2702AFB665330C1EE4EFA70FAF29767B6B52BAF"
|
|
||||||
},
|
|
||||||
"viewing_public_key": "0361220C5D277E7A1709340FD31A52600C1432B9C45B9BCF88A43581D58824A8B6"
|
|
||||||
},
|
|
||||||
"utxos": {}
|
|
||||||
},
|
},
|
||||||
{
|
"utxo_secret_key_holder": {
|
||||||
"address": [
|
"nullifier_secret_key": "BB54A8D3C9C51B82C431082D1845A74677B0EF829A11B517E1D9885DE3139506",
|
||||||
151,
|
"viewing_secret_key": "AD923E92F6A5683E30140CEAB2702AFB665330C1EE4EFA70FAF29767B6B52BAF"
|
||||||
72,
|
},
|
||||||
112,
|
"viewing_public_key": "0361220C5D277E7A1709340FD31A52600C1432B9C45B9BCF88A43581D58824A8B6"
|
||||||
233,
|
},
|
||||||
190,
|
"utxos": {}
|
||||||
141,
|
},
|
||||||
10,
|
{
|
||||||
192,
|
"address": "4d4b6cd1361032ca9bd2aeb9d900aa4d45d9ead80ac9423374c451a7254d0766",
|
||||||
138,
|
"balance": 20000,
|
||||||
168,
|
"key_holder": {
|
||||||
59,
|
"address": "4d4b6cd1361032ca9bd2aeb9d900aa4d45d9ead80ac9423374c451a7254d0766",
|
||||||
63,
|
"nullifer_public_key": "02172F50274DE67C4087C344F5D58E11DF761D90285B095060E0994FAA6BCDE271",
|
||||||
199,
|
"pub_account_signing_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],
|
||||||
167,
|
"top_secret_key_holder": {
|
||||||
166,
|
"secret_spending_key": "80A186737C8D38B4288A03F0F589957D9C040D79C19F3E0CC4BA80F8494E5179"
|
||||||
134,
|
},
|
||||||
41,
|
"utxo_secret_key_holder": {
|
||||||
29,
|
"nullifier_secret_key": "746928E63F0984F6F4818933493CE9C067562D9CB932FDC06D82C86CDF6D7122",
|
||||||
135,
|
"viewing_secret_key": "89176CF4BC9E673807643FD52110EF99D4894335AFB10D881AC0B5041FE1FCB7"
|
||||||
50,
|
},
|
||||||
80,
|
"viewing_public_key": "026072A8F83FEC3472E30CDD4767683F30B91661D25B1040AD9A5FC2E01D659F99"
|
||||||
138,
|
},
|
||||||
186,
|
"utxos": {}
|
||||||
152,
|
}
|
||||||
179,
|
]
|
||||||
96,
|
}
|
||||||
128,
|
|
||||||
243,
|
|
||||||
156,
|
|
||||||
44,
|
|
||||||
243,
|
|
||||||
100
|
|
||||||
],
|
|
||||||
"balance": 20000,
|
|
||||||
"nonce": 0,
|
|
||||||
"key_holder": {
|
|
||||||
"address": [
|
|
||||||
151,
|
|
||||||
72,
|
|
||||||
112,
|
|
||||||
233,
|
|
||||||
190,
|
|
||||||
141,
|
|
||||||
10,
|
|
||||||
192,
|
|
||||||
138,
|
|
||||||
168,
|
|
||||||
59,
|
|
||||||
63,
|
|
||||||
199,
|
|
||||||
167,
|
|
||||||
166,
|
|
||||||
134,
|
|
||||||
41,
|
|
||||||
29,
|
|
||||||
135,
|
|
||||||
50,
|
|
||||||
80,
|
|
||||||
138,
|
|
||||||
186,
|
|
||||||
152,
|
|
||||||
179,
|
|
||||||
96,
|
|
||||||
128,
|
|
||||||
243,
|
|
||||||
156,
|
|
||||||
44,
|
|
||||||
243,
|
|
||||||
100
|
|
||||||
],
|
|
||||||
"nullifer_public_key": "02172F50274DE67C4087C344F5D58E11DF761D90285B095060E0994FAA6BCDE271",
|
|
||||||
"pub_account_signing_key": [
|
|
||||||
54,
|
|
||||||
90,
|
|
||||||
62,
|
|
||||||
225,
|
|
||||||
71,
|
|
||||||
225,
|
|
||||||
228,
|
|
||||||
148,
|
|
||||||
143,
|
|
||||||
53,
|
|
||||||
210,
|
|
||||||
23,
|
|
||||||
137,
|
|
||||||
158,
|
|
||||||
171,
|
|
||||||
156,
|
|
||||||
48,
|
|
||||||
7,
|
|
||||||
139,
|
|
||||||
52,
|
|
||||||
117,
|
|
||||||
242,
|
|
||||||
214,
|
|
||||||
7,
|
|
||||||
99,
|
|
||||||
29,
|
|
||||||
122,
|
|
||||||
184,
|
|
||||||
59,
|
|
||||||
116,
|
|
||||||
144,
|
|
||||||
107
|
|
||||||
],
|
|
||||||
"top_secret_key_holder": {
|
|
||||||
"secret_spending_key": "80A186737C8D38B4288A03F0F589957D9C040D79C19F3E0CC4BA80F8494E5179"
|
|
||||||
},
|
|
||||||
"utxo_secret_key_holder": {
|
|
||||||
"nullifier_secret_key": "746928E63F0984F6F4818933493CE9C067562D9CB932FDC06D82C86CDF6D7122",
|
|
||||||
"viewing_secret_key": "89176CF4BC9E673807643FD52110EF99D4894335AFB10D881AC0B5041FE1FCB7"
|
|
||||||
},
|
|
||||||
"viewing_public_key": "026072A8F83FEC3472E30CDD4767683F30B91661D25B1040AD9A5FC2E01D659F99"
|
|
||||||
},
|
|
||||||
"utxos": {}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|||||||
@ -20,8 +20,8 @@ struct Args {
|
|||||||
test_name: String,
|
test_name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const ACC_SENDER: &str = "0d96dfcc414019380c9dde0cd3dce5aac90fb5443bf871108741aeafde552ad7";
|
pub const ACC_SENDER: &str = "1b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f";
|
||||||
pub const ACC_RECEIVER: &str = "974870e9be8d0ac08aa83b3fc7a7a686291d8732508aba98b36080f39c2cf364";
|
pub const ACC_RECEIVER: &str = "4d4b6cd1361032ca9bd2aeb9d900aa4d45d9ead80ac9423374c451a7254d0766";
|
||||||
|
|
||||||
pub const TIME_TO_WAIT_FOR_BLOCK_SECONDS: u64 = 12;
|
pub const TIME_TO_WAIT_FOR_BLOCK_SECONDS: u64 = 12;
|
||||||
|
|
||||||
|
|||||||
@ -1,14 +1,10 @@
|
|||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
use mempoolitem::MemPoolItem;
|
pub struct MemPool<Item> {
|
||||||
|
|
||||||
pub mod mempoolitem;
|
|
||||||
|
|
||||||
pub struct MemPool<Item: MemPoolItem> {
|
|
||||||
items: VecDeque<Item>,
|
items: VecDeque<Item>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Item: MemPoolItem> MemPool<Item> {
|
impl<Item> MemPool<Item> {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
items: VecDeque::new(),
|
items: VecDeque::new(),
|
||||||
@ -55,7 +51,7 @@ impl<Item: MemPoolItem> MemPool<Item> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Item: MemPoolItem> Default for MemPool<Item> {
|
impl<Item> Default for MemPool<Item> {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::new()
|
Self::new()
|
||||||
}
|
}
|
||||||
@ -74,14 +70,6 @@ mod tests {
|
|||||||
id: ItemId,
|
id: ItemId,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MemPoolItem for TestItem {
|
|
||||||
type Identifier = ItemId;
|
|
||||||
|
|
||||||
fn identifier(&self) -> Self::Identifier {
|
|
||||||
self.id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn test_item_with_id(id: u64) -> TestItem {
|
fn test_item_with_id(id: u64) -> TestItem {
|
||||||
TestItem { id }
|
TestItem { id }
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +0,0 @@
|
|||||||
pub trait MemPoolItem {
|
|
||||||
type Identifier;
|
|
||||||
fn identifier(&self) -> Self::Identifier;
|
|
||||||
}
|
|
||||||
21
nssa/Cargo.toml
Normal file
21
nssa/Cargo.toml
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
[package]
|
||||||
|
name = "nssa"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
thiserror = "2.0.12"
|
||||||
|
risc0-zkvm = "2.3.1"
|
||||||
|
nssa-core = { path = "core" }
|
||||||
|
program-methods = { path = "program_methods" }
|
||||||
|
serde = "1.0.219"
|
||||||
|
sha2 = "0.10.9"
|
||||||
|
secp256k1 = "0.31.1"
|
||||||
|
rand = "0.8"
|
||||||
|
hex = "0.4.3"
|
||||||
|
anyhow.workspace = true
|
||||||
|
serde_json.workspace = true
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
test-program-methods = { path = "test_program_methods" }
|
||||||
|
|
||||||
8
nssa/core/Cargo.toml
Normal file
8
nssa/core/Cargo.toml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
[package]
|
||||||
|
name = "nssa-core"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
risc0-zkvm = "2.3.1"
|
||||||
|
serde = { version = "1.0", default-features = false }
|
||||||
56
nssa/core/src/account/mod.rs
Normal file
56
nssa/core/src/account/mod.rs
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::program::ProgramId;
|
||||||
|
|
||||||
|
pub type Nonce = u128;
|
||||||
|
type Data = Vec<u8>;
|
||||||
|
|
||||||
|
/// Account to be used both in public and private contexts
|
||||||
|
#[derive(Default, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||||
|
pub struct Account {
|
||||||
|
pub program_owner: ProgramId,
|
||||||
|
pub balance: u128,
|
||||||
|
pub data: Data,
|
||||||
|
pub nonce: Nonce,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
|
pub struct AccountWithMetadata {
|
||||||
|
pub account: Account,
|
||||||
|
pub is_authorized: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::program::DEFAULT_PROGRAM_ID;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_zero_balance_account_data_creation() {
|
||||||
|
let new_acc = Account::default();
|
||||||
|
|
||||||
|
assert_eq!(new_acc.balance, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_zero_nonce_account_data_creation() {
|
||||||
|
let new_acc = Account::default();
|
||||||
|
|
||||||
|
assert_eq!(new_acc.nonce, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_empty_data_account_data_creation() {
|
||||||
|
let new_acc = Account::default();
|
||||||
|
|
||||||
|
assert!(new_acc.data.is_empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_default_program_owner_account_data_creation() {
|
||||||
|
let new_acc = Account::default();
|
||||||
|
|
||||||
|
assert_eq!(new_acc.program_owner, DEFAULT_PROGRAM_ID);
|
||||||
|
}
|
||||||
|
}
|
||||||
2
nssa/core/src/lib.rs
Normal file
2
nssa/core/src/lib.rs
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
pub mod account;
|
||||||
|
pub mod program;
|
||||||
64
nssa/core/src/program.rs
Normal file
64
nssa/core/src/program.rs
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
use crate::account::{Account, AccountWithMetadata};
|
||||||
|
use risc0_zkvm::serde::Deserializer;
|
||||||
|
use risc0_zkvm::{DeserializeOwned, guest::env};
|
||||||
|
|
||||||
|
pub type ProgramId = [u32; 8];
|
||||||
|
pub type InstructionData = Vec<u32>;
|
||||||
|
pub const DEFAULT_PROGRAM_ID: ProgramId = [0; 8];
|
||||||
|
|
||||||
|
pub fn read_nssa_inputs<T: DeserializeOwned>() -> (Vec<AccountWithMetadata>, T) {
|
||||||
|
let pre_states: Vec<AccountWithMetadata> = env::read();
|
||||||
|
let words: InstructionData = env::read();
|
||||||
|
let instruction_data = T::deserialize(&mut Deserializer::new(words.as_ref())).unwrap();
|
||||||
|
(pre_states, instruction_data)
|
||||||
|
}
|
||||||
|
/// Validates well-behaved program execution
|
||||||
|
///
|
||||||
|
/// # Parameters
|
||||||
|
/// - `pre_states`: The list of input accounts, each annotated with authorization metadata.
|
||||||
|
/// - `post_states`: The list of resulting accounts after executing the program logic.
|
||||||
|
/// - `executing_program_id`: The identifier of the program that was executed.
|
||||||
|
pub fn validate_execution(
|
||||||
|
pre_states: &[AccountWithMetadata],
|
||||||
|
post_states: &[Account],
|
||||||
|
executing_program_id: ProgramId,
|
||||||
|
) -> bool {
|
||||||
|
// 1. Lengths must match
|
||||||
|
if pre_states.len() != post_states.len() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (pre, post) in pre_states.iter().zip(post_states) {
|
||||||
|
// 2. Nonce must remain unchanged
|
||||||
|
if pre.account.nonce != post.nonce {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Ownership change only allowed from default accounts
|
||||||
|
if pre.account.program_owner != post.program_owner && pre.account != Account::default() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Decreasing balance only allowed if owned by executing program
|
||||||
|
if post.balance < pre.account.balance && pre.account.program_owner != executing_program_id {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. Data changes only allowed if owned by executing program
|
||||||
|
if pre.account.data != post.data
|
||||||
|
&& (executing_program_id != pre.account.program_owner
|
||||||
|
|| executing_program_id != post.program_owner)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6. Total balance is preserved
|
||||||
|
let total_balance_pre_states: u128 = pre_states.iter().map(|pre| pre.account.balance).sum();
|
||||||
|
let total_balance_post_states: u128 = post_states.iter().map(|post| post.balance).sum();
|
||||||
|
if total_balance_pre_states != total_balance_post_states {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
10
nssa/program_methods/Cargo.toml
Normal file
10
nssa/program_methods/Cargo.toml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
[package]
|
||||||
|
name = "program-methods"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
risc0-build = { version = "2.3.1" }
|
||||||
|
|
||||||
|
[package.metadata.risc0]
|
||||||
|
methods = ["guest"]
|
||||||
3
nssa/program_methods/build.rs
Normal file
3
nssa/program_methods/build.rs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
fn main() {
|
||||||
|
risc0_build::embed_methods();
|
||||||
|
}
|
||||||
2868
Cargo.lock → nssa/program_methods/guest/Cargo.lock
generated
2868
Cargo.lock → nssa/program_methods/guest/Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
10
nssa/program_methods/guest/Cargo.toml
Normal file
10
nssa/program_methods/guest/Cargo.toml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
[package]
|
||||||
|
name = "programs"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[workspace]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
risc0-zkvm = { version = "2.3.1", default-features = false, features = ['std'] }
|
||||||
|
nssa-core = { path = "../../core" }
|
||||||
36
nssa/program_methods/guest/src/bin/authenticated_transfer.rs
Normal file
36
nssa/program_methods/guest/src/bin/authenticated_transfer.rs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
use nssa_core::program::read_nssa_inputs;
|
||||||
|
use risc0_zkvm::guest::env;
|
||||||
|
|
||||||
|
type Instruction = u128;
|
||||||
|
|
||||||
|
/// A transfer of balance program.
|
||||||
|
/// To be used both in public and private contexts.
|
||||||
|
fn main() {
|
||||||
|
// Read input accounts.
|
||||||
|
// It is expected to receive only two accounts: [sender_account, receiver_account]
|
||||||
|
let (input_accounts, balance_to_move) = read_nssa_inputs::<Instruction>();
|
||||||
|
|
||||||
|
// Continue only if input_accounts is an array of two elements
|
||||||
|
let [sender, receiver] = match input_accounts.try_into() {
|
||||||
|
Ok(array) => array,
|
||||||
|
Err(_) => return,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Continue only if the sender has authorized this operation
|
||||||
|
if !sender.is_authorized {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Continue only if the sender has enough balance
|
||||||
|
if sender.account.balance < balance_to_move {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create accounts post states, with updated balances
|
||||||
|
let mut sender_post = sender.account.clone();
|
||||||
|
let mut receiver_post = receiver.account.clone();
|
||||||
|
sender_post.balance -= balance_to_move;
|
||||||
|
receiver_post.balance += balance_to_move;
|
||||||
|
|
||||||
|
env::commit(&vec![sender_post, receiver_post]);
|
||||||
|
}
|
||||||
1
nssa/program_methods/src/lib.rs
Normal file
1
nssa/program_methods/src/lib.rs
Normal file
@ -0,0 +1 @@
|
|||||||
|
include!(concat!(env!("OUT_DIR"), "/methods.rs"));
|
||||||
4
nssa/rust-toolchain.toml
Normal file
4
nssa/rust-toolchain.toml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
[toolchain]
|
||||||
|
channel = "stable"
|
||||||
|
components = ["rustfmt", "rust-src"]
|
||||||
|
profile = "minimal"
|
||||||
235
nssa/src/address.rs
Normal file
235
nssa/src/address.rs
Normal file
@ -0,0 +1,235 @@
|
|||||||
|
use anyhow::anyhow;
|
||||||
|
use serde::{Deserialize, Serialize, de::Visitor};
|
||||||
|
|
||||||
|
use crate::signature::PublicKey;
|
||||||
|
|
||||||
|
pub const LENGTH_MISMATCH_ERROR_MESSAGE: &str = "Slice length != 32 ";
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
|
||||||
|
pub struct Address {
|
||||||
|
value: [u8; 32],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Address {
|
||||||
|
pub fn new(value: [u8; 32]) -> Self {
|
||||||
|
Self { value }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tag(&self) -> u8 {
|
||||||
|
self.value[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn value(&self) -> &[u8; 32] {
|
||||||
|
&self.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsRef<[u8]> for Address {
|
||||||
|
fn as_ref(&self) -> &[u8] {
|
||||||
|
&self.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<Vec<u8>> for Address {
|
||||||
|
type Error = anyhow::Error;
|
||||||
|
|
||||||
|
fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
|
||||||
|
let addr_val: [u8; 32] = value
|
||||||
|
.try_into()
|
||||||
|
.map_err(|_| anyhow!(LENGTH_MISMATCH_ERROR_MESSAGE))?;
|
||||||
|
|
||||||
|
Ok(Address::new(addr_val))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&PublicKey> for Address {
|
||||||
|
fn from(value: &PublicKey) -> Self {
|
||||||
|
// TODO: Check specs
|
||||||
|
Self::new(*value.value())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct HexString(String);
|
||||||
|
|
||||||
|
impl HexString {
|
||||||
|
pub fn inner(&self) -> &str {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
pub enum HexStringConsistencyError {
|
||||||
|
#[error("Hex decode error")]
|
||||||
|
HexError(#[from] hex::FromHexError),
|
||||||
|
#[error("Decode slice does not fit 32 bytes")]
|
||||||
|
SizeError(#[from] anyhow::Error),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<&str> for HexString {
|
||||||
|
type Error = HexStringConsistencyError;
|
||||||
|
|
||||||
|
fn try_from(value: &str) -> Result<Self, Self::Error> {
|
||||||
|
let decoded_str = hex::decode(value)?;
|
||||||
|
let _: Address = decoded_str.try_into()?;
|
||||||
|
|
||||||
|
Ok(Self(value.to_string()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Serialize for HexString {
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: serde::Serializer,
|
||||||
|
{
|
||||||
|
serializer.serialize_str(&self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct HexStringVisitor;
|
||||||
|
|
||||||
|
impl<'de> Visitor<'de> for HexStringVisitor {
|
||||||
|
type Value = String;
|
||||||
|
|
||||||
|
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
formatter.write_str("expected a valid string")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: serde::de::Error,
|
||||||
|
{
|
||||||
|
Ok(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: serde::de::Error,
|
||||||
|
{
|
||||||
|
Ok(v.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for HexString {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: serde::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
let str_cand = deserializer.deserialize_string(HexStringVisitor)?;
|
||||||
|
|
||||||
|
let hex_string =
|
||||||
|
HexString::try_from(str_cand.as_str()).map_err(|err| serde::de::Error::custom(err))?;
|
||||||
|
|
||||||
|
Ok(hex_string)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<HexString> for Address {
|
||||||
|
fn from(value: HexString) -> Self {
|
||||||
|
Address::try_from(hex::decode(value.inner()).unwrap()).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Address> for HexString {
|
||||||
|
fn from(value: Address) -> Self {
|
||||||
|
HexString::try_from(hex::encode(value).as_str()).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Serialize for Address {
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: serde::Serializer,
|
||||||
|
{
|
||||||
|
let hex_string: HexString = (*self).into();
|
||||||
|
|
||||||
|
hex_string.serialize(serializer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for Address {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: serde::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
let hex_sring = HexString::deserialize(deserializer)?;
|
||||||
|
|
||||||
|
Ok(hex_sring.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
struct Ser1 {
|
||||||
|
f1: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
||||||
|
struct Ser2 {
|
||||||
|
f1: HexString,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
||||||
|
struct Ser3 {
|
||||||
|
f1: Address,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_hex_ser() {
|
||||||
|
let str_for_tests = hex::encode([42; 32]);
|
||||||
|
|
||||||
|
let hex_str_for_tests = HexString::try_from(str_for_tests.as_str()).unwrap();
|
||||||
|
|
||||||
|
let ser1_str = Ser1 { f1: str_for_tests };
|
||||||
|
|
||||||
|
let ser2_str = Ser2 {
|
||||||
|
f1: hex_str_for_tests,
|
||||||
|
};
|
||||||
|
|
||||||
|
let ser1_str_ser = serde_json::to_string(&ser1_str).unwrap();
|
||||||
|
let ser2_str_ser = serde_json::to_string(&ser2_str).unwrap();
|
||||||
|
|
||||||
|
println!("{ser2_str_ser:#?}");
|
||||||
|
|
||||||
|
assert_eq!(ser1_str_ser, ser2_str_ser);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_hex_deser() {
|
||||||
|
let raw_json = r#"{
|
||||||
|
"f1": "2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a"
|
||||||
|
}"#;
|
||||||
|
|
||||||
|
let str_for_tests = hex::encode([42; 32]);
|
||||||
|
|
||||||
|
let hex_str_for_tests = HexString::try_from(str_for_tests.as_str()).unwrap();
|
||||||
|
|
||||||
|
let ser2_str = Ser2 {
|
||||||
|
f1: hex_str_for_tests,
|
||||||
|
};
|
||||||
|
|
||||||
|
let ser1_str: Ser2 = serde_json::from_str(raw_json).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(ser1_str, ser2_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_addr_deser() {
|
||||||
|
let raw_json = r#"{
|
||||||
|
"f1": "2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a"
|
||||||
|
}"#;
|
||||||
|
|
||||||
|
let addr_for_tests = Address::new([42; 32]);
|
||||||
|
|
||||||
|
let ser2_str = Ser3 {
|
||||||
|
f1: addr_for_tests,
|
||||||
|
};
|
||||||
|
|
||||||
|
let ser1_str: Ser3 = serde_json::from_str(raw_json).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(ser1_str, ser2_str);
|
||||||
|
}
|
||||||
|
}
|
||||||
27
nssa/src/error.rs
Normal file
27
nssa/src/error.rs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
use std::io;
|
||||||
|
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
pub enum NssaError {
|
||||||
|
#[error("Invalid input: {0}")]
|
||||||
|
InvalidInput(String),
|
||||||
|
|
||||||
|
#[error("Risc0 error: {0}")]
|
||||||
|
ProgramExecutionFailed(String),
|
||||||
|
|
||||||
|
#[error("Program violated execution rules")]
|
||||||
|
InvalidProgramBehavior,
|
||||||
|
|
||||||
|
#[error("Serialization error: {0}")]
|
||||||
|
InstructionSerializationError(String),
|
||||||
|
|
||||||
|
#[error("Invalid private key")]
|
||||||
|
InvalidPrivateKey,
|
||||||
|
|
||||||
|
#[error("IO error: {0}")]
|
||||||
|
Io(#[from] io::Error),
|
||||||
|
|
||||||
|
#[error("Invalid Public Key")]
|
||||||
|
InvalidPublicKey,
|
||||||
|
}
|
||||||
13
nssa/src/lib.rs
Normal file
13
nssa/src/lib.rs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
pub mod address;
|
||||||
|
pub mod error;
|
||||||
|
pub mod program;
|
||||||
|
pub mod public_transaction;
|
||||||
|
mod signature;
|
||||||
|
mod state;
|
||||||
|
|
||||||
|
pub use address::Address;
|
||||||
|
pub use public_transaction::PublicTransaction;
|
||||||
|
pub use signature::PrivateKey;
|
||||||
|
pub use signature::PublicKey;
|
||||||
|
pub use signature::Signature;
|
||||||
|
pub use state::V01State;
|
||||||
206
nssa/src/program.rs
Normal file
206
nssa/src/program.rs
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
use nssa_core::{
|
||||||
|
account::{Account, AccountWithMetadata},
|
||||||
|
program::{DEFAULT_PROGRAM_ID, InstructionData, ProgramId},
|
||||||
|
};
|
||||||
|
use program_methods::{AUTHENTICATED_TRANSFER_ELF, AUTHENTICATED_TRANSFER_ID};
|
||||||
|
use risc0_zkvm::{ExecutorEnv, ExecutorEnvBuilder, default_executor, serde::to_vec};
|
||||||
|
use serde::Serialize;
|
||||||
|
|
||||||
|
use crate::error::NssaError;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
pub struct Program {
|
||||||
|
id: ProgramId,
|
||||||
|
elf: &'static [u8],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Program {
|
||||||
|
pub fn id(&self) -> ProgramId {
|
||||||
|
self.id
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn serialize_instruction<T: Serialize>(
|
||||||
|
instruction: T,
|
||||||
|
) -> Result<InstructionData, NssaError> {
|
||||||
|
to_vec(&instruction).map_err(|e| NssaError::InstructionSerializationError(e.to_string()))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn execute(
|
||||||
|
&self,
|
||||||
|
pre_states: &[AccountWithMetadata],
|
||||||
|
instruction_data: &InstructionData,
|
||||||
|
) -> Result<Vec<Account>, NssaError> {
|
||||||
|
// Write inputs to the program
|
||||||
|
let mut env_builder = ExecutorEnv::builder();
|
||||||
|
Self::write_inputs(pre_states, instruction_data, &mut env_builder)?;
|
||||||
|
let env = env_builder.build().unwrap();
|
||||||
|
|
||||||
|
// Execute the program (without proving)
|
||||||
|
let executor = default_executor();
|
||||||
|
let session_info = executor
|
||||||
|
.execute(env, self.elf)
|
||||||
|
.map_err(|e| NssaError::ProgramExecutionFailed(e.to_string()))?;
|
||||||
|
|
||||||
|
// Get outputs
|
||||||
|
let mut post_states: Vec<Account> = session_info
|
||||||
|
.journal
|
||||||
|
.decode()
|
||||||
|
.map_err(|e| NssaError::ProgramExecutionFailed(e.to_string()))?;
|
||||||
|
|
||||||
|
// Claim any output account with default program owner field
|
||||||
|
for account in post_states.iter_mut() {
|
||||||
|
if account.program_owner == DEFAULT_PROGRAM_ID {
|
||||||
|
account.program_owner = self.id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(post_states)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Writes inputs to `env_builder` in the order expected by the programs
|
||||||
|
fn write_inputs(
|
||||||
|
pre_states: &[AccountWithMetadata],
|
||||||
|
instruction_data: &[u32],
|
||||||
|
env_builder: &mut ExecutorEnvBuilder,
|
||||||
|
) -> Result<(), NssaError> {
|
||||||
|
let pre_states = pre_states.to_vec();
|
||||||
|
env_builder
|
||||||
|
.write(&(pre_states, instruction_data))
|
||||||
|
.map_err(|e| NssaError::ProgramExecutionFailed(e.to_string()))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn authenticated_transfer_program() -> Self {
|
||||||
|
Self {
|
||||||
|
id: AUTHENTICATED_TRANSFER_ID,
|
||||||
|
elf: AUTHENTICATED_TRANSFER_ELF,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use nssa_core::account::{Account, AccountWithMetadata};
|
||||||
|
|
||||||
|
use crate::program::Program;
|
||||||
|
|
||||||
|
impl Program {
|
||||||
|
/// A program that changes the nonce of an account
|
||||||
|
pub fn nonce_changer_program() -> Self {
|
||||||
|
use test_program_methods::{NONCE_CHANGER_ELF, NONCE_CHANGER_ID};
|
||||||
|
|
||||||
|
Program {
|
||||||
|
id: NONCE_CHANGER_ID,
|
||||||
|
elf: NONCE_CHANGER_ELF,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A program that produces more output accounts than the inputs it received
|
||||||
|
pub fn extra_output_program() -> Self {
|
||||||
|
use test_program_methods::{EXTRA_OUTPUT_ELF, EXTRA_OUTPUT_ID};
|
||||||
|
|
||||||
|
Program {
|
||||||
|
id: EXTRA_OUTPUT_ID,
|
||||||
|
elf: EXTRA_OUTPUT_ELF,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A program that produces less output accounts than the inputs it received
|
||||||
|
pub fn missing_output_program() -> Self {
|
||||||
|
use test_program_methods::{MISSING_OUTPUT_ELF, MISSING_OUTPUT_ID};
|
||||||
|
|
||||||
|
Program {
|
||||||
|
id: MISSING_OUTPUT_ID,
|
||||||
|
elf: MISSING_OUTPUT_ELF,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A program that changes the program owner of an account to [0, 1, 2, 3, 4, 5, 6, 7]
|
||||||
|
pub fn program_owner_changer() -> Self {
|
||||||
|
use test_program_methods::{PROGRAM_OWNER_CHANGER_ELF, PROGRAM_OWNER_CHANGER_ID};
|
||||||
|
|
||||||
|
Program {
|
||||||
|
id: PROGRAM_OWNER_CHANGER_ID,
|
||||||
|
elf: PROGRAM_OWNER_CHANGER_ELF,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A program that transfers balance without caring about authorizations
|
||||||
|
pub fn simple_balance_transfer() -> Self {
|
||||||
|
use test_program_methods::{SIMPLE_BALANCE_TRANSFER_ELF, SIMPLE_BALANCE_TRANSFER_ID};
|
||||||
|
|
||||||
|
Program {
|
||||||
|
id: SIMPLE_BALANCE_TRANSFER_ID,
|
||||||
|
elf: SIMPLE_BALANCE_TRANSFER_ELF,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A program that modifies the data of an account
|
||||||
|
pub fn data_changer() -> Self {
|
||||||
|
use test_program_methods::{DATA_CHANGER_ELF, DATA_CHANGER_ID};
|
||||||
|
|
||||||
|
Program {
|
||||||
|
id: DATA_CHANGER_ID,
|
||||||
|
elf: DATA_CHANGER_ELF,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A program that mints balance
|
||||||
|
pub fn minter() -> Self {
|
||||||
|
use test_program_methods::{MINTER_ELF, MINTER_ID};
|
||||||
|
|
||||||
|
Program {
|
||||||
|
id: MINTER_ID,
|
||||||
|
elf: MINTER_ELF,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A program that burns balance
|
||||||
|
pub fn burner() -> Self {
|
||||||
|
use test_program_methods::{BURNER_ELF, BURNER_ID};
|
||||||
|
|
||||||
|
Program {
|
||||||
|
id: BURNER_ID,
|
||||||
|
elf: BURNER_ELF,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_program_execution() {
|
||||||
|
let program = Program::simple_balance_transfer();
|
||||||
|
let balance_to_move: u128 = 11223344556677;
|
||||||
|
let instruction_data = Program::serialize_instruction(balance_to_move).unwrap();
|
||||||
|
let sender = AccountWithMetadata {
|
||||||
|
account: Account {
|
||||||
|
balance: 77665544332211,
|
||||||
|
..Account::default()
|
||||||
|
},
|
||||||
|
is_authorized: false,
|
||||||
|
};
|
||||||
|
let recipient = AccountWithMetadata {
|
||||||
|
account: Account::default(),
|
||||||
|
is_authorized: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
let expected_sender_post = Account {
|
||||||
|
balance: 77665544332211 - balance_to_move,
|
||||||
|
program_owner: program.id(),
|
||||||
|
..Account::default()
|
||||||
|
};
|
||||||
|
let expected_recipient_post = Account {
|
||||||
|
balance: balance_to_move,
|
||||||
|
// Program claims the account since the pre_state has default prorgam owner
|
||||||
|
program_owner: program.id(),
|
||||||
|
..Account::default()
|
||||||
|
};
|
||||||
|
let [sender_post, recipient_post] = program
|
||||||
|
.execute(&[sender, recipient], &instruction_data)
|
||||||
|
.unwrap()
|
||||||
|
.try_into()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(sender_post, expected_sender_post);
|
||||||
|
assert_eq!(recipient_post, expected_recipient_post);
|
||||||
|
}
|
||||||
|
}
|
||||||
145
nssa/src/public_transaction/encoding.rs
Normal file
145
nssa/src/public_transaction/encoding.rs
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
use std::io::{Cursor, Read};
|
||||||
|
|
||||||
|
use nssa_core::program::ProgramId;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
Address, PublicKey, PublicTransaction, Signature,
|
||||||
|
error::NssaError,
|
||||||
|
public_transaction::{Message, WitnessSet},
|
||||||
|
};
|
||||||
|
|
||||||
|
const MESSAGE_ENCODING_PREFIX_LEN: usize = 19;
|
||||||
|
const MESSAGE_ENCODING_PREFIX: &[u8; MESSAGE_ENCODING_PREFIX_LEN] = b"NSSA/v0.1/TxMessage";
|
||||||
|
|
||||||
|
impl Message {
|
||||||
|
/// Serializes a `Message` into bytes in the following layout:
|
||||||
|
/// PREFIX || <program_id> (4 bytes LE) * 8 || addresses_len (4 bytes LE) || addresses (32 bytes * N) || nonces_len (4 bytes LE) || nonces (16 bytes LE * M) || instruction_data_len || instruction_data (4 bytes LE * K)
|
||||||
|
/// Integers and words 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();
|
||||||
|
// program_id: [u32; 8]
|
||||||
|
for word in &self.program_id {
|
||||||
|
bytes.extend_from_slice(&word.to_le_bytes());
|
||||||
|
}
|
||||||
|
// addresses: Vec<[u8;32]>
|
||||||
|
// serialize length as u32 little endian, then all addresses concatenated
|
||||||
|
let addresses_len = self.addresses.len() as u32;
|
||||||
|
bytes.extend(&addresses_len.to_le_bytes());
|
||||||
|
for addr in &self.addresses {
|
||||||
|
bytes.extend_from_slice(addr.value());
|
||||||
|
}
|
||||||
|
// nonces: Vec<u128>
|
||||||
|
// serialize length as u32 little endian, then all nonces concatenated in LE
|
||||||
|
let nonces_len = self.nonces.len() as u32;
|
||||||
|
bytes.extend(&nonces_len.to_le_bytes());
|
||||||
|
for nonce in &self.nonces {
|
||||||
|
bytes.extend(&nonce.to_le_bytes());
|
||||||
|
}
|
||||||
|
// instruction_data: Vec<u32>
|
||||||
|
// serialize length as u32 little endian, then all addresses concatenated
|
||||||
|
let instr_len = self.instruction_data.len() as u32;
|
||||||
|
bytes.extend(&instr_len.to_le_bytes());
|
||||||
|
for word in &self.instruction_data {
|
||||||
|
bytes.extend(&word.to_le_bytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
};
|
||||||
|
assert_eq!(&prefix, MESSAGE_ENCODING_PREFIX);
|
||||||
|
let program_id: ProgramId = {
|
||||||
|
let mut this = [0u32; 8];
|
||||||
|
for item in &mut this {
|
||||||
|
*item = u32_from_cursor(cursor)?;
|
||||||
|
}
|
||||||
|
this
|
||||||
|
};
|
||||||
|
let addresses_len = u32_from_cursor(cursor)?;
|
||||||
|
let mut addresses = Vec::with_capacity(addresses_len as usize);
|
||||||
|
for _ in 0..addresses_len {
|
||||||
|
let mut value = [0u8; 32];
|
||||||
|
cursor.read_exact(&mut value)?;
|
||||||
|
addresses.push(Address::new(value))
|
||||||
|
}
|
||||||
|
let nonces_len = u32_from_cursor(cursor)?;
|
||||||
|
let mut nonces = Vec::with_capacity(nonces_len as usize);
|
||||||
|
for _ in 0..nonces_len {
|
||||||
|
let mut buf = [0u8; 16];
|
||||||
|
cursor.read_exact(&mut buf)?;
|
||||||
|
nonces.push(u128::from_le_bytes(buf))
|
||||||
|
}
|
||||||
|
let instruction_data_len = u32_from_cursor(cursor)?;
|
||||||
|
let mut instruction_data = Vec::with_capacity(instruction_data_len as usize);
|
||||||
|
for _ in 0..instruction_data_len {
|
||||||
|
let word = u32_from_cursor(cursor)?;
|
||||||
|
instruction_data.push(word)
|
||||||
|
}
|
||||||
|
Ok(Self {
|
||||||
|
program_id,
|
||||||
|
addresses,
|
||||||
|
nonces,
|
||||||
|
instruction_data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WitnessSet {
|
||||||
|
pub(crate) fn to_bytes(&self) -> Vec<u8> {
|
||||||
|
let mut bytes = Vec::new();
|
||||||
|
let size = self.signatures_and_public_keys().len() as u32;
|
||||||
|
bytes.extend_from_slice(&size.to_le_bytes());
|
||||||
|
for (signature, public_key) in self.signatures_and_public_keys() {
|
||||||
|
bytes.extend_from_slice(signature.to_bytes());
|
||||||
|
bytes.extend_from_slice(public_key.to_bytes());
|
||||||
|
}
|
||||||
|
bytes
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn from_cursor(cursor: &mut Cursor<&[u8]>) -> Result<Self, NssaError> {
|
||||||
|
let num_signatures: u32 = {
|
||||||
|
let mut buf = [0u8; 4];
|
||||||
|
cursor.read_exact(&mut buf)?;
|
||||||
|
u32::from_le_bytes(buf)
|
||||||
|
};
|
||||||
|
let mut signatures_and_public_keys = Vec::with_capacity(num_signatures as usize);
|
||||||
|
for _i in 0..num_signatures {
|
||||||
|
let signature = Signature::from_cursor(cursor)?;
|
||||||
|
let public_key = PublicKey::from_cursor(cursor)?;
|
||||||
|
signatures_and_public_keys.push((signature, public_key))
|
||||||
|
}
|
||||||
|
Ok(Self {
|
||||||
|
signatures_and_public_keys,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PublicTransaction {
|
||||||
|
pub fn to_bytes(&self) -> Vec<u8> {
|
||||||
|
let mut bytes = self.message().to_bytes();
|
||||||
|
bytes.extend_from_slice(&self.witness_set().to_bytes());
|
||||||
|
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)?;
|
||||||
|
let witness_set = WitnessSet::from_cursor(cursor)?;
|
||||||
|
Ok(PublicTransaction::new(message, witness_set))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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))
|
||||||
|
}
|
||||||
32
nssa/src/public_transaction/message.rs
Normal file
32
nssa/src/public_transaction/message.rs
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
use nssa_core::{
|
||||||
|
account::Nonce,
|
||||||
|
program::{InstructionData, ProgramId},
|
||||||
|
};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::{Address, error::NssaError, program::Program};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||||
|
pub struct Message {
|
||||||
|
pub(crate) program_id: ProgramId,
|
||||||
|
pub(crate) addresses: Vec<Address>,
|
||||||
|
pub(crate) nonces: Vec<Nonce>,
|
||||||
|
pub(crate) instruction_data: InstructionData,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Message {
|
||||||
|
pub fn try_new<T: Serialize>(
|
||||||
|
program_id: ProgramId,
|
||||||
|
addresses: Vec<Address>,
|
||||||
|
nonces: Vec<Nonce>,
|
||||||
|
instruction: T,
|
||||||
|
) -> Result<Self, NssaError> {
|
||||||
|
let instruction_data = Program::serialize_instruction(instruction)?;
|
||||||
|
Ok(Self {
|
||||||
|
program_id,
|
||||||
|
addresses,
|
||||||
|
nonces,
|
||||||
|
instruction_data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
8
nssa/src/public_transaction/mod.rs
Normal file
8
nssa/src/public_transaction/mod.rs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
mod encoding;
|
||||||
|
mod message;
|
||||||
|
mod transaction;
|
||||||
|
mod witness_set;
|
||||||
|
|
||||||
|
pub use message::Message;
|
||||||
|
pub use transaction::PublicTransaction;
|
||||||
|
pub use witness_set::WitnessSet;
|
||||||
315
nssa/src/public_transaction/transaction.rs
Normal file
315
nssa/src/public_transaction/transaction.rs
Normal file
@ -0,0 +1,315 @@
|
|||||||
|
use std::collections::{HashMap, HashSet};
|
||||||
|
|
||||||
|
use nssa_core::{
|
||||||
|
account::{Account, AccountWithMetadata},
|
||||||
|
program::validate_execution,
|
||||||
|
};
|
||||||
|
use sha2::{Digest, digest::FixedOutput};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
V01State,
|
||||||
|
address::Address,
|
||||||
|
error::NssaError,
|
||||||
|
public_transaction::{Message, WitnessSet},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct PublicTransaction {
|
||||||
|
message: Message,
|
||||||
|
witness_set: WitnessSet,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PublicTransaction {
|
||||||
|
pub fn new(message: Message, witness_set: WitnessSet) -> Self {
|
||||||
|
Self {
|
||||||
|
message,
|
||||||
|
witness_set,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn message(&self) -> &Message {
|
||||||
|
&self.message
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn witness_set(&self) -> &WitnessSet {
|
||||||
|
&self.witness_set
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn signer_addresses(&self) -> Vec<Address> {
|
||||||
|
self.witness_set
|
||||||
|
.signatures_and_public_keys()
|
||||||
|
.iter()
|
||||||
|
.map(|(_, public_key)| Address::from(public_key))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn hash(&self) -> [u8; 32] {
|
||||||
|
let bytes = self.to_bytes();
|
||||||
|
let mut hasher = sha2::Sha256::new();
|
||||||
|
hasher.update(&bytes);
|
||||||
|
hasher.finalize_fixed().into()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn validate_and_compute_post_states(
|
||||||
|
&self,
|
||||||
|
state: &V01State,
|
||||||
|
) -> Result<HashMap<Address, Account>, NssaError> {
|
||||||
|
let message = self.message();
|
||||||
|
let witness_set = self.witness_set();
|
||||||
|
|
||||||
|
// All addresses must be different
|
||||||
|
if message.addresses.iter().collect::<HashSet<_>>().len() != message.addresses.len() {
|
||||||
|
return Err(NssaError::InvalidInput(
|
||||||
|
"Duplicate addresses found in message".into(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if message.nonces.len() != witness_set.signatures_and_public_keys.len() {
|
||||||
|
return Err(NssaError::InvalidInput(
|
||||||
|
"Mismatch between number of nonces and signatures/public keys".into(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the signatures are valid
|
||||||
|
if !witness_set.is_valid_for(message) {
|
||||||
|
return Err(NssaError::InvalidInput(
|
||||||
|
"Invalid signature for given message and public key".into(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let signer_addresses = self.signer_addresses();
|
||||||
|
// Check nonces corresponds to the current nonces on the public state.
|
||||||
|
for (address, nonce) in signer_addresses.iter().zip(&message.nonces) {
|
||||||
|
let current_nonce = state.get_account_by_address(address).nonce;
|
||||||
|
if current_nonce != *nonce {
|
||||||
|
return Err(NssaError::InvalidInput("Nonce mismatch".into()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build pre_states for execution
|
||||||
|
let pre_states: Vec<_> = message
|
||||||
|
.addresses
|
||||||
|
.iter()
|
||||||
|
.map(|address| AccountWithMetadata {
|
||||||
|
account: state.get_account_by_address(address),
|
||||||
|
is_authorized: signer_addresses.contains(address),
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
// Check the `program_id` corresponds to a built-in program
|
||||||
|
// Only allowed program so far is the authenticated transfer program
|
||||||
|
let Some(program) = state.builtin_programs().get(&message.program_id) else {
|
||||||
|
return Err(NssaError::InvalidInput("Unknown program".into()));
|
||||||
|
};
|
||||||
|
|
||||||
|
// // Execute program
|
||||||
|
let post_states = program.execute(&pre_states, &message.instruction_data)?;
|
||||||
|
|
||||||
|
// Verify execution corresponds to a well-behaved program.
|
||||||
|
// See the # Programs section for the definition of the `validate_execution` method.
|
||||||
|
if !validate_execution(&pre_states, &post_states, message.program_id) {
|
||||||
|
return Err(NssaError::InvalidProgramBehavior);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(message.addresses.iter().cloned().zip(post_states).collect())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
pub mod tests {
|
||||||
|
use sha2::{Digest, digest::FixedOutput};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
Address, PrivateKey, PublicKey, PublicTransaction, Signature, V01State,
|
||||||
|
error::NssaError,
|
||||||
|
program::Program,
|
||||||
|
public_transaction::{Message, WitnessSet},
|
||||||
|
};
|
||||||
|
|
||||||
|
fn keys_for_tests() -> (PrivateKey, PrivateKey, Address, Address) {
|
||||||
|
let key1 = PrivateKey::try_new([1; 32]).unwrap();
|
||||||
|
let key2 = PrivateKey::try_new([2; 32]).unwrap();
|
||||||
|
let addr1 = Address::from(&PublicKey::new_from_private_key(&key1));
|
||||||
|
let addr2 = Address::from(&PublicKey::new_from_private_key(&key2));
|
||||||
|
(key1, key2, addr1, addr2)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn state_for_tests() -> V01State {
|
||||||
|
let (_, _, addr1, addr2) = keys_for_tests();
|
||||||
|
let initial_data = [(addr1, 10000), (addr2, 20000)];
|
||||||
|
V01State::new_with_genesis_accounts(&initial_data)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn transaction_for_tests() -> PublicTransaction {
|
||||||
|
let (key1, key2, addr1, addr2) = keys_for_tests();
|
||||||
|
let nonces = vec![0, 0];
|
||||||
|
let instruction = 1337;
|
||||||
|
let message = Message::try_new(
|
||||||
|
Program::authenticated_transfer_program().id(),
|
||||||
|
vec![addr1, addr2],
|
||||||
|
nonces,
|
||||||
|
instruction,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let witness_set = WitnessSet::for_message(&message, &[&key1, &key2]);
|
||||||
|
PublicTransaction::new(message, witness_set)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_new_constructor() {
|
||||||
|
let tx = transaction_for_tests();
|
||||||
|
let message = tx.message().clone();
|
||||||
|
let witness_set = tx.witness_set().clone();
|
||||||
|
let tx_from_constructor = PublicTransaction::new(message.clone(), witness_set.clone());
|
||||||
|
assert_eq!(tx_from_constructor.message, message);
|
||||||
|
assert_eq!(tx_from_constructor.witness_set, witness_set);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_message_getter() {
|
||||||
|
let tx = transaction_for_tests();
|
||||||
|
assert_eq!(&tx.message, tx.message());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_witness_set_getter() {
|
||||||
|
let tx = transaction_for_tests();
|
||||||
|
assert_eq!(&tx.witness_set, tx.witness_set());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_signer_addresses() {
|
||||||
|
let tx = transaction_for_tests();
|
||||||
|
let expected_signer_addresses = vec![
|
||||||
|
Address::new([
|
||||||
|
27, 132, 197, 86, 123, 18, 100, 64, 153, 93, 62, 213, 170, 186, 5, 101, 215, 30,
|
||||||
|
24, 52, 96, 72, 25, 255, 156, 23, 245, 233, 213, 221, 7, 143,
|
||||||
|
]),
|
||||||
|
Address::new([
|
||||||
|
77, 75, 108, 209, 54, 16, 50, 202, 155, 210, 174, 185, 217, 0, 170, 77, 69, 217,
|
||||||
|
234, 216, 10, 201, 66, 51, 116, 196, 81, 167, 37, 77, 7, 102,
|
||||||
|
]),
|
||||||
|
];
|
||||||
|
let signer_addresses = tx.signer_addresses();
|
||||||
|
assert_eq!(signer_addresses, expected_signer_addresses);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_public_transaction_encoding_bytes_roundtrip() {
|
||||||
|
let tx = transaction_for_tests();
|
||||||
|
let bytes = tx.to_bytes();
|
||||||
|
let tx_from_bytes = PublicTransaction::from_bytes(&bytes).unwrap();
|
||||||
|
assert_eq!(tx, tx_from_bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_hash_is_sha256_of_transaction_bytes() {
|
||||||
|
let tx = transaction_for_tests();
|
||||||
|
let hash = tx.hash();
|
||||||
|
let expected_hash: [u8; 32] = {
|
||||||
|
let bytes = tx.to_bytes();
|
||||||
|
let mut hasher = sha2::Sha256::new();
|
||||||
|
hasher.update(&bytes);
|
||||||
|
hasher.finalize_fixed().into()
|
||||||
|
};
|
||||||
|
assert_eq!(hash, expected_hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_address_list_cant_have_duplicates() {
|
||||||
|
let (key1, _, addr1, _) = keys_for_tests();
|
||||||
|
let state = state_for_tests();
|
||||||
|
let nonces = vec![0, 0];
|
||||||
|
let instruction = 1337;
|
||||||
|
let message = Message::try_new(
|
||||||
|
Program::authenticated_transfer_program().id(),
|
||||||
|
vec![addr1.clone(), addr1],
|
||||||
|
nonces,
|
||||||
|
instruction,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let witness_set = WitnessSet::for_message(&message, &[&key1, &key1]);
|
||||||
|
let tx = PublicTransaction::new(message, witness_set);
|
||||||
|
let result = tx.validate_and_compute_post_states(&state);
|
||||||
|
assert!(matches!(result, Err(NssaError::InvalidInput(_))))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_number_of_nonces_must_match_number_of_signatures() {
|
||||||
|
let (key1, key2, addr1, addr2) = keys_for_tests();
|
||||||
|
let state = state_for_tests();
|
||||||
|
let nonces = vec![0];
|
||||||
|
let instruction = 1337;
|
||||||
|
let message = Message::try_new(
|
||||||
|
Program::authenticated_transfer_program().id(),
|
||||||
|
vec![addr1, addr2],
|
||||||
|
nonces,
|
||||||
|
instruction,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let witness_set = WitnessSet::for_message(&message, &[&key1, &key2]);
|
||||||
|
let tx = PublicTransaction::new(message, witness_set);
|
||||||
|
let result = tx.validate_and_compute_post_states(&state);
|
||||||
|
assert!(matches!(result, Err(NssaError::InvalidInput(_))))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_all_signatures_must_be_valid() {
|
||||||
|
let (key1, key2, addr1, addr2) = keys_for_tests();
|
||||||
|
let state = state_for_tests();
|
||||||
|
let nonces = vec![0, 0];
|
||||||
|
let instruction = 1337;
|
||||||
|
let message = Message::try_new(
|
||||||
|
Program::authenticated_transfer_program().id(),
|
||||||
|
vec![addr1, addr2],
|
||||||
|
nonces,
|
||||||
|
instruction,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let mut witness_set = WitnessSet::for_message(&message, &[&key1, &key2]);
|
||||||
|
witness_set.signatures_and_public_keys[0].0 = Signature::new_for_tests([1; 64]);
|
||||||
|
let tx = PublicTransaction::new(message, witness_set);
|
||||||
|
let result = tx.validate_and_compute_post_states(&state);
|
||||||
|
assert!(matches!(result, Err(NssaError::InvalidInput(_))))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_nonces_must_match_the_state_current_nonces() {
|
||||||
|
let (key1, key2, addr1, addr2) = keys_for_tests();
|
||||||
|
let state = state_for_tests();
|
||||||
|
let nonces = vec![0, 1];
|
||||||
|
let instruction = 1337;
|
||||||
|
let message = Message::try_new(
|
||||||
|
Program::authenticated_transfer_program().id(),
|
||||||
|
vec![addr1, addr2],
|
||||||
|
nonces,
|
||||||
|
instruction,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let witness_set = WitnessSet::for_message(&message, &[&key1, &key2]);
|
||||||
|
let tx = PublicTransaction::new(message, witness_set);
|
||||||
|
let result = tx.validate_and_compute_post_states(&state);
|
||||||
|
assert!(matches!(result, Err(NssaError::InvalidInput(_))))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_program_id_must_belong_to_bulitin_program_ids() {
|
||||||
|
let (key1, key2, addr1, addr2) = keys_for_tests();
|
||||||
|
let state = state_for_tests();
|
||||||
|
let nonces = vec![0, 0];
|
||||||
|
let instruction = 1337;
|
||||||
|
let unknown_program_id = [0xdeadbeef; 8];
|
||||||
|
let message =
|
||||||
|
Message::try_new(unknown_program_id, vec![addr1, addr2], nonces, instruction).unwrap();
|
||||||
|
|
||||||
|
let witness_set = WitnessSet::for_message(&message, &[&key1, &key2]);
|
||||||
|
let tx = PublicTransaction::new(message, witness_set);
|
||||||
|
let result = tx.validate_and_compute_post_states(&state);
|
||||||
|
assert!(matches!(result, Err(NssaError::InvalidInput(_))))
|
||||||
|
}
|
||||||
|
}
|
||||||
72
nssa/src/public_transaction/witness_set.rs
Normal file
72
nssa/src/public_transaction/witness_set.rs
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
use crate::{PrivateKey, PublicKey, Signature, public_transaction::Message};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct WitnessSet {
|
||||||
|
pub(super) signatures_and_public_keys: Vec<(Signature, PublicKey)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WitnessSet {
|
||||||
|
pub fn for_message(message: &Message, private_keys: &[&PrivateKey]) -> Self {
|
||||||
|
let message_bytes = message.to_bytes();
|
||||||
|
let signatures_and_public_keys = private_keys
|
||||||
|
.iter()
|
||||||
|
.map(|&key| {
|
||||||
|
(
|
||||||
|
Signature::new(key, &message_bytes),
|
||||||
|
PublicKey::new_from_private_key(key),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
Self {
|
||||||
|
signatures_and_public_keys,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_valid_for(&self, message: &Message) -> bool {
|
||||||
|
let message_bytes = message.to_bytes();
|
||||||
|
for (signature, public_key) in self.signatures_and_public_keys() {
|
||||||
|
if !signature.is_valid_for(&message_bytes, public_key) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn signatures_and_public_keys(&self) -> &[(Signature, PublicKey)] {
|
||||||
|
&self.signatures_and_public_keys
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::Address;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_for_message_constructor() {
|
||||||
|
let key1 = PrivateKey::try_new([1; 32]).unwrap();
|
||||||
|
let key2 = PrivateKey::try_new([2; 32]).unwrap();
|
||||||
|
let pubkey1 = PublicKey::new_from_private_key(&key1);
|
||||||
|
let pubkey2 = PublicKey::new_from_private_key(&key2);
|
||||||
|
let addr1 = Address::from(&pubkey1);
|
||||||
|
let addr2 = Address::from(&pubkey2);
|
||||||
|
let nonces = vec![1, 2];
|
||||||
|
let instruction = vec![1, 2, 3, 4];
|
||||||
|
let message = Message::try_new([0; 8], vec![addr1, addr2], nonces, instruction).unwrap();
|
||||||
|
|
||||||
|
let witness_set = WitnessSet::for_message(&message, &[&key1, &key2]);
|
||||||
|
|
||||||
|
assert_eq!(witness_set.signatures_and_public_keys.len(), 2);
|
||||||
|
|
||||||
|
let message_bytes = message.to_bytes();
|
||||||
|
for ((signature, public_key), expected_public_key) in witness_set
|
||||||
|
.signatures_and_public_keys
|
||||||
|
.into_iter()
|
||||||
|
.zip([pubkey1, pubkey2])
|
||||||
|
{
|
||||||
|
assert_eq!(public_key, expected_public_key);
|
||||||
|
assert!(signature.is_valid_for(&message_bytes, &expected_public_key));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
367
nssa/src/signature/bip340_test_vectors.rs
Normal file
367
nssa/src/signature/bip340_test_vectors.rs
Normal file
@ -0,0 +1,367 @@
|
|||||||
|
use crate::{PrivateKey, PublicKey, Signature};
|
||||||
|
|
||||||
|
fn hex_to_bytes<const N: usize>(hex: &str) -> [u8; N] {
|
||||||
|
hex::decode(hex).unwrap().try_into().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct TestVector {
|
||||||
|
pub seckey: Option<PrivateKey>,
|
||||||
|
pub pubkey: PublicKey,
|
||||||
|
pub aux_rand: Option<[u8; 32]>,
|
||||||
|
pub message: Option<Vec<u8>>,
|
||||||
|
pub signature: Signature,
|
||||||
|
pub verification_result: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Test vectors from
|
||||||
|
/// https://github.com/bitcoin/bips/blob/master/bip-0340/test-vectors.csv
|
||||||
|
//
|
||||||
|
pub fn test_vectors() -> Vec<TestVector> {
|
||||||
|
vec![
|
||||||
|
TestVector {
|
||||||
|
seckey: Some(PrivateKey::try_new(hex_to_bytes(
|
||||||
|
"0000000000000000000000000000000000000000000000000000000000000003",
|
||||||
|
)).unwrap()),
|
||||||
|
pubkey: PublicKey::try_new(hex_to_bytes(
|
||||||
|
"F9308A019258C31049344F85F89D5229B531C845836F99B08601F113BCE036F9",
|
||||||
|
)).unwrap(),
|
||||||
|
aux_rand: Some(hex_to_bytes::<32>(
|
||||||
|
"0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
)),
|
||||||
|
message: Some(
|
||||||
|
hex::decode("0000000000000000000000000000000000000000000000000000000000000000")
|
||||||
|
.unwrap(),
|
||||||
|
),
|
||||||
|
signature: Signature {
|
||||||
|
value: hex_to_bytes(
|
||||||
|
"E907831F80848D1069A5371B402410364BDF1C5F8307B0084C55F1CE2DCA821525F66A4A85EA8B71E482A74F382D2CE5EBEEE8FDB2172F477DF4900D310536C0",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
verification_result: true,
|
||||||
|
},
|
||||||
|
TestVector {
|
||||||
|
seckey: Some(PrivateKey::try_new(hex_to_bytes(
|
||||||
|
"B7E151628AED2A6ABF7158809CF4F3C762E7160F38B4DA56A784D9045190CFEF",
|
||||||
|
)).unwrap()),
|
||||||
|
pubkey: PublicKey::try_new(hex_to_bytes(
|
||||||
|
"DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659",
|
||||||
|
)).unwrap(),
|
||||||
|
aux_rand: Some(hex_to_bytes::<32>(
|
||||||
|
"0000000000000000000000000000000000000000000000000000000000000001",
|
||||||
|
)),
|
||||||
|
message: Some(
|
||||||
|
hex::decode("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89")
|
||||||
|
.unwrap(),
|
||||||
|
),
|
||||||
|
signature: Signature {
|
||||||
|
value: hex_to_bytes(
|
||||||
|
"6896BD60EEAE296DB48A229FF71DFE071BDE413E6D43F917DC8DCF8C78DE33418906D11AC976ABCCB20B091292BFF4EA897EFCB639EA871CFA95F6DE339E4B0A",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
verification_result: true,
|
||||||
|
},
|
||||||
|
TestVector {
|
||||||
|
seckey: Some(PrivateKey::try_new(hex_to_bytes(
|
||||||
|
"C90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B14E5C9",
|
||||||
|
)).unwrap()),
|
||||||
|
pubkey: PublicKey::try_new(hex_to_bytes(
|
||||||
|
"DD308AFEC5777E13121FA72B9CC1B7CC0139715309B086C960E18FD969774EB8",
|
||||||
|
)).unwrap(),
|
||||||
|
aux_rand: Some(hex_to_bytes::<32>(
|
||||||
|
"C87AA53824B4D7AE2EB035A2B5BBBCCC080E76CDC6D1692C4B0B62D798E6D906",
|
||||||
|
)),
|
||||||
|
message: Some(
|
||||||
|
hex::decode("7E2D58D8B3BCDF1ABADEC7829054F90DDA9805AAB56C77333024B9D0A508B75C")
|
||||||
|
.unwrap(),
|
||||||
|
),
|
||||||
|
signature: Signature {
|
||||||
|
value: hex_to_bytes(
|
||||||
|
"5831AAEED7B44BB74E5EAB94BA9D4294C49BCF2A60728D8B4C200F50DD313C1BAB745879A5AD954A72C45A91C3A51D3C7ADEA98D82F8481E0E1E03674A6F3FB7",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
verification_result: true,
|
||||||
|
},
|
||||||
|
TestVector {
|
||||||
|
seckey: Some(PrivateKey::try_new(hex_to_bytes(
|
||||||
|
"0B432B2677937381AEF05BB02A66ECD012773062CF3FA2549E44F58ED2401710",
|
||||||
|
)).unwrap()),
|
||||||
|
pubkey: PublicKey::try_new(hex_to_bytes(
|
||||||
|
"25D1DFF95105F5253C4022F628A996AD3A0D95FBF21D468A1B33F8C160D8F517",
|
||||||
|
)).unwrap(),
|
||||||
|
aux_rand: Some(hex_to_bytes::<32>(
|
||||||
|
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
|
||||||
|
)),
|
||||||
|
message: Some(
|
||||||
|
hex::decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")
|
||||||
|
.unwrap(),
|
||||||
|
),
|
||||||
|
signature: Signature {
|
||||||
|
value: hex_to_bytes(
|
||||||
|
"7EB0509757E246F19449885651611CB965ECC1A187DD51B64FDA1EDC9637D5EC97582B9CB13DB3933705B32BA982AF5AF25FD78881EBB32771FC5922EFC66EA3",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
verification_result: true,
|
||||||
|
},
|
||||||
|
TestVector {
|
||||||
|
seckey: None,
|
||||||
|
pubkey: PublicKey::try_new(hex_to_bytes(
|
||||||
|
"D69C3509BB99E412E68B0FE8544E72837DFA30746D8BE2AA65975F29D22DC7B9",
|
||||||
|
)).unwrap(),
|
||||||
|
aux_rand: None,
|
||||||
|
message: Some(
|
||||||
|
hex::decode("4DF3C3F68FCC83B27E9D42C90431A72499F17875C81A599B566C9889B9696703")
|
||||||
|
.unwrap(),
|
||||||
|
),
|
||||||
|
signature: Signature {
|
||||||
|
value: hex_to_bytes(
|
||||||
|
"00000000000000000000003B78CE563F89A0ED9414F5AA28AD0D96D6795F9C6376AFB1548AF603B3EB45C9F8207DEE1060CB71C04E80F593060B07D28308D7F4",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
verification_result: true,
|
||||||
|
},
|
||||||
|
// Test with invalid public key
|
||||||
|
// TestVector {
|
||||||
|
// seckey: None,
|
||||||
|
// pubkey: PublicKey::new(hex_to_bytes(
|
||||||
|
// "EEFDEA4CDB677750A420FEE807EACF21EB9898AE79B9768766E4FAA04A2D4A34",
|
||||||
|
// )).unwrap(),
|
||||||
|
// aux_rand: None,
|
||||||
|
// message: Some(
|
||||||
|
// hex::decode("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89").unwrap(),
|
||||||
|
// ),
|
||||||
|
// signature: Signature {
|
||||||
|
// value: hex_to_bytes(
|
||||||
|
// "6CFF5C3BA86C69EA4B7376F31A9BCB4F74C1976089B2D9963DA2E5543E17776969E89B4C5564D00349106B8497785DD7D1D713A8AE82B32FA79D5F7FC407D39B",
|
||||||
|
// ),
|
||||||
|
// },
|
||||||
|
// verification_result: false,
|
||||||
|
// },
|
||||||
|
TestVector {
|
||||||
|
seckey: None,
|
||||||
|
pubkey: PublicKey::try_new(hex_to_bytes(
|
||||||
|
"DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659",
|
||||||
|
)).unwrap(),
|
||||||
|
aux_rand: None,
|
||||||
|
message: Some(
|
||||||
|
hex::decode("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89")
|
||||||
|
.unwrap(),
|
||||||
|
),
|
||||||
|
signature: Signature {
|
||||||
|
value: hex_to_bytes(
|
||||||
|
"FFF97BD5755EEEA420453A14355235D382F6472F8568A18B2F057A14602975563CC27944640AC607CD107AE10923D9EF7A73C643E166BE5EBEAFA34B1AC553E2",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
verification_result: false,
|
||||||
|
},
|
||||||
|
TestVector {
|
||||||
|
seckey: None,
|
||||||
|
pubkey: PublicKey::try_new(hex_to_bytes(
|
||||||
|
"DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659",
|
||||||
|
)).unwrap(),
|
||||||
|
aux_rand: None,
|
||||||
|
message: Some(
|
||||||
|
hex::decode("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89")
|
||||||
|
.unwrap(),
|
||||||
|
),
|
||||||
|
signature: Signature {
|
||||||
|
value: hex_to_bytes(
|
||||||
|
"1FA62E331EDBC21C394792D2AB1100A7B432B013DF3F6FF4F99FCB33E0E1515F28890B3EDB6E7189B630448B515CE4F8622A954CFE545735AAEA5134FCCDB2BD",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
verification_result: false,
|
||||||
|
},
|
||||||
|
TestVector {
|
||||||
|
seckey: None,
|
||||||
|
pubkey: PublicKey::try_new(hex_to_bytes(
|
||||||
|
"DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659",
|
||||||
|
)).unwrap(),
|
||||||
|
aux_rand: None,
|
||||||
|
message: Some(
|
||||||
|
hex::decode("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89")
|
||||||
|
.unwrap(),
|
||||||
|
),
|
||||||
|
signature: Signature {
|
||||||
|
value: hex_to_bytes(
|
||||||
|
"6CFF5C3BA86C69EA4B7376F31A9BCB4F74C1976089B2D9963DA2E5543E177769961764B3AA9B2FFCB6EF947B6887A226E8D7C93E00C5ED0C1834FF0D0C2E6DA6",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
verification_result: false,
|
||||||
|
},
|
||||||
|
TestVector {
|
||||||
|
seckey: None,
|
||||||
|
pubkey: PublicKey::try_new(hex_to_bytes(
|
||||||
|
"DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659",
|
||||||
|
)).unwrap(),
|
||||||
|
aux_rand: None,
|
||||||
|
message: Some(
|
||||||
|
hex::decode("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89")
|
||||||
|
.unwrap(),
|
||||||
|
),
|
||||||
|
signature: Signature {
|
||||||
|
value: hex_to_bytes(
|
||||||
|
"0000000000000000000000000000000000000000000000000000000000000000123DDA8328AF9C23A94C1FEECFD123BA4FB73476F0D594DCB65C6425BD186051",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
verification_result: false,
|
||||||
|
},
|
||||||
|
TestVector {
|
||||||
|
seckey: None,
|
||||||
|
pubkey: PublicKey::try_new(hex_to_bytes(
|
||||||
|
"DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659",
|
||||||
|
)).unwrap(),
|
||||||
|
aux_rand: None,
|
||||||
|
message: Some(
|
||||||
|
hex::decode("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89")
|
||||||
|
.unwrap(),
|
||||||
|
),
|
||||||
|
signature: Signature {
|
||||||
|
value: hex_to_bytes(
|
||||||
|
"00000000000000000000000000000000000000000000000000000000000000017615FBAF5AE28864013C099742DEADB4DBA87F11AC6754F93780D5A1837CF197",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
verification_result: false,
|
||||||
|
},
|
||||||
|
TestVector {
|
||||||
|
seckey: None,
|
||||||
|
pubkey: PublicKey::try_new(hex_to_bytes(
|
||||||
|
"DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659",
|
||||||
|
)).unwrap(),
|
||||||
|
aux_rand: None,
|
||||||
|
message: Some(
|
||||||
|
hex::decode("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89")
|
||||||
|
.unwrap(),
|
||||||
|
),
|
||||||
|
signature: Signature {
|
||||||
|
value: hex_to_bytes(
|
||||||
|
"4A298DACAE57395A15D0795DDBFD1DCB564DA82B0F269BC70A74F8220429BA1D69E89B4C5564D00349106B8497785DD7D1D713A8AE82B32FA79D5F7FC407D39B",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
verification_result: false,
|
||||||
|
},
|
||||||
|
TestVector {
|
||||||
|
seckey: None,
|
||||||
|
pubkey: PublicKey::try_new(hex_to_bytes(
|
||||||
|
"DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659",
|
||||||
|
)).unwrap(),
|
||||||
|
aux_rand: None,
|
||||||
|
message: Some(
|
||||||
|
hex::decode("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89")
|
||||||
|
.unwrap(),
|
||||||
|
),
|
||||||
|
signature: Signature {
|
||||||
|
value: hex_to_bytes(
|
||||||
|
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F69E89B4C5564D00349106B8497785DD7D1D713A8AE82B32FA79D5F7FC407D39B",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
verification_result: false,
|
||||||
|
},
|
||||||
|
TestVector {
|
||||||
|
seckey: None,
|
||||||
|
pubkey: PublicKey::try_new(hex_to_bytes(
|
||||||
|
"DFF1D77F2A671C5F36183726DB2341BE58FEAE1DA2DECED843240F7B502BA659",
|
||||||
|
)).unwrap(),
|
||||||
|
aux_rand: None,
|
||||||
|
message: Some(
|
||||||
|
hex::decode("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89")
|
||||||
|
.unwrap(),
|
||||||
|
),
|
||||||
|
signature: Signature {
|
||||||
|
value: hex_to_bytes(
|
||||||
|
"6CFF5C3BA86C69EA4B7376F31A9BCB4F74C1976089B2D9963DA2E5543E177769FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
verification_result: false,
|
||||||
|
},
|
||||||
|
// Test with invalid public key
|
||||||
|
// TestVector {
|
||||||
|
// seckey: None,
|
||||||
|
// pubkey: PublicKey::new(hex_to_bytes(
|
||||||
|
// "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC30",
|
||||||
|
// )).unwrap(),
|
||||||
|
// aux_rand: None,
|
||||||
|
// message: Some(
|
||||||
|
// hex::decode("243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89").unwrap(),
|
||||||
|
// ),
|
||||||
|
// signature: Signature {
|
||||||
|
// value: hex_to_bytes(
|
||||||
|
// "6CFF5C3BA86C69EA4B7376F31A9BCB4F74C1976089B2D9963DA2E5543E17776969E89B4C5564D00349106B8497785DD7D1D713A8AE82B32FA79D5F7FC407D39B",
|
||||||
|
// ),
|
||||||
|
// },
|
||||||
|
// verification_result: false,
|
||||||
|
// },
|
||||||
|
TestVector {
|
||||||
|
seckey: Some(PrivateKey::try_new(hex_to_bytes(
|
||||||
|
"0340034003400340034003400340034003400340034003400340034003400340",
|
||||||
|
)).unwrap()),
|
||||||
|
pubkey: PublicKey::try_new(hex_to_bytes(
|
||||||
|
"778CAA53B4393AC467774D09497A87224BF9FAB6F6E68B23086497324D6FD117",
|
||||||
|
)).unwrap(),
|
||||||
|
aux_rand: Some(hex_to_bytes::<32>(
|
||||||
|
"0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
)),
|
||||||
|
message: None,
|
||||||
|
signature: Signature {
|
||||||
|
value: hex_to_bytes(
|
||||||
|
"71535DB165ECD9FBBC046E5FFAEA61186BB6AD436732FCCC25291A55895464CF6069CE26BF03466228F19A3A62DB8A649F2D560FAC652827D1AF0574E427AB63",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
verification_result: true,
|
||||||
|
},
|
||||||
|
TestVector {
|
||||||
|
seckey: Some(PrivateKey::try_new(hex_to_bytes(
|
||||||
|
"0340034003400340034003400340034003400340034003400340034003400340",
|
||||||
|
)).unwrap()),
|
||||||
|
pubkey: PublicKey::try_new(hex_to_bytes(
|
||||||
|
"778CAA53B4393AC467774D09497A87224BF9FAB6F6E68B23086497324D6FD117",
|
||||||
|
)).unwrap(),
|
||||||
|
aux_rand: Some(hex_to_bytes::<32>(
|
||||||
|
"0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
)),
|
||||||
|
message: Some(hex::decode("11").unwrap()),
|
||||||
|
signature: Signature {
|
||||||
|
value: hex_to_bytes(
|
||||||
|
"08A20A0AFEF64124649232E0693C583AB1B9934AE63B4C3511F3AE1134C6A303EA3173BFEA6683BD101FA5AA5DBC1996FE7CACFC5A577D33EC14564CEC2BACBF",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
verification_result: true,
|
||||||
|
},
|
||||||
|
TestVector {
|
||||||
|
seckey: Some(PrivateKey::try_new(hex_to_bytes(
|
||||||
|
"0340034003400340034003400340034003400340034003400340034003400340",
|
||||||
|
)).unwrap()),
|
||||||
|
pubkey: PublicKey::try_new(hex_to_bytes(
|
||||||
|
"778CAA53B4393AC467774D09497A87224BF9FAB6F6E68B23086497324D6FD117",
|
||||||
|
)).unwrap(),
|
||||||
|
aux_rand: Some(hex_to_bytes::<32>(
|
||||||
|
"0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
)),
|
||||||
|
message: Some(hex::decode("0102030405060708090A0B0C0D0E0F1011").unwrap()),
|
||||||
|
signature: Signature {
|
||||||
|
value: hex_to_bytes(
|
||||||
|
"5130F39A4059B43BC7CAC09A19ECE52B5D8699D1A71E3C52DA9AFDB6B50AC370C4A482B77BF960F8681540E25B6771ECE1E5A37FD80E5A51897C5566A97EA5A5",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
verification_result: true,
|
||||||
|
},
|
||||||
|
TestVector {
|
||||||
|
seckey: Some(PrivateKey::try_new(hex_to_bytes(
|
||||||
|
"0340034003400340034003400340034003400340034003400340034003400340",
|
||||||
|
)).unwrap()),
|
||||||
|
pubkey: PublicKey::try_new(hex_to_bytes(
|
||||||
|
"778CAA53B4393AC467774D09497A87224BF9FAB6F6E68B23086497324D6FD117",
|
||||||
|
)).unwrap(),
|
||||||
|
aux_rand: Some(hex_to_bytes::<32>(
|
||||||
|
"0000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
)),
|
||||||
|
message: Some(
|
||||||
|
hex::decode("99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999").unwrap(),
|
||||||
|
),
|
||||||
|
signature: Signature {
|
||||||
|
value: hex_to_bytes(
|
||||||
|
"403B12B0D8555A344175EA7EC746566303321E5DBFA8BE6F091635163ECA79A8585ED3E3170807E7C03B720FC54C7B23897FCBA0E9D0B4A06894CFD249F22367",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
verification_result: true,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
27
nssa/src/signature/encoding.rs
Normal file
27
nssa/src/signature/encoding.rs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
use std::io::{Cursor, Read};
|
||||||
|
|
||||||
|
use crate::{PublicKey, Signature, error::NssaError};
|
||||||
|
|
||||||
|
impl PublicKey {
|
||||||
|
pub(crate) fn from_cursor(cursor: &mut Cursor<&[u8]>) -> Result<Self, NssaError> {
|
||||||
|
let mut value = [0u8; 32];
|
||||||
|
cursor.read_exact(&mut value)?;
|
||||||
|
Self::try_new(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn to_bytes(&self) -> &[u8] {
|
||||||
|
self.value()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Signature {
|
||||||
|
pub(crate) fn from_cursor(cursor: &mut Cursor<&[u8]>) -> Result<Self, NssaError> {
|
||||||
|
let mut value = [0u8; 64];
|
||||||
|
cursor.read_exact(&mut value)?;
|
||||||
|
Ok(Self { value })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn to_bytes(&self) -> &[u8] {
|
||||||
|
&self.value
|
||||||
|
}
|
||||||
|
}
|
||||||
95
nssa/src/signature/mod.rs
Normal file
95
nssa/src/signature/mod.rs
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
mod encoding;
|
||||||
|
mod private_key;
|
||||||
|
mod public_key;
|
||||||
|
|
||||||
|
pub use private_key::PrivateKey;
|
||||||
|
pub use public_key::PublicKey;
|
||||||
|
|
||||||
|
use rand::{RngCore, rngs::OsRng};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct Signature {
|
||||||
|
value: [u8; 64],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Signature {
|
||||||
|
pub fn new(key: &PrivateKey, message: &[u8]) -> Self {
|
||||||
|
let mut aux_random = [0u8; 32];
|
||||||
|
OsRng.fill_bytes(&mut aux_random);
|
||||||
|
Self::new_with_aux_random(key, message, aux_random)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn new_with_aux_random(
|
||||||
|
key: &PrivateKey,
|
||||||
|
message: &[u8],
|
||||||
|
aux_random: [u8; 32],
|
||||||
|
) -> Self {
|
||||||
|
let value = {
|
||||||
|
let secp = secp256k1::Secp256k1::new();
|
||||||
|
let secret_key = secp256k1::SecretKey::from_byte_array(*key.value()).unwrap();
|
||||||
|
let keypair = secp256k1::Keypair::from_secret_key(&secp, &secret_key);
|
||||||
|
let signature = secp.sign_schnorr_with_aux_rand(message, &keypair, &aux_random);
|
||||||
|
signature.to_byte_array()
|
||||||
|
};
|
||||||
|
Self { value }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_valid_for(&self, bytes: &[u8], public_key: &PublicKey) -> bool {
|
||||||
|
let pk = secp256k1::XOnlyPublicKey::from_byte_array(*public_key.value()).unwrap();
|
||||||
|
let secp = secp256k1::Secp256k1::new();
|
||||||
|
let sig = secp256k1::schnorr::Signature::from_byte_array(self.value);
|
||||||
|
secp.verify_schnorr(&sig, bytes, &pk).is_ok()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod bip340_test_vectors;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
|
||||||
|
use crate::{Signature, signature::bip340_test_vectors};
|
||||||
|
|
||||||
|
impl Signature {
|
||||||
|
pub(crate) fn new_for_tests(value: [u8; 64]) -> Self {
|
||||||
|
Self { value }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_signature_generation_from_bip340_test_vectors() {
|
||||||
|
for (i, test_vector) in bip340_test_vectors::test_vectors().into_iter().enumerate() {
|
||||||
|
let Some(private_key) = test_vector.seckey else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
let Some(aux_random) = test_vector.aux_rand else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
let Some(message) = test_vector.message else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
if !test_vector.verification_result {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let expected_signature = &test_vector.signature;
|
||||||
|
|
||||||
|
let signature = Signature::new_with_aux_random(&private_key, &message, aux_random);
|
||||||
|
|
||||||
|
assert_eq!(&signature, expected_signature, "Failed test vector {i}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_signature_verification_from_bip340_test_vectors() {
|
||||||
|
for (i, test_vector) in bip340_test_vectors::test_vectors().into_iter().enumerate() {
|
||||||
|
let message = test_vector.message.unwrap_or(vec![]);
|
||||||
|
let expected_result = test_vector.verification_result;
|
||||||
|
|
||||||
|
let result = test_vector
|
||||||
|
.signature
|
||||||
|
.is_valid_for(&message, &test_vector.pubkey);
|
||||||
|
|
||||||
|
assert_eq!(result, expected_result, "Failed test vector {i}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
36
nssa/src/signature/private_key.rs
Normal file
36
nssa/src/signature/private_key.rs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::error::NssaError;
|
||||||
|
|
||||||
|
// TODO: Remove Debug, Clone, Serialize, Deserialize, PartialEq and Eq for security reasons
|
||||||
|
// TODO: Implement Zeroize
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||||
|
pub struct PrivateKey([u8; 32]);
|
||||||
|
|
||||||
|
impl PrivateKey {
|
||||||
|
fn is_valid_key(value: [u8; 32]) -> bool {
|
||||||
|
secp256k1::SecretKey::from_byte_array(value).is_ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn try_new(value: [u8; 32]) -> Result<Self, NssaError> {
|
||||||
|
if Self::is_valid_key(value) {
|
||||||
|
Ok(Self(value))
|
||||||
|
} else {
|
||||||
|
Err(NssaError::InvalidPrivateKey)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn value(&self) -> &[u8; 32] {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
#[test]
|
||||||
|
fn test_value_getter() {
|
||||||
|
let key = PrivateKey::try_new([1; 32]).unwrap();
|
||||||
|
assert_eq!(key.value(), &key.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
81
nssa/src/signature/public_key.rs
Normal file
81
nssa/src/signature/public_key.rs
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
use crate::{PrivateKey, error::NssaError};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct PublicKey([u8; 32]);
|
||||||
|
|
||||||
|
impl PublicKey {
|
||||||
|
pub fn new_from_private_key(key: &PrivateKey) -> Self {
|
||||||
|
let value = {
|
||||||
|
let secret_key = secp256k1::SecretKey::from_byte_array(*key.value()).unwrap();
|
||||||
|
let public_key =
|
||||||
|
secp256k1::PublicKey::from_secret_key(&secp256k1::Secp256k1::new(), &secret_key);
|
||||||
|
let (x_only, _) = public_key.x_only_public_key();
|
||||||
|
x_only.serialize()
|
||||||
|
};
|
||||||
|
Self(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn try_new(value: [u8; 32]) -> Result<Self, NssaError> {
|
||||||
|
// Check point is valid
|
||||||
|
let _ = secp256k1::XOnlyPublicKey::from_byte_array(value)
|
||||||
|
.map_err(|_| NssaError::InvalidPublicKey)?;
|
||||||
|
Ok(Self(value))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn value(&self) -> &[u8; 32] {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use crate::{PublicKey, error::NssaError, signature::bip340_test_vectors};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_try_new_invalid_public_key_from_bip340_test_vectors_5() {
|
||||||
|
let value_invalid_key = [
|
||||||
|
238, 253, 234, 76, 219, 103, 119, 80, 164, 32, 254, 232, 7, 234, 207, 33, 235, 152,
|
||||||
|
152, 174, 121, 185, 118, 135, 102, 228, 250, 160, 74, 45, 74, 52,
|
||||||
|
];
|
||||||
|
|
||||||
|
let result = PublicKey::try_new(value_invalid_key);
|
||||||
|
|
||||||
|
assert!(matches!(result, Err(NssaError::InvalidPublicKey)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_try_new_invalid_public_key_from_bip340_test_vector_14() {
|
||||||
|
let value_invalid_key = [
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
|
||||||
|
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 254, 255, 255, 252, 48,
|
||||||
|
];
|
||||||
|
|
||||||
|
let result = PublicKey::try_new(value_invalid_key);
|
||||||
|
|
||||||
|
assert!(matches!(result, Err(NssaError::InvalidPublicKey)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_try_new_valid_public_keys() {
|
||||||
|
for (i, test_vector) in bip340_test_vectors::test_vectors().into_iter().enumerate() {
|
||||||
|
let expected_public_key = test_vector.pubkey;
|
||||||
|
let public_key = PublicKey::try_new(*expected_public_key.value()).unwrap();
|
||||||
|
assert_eq!(public_key, expected_public_key, "Failed on test vector {i}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_public_key_generation_from_bip340_test_vectors() {
|
||||||
|
for (i, test_vector) in bip340_test_vectors::test_vectors().into_iter().enumerate() {
|
||||||
|
let Some(private_key) = &test_vector.seckey else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
let public_key = PublicKey::new_from_private_key(private_key);
|
||||||
|
let expected_public_key = &test_vector.pubkey;
|
||||||
|
assert_eq!(
|
||||||
|
&public_key, expected_public_key,
|
||||||
|
"Failed test vector at index {i}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
573
nssa/src/state.rs
Normal file
573
nssa/src/state.rs
Normal file
@ -0,0 +1,573 @@
|
|||||||
|
use crate::{
|
||||||
|
address::Address, error::NssaError, program::Program, public_transaction::PublicTransaction,
|
||||||
|
};
|
||||||
|
use nssa_core::{account::Account, program::ProgramId};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
pub struct V01State {
|
||||||
|
public_state: HashMap<Address, Account>,
|
||||||
|
builtin_programs: HashMap<ProgramId, Program>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl V01State {
|
||||||
|
pub fn new_with_genesis_accounts(initial_data: &[(Address, u128)]) -> Self {
|
||||||
|
let authenticated_transfer_program = Program::authenticated_transfer_program();
|
||||||
|
let public_state = initial_data
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.map(|(address, balance)| {
|
||||||
|
let account = Account {
|
||||||
|
balance,
|
||||||
|
program_owner: authenticated_transfer_program.id(),
|
||||||
|
..Account::default()
|
||||||
|
};
|
||||||
|
(address, account)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let mut this = Self {
|
||||||
|
public_state,
|
||||||
|
builtin_programs: HashMap::new(),
|
||||||
|
};
|
||||||
|
|
||||||
|
this.insert_program(Program::authenticated_transfer_program());
|
||||||
|
|
||||||
|
this
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn insert_program(&mut self, program: Program) {
|
||||||
|
self.builtin_programs.insert(program.id(), program);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn transition_from_public_transaction(
|
||||||
|
&mut self,
|
||||||
|
tx: &PublicTransaction,
|
||||||
|
) -> Result<(), NssaError> {
|
||||||
|
let state_diff = tx.validate_and_compute_post_states(self)?;
|
||||||
|
|
||||||
|
for (address, post) in state_diff.into_iter() {
|
||||||
|
let current_account = self.get_account_by_address_mut(address);
|
||||||
|
*current_account = post;
|
||||||
|
}
|
||||||
|
|
||||||
|
for address in tx.signer_addresses() {
|
||||||
|
let current_account = self.get_account_by_address_mut(address);
|
||||||
|
current_account.nonce += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_account_by_address_mut(&mut self, address: Address) -> &mut Account {
|
||||||
|
self.public_state.entry(address).or_default()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_account_by_address(&self, address: &Address) -> Account {
|
||||||
|
self.public_state
|
||||||
|
.get(address)
|
||||||
|
.cloned()
|
||||||
|
.unwrap_or(Account::default())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn builtin_programs(&self) -> &HashMap<ProgramId, Program> {
|
||||||
|
&self.builtin_programs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
Address, PublicKey, PublicTransaction, V01State, error::NssaError, program::Program,
|
||||||
|
public_transaction, signature::PrivateKey,
|
||||||
|
};
|
||||||
|
use nssa_core::account::Account;
|
||||||
|
|
||||||
|
fn transfer_transaction(
|
||||||
|
from: Address,
|
||||||
|
from_key: PrivateKey,
|
||||||
|
nonce: u128,
|
||||||
|
to: Address,
|
||||||
|
balance: u128,
|
||||||
|
) -> PublicTransaction {
|
||||||
|
let addresses = vec![from, to];
|
||||||
|
let nonces = vec![nonce];
|
||||||
|
let program_id = Program::authenticated_transfer_program().id();
|
||||||
|
let message =
|
||||||
|
public_transaction::Message::try_new(program_id, addresses, nonces, balance).unwrap();
|
||||||
|
let witness_set = public_transaction::WitnessSet::for_message(&message, &[&from_key]);
|
||||||
|
PublicTransaction::new(message, witness_set)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_new_with_genesis() {
|
||||||
|
let key1 = PrivateKey::try_new([1; 32]).unwrap();
|
||||||
|
let key2 = PrivateKey::try_new([2; 32]).unwrap();
|
||||||
|
let addr1 = Address::from(&PublicKey::new_from_private_key(&key1));
|
||||||
|
let addr2 = Address::from(&PublicKey::new_from_private_key(&key2));
|
||||||
|
let initial_data = [(addr1, 100u128), (addr2, 151u128)];
|
||||||
|
let program = Program::authenticated_transfer_program();
|
||||||
|
let expected_public_state = {
|
||||||
|
let mut this = HashMap::new();
|
||||||
|
this.insert(
|
||||||
|
addr1,
|
||||||
|
Account {
|
||||||
|
balance: 100,
|
||||||
|
program_owner: program.id(),
|
||||||
|
..Account::default()
|
||||||
|
},
|
||||||
|
);
|
||||||
|
this.insert(
|
||||||
|
addr2,
|
||||||
|
Account {
|
||||||
|
balance: 151,
|
||||||
|
program_owner: program.id(),
|
||||||
|
..Account::default()
|
||||||
|
},
|
||||||
|
);
|
||||||
|
this
|
||||||
|
};
|
||||||
|
let expected_builtin_programs = {
|
||||||
|
let mut this = HashMap::new();
|
||||||
|
this.insert(program.id(), program);
|
||||||
|
this
|
||||||
|
};
|
||||||
|
|
||||||
|
let state = V01State::new_with_genesis_accounts(&initial_data);
|
||||||
|
|
||||||
|
assert_eq!(state.public_state, expected_public_state);
|
||||||
|
assert_eq!(state.builtin_programs, expected_builtin_programs);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_insert_program() {
|
||||||
|
let mut state = V01State::new_with_genesis_accounts(&[]);
|
||||||
|
let program_to_insert = Program::simple_balance_transfer();
|
||||||
|
let program_id = program_to_insert.id();
|
||||||
|
assert!(!state.builtin_programs.contains_key(&program_id));
|
||||||
|
|
||||||
|
state.insert_program(program_to_insert);
|
||||||
|
|
||||||
|
assert!(state.builtin_programs.contains_key(&program_id));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_get_account_by_address_non_default_account() {
|
||||||
|
let key = PrivateKey::try_new([1; 32]).unwrap();
|
||||||
|
let addr = Address::from(&PublicKey::new_from_private_key(&key));
|
||||||
|
let initial_data = [(addr, 100u128)];
|
||||||
|
let state = V01State::new_with_genesis_accounts(&initial_data);
|
||||||
|
let expected_account = state.public_state.get(&addr).unwrap();
|
||||||
|
|
||||||
|
let account = state.get_account_by_address(&addr);
|
||||||
|
|
||||||
|
assert_eq!(&account, expected_account);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_get_account_by_address_default_account() {
|
||||||
|
let addr2 = Address::new([0; 32]);
|
||||||
|
let state = V01State::new_with_genesis_accounts(&[]);
|
||||||
|
let expected_account = Account::default();
|
||||||
|
|
||||||
|
let account = state.get_account_by_address(&addr2);
|
||||||
|
|
||||||
|
assert_eq!(account, expected_account);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_builtin_programs_getter() {
|
||||||
|
let state = V01State::new_with_genesis_accounts(&[]);
|
||||||
|
|
||||||
|
let builtin_programs = state.builtin_programs();
|
||||||
|
|
||||||
|
assert_eq!(builtin_programs, &state.builtin_programs);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn transition_from_authenticated_transfer_program_invocation_default_account_destination() {
|
||||||
|
let key = PrivateKey::try_new([1; 32]).unwrap();
|
||||||
|
let address = Address::from(&PublicKey::new_from_private_key(&key));
|
||||||
|
let initial_data = [(address, 100)];
|
||||||
|
let mut state = V01State::new_with_genesis_accounts(&initial_data);
|
||||||
|
let from = address;
|
||||||
|
let to = Address::new([2; 32]);
|
||||||
|
assert_eq!(state.get_account_by_address(&to), Account::default());
|
||||||
|
let balance_to_move = 5;
|
||||||
|
|
||||||
|
let tx = transfer_transaction(from.clone(), key, 0, to.clone(), balance_to_move);
|
||||||
|
state.transition_from_public_transaction(&tx).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(state.get_account_by_address(&from).balance, 95);
|
||||||
|
assert_eq!(state.get_account_by_address(&to).balance, 5);
|
||||||
|
assert_eq!(state.get_account_by_address(&from).nonce, 1);
|
||||||
|
assert_eq!(state.get_account_by_address(&to).nonce, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn transition_from_authenticated_transfer_program_invocation_insuficient_balance() {
|
||||||
|
let key = PrivateKey::try_new([1; 32]).unwrap();
|
||||||
|
let address = Address::from(&PublicKey::new_from_private_key(&key));
|
||||||
|
let initial_data = [(address, 100)];
|
||||||
|
let mut state = V01State::new_with_genesis_accounts(&initial_data);
|
||||||
|
let from = address;
|
||||||
|
let from_key = key;
|
||||||
|
let to = Address::new([2; 32]);
|
||||||
|
let balance_to_move = 101;
|
||||||
|
assert!(state.get_account_by_address(&from).balance < balance_to_move);
|
||||||
|
|
||||||
|
let tx = transfer_transaction(from.clone(), from_key, 0, to.clone(), balance_to_move);
|
||||||
|
let result = state.transition_from_public_transaction(&tx);
|
||||||
|
|
||||||
|
assert!(matches!(result, Err(NssaError::ProgramExecutionFailed(_))));
|
||||||
|
assert_eq!(state.get_account_by_address(&from).balance, 100);
|
||||||
|
assert_eq!(state.get_account_by_address(&to).balance, 0);
|
||||||
|
assert_eq!(state.get_account_by_address(&from).nonce, 0);
|
||||||
|
assert_eq!(state.get_account_by_address(&to).nonce, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn transition_from_authenticated_transfer_program_invocation_non_default_account_destination() {
|
||||||
|
let key1 = PrivateKey::try_new([1; 32]).unwrap();
|
||||||
|
let key2 = PrivateKey::try_new([2; 32]).unwrap();
|
||||||
|
let address1 = Address::from(&PublicKey::new_from_private_key(&key1));
|
||||||
|
let address2 = Address::from(&PublicKey::new_from_private_key(&key2));
|
||||||
|
let initial_data = [(address1, 100), (address2, 200)];
|
||||||
|
let mut state = V01State::new_with_genesis_accounts(&initial_data);
|
||||||
|
let from = address2;
|
||||||
|
let from_key = key2;
|
||||||
|
let to = address1;
|
||||||
|
assert_ne!(state.get_account_by_address(&to), Account::default());
|
||||||
|
let balance_to_move = 8;
|
||||||
|
|
||||||
|
let tx = transfer_transaction(from.clone(), from_key, 0, to.clone(), balance_to_move);
|
||||||
|
state.transition_from_public_transaction(&tx).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(state.get_account_by_address(&from).balance, 192);
|
||||||
|
assert_eq!(state.get_account_by_address(&to).balance, 108);
|
||||||
|
assert_eq!(state.get_account_by_address(&from).nonce, 1);
|
||||||
|
assert_eq!(state.get_account_by_address(&to).nonce, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn transition_from_chained_authenticated_transfer_program_invocations() {
|
||||||
|
let key1 = PrivateKey::try_new([8; 32]).unwrap();
|
||||||
|
let address1 = Address::from(&PublicKey::new_from_private_key(&key1));
|
||||||
|
let key2 = PrivateKey::try_new([2; 32]).unwrap();
|
||||||
|
let address2 = Address::from(&PublicKey::new_from_private_key(&key2));
|
||||||
|
let initial_data = [(address1, 100)];
|
||||||
|
let mut state = V01State::new_with_genesis_accounts(&initial_data);
|
||||||
|
let address3 = Address::new([3; 32]);
|
||||||
|
let balance_to_move = 5;
|
||||||
|
|
||||||
|
let tx = transfer_transaction(address1.clone(), key1, 0, address2.clone(), balance_to_move);
|
||||||
|
state.transition_from_public_transaction(&tx).unwrap();
|
||||||
|
let balance_to_move = 3;
|
||||||
|
let tx = transfer_transaction(address2.clone(), key2, 0, address3.clone(), balance_to_move);
|
||||||
|
state.transition_from_public_transaction(&tx).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(state.get_account_by_address(&address1).balance, 95);
|
||||||
|
assert_eq!(state.get_account_by_address(&address2).balance, 2);
|
||||||
|
assert_eq!(state.get_account_by_address(&address3).balance, 3);
|
||||||
|
assert_eq!(state.get_account_by_address(&address1).nonce, 1);
|
||||||
|
assert_eq!(state.get_account_by_address(&address2).nonce, 1);
|
||||||
|
assert_eq!(state.get_account_by_address(&address3).nonce, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl V01State {
|
||||||
|
pub fn force_insert_account(&mut self, address: Address, account: Account) {
|
||||||
|
self.public_state.insert(address, account);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Include test programs in the builtin programs map
|
||||||
|
pub fn with_test_programs(mut self) -> Self {
|
||||||
|
self.insert_program(Program::nonce_changer_program());
|
||||||
|
self.insert_program(Program::extra_output_program());
|
||||||
|
self.insert_program(Program::missing_output_program());
|
||||||
|
self.insert_program(Program::program_owner_changer());
|
||||||
|
self.insert_program(Program::simple_balance_transfer());
|
||||||
|
self.insert_program(Program::data_changer());
|
||||||
|
self.insert_program(Program::minter());
|
||||||
|
self.insert_program(Program::burner());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_non_default_accounts_but_default_program_owners(mut self) -> Self {
|
||||||
|
let account_with_default_values_except_balance = Account {
|
||||||
|
balance: 100,
|
||||||
|
..Account::default()
|
||||||
|
};
|
||||||
|
let account_with_default_values_except_nonce = Account {
|
||||||
|
nonce: 37,
|
||||||
|
..Account::default()
|
||||||
|
};
|
||||||
|
let account_with_default_values_except_data = Account {
|
||||||
|
data: vec![0xca, 0xfe],
|
||||||
|
..Account::default()
|
||||||
|
};
|
||||||
|
self.force_insert_account(
|
||||||
|
Address::new([255; 32]),
|
||||||
|
account_with_default_values_except_balance,
|
||||||
|
);
|
||||||
|
self.force_insert_account(
|
||||||
|
Address::new([254; 32]),
|
||||||
|
account_with_default_values_except_nonce,
|
||||||
|
);
|
||||||
|
self.force_insert_account(
|
||||||
|
Address::new([253; 32]),
|
||||||
|
account_with_default_values_except_data,
|
||||||
|
);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_account_owned_by_burner_program(mut self) -> Self {
|
||||||
|
let account = Account {
|
||||||
|
program_owner: Program::burner().id(),
|
||||||
|
balance: 100,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
self.force_insert_account(Address::new([252; 32]), account);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_program_should_fail_if_modifies_nonces() {
|
||||||
|
let initial_data = [(Address::new([1; 32]), 100)];
|
||||||
|
let mut state = V01State::new_with_genesis_accounts(&initial_data).with_test_programs();
|
||||||
|
let addresses = vec![Address::new([1; 32])];
|
||||||
|
let program_id = Program::nonce_changer_program().id();
|
||||||
|
let message =
|
||||||
|
public_transaction::Message::try_new(program_id, addresses, vec![], ()).unwrap();
|
||||||
|
let witness_set = public_transaction::WitnessSet::for_message(&message, &[]);
|
||||||
|
let tx = PublicTransaction::new(message, witness_set);
|
||||||
|
|
||||||
|
let result = state.transition_from_public_transaction(&tx);
|
||||||
|
|
||||||
|
assert!(matches!(result, Err(NssaError::InvalidProgramBehavior)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_program_should_fail_if_output_accounts_exceed_inputs() {
|
||||||
|
let initial_data = [(Address::new([1; 32]), 100)];
|
||||||
|
let mut state = V01State::new_with_genesis_accounts(&initial_data).with_test_programs();
|
||||||
|
let addresses = vec![Address::new([1; 32])];
|
||||||
|
let program_id = Program::extra_output_program().id();
|
||||||
|
let message =
|
||||||
|
public_transaction::Message::try_new(program_id, addresses, vec![], ()).unwrap();
|
||||||
|
let witness_set = public_transaction::WitnessSet::for_message(&message, &[]);
|
||||||
|
let tx = PublicTransaction::new(message, witness_set);
|
||||||
|
|
||||||
|
let result = state.transition_from_public_transaction(&tx);
|
||||||
|
|
||||||
|
assert!(matches!(result, Err(NssaError::InvalidProgramBehavior)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_program_should_fail_with_missing_output_accounts() {
|
||||||
|
let initial_data = [(Address::new([1; 32]), 100)];
|
||||||
|
let mut state = V01State::new_with_genesis_accounts(&initial_data).with_test_programs();
|
||||||
|
let addresses = vec![Address::new([1; 32]), Address::new([2; 32])];
|
||||||
|
let program_id = Program::missing_output_program().id();
|
||||||
|
let message =
|
||||||
|
public_transaction::Message::try_new(program_id, addresses, vec![], ()).unwrap();
|
||||||
|
let witness_set = public_transaction::WitnessSet::for_message(&message, &[]);
|
||||||
|
let tx = PublicTransaction::new(message, witness_set);
|
||||||
|
|
||||||
|
let result = state.transition_from_public_transaction(&tx);
|
||||||
|
|
||||||
|
assert!(matches!(result, Err(NssaError::InvalidProgramBehavior)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_program_should_fail_if_modifies_program_owner_with_only_non_default_program_owner() {
|
||||||
|
let initial_data = [(Address::new([1; 32]), 0)];
|
||||||
|
let mut state = V01State::new_with_genesis_accounts(&initial_data).with_test_programs();
|
||||||
|
let address = Address::new([1; 32]);
|
||||||
|
let account = state.get_account_by_address(&address);
|
||||||
|
// Assert the target account only differs from the default account in the program owner field
|
||||||
|
assert_ne!(account.program_owner, Account::default().program_owner);
|
||||||
|
assert_eq!(account.balance, Account::default().balance);
|
||||||
|
assert_eq!(account.nonce, Account::default().nonce);
|
||||||
|
assert_eq!(account.data, Account::default().data);
|
||||||
|
let program_id = Program::program_owner_changer().id();
|
||||||
|
let message =
|
||||||
|
public_transaction::Message::try_new(program_id, vec![address], vec![], ()).unwrap();
|
||||||
|
let witness_set = public_transaction::WitnessSet::for_message(&message, &[]);
|
||||||
|
let tx = PublicTransaction::new(message, witness_set);
|
||||||
|
|
||||||
|
let result = state.transition_from_public_transaction(&tx);
|
||||||
|
|
||||||
|
assert!(matches!(result, Err(NssaError::InvalidProgramBehavior)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_program_should_fail_if_modifies_program_owner_with_only_non_default_balance() {
|
||||||
|
let initial_data = [];
|
||||||
|
let mut state = V01State::new_with_genesis_accounts(&initial_data)
|
||||||
|
.with_test_programs()
|
||||||
|
.with_non_default_accounts_but_default_program_owners();
|
||||||
|
let address = Address::new([255; 32]);
|
||||||
|
let account = state.get_account_by_address(&address);
|
||||||
|
// Assert the target account only differs from the default account in balance field
|
||||||
|
assert_eq!(account.program_owner, Account::default().program_owner);
|
||||||
|
assert_ne!(account.balance, Account::default().balance);
|
||||||
|
assert_eq!(account.nonce, Account::default().nonce);
|
||||||
|
assert_eq!(account.data, Account::default().data);
|
||||||
|
let program_id = Program::program_owner_changer().id();
|
||||||
|
let message =
|
||||||
|
public_transaction::Message::try_new(program_id, vec![address], vec![], ()).unwrap();
|
||||||
|
let witness_set = public_transaction::WitnessSet::for_message(&message, &[]);
|
||||||
|
let tx = PublicTransaction::new(message, witness_set);
|
||||||
|
|
||||||
|
let result = state.transition_from_public_transaction(&tx);
|
||||||
|
|
||||||
|
assert!(matches!(result, Err(NssaError::InvalidProgramBehavior)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_program_should_fail_if_modifies_program_owner_with_only_non_default_nonce() {
|
||||||
|
let initial_data = [];
|
||||||
|
let mut state = V01State::new_with_genesis_accounts(&initial_data)
|
||||||
|
.with_test_programs()
|
||||||
|
.with_non_default_accounts_but_default_program_owners();
|
||||||
|
let address = Address::new([254; 32]);
|
||||||
|
let account = state.get_account_by_address(&address);
|
||||||
|
// Assert the target account only differs from the default account in nonce field
|
||||||
|
assert_eq!(account.program_owner, Account::default().program_owner);
|
||||||
|
assert_eq!(account.balance, Account::default().balance);
|
||||||
|
assert_ne!(account.nonce, Account::default().nonce);
|
||||||
|
assert_eq!(account.data, Account::default().data);
|
||||||
|
let program_id = Program::program_owner_changer().id();
|
||||||
|
let message =
|
||||||
|
public_transaction::Message::try_new(program_id, vec![address], vec![], ()).unwrap();
|
||||||
|
let witness_set = public_transaction::WitnessSet::for_message(&message, &[]);
|
||||||
|
let tx = PublicTransaction::new(message, witness_set);
|
||||||
|
|
||||||
|
let result = state.transition_from_public_transaction(&tx);
|
||||||
|
|
||||||
|
assert!(matches!(result, Err(NssaError::InvalidProgramBehavior)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_program_should_fail_if_modifies_program_owner_with_only_non_default_data() {
|
||||||
|
let initial_data = [];
|
||||||
|
let mut state = V01State::new_with_genesis_accounts(&initial_data)
|
||||||
|
.with_test_programs()
|
||||||
|
.with_non_default_accounts_but_default_program_owners();
|
||||||
|
let address = Address::new([253; 32]);
|
||||||
|
let account = state.get_account_by_address(&address);
|
||||||
|
// Assert the target account only differs from the default account in data field
|
||||||
|
assert_eq!(account.program_owner, Account::default().program_owner);
|
||||||
|
assert_eq!(account.balance, Account::default().balance);
|
||||||
|
assert_eq!(account.nonce, Account::default().nonce);
|
||||||
|
assert_ne!(account.data, Account::default().data);
|
||||||
|
let program_id = Program::program_owner_changer().id();
|
||||||
|
let message =
|
||||||
|
public_transaction::Message::try_new(program_id, vec![address], vec![], ()).unwrap();
|
||||||
|
let witness_set = public_transaction::WitnessSet::for_message(&message, &[]);
|
||||||
|
let tx = PublicTransaction::new(message, witness_set);
|
||||||
|
|
||||||
|
let result = state.transition_from_public_transaction(&tx);
|
||||||
|
|
||||||
|
assert!(matches!(result, Err(NssaError::InvalidProgramBehavior)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_program_should_fail_if_transfers_balance_from_non_owned_account() {
|
||||||
|
let initial_data = [(Address::new([1; 32]), 100)];
|
||||||
|
let mut state = V01State::new_with_genesis_accounts(&initial_data).with_test_programs();
|
||||||
|
let sender_address = Address::new([1; 32]);
|
||||||
|
let receiver_address = Address::new([2; 32]);
|
||||||
|
let balance_to_move: u128 = 1;
|
||||||
|
let program_id = Program::simple_balance_transfer().id();
|
||||||
|
assert_ne!(
|
||||||
|
state.get_account_by_address(&sender_address).program_owner,
|
||||||
|
program_id
|
||||||
|
);
|
||||||
|
let message = public_transaction::Message::try_new(
|
||||||
|
program_id,
|
||||||
|
vec![sender_address, receiver_address],
|
||||||
|
vec![],
|
||||||
|
balance_to_move,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let witness_set = public_transaction::WitnessSet::for_message(&message, &[]);
|
||||||
|
let tx = PublicTransaction::new(message, witness_set);
|
||||||
|
|
||||||
|
let result = state.transition_from_public_transaction(&tx);
|
||||||
|
|
||||||
|
assert!(matches!(result, Err(NssaError::InvalidProgramBehavior)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_program_should_fail_if_modifies_data_of_non_owned_account() {
|
||||||
|
let initial_data = [];
|
||||||
|
let mut state = V01State::new_with_genesis_accounts(&initial_data).with_test_programs();
|
||||||
|
let address = Address::new([1; 32]);
|
||||||
|
let program_id = Program::data_changer().id();
|
||||||
|
|
||||||
|
// Consider the extreme case where the target account is the default account
|
||||||
|
assert_eq!(state.get_account_by_address(&address), Account::default());
|
||||||
|
assert_ne!(
|
||||||
|
state.get_account_by_address(&address).program_owner,
|
||||||
|
program_id
|
||||||
|
);
|
||||||
|
let message =
|
||||||
|
public_transaction::Message::try_new(program_id, vec![address], vec![], ()).unwrap();
|
||||||
|
let witness_set = public_transaction::WitnessSet::for_message(&message, &[]);
|
||||||
|
let tx = PublicTransaction::new(message, witness_set);
|
||||||
|
|
||||||
|
let result = state.transition_from_public_transaction(&tx);
|
||||||
|
|
||||||
|
assert!(matches!(result, Err(NssaError::InvalidProgramBehavior)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_program_should_fail_if_does_not_preserve_total_balance_by_minting() {
|
||||||
|
let initial_data = [];
|
||||||
|
let mut state = V01State::new_with_genesis_accounts(&initial_data).with_test_programs();
|
||||||
|
let address = Address::new([1; 32]);
|
||||||
|
let program_id = Program::minter().id();
|
||||||
|
|
||||||
|
let message =
|
||||||
|
public_transaction::Message::try_new(program_id, vec![address], vec![], ()).unwrap();
|
||||||
|
let witness_set = public_transaction::WitnessSet::for_message(&message, &[]);
|
||||||
|
let tx = PublicTransaction::new(message, witness_set);
|
||||||
|
|
||||||
|
let result = state.transition_from_public_transaction(&tx);
|
||||||
|
|
||||||
|
assert!(matches!(result, Err(NssaError::InvalidProgramBehavior)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_program_should_fail_if_does_not_preserve_total_balance_by_burning() {
|
||||||
|
let initial_data = [];
|
||||||
|
let mut state = V01State::new_with_genesis_accounts(&initial_data)
|
||||||
|
.with_test_programs()
|
||||||
|
.with_account_owned_by_burner_program();
|
||||||
|
let program_id = Program::burner().id();
|
||||||
|
let address = Address::new([252; 32]);
|
||||||
|
assert_eq!(
|
||||||
|
state.get_account_by_address(&address).program_owner,
|
||||||
|
program_id
|
||||||
|
);
|
||||||
|
let balance_to_burn: u128 = 1;
|
||||||
|
assert!(state.get_account_by_address(&address).balance > balance_to_burn);
|
||||||
|
|
||||||
|
let message = public_transaction::Message::try_new(
|
||||||
|
program_id,
|
||||||
|
vec![address],
|
||||||
|
vec![],
|
||||||
|
balance_to_burn,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let witness_set = public_transaction::WitnessSet::for_message(&message, &[]);
|
||||||
|
let tx = PublicTransaction::new(message, witness_set);
|
||||||
|
let result = state.transition_from_public_transaction(&tx);
|
||||||
|
|
||||||
|
assert!(matches!(result, Err(NssaError::InvalidProgramBehavior)));
|
||||||
|
}
|
||||||
|
}
|
||||||
10
nssa/test_program_methods/Cargo.toml
Normal file
10
nssa/test_program_methods/Cargo.toml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
[package]
|
||||||
|
name = "test-program-methods"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
risc0-build = { version = "2.3.1" }
|
||||||
|
|
||||||
|
[package.metadata.risc0]
|
||||||
|
methods = ["guest"]
|
||||||
3
nssa/test_program_methods/build.rs
Normal file
3
nssa/test_program_methods/build.rs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
fn main() {
|
||||||
|
risc0_build::embed_methods();
|
||||||
|
}
|
||||||
10
nssa/test_program_methods/guest/Cargo.toml
Normal file
10
nssa/test_program_methods/guest/Cargo.toml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
[package]
|
||||||
|
name = "programs"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[workspace]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
risc0-zkvm = { version = "2.3.1", default-features = false, features = ['std'] }
|
||||||
|
nssa-core = { path = "../../core" }
|
||||||
19
nssa/test_program_methods/guest/src/bin/burner.rs
Normal file
19
nssa/test_program_methods/guest/src/bin/burner.rs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
use nssa_core::program::read_nssa_inputs;
|
||||||
|
use risc0_zkvm::guest::env;
|
||||||
|
|
||||||
|
type Instruction = u128;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let (input_accounts, balance_to_burn) = read_nssa_inputs::<Instruction>();
|
||||||
|
|
||||||
|
let [pre] = match input_accounts.try_into() {
|
||||||
|
Ok(array) => array,
|
||||||
|
Err(_) => return,
|
||||||
|
};
|
||||||
|
|
||||||
|
let account_pre = pre.account;
|
||||||
|
let mut account_post = account_pre.clone();
|
||||||
|
account_post.balance -= balance_to_burn;
|
||||||
|
|
||||||
|
env::commit(&vec![account_post]);
|
||||||
|
}
|
||||||
20
nssa/test_program_methods/guest/src/bin/data_changer.rs
Normal file
20
nssa/test_program_methods/guest/src/bin/data_changer.rs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
use nssa_core::program::read_nssa_inputs;
|
||||||
|
use risc0_zkvm::guest::env;
|
||||||
|
|
||||||
|
type Instruction = ();
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let (input_accounts, _) = read_nssa_inputs::<Instruction>();
|
||||||
|
|
||||||
|
let [pre] = match input_accounts.try_into() {
|
||||||
|
Ok(array) => array,
|
||||||
|
Err(_) => return,
|
||||||
|
};
|
||||||
|
|
||||||
|
let account_pre = pre.account;
|
||||||
|
let mut account_post = account_pre.clone();
|
||||||
|
account_post.data.push(0);
|
||||||
|
|
||||||
|
env::commit(&vec![account_post]);
|
||||||
|
}
|
||||||
|
|
||||||
17
nssa/test_program_methods/guest/src/bin/extra_output.rs
Normal file
17
nssa/test_program_methods/guest/src/bin/extra_output.rs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
use nssa_core::{account::Account, program::read_nssa_inputs};
|
||||||
|
use risc0_zkvm::guest::env;
|
||||||
|
|
||||||
|
type Instruction = ();
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let (input_accounts, _) = read_nssa_inputs::<Instruction>();
|
||||||
|
|
||||||
|
let [pre] = match input_accounts.try_into() {
|
||||||
|
Ok(array) => array,
|
||||||
|
Err(_) => return,
|
||||||
|
};
|
||||||
|
|
||||||
|
let account_pre = pre.account;
|
||||||
|
|
||||||
|
env::commit(&vec![account_pre, Account::default()]);
|
||||||
|
}
|
||||||
19
nssa/test_program_methods/guest/src/bin/minter.rs
Normal file
19
nssa/test_program_methods/guest/src/bin/minter.rs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
use nssa_core::program::read_nssa_inputs;
|
||||||
|
use risc0_zkvm::guest::env;
|
||||||
|
|
||||||
|
type Instruction = ();
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let (input_accounts, _) = read_nssa_inputs::<Instruction>();
|
||||||
|
|
||||||
|
let [pre] = match input_accounts.try_into() {
|
||||||
|
Ok(array) => array,
|
||||||
|
Err(_) => return,
|
||||||
|
};
|
||||||
|
|
||||||
|
let account_pre = pre.account;
|
||||||
|
let mut account_post = account_pre.clone();
|
||||||
|
account_post.balance += 1;
|
||||||
|
|
||||||
|
env::commit(&vec![account_post]);
|
||||||
|
}
|
||||||
17
nssa/test_program_methods/guest/src/bin/missing_output.rs
Normal file
17
nssa/test_program_methods/guest/src/bin/missing_output.rs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
use nssa_core::program::read_nssa_inputs;
|
||||||
|
use risc0_zkvm::guest::env;
|
||||||
|
|
||||||
|
type Instruction = ();
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let (input_accounts, _) = read_nssa_inputs::<Instruction>();
|
||||||
|
|
||||||
|
let [pre1, _] = match input_accounts.try_into() {
|
||||||
|
Ok(array) => array,
|
||||||
|
Err(_) => return,
|
||||||
|
};
|
||||||
|
|
||||||
|
let account_pre1 = pre1.account;
|
||||||
|
|
||||||
|
env::commit(&vec![account_pre1]);
|
||||||
|
}
|
||||||
19
nssa/test_program_methods/guest/src/bin/nonce_changer.rs
Normal file
19
nssa/test_program_methods/guest/src/bin/nonce_changer.rs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
use nssa_core::program::read_nssa_inputs;
|
||||||
|
use risc0_zkvm::guest::env;
|
||||||
|
|
||||||
|
type Instruction = ();
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let (input_accounts, _) = read_nssa_inputs::<Instruction>();
|
||||||
|
|
||||||
|
let [pre] = match input_accounts.try_into() {
|
||||||
|
Ok(array) => array,
|
||||||
|
Err(_) => return,
|
||||||
|
};
|
||||||
|
|
||||||
|
let account_pre = pre.account;
|
||||||
|
let mut account_post = account_pre.clone();
|
||||||
|
account_post.nonce += 1;
|
||||||
|
|
||||||
|
env::commit(&vec![account_post]);
|
||||||
|
}
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
use nssa_core::program::read_nssa_inputs;
|
||||||
|
use risc0_zkvm::guest::env;
|
||||||
|
|
||||||
|
type Instruction = ();
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let (input_accounts, _) = read_nssa_inputs::<Instruction>();
|
||||||
|
|
||||||
|
let [pre] = match input_accounts.try_into() {
|
||||||
|
Ok(array) => array,
|
||||||
|
Err(_) => return,
|
||||||
|
};
|
||||||
|
|
||||||
|
let account_pre = pre.account;
|
||||||
|
let mut account_post = account_pre.clone();
|
||||||
|
account_post.program_owner = [0, 1, 2, 3, 4, 5, 6, 7];
|
||||||
|
|
||||||
|
env::commit(&vec![account_post]);
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
use nssa_core::program::read_nssa_inputs;
|
||||||
|
use risc0_zkvm::guest::env;
|
||||||
|
|
||||||
|
type Instruction = u128;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let (input_accounts, balance) = read_nssa_inputs::<Instruction>();
|
||||||
|
|
||||||
|
let [sender_pre, receiver_pre] = match input_accounts.try_into() {
|
||||||
|
Ok(array) => array,
|
||||||
|
Err(_) => return,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut sender_post = sender_pre.account.clone();
|
||||||
|
let mut receiver_post = receiver_pre.account.clone();
|
||||||
|
sender_post.balance -= balance;
|
||||||
|
receiver_post.balance += balance;
|
||||||
|
|
||||||
|
env::commit(&vec![sender_post, receiver_post]);
|
||||||
|
}
|
||||||
1
nssa/test_program_methods/src/lib.rs
Normal file
1
nssa/test_program_methods/src/lib.rs
Normal file
@ -0,0 +1 @@
|
|||||||
|
include!(concat!(env!("OUT_DIR"), "/methods.rs"));
|
||||||
@ -19,7 +19,7 @@ light-poseidon.workspace = true
|
|||||||
ark-bn254.workspace = true
|
ark-bn254.workspace = true
|
||||||
ark-ff.workspace = true
|
ark-ff.workspace = true
|
||||||
|
|
||||||
risc0-zkvm = { git = "https://github.com/risc0/risc0.git", branch = "release-2.3" }
|
risc0-zkvm = "2.3.1"
|
||||||
|
|
||||||
[dependencies.accounts]
|
[dependencies.accounts]
|
||||||
path = "../accounts"
|
path = "../accounts"
|
||||||
@ -33,6 +33,9 @@ path = "../utxo"
|
|||||||
[dependencies.common]
|
[dependencies.common]
|
||||||
path = "../common"
|
path = "../common"
|
||||||
|
|
||||||
|
[dependencies.nssa]
|
||||||
|
path = "../nssa"
|
||||||
|
|
||||||
[dependencies.secp256k1-zkp]
|
[dependencies.secp256k1-zkp]
|
||||||
workspace = true
|
workspace = true
|
||||||
features = ["std", "rand-std", "rand", "serde", "global-context"]
|
features = ["std", "rand-std", "rand", "serde", "global-context"]
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
use bincode;
|
use bincode;
|
||||||
use common::merkle_tree_public::merkle_tree::UTXOCommitmentsMerkleTree;
|
use common::merkle_tree_public::merkle_tree::UTXOCommitmentsMerkleTree;
|
||||||
|
use nssa::Address;
|
||||||
use rand::{thread_rng, RngCore};
|
use rand::{thread_rng, RngCore};
|
||||||
use secp256k1_zkp::{CommitmentSecrets, Generator, PedersenCommitment, Tag, Tweak, SECP256K1};
|
use secp256k1_zkp::{CommitmentSecrets, Generator, PedersenCommitment, Tag, Tweak, SECP256K1};
|
||||||
use sha2::{Digest, Sha256};
|
use sha2::{Digest, Sha256};
|
||||||
@ -82,7 +83,7 @@ pub fn private_circuit(
|
|||||||
for in_utxo in input_utxos {
|
for in_utxo in input_utxos {
|
||||||
let nullifier_public_key = public_context
|
let nullifier_public_key = public_context
|
||||||
.account_masks
|
.account_masks
|
||||||
.get(&in_utxo.owner)
|
.get(&Address::new(in_utxo.owner))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.nullifier_public_key;
|
.nullifier_public_key;
|
||||||
|
|
||||||
@ -125,7 +126,7 @@ pub fn deshielded_circuit(
|
|||||||
for in_utxo in input_utxos {
|
for in_utxo in input_utxos {
|
||||||
let nullifier_public_key = public_context
|
let nullifier_public_key = public_context
|
||||||
.account_masks
|
.account_masks
|
||||||
.get(&in_utxo.owner)
|
.get(&Address::new(in_utxo.owner))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.nullifier_public_key;
|
.nullifier_public_key;
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
use accounts::account_core::{address::AccountAddress, AccountPublicMask};
|
use accounts::account_core::AccountPublicMask;
|
||||||
use common::merkle_tree_public::{merkle_tree::UTXOCommitmentsMerkleTree, TreeHashType};
|
use common::merkle_tree_public::{merkle_tree::UTXOCommitmentsMerkleTree, TreeHashType};
|
||||||
|
use nssa::Address;
|
||||||
use serde::{ser::SerializeStruct, Serialize};
|
use serde::{ser::SerializeStruct, Serialize};
|
||||||
|
|
||||||
pub const PUBLIC_SC_CONTEXT: &str = "PublicSCContext";
|
pub const PUBLIC_SC_CONTEXT: &str = "PublicSCContext";
|
||||||
@ -16,9 +17,9 @@ pub const NULLIFIERS_SET: &str = "nullifiers_set";
|
|||||||
|
|
||||||
///Strucutre, representing context, given to a smart contract on a call
|
///Strucutre, representing context, given to a smart contract on a call
|
||||||
pub struct PublicSCContext {
|
pub struct PublicSCContext {
|
||||||
pub caller_address: AccountAddress,
|
pub caller_address: Address,
|
||||||
pub caller_balance: u64,
|
pub caller_balance: u64,
|
||||||
pub account_masks: BTreeMap<AccountAddress, AccountPublicMask>,
|
pub account_masks: BTreeMap<Address, AccountPublicMask>,
|
||||||
pub comitment_store_root: TreeHashType,
|
pub comitment_store_root: TreeHashType,
|
||||||
pub commitments_tree: UTXOCommitmentsMerkleTree,
|
pub commitments_tree: UTXOCommitmentsMerkleTree,
|
||||||
}
|
}
|
||||||
@ -28,7 +29,12 @@ impl Serialize for PublicSCContext {
|
|||||||
where
|
where
|
||||||
S: serde::Serializer,
|
S: serde::Serializer,
|
||||||
{
|
{
|
||||||
let mut account_masks_keys: Vec<[u8; 32]> = self.account_masks.keys().cloned().collect();
|
let mut account_masks_keys: Vec<[u8; 32]> = self
|
||||||
|
.account_masks
|
||||||
|
.keys()
|
||||||
|
.cloned()
|
||||||
|
.map(|addr| *addr.value())
|
||||||
|
.collect();
|
||||||
account_masks_keys.sort();
|
account_masks_keys.sort();
|
||||||
|
|
||||||
let mut account_mask_values: Vec<AccountPublicMask> =
|
let mut account_mask_values: Vec<AccountPublicMask> =
|
||||||
@ -94,7 +100,7 @@ mod tests {
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
fn create_test_context() -> PublicSCContext {
|
fn create_test_context() -> PublicSCContext {
|
||||||
let caller_address = [1; 32];
|
let caller_address = Address::new([1; 32]);
|
||||||
let comitment_store_root = [3; 32];
|
let comitment_store_root = [3; 32];
|
||||||
|
|
||||||
let commitments_tree =
|
let commitments_tree =
|
||||||
|
|||||||
@ -28,6 +28,9 @@ path = "../accounts"
|
|||||||
[dependencies.common]
|
[dependencies.common]
|
||||||
path = "../common"
|
path = "../common"
|
||||||
|
|
||||||
|
[dependencies.nssa]
|
||||||
|
path = "../nssa"
|
||||||
|
|
||||||
[dependencies.secp256k1-zkp]
|
[dependencies.secp256k1-zkp]
|
||||||
workspace = true
|
workspace = true
|
||||||
features = ["std", "rand-std", "rand", "serde", "global-context"]
|
features = ["std", "rand-std", "rand", "serde", "global-context"]
|
||||||
|
|||||||
@ -6,7 +6,7 @@ use std::path::PathBuf;
|
|||||||
pub struct AccountInitialData {
|
pub struct AccountInitialData {
|
||||||
///Hex encoded `AccountAddress`
|
///Hex encoded `AccountAddress`
|
||||||
pub addr: String,
|
pub addr: String,
|
||||||
pub balance: u64,
|
pub balance: u128,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Serialize, Deserialize)]
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
|
|||||||
@ -1,28 +1,18 @@
|
|||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
|
|
||||||
use accounts::account_core::address::{self, AccountAddress};
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use common::{
|
use common::{block::HashableBlockData, merkle_tree_public::TreeHashType};
|
||||||
block::HashableBlockData,
|
|
||||||
execution_input::PublicNativeTokenSend,
|
|
||||||
merkle_tree_public::TreeHashType,
|
|
||||||
nullifier::UTXONullifier,
|
|
||||||
transaction::{AuthenticatedTransaction, Transaction, TransactionBody, TxKind},
|
|
||||||
utxo_commitment::UTXOCommitment,
|
|
||||||
};
|
|
||||||
use config::SequencerConfig;
|
use config::SequencerConfig;
|
||||||
use mempool::MemPool;
|
use mempool::MemPool;
|
||||||
use mempool_transaction::MempoolTransaction;
|
|
||||||
use sequencer_store::SequecerChainStore;
|
use sequencer_store::SequecerChainStore;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
pub mod config;
|
pub mod config;
|
||||||
pub mod mempool_transaction;
|
|
||||||
pub mod sequencer_store;
|
pub mod sequencer_store;
|
||||||
|
|
||||||
pub struct SequencerCore {
|
pub struct SequencerCore {
|
||||||
pub store: SequecerChainStore,
|
pub store: SequecerChainStore,
|
||||||
pub mempool: MemPool<MempoolTransaction>,
|
pub mempool: MemPool<nssa::PublicTransaction>,
|
||||||
pub sequencer_config: SequencerConfig,
|
pub sequencer_config: SequencerConfig,
|
||||||
pub chain_height: u64,
|
pub chain_height: u64,
|
||||||
}
|
}
|
||||||
@ -34,7 +24,7 @@ pub enum TransactionMalformationErrorKind {
|
|||||||
TxHashAlreadyPresentInTree { tx: TreeHashType },
|
TxHashAlreadyPresentInTree { tx: TreeHashType },
|
||||||
NullifierAlreadyPresentInTree { tx: TreeHashType },
|
NullifierAlreadyPresentInTree { tx: TreeHashType },
|
||||||
UTXOCommitmentAlreadyPresentInTree { tx: TreeHashType },
|
UTXOCommitmentAlreadyPresentInTree { tx: TreeHashType },
|
||||||
MempoolFullForRound { tx: TreeHashType },
|
MempoolFullForRound,
|
||||||
ChainStateFurtherThanTransactionState { tx: TreeHashType },
|
ChainStateFurtherThanTransactionState { tx: TreeHashType },
|
||||||
FailedToInsert { tx: TreeHashType, details: String },
|
FailedToInsert { tx: TreeHashType, details: String },
|
||||||
InvalidSignature,
|
InvalidSignature,
|
||||||
@ -61,219 +51,47 @@ impl SequencerCore {
|
|||||||
config.is_genesis_random,
|
config.is_genesis_random,
|
||||||
&config.initial_accounts,
|
&config.initial_accounts,
|
||||||
),
|
),
|
||||||
mempool: MemPool::<MempoolTransaction>::default(),
|
mempool: MemPool::default(),
|
||||||
chain_height: config.genesis_id,
|
chain_height: config.genesis_id,
|
||||||
sequencer_config: config,
|
sequencer_config: config,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_tree_roots(&self) -> [[u8; 32]; 2] {
|
|
||||||
[
|
|
||||||
self.store
|
|
||||||
.utxo_commitments_store
|
|
||||||
.get_root()
|
|
||||||
.unwrap_or([0; 32]),
|
|
||||||
self.store.pub_tx_store.get_root().unwrap_or([0; 32]),
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn transaction_pre_check(
|
pub fn transaction_pre_check(
|
||||||
&mut self,
|
&mut self,
|
||||||
tx: Transaction,
|
tx: nssa::PublicTransaction,
|
||||||
) -> Result<AuthenticatedTransaction, TransactionMalformationErrorKind> {
|
) -> Result<nssa::PublicTransaction, TransactionMalformationErrorKind> {
|
||||||
let tx = tx
|
// Stateless checks here
|
||||||
.into_authenticated()
|
if tx.witness_set().is_valid_for(tx.message()) {
|
||||||
.map_err(|_| TransactionMalformationErrorKind::InvalidSignature)?;
|
Ok(tx)
|
||||||
|
} else {
|
||||||
let TransactionBody {
|
Err(TransactionMalformationErrorKind::InvalidSignature)
|
||||||
tx_kind,
|
|
||||||
ref execution_input,
|
|
||||||
ref execution_output,
|
|
||||||
ref utxo_commitments_created_hashes,
|
|
||||||
ref nullifier_created_hashes,
|
|
||||||
..
|
|
||||||
} = tx.transaction().body();
|
|
||||||
|
|
||||||
let tx_hash = *tx.hash();
|
|
||||||
|
|
||||||
let mempool_size = self.mempool.len();
|
|
||||||
|
|
||||||
if mempool_size >= self.sequencer_config.max_num_tx_in_block {
|
|
||||||
return Err(TransactionMalformationErrorKind::MempoolFullForRound { tx: tx_hash });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Sanity check
|
|
||||||
match tx_kind {
|
|
||||||
TxKind::Public => {
|
|
||||||
if !utxo_commitments_created_hashes.is_empty()
|
|
||||||
|| !nullifier_created_hashes.is_empty()
|
|
||||||
{
|
|
||||||
//Public transactions can not make private operations.
|
|
||||||
return Err(
|
|
||||||
TransactionMalformationErrorKind::PublicTransactionChangedPrivateData {
|
|
||||||
tx: tx_hash,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TxKind::Private => {
|
|
||||||
if !execution_input.is_empty() || !execution_output.is_empty() {
|
|
||||||
//Not entirely necessary, but useful simplification for a future.
|
|
||||||
//This way only shielded and deshielded transactions can be used for interaction
|
|
||||||
//between public and private state.
|
|
||||||
return Err(
|
|
||||||
TransactionMalformationErrorKind::PrivateTransactionChangedPublicData {
|
|
||||||
tx: tx_hash,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
};
|
|
||||||
|
|
||||||
//Native transfers checks
|
|
||||||
if let Ok(native_transfer_action) =
|
|
||||||
serde_json::from_slice::<PublicNativeTokenSend>(execution_input)
|
|
||||||
{
|
|
||||||
let signer_address = address::from_public_key(&tx.transaction().public_key);
|
|
||||||
|
|
||||||
//Correct sender check
|
|
||||||
if native_transfer_action.from != signer_address {
|
|
||||||
return Err(TransactionMalformationErrorKind::IncorrectSender);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Tree checks
|
|
||||||
let tx_tree_check = self.store.pub_tx_store.get_tx(tx_hash).is_some();
|
|
||||||
let nullifier_tree_check = nullifier_created_hashes.iter().any(|nullifier_hash| {
|
|
||||||
self.store.nullifier_store.contains(&UTXONullifier {
|
|
||||||
utxo_hash: *nullifier_hash,
|
|
||||||
})
|
|
||||||
});
|
|
||||||
let utxo_commitments_check =
|
|
||||||
utxo_commitments_created_hashes
|
|
||||||
.iter()
|
|
||||||
.any(|utxo_commitment_hash| {
|
|
||||||
self.store
|
|
||||||
.utxo_commitments_store
|
|
||||||
.get_tx(*utxo_commitment_hash)
|
|
||||||
.is_some()
|
|
||||||
});
|
|
||||||
|
|
||||||
if tx_tree_check {
|
|
||||||
return Err(
|
|
||||||
TransactionMalformationErrorKind::TxHashAlreadyPresentInTree { tx: *tx.hash() },
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if nullifier_tree_check {
|
|
||||||
return Err(
|
|
||||||
TransactionMalformationErrorKind::NullifierAlreadyPresentInTree { tx: *tx.hash() },
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if utxo_commitments_check {
|
|
||||||
return Err(
|
|
||||||
TransactionMalformationErrorKind::UTXOCommitmentAlreadyPresentInTree {
|
|
||||||
tx: *tx.hash(),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(tx)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_tx_into_mempool_pre_check(
|
pub fn push_tx_into_mempool_pre_check(
|
||||||
&mut self,
|
&mut self,
|
||||||
transaction: Transaction,
|
transaction: nssa::PublicTransaction,
|
||||||
) -> Result<(), TransactionMalformationErrorKind> {
|
) -> Result<(), TransactionMalformationErrorKind> {
|
||||||
let mempool_size = self.mempool.len();
|
let mempool_size = self.mempool.len();
|
||||||
if mempool_size >= self.sequencer_config.max_num_tx_in_block {
|
if mempool_size >= self.sequencer_config.max_num_tx_in_block {
|
||||||
return Err(TransactionMalformationErrorKind::MempoolFullForRound {
|
return Err(TransactionMalformationErrorKind::MempoolFullForRound);
|
||||||
tx: transaction.body().hash(),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let authenticated_tx = self.transaction_pre_check(transaction)?;
|
let authenticated_tx = self.transaction_pre_check(transaction)?;
|
||||||
|
|
||||||
self.mempool.push_item(authenticated_tx.into());
|
self.mempool.push_item(authenticated_tx);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn execute_check_transaction_on_state(
|
fn execute_check_transaction_on_state(
|
||||||
&mut self,
|
&mut self,
|
||||||
mempool_tx: &MempoolTransaction,
|
tx: nssa::PublicTransaction,
|
||||||
) -> Result<(), TransactionMalformationErrorKind> {
|
) -> Result<nssa::PublicTransaction, nssa::error::NssaError> {
|
||||||
let TransactionBody {
|
self.store.state.transition_from_public_transaction(&tx)?;
|
||||||
ref utxo_commitments_created_hashes,
|
|
||||||
ref nullifier_created_hashes,
|
|
||||||
execution_input,
|
|
||||||
..
|
|
||||||
} = mempool_tx.auth_tx.transaction().body();
|
|
||||||
|
|
||||||
let tx_hash = *mempool_tx.auth_tx.hash();
|
Ok(tx)
|
||||||
|
|
||||||
//Balance move
|
|
||||||
if let Ok(native_transfer_action) =
|
|
||||||
serde_json::from_slice::<PublicNativeTokenSend>(execution_input)
|
|
||||||
{
|
|
||||||
// Nonce check
|
|
||||||
let signer_addres =
|
|
||||||
address::from_public_key(&mempool_tx.auth_tx.transaction().public_key);
|
|
||||||
if self.store.acc_store.get_account_nonce(&signer_addres)
|
|
||||||
!= native_transfer_action.nonce
|
|
||||||
{
|
|
||||||
return Err(TransactionMalformationErrorKind::NonceMismatch { tx: tx_hash });
|
|
||||||
}
|
|
||||||
|
|
||||||
let from_balance = self
|
|
||||||
.store
|
|
||||||
.acc_store
|
|
||||||
.get_account_balance(&native_transfer_action.from);
|
|
||||||
let to_balance = self
|
|
||||||
.store
|
|
||||||
.acc_store
|
|
||||||
.get_account_balance(&native_transfer_action.to);
|
|
||||||
|
|
||||||
//Balance check
|
|
||||||
if from_balance < native_transfer_action.balance_to_move {
|
|
||||||
return Err(TransactionMalformationErrorKind::BalanceMismatch { tx: tx_hash });
|
|
||||||
}
|
|
||||||
|
|
||||||
self.store.acc_store.set_account_balance(
|
|
||||||
&native_transfer_action.from,
|
|
||||||
from_balance - native_transfer_action.balance_to_move,
|
|
||||||
);
|
|
||||||
self.store.acc_store.set_account_balance(
|
|
||||||
&native_transfer_action.to,
|
|
||||||
to_balance + native_transfer_action.balance_to_move,
|
|
||||||
);
|
|
||||||
|
|
||||||
self.store.acc_store.increase_nonce(&signer_addres);
|
|
||||||
}
|
|
||||||
|
|
||||||
for utxo_comm in utxo_commitments_created_hashes {
|
|
||||||
self.store
|
|
||||||
.utxo_commitments_store
|
|
||||||
.add_tx(&UTXOCommitment { hash: *utxo_comm });
|
|
||||||
}
|
|
||||||
|
|
||||||
for nullifier in nullifier_created_hashes.iter() {
|
|
||||||
self.store.nullifier_store.insert(UTXONullifier {
|
|
||||||
utxo_hash: *nullifier,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
self.store
|
|
||||||
.pub_tx_store
|
|
||||||
.add_tx(mempool_tx.auth_tx.transaction());
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn register_account(&mut self, account_addr: AccountAddress) {
|
|
||||||
self.store.acc_store.register_account(account_addr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
///Produces new block from transactions in mempool
|
///Produces new block from transactions in mempool
|
||||||
@ -284,15 +102,9 @@ impl SequencerCore {
|
|||||||
.mempool
|
.mempool
|
||||||
.pop_size(self.sequencer_config.max_num_tx_in_block);
|
.pop_size(self.sequencer_config.max_num_tx_in_block);
|
||||||
|
|
||||||
let valid_transactions = transactions
|
let valid_transactions: Vec<_> = transactions
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(|mempool_tx| {
|
.filter_map(|tx| self.execute_check_transaction_on_state(tx).ok())
|
||||||
if self.execute_check_transaction_on_state(&mempool_tx).is_ok() {
|
|
||||||
Some(mempool_tx.auth_tx.into_transaction())
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let prev_block_hash = self
|
let prev_block_hash = self
|
||||||
@ -305,7 +117,6 @@ impl SequencerCore {
|
|||||||
block_id: new_block_height,
|
block_id: new_block_height,
|
||||||
prev_block_id: self.chain_height,
|
prev_block_id: self.chain_height,
|
||||||
transactions: valid_transactions,
|
transactions: valid_transactions,
|
||||||
data: vec![],
|
|
||||||
prev_block_hash,
|
prev_block_hash,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -324,8 +135,6 @@ mod tests {
|
|||||||
use crate::config::AccountInitialData;
|
use crate::config::AccountInitialData;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use k256::{ecdsa::SigningKey, FieldBytes};
|
|
||||||
use mempool_transaction::MempoolTransaction;
|
|
||||||
|
|
||||||
fn setup_sequencer_config_variable_initial_accounts(
|
fn setup_sequencer_config_variable_initial_accounts(
|
||||||
initial_accounts: Vec<AccountInitialData>,
|
initial_accounts: Vec<AccountInitialData>,
|
||||||
@ -347,13 +156,13 @@ mod tests {
|
|||||||
|
|
||||||
fn setup_sequencer_config() -> SequencerConfig {
|
fn setup_sequencer_config() -> SequencerConfig {
|
||||||
let acc1_addr = vec![
|
let acc1_addr = vec![
|
||||||
13, 150, 223, 204, 65, 64, 25, 56, 12, 157, 222, 12, 211, 220, 229, 170, 201, 15, 181,
|
27, 132, 197, 86, 123, 18, 100, 64, 153, 93, 62, 213, 170, 186, 5, 101, 215, 30, 24,
|
||||||
68, 59, 248, 113, 16, 135, 65, 174, 175, 222, 85, 42, 215,
|
52, 96, 72, 25, 255, 156, 23, 245, 233, 213, 221, 7, 143,
|
||||||
];
|
];
|
||||||
|
|
||||||
let acc2_addr = vec![
|
let acc2_addr = vec![
|
||||||
151, 72, 112, 233, 190, 141, 10, 192, 138, 168, 59, 63, 199, 167, 166, 134, 41, 29,
|
77, 75, 108, 209, 54, 16, 50, 202, 155, 210, 174, 185, 217, 0, 170, 77, 69, 217, 234,
|
||||||
135, 50, 80, 138, 186, 152, 179, 96, 128, 243, 156, 44, 243, 100,
|
216, 10, 201, 66, 51, 116, 196, 81, 167, 37, 77, 7, 102,
|
||||||
];
|
];
|
||||||
|
|
||||||
let initial_acc1 = AccountInitialData {
|
let initial_acc1 = AccountInitialData {
|
||||||
@ -371,36 +180,17 @@ mod tests {
|
|||||||
setup_sequencer_config_variable_initial_accounts(initial_accounts)
|
setup_sequencer_config_variable_initial_accounts(initial_accounts)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_signing_key_for_account1() -> SigningKey {
|
fn create_signing_key_for_account1() -> nssa::PrivateKey {
|
||||||
let pub_sign_key_acc1 = [
|
nssa::PrivateKey::try_new([1; 32]).unwrap()
|
||||||
133, 143, 177, 187, 252, 66, 237, 236, 234, 252, 244, 138, 5, 151, 3, 99, 217, 231,
|
|
||||||
112, 217, 77, 211, 58, 218, 176, 68, 99, 53, 152, 228, 198, 190,
|
|
||||||
];
|
|
||||||
|
|
||||||
let field_bytes = FieldBytes::from_slice(&pub_sign_key_acc1);
|
|
||||||
SigningKey::from_bytes(field_bytes).unwrap()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_signing_key_for_account2() -> SigningKey {
|
fn create_signing_key_for_account2() -> nssa::PrivateKey {
|
||||||
let pub_sign_key_acc2 = [
|
nssa::PrivateKey::try_new([2; 32]).unwrap()
|
||||||
54, 90, 62, 225, 71, 225, 228, 148, 143, 53, 210, 23, 137, 158, 171, 156, 48, 7, 139,
|
|
||||||
52, 117, 242, 214, 7, 99, 29, 122, 184, 59, 116, 144, 107,
|
|
||||||
];
|
|
||||||
|
|
||||||
let field_bytes = FieldBytes::from_slice(&pub_sign_key_acc2);
|
|
||||||
SigningKey::from_bytes(field_bytes).unwrap()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn common_setup(sequencer: &mut SequencerCore) {
|
fn common_setup(sequencer: &mut SequencerCore) {
|
||||||
let tx = common::test_utils::create_dummy_private_transaction_random_signer(
|
let tx = common::test_utils::produce_dummy_empty_transaction();
|
||||||
vec![[9; 32]],
|
sequencer.mempool.push_item(tx);
|
||||||
vec![[7; 32]],
|
|
||||||
vec![[8; 32]],
|
|
||||||
);
|
|
||||||
let mempool_tx = MempoolTransaction {
|
|
||||||
auth_tx: tx.into_authenticated().unwrap(),
|
|
||||||
};
|
|
||||||
sequencer.mempool.push_item(mempool_tx);
|
|
||||||
|
|
||||||
sequencer
|
sequencer
|
||||||
.produce_new_block_with_mempool_transactions()
|
.produce_new_block_with_mempool_transactions()
|
||||||
@ -425,29 +215,31 @@ mod tests {
|
|||||||
.try_into()
|
.try_into()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
assert!(sequencer.store.acc_store.contains_account(&acc1_addr));
|
let balance_acc_1 = sequencer
|
||||||
assert!(sequencer.store.acc_store.contains_account(&acc2_addr));
|
.store
|
||||||
|
.state
|
||||||
|
.get_account_by_address(&nssa::Address::new(acc1_addr))
|
||||||
|
.balance;
|
||||||
|
let balance_acc_2 = sequencer
|
||||||
|
.store
|
||||||
|
.state
|
||||||
|
.get_account_by_address(&nssa::Address::new(acc2_addr))
|
||||||
|
.balance;
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(10000, balance_acc_1);
|
||||||
10000,
|
assert_eq!(20000, balance_acc_2);
|
||||||
sequencer.store.acc_store.get_account_balance(&acc1_addr)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
20000,
|
|
||||||
sequencer.store.acc_store.get_account_balance(&acc2_addr)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_start_different_intial_accounts_balances() {
|
fn test_start_different_intial_accounts_balances() {
|
||||||
let acc1_addr = vec![
|
let acc1_addr = vec![
|
||||||
13, 150, 223, 204, 65, 64, 25, 56, 12, 157, 222, 12, 211, 220, 229, 170, 201, 15, 181,
|
27, 132, 197, 86, 123, 18, 100, 64, 153, 93, 62, 213, 170, 186, 5, 101, 215, 30, 24,
|
||||||
68, 59, 248, 113, 16, 135, 65, 174, 175, 222, 42, 42, 42,
|
52, 96, 72, 25, 255, 156, 23, 245, 233, 213, 221, 7, 143,
|
||||||
];
|
];
|
||||||
|
|
||||||
let acc2_addr = vec![
|
let acc2_addr = vec![
|
||||||
151, 72, 112, 233, 190, 141, 10, 192, 138, 168, 59, 63, 199, 167, 166, 134, 41, 29,
|
77, 75, 108, 209, 54, 16, 50, 202, 155, 210, 174, 185, 217, 0, 170, 77, 69, 217, 234,
|
||||||
135, 50, 80, 138, 186, 152, 179, 96, 128, 243, 156, 42, 42, 42,
|
216, 10, 201, 66, 51, 116, 196, 81, 167, 37, 77, 7, 102,
|
||||||
];
|
];
|
||||||
|
|
||||||
let initial_acc1 = AccountInitialData {
|
let initial_acc1 = AccountInitialData {
|
||||||
@ -462,8 +254,6 @@ mod tests {
|
|||||||
|
|
||||||
let initial_accounts = vec![initial_acc1, initial_acc2];
|
let initial_accounts = vec![initial_acc1, initial_acc2];
|
||||||
|
|
||||||
let intial_accounts_len = initial_accounts.len();
|
|
||||||
|
|
||||||
let config = setup_sequencer_config_variable_initial_accounts(initial_accounts);
|
let config = setup_sequencer_config_variable_initial_accounts(initial_accounts);
|
||||||
let sequencer = SequencerCore::start_from_config(config.clone());
|
let sequencer = SequencerCore::start_from_config(config.clone());
|
||||||
|
|
||||||
@ -476,32 +266,24 @@ mod tests {
|
|||||||
.try_into()
|
.try_into()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
assert!(sequencer.store.acc_store.contains_account(&acc1_addr));
|
|
||||||
assert!(sequencer.store.acc_store.contains_account(&acc2_addr));
|
|
||||||
|
|
||||||
assert_eq!(sequencer.store.acc_store.len(), intial_accounts_len);
|
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
10000,
|
10000,
|
||||||
sequencer.store.acc_store.get_account_balance(&acc1_addr)
|
sequencer
|
||||||
|
.store
|
||||||
|
.state
|
||||||
|
.get_account_by_address(&nssa::Address::new(acc1_addr))
|
||||||
|
.balance
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
20000,
|
20000,
|
||||||
sequencer.store.acc_store.get_account_balance(&acc2_addr)
|
sequencer
|
||||||
|
.store
|
||||||
|
.state
|
||||||
|
.get_account_by_address(&nssa::Address::new(acc2_addr))
|
||||||
|
.balance
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_get_tree_roots() {
|
|
||||||
let config = setup_sequencer_config();
|
|
||||||
let mut sequencer = SequencerCore::start_from_config(config);
|
|
||||||
|
|
||||||
common_setup(&mut sequencer);
|
|
||||||
|
|
||||||
let roots = sequencer.get_tree_roots();
|
|
||||||
assert_eq!(roots.len(), 2); // Should return two roots
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_transaction_pre_check_pass() {
|
fn test_transaction_pre_check_pass() {
|
||||||
let config = setup_sequencer_config();
|
let config = setup_sequencer_config();
|
||||||
@ -509,12 +291,7 @@ mod tests {
|
|||||||
|
|
||||||
common_setup(&mut sequencer);
|
common_setup(&mut sequencer);
|
||||||
|
|
||||||
let tx = common::test_utils::create_dummy_private_transaction_random_signer(
|
let tx = common::test_utils::produce_dummy_empty_transaction();
|
||||||
vec![[91; 32]],
|
|
||||||
vec![[71; 32]],
|
|
||||||
vec![[81; 32]],
|
|
||||||
);
|
|
||||||
|
|
||||||
let result = sequencer.transaction_pre_check(tx);
|
let result = sequencer.transaction_pre_check(tx);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert!(result.is_ok());
|
||||||
@ -538,10 +315,9 @@ mod tests {
|
|||||||
|
|
||||||
let sign_key1 = create_signing_key_for_account1();
|
let sign_key1 = create_signing_key_for_account1();
|
||||||
|
|
||||||
let tx = common::test_utils::create_dummy_transaction_native_token_transfer(
|
let tx = common::test_utils::create_transaction_native_token_transfer(
|
||||||
acc1, 0, acc2, 10, sign_key1,
|
acc1, 0, acc2, 10, sign_key1,
|
||||||
);
|
);
|
||||||
|
|
||||||
let result = sequencer.transaction_pre_check(tx);
|
let result = sequencer.transaction_pre_check(tx);
|
||||||
|
|
||||||
assert!(result.is_ok());
|
assert!(result.is_ok());
|
||||||
@ -565,16 +341,20 @@ mod tests {
|
|||||||
|
|
||||||
let sign_key2 = create_signing_key_for_account2();
|
let sign_key2 = create_signing_key_for_account2();
|
||||||
|
|
||||||
let tx = common::test_utils::create_dummy_transaction_native_token_transfer(
|
let tx = common::test_utils::create_transaction_native_token_transfer(
|
||||||
acc1, 0, acc2, 10, sign_key2,
|
acc1, 0, acc2, 10, sign_key2,
|
||||||
);
|
);
|
||||||
|
|
||||||
let result = sequencer.transaction_pre_check(tx);
|
// Signature is valid, stateless check pass
|
||||||
|
let tx = sequencer.transaction_pre_check(tx).unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
// Signature is not from sender. Execution fails
|
||||||
result.err().unwrap(),
|
let result = sequencer.execute_check_transaction_on_state(tx);
|
||||||
TransactionMalformationErrorKind::IncorrectSender
|
|
||||||
);
|
assert!(matches!(
|
||||||
|
result,
|
||||||
|
Err(nssa::error::NssaError::ProgramExecutionFailed(_))
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -595,7 +375,7 @@ mod tests {
|
|||||||
|
|
||||||
let sign_key1 = create_signing_key_for_account1();
|
let sign_key1 = create_signing_key_for_account1();
|
||||||
|
|
||||||
let tx = common::test_utils::create_dummy_transaction_native_token_transfer(
|
let tx = common::test_utils::create_transaction_native_token_transfer(
|
||||||
acc1, 0, acc2, 10000000, sign_key1,
|
acc1, 0, acc2, 10000000, sign_key1,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -604,10 +384,10 @@ mod tests {
|
|||||||
//Passed pre-check
|
//Passed pre-check
|
||||||
assert!(result.is_ok());
|
assert!(result.is_ok());
|
||||||
|
|
||||||
let result = sequencer.execute_check_transaction_on_state(&result.unwrap().into());
|
let result = sequencer.execute_check_transaction_on_state(result.unwrap());
|
||||||
let is_failed_at_balance_mismatch = matches!(
|
let is_failed_at_balance_mismatch = matches!(
|
||||||
result.err().unwrap(),
|
result.err().unwrap(),
|
||||||
TransactionMalformationErrorKind::BalanceMismatch { tx: _ }
|
nssa::error::NssaError::ProgramExecutionFailed(_)
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(is_failed_at_balance_mismatch);
|
assert!(is_failed_at_balance_mismatch);
|
||||||
@ -631,16 +411,22 @@ mod tests {
|
|||||||
|
|
||||||
let sign_key1 = create_signing_key_for_account1();
|
let sign_key1 = create_signing_key_for_account1();
|
||||||
|
|
||||||
let tx = common::test_utils::create_dummy_transaction_native_token_transfer(
|
let tx = common::test_utils::create_transaction_native_token_transfer(
|
||||||
acc1, 0, acc2, 100, sign_key1,
|
acc1, 0, acc2, 100, sign_key1,
|
||||||
);
|
);
|
||||||
|
|
||||||
sequencer
|
sequencer.execute_check_transaction_on_state(tx).unwrap();
|
||||||
.execute_check_transaction_on_state(&tx.into_authenticated().unwrap().into())
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let bal_from = sequencer.store.acc_store.get_account_balance(&acc1);
|
let bal_from = sequencer
|
||||||
let bal_to = sequencer.store.acc_store.get_account_balance(&acc2);
|
.store
|
||||||
|
.state
|
||||||
|
.get_account_by_address(&nssa::Address::new(acc1))
|
||||||
|
.balance;
|
||||||
|
let bal_to = sequencer
|
||||||
|
.store
|
||||||
|
.state
|
||||||
|
.get_account_by_address(&nssa::Address::new(acc2))
|
||||||
|
.balance;
|
||||||
|
|
||||||
assert_eq!(bal_from, 9900);
|
assert_eq!(bal_from, 9900);
|
||||||
assert_eq!(bal_to, 20100);
|
assert_eq!(bal_to, 20100);
|
||||||
@ -656,23 +442,16 @@ mod tests {
|
|||||||
|
|
||||||
common_setup(&mut sequencer);
|
common_setup(&mut sequencer);
|
||||||
|
|
||||||
let tx = common::test_utils::create_dummy_private_transaction_random_signer(
|
let tx = common::test_utils::produce_dummy_empty_transaction();
|
||||||
vec![[92; 32]],
|
|
||||||
vec![[72; 32]],
|
|
||||||
vec![[82; 32]],
|
|
||||||
);
|
|
||||||
|
|
||||||
// Fill the mempool
|
// Fill the mempool
|
||||||
let dummy_tx = MempoolTransaction {
|
sequencer.mempool.push_item(tx.clone());
|
||||||
auth_tx: tx.clone().into_authenticated().unwrap(),
|
|
||||||
};
|
|
||||||
sequencer.mempool.push_item(dummy_tx);
|
|
||||||
|
|
||||||
let result = sequencer.push_tx_into_mempool_pre_check(tx);
|
let result = sequencer.push_tx_into_mempool_pre_check(tx);
|
||||||
|
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
result,
|
result,
|
||||||
Err(TransactionMalformationErrorKind::MempoolFullForRound { .. })
|
Err(TransactionMalformationErrorKind::MempoolFullForRound)
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -683,11 +462,7 @@ mod tests {
|
|||||||
|
|
||||||
common_setup(&mut sequencer);
|
common_setup(&mut sequencer);
|
||||||
|
|
||||||
let tx = common::test_utils::create_dummy_private_transaction_random_signer(
|
let tx = common::test_utils::produce_dummy_empty_transaction();
|
||||||
vec![[93; 32]],
|
|
||||||
vec![[73; 32]],
|
|
||||||
vec![[83; 32]],
|
|
||||||
);
|
|
||||||
|
|
||||||
let result = sequencer.push_tx_into_mempool_pre_check(tx);
|
let result = sequencer.push_tx_into_mempool_pre_check(tx);
|
||||||
assert!(result.is_ok());
|
assert!(result.is_ok());
|
||||||
@ -700,15 +475,8 @@ mod tests {
|
|||||||
let mut sequencer = SequencerCore::start_from_config(config);
|
let mut sequencer = SequencerCore::start_from_config(config);
|
||||||
let genesis_height = sequencer.chain_height;
|
let genesis_height = sequencer.chain_height;
|
||||||
|
|
||||||
let tx = common::test_utils::create_dummy_private_transaction_random_signer(
|
let tx = common::test_utils::produce_dummy_empty_transaction();
|
||||||
vec![[94; 32]],
|
sequencer.mempool.push_item(tx);
|
||||||
vec![[7; 32]],
|
|
||||||
vec![[8; 32]],
|
|
||||||
);
|
|
||||||
let tx_mempool = MempoolTransaction {
|
|
||||||
auth_tx: tx.into_authenticated().unwrap(),
|
|
||||||
};
|
|
||||||
sequencer.mempool.push_item(tx_mempool);
|
|
||||||
|
|
||||||
let block_id = sequencer.produce_new_block_with_mempool_transactions();
|
let block_id = sequencer.produce_new_block_with_mempool_transactions();
|
||||||
assert!(block_id.is_ok());
|
assert!(block_id.is_ok());
|
||||||
@ -733,20 +501,15 @@ mod tests {
|
|||||||
|
|
||||||
let sign_key1 = create_signing_key_for_account1();
|
let sign_key1 = create_signing_key_for_account1();
|
||||||
|
|
||||||
let tx = common::test_utils::create_dummy_transaction_native_token_transfer(
|
let tx = common::test_utils::create_transaction_native_token_transfer(
|
||||||
acc1, 0, acc2, 100, sign_key1,
|
acc1, 0, acc2, 100, sign_key1,
|
||||||
);
|
);
|
||||||
|
|
||||||
let tx_mempool_original = MempoolTransaction {
|
let tx_original = tx.clone();
|
||||||
auth_tx: tx.clone().into_authenticated().unwrap(),
|
let tx_replay = tx.clone();
|
||||||
};
|
|
||||||
let tx_mempool_replay = MempoolTransaction {
|
|
||||||
auth_tx: tx.clone().into_authenticated().unwrap(),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Pushing two copies of the same tx to the mempool
|
// Pushing two copies of the same tx to the mempool
|
||||||
sequencer.mempool.push_item(tx_mempool_original);
|
sequencer.mempool.push_item(tx_original);
|
||||||
sequencer.mempool.push_item(tx_mempool_replay);
|
sequencer.mempool.push_item(tx_replay);
|
||||||
|
|
||||||
// Create block
|
// Create block
|
||||||
let current_height = sequencer
|
let current_height = sequencer
|
||||||
@ -780,15 +543,12 @@ mod tests {
|
|||||||
|
|
||||||
let sign_key1 = create_signing_key_for_account1();
|
let sign_key1 = create_signing_key_for_account1();
|
||||||
|
|
||||||
let tx = common::test_utils::create_dummy_transaction_native_token_transfer(
|
let tx = common::test_utils::create_transaction_native_token_transfer(
|
||||||
acc1, 0, acc2, 100, sign_key1,
|
acc1, 0, acc2, 100, sign_key1,
|
||||||
);
|
);
|
||||||
|
|
||||||
// The transaction should be included the first time
|
// The transaction should be included the first time
|
||||||
let tx_mempool_original = MempoolTransaction {
|
sequencer.mempool.push_item(tx.clone());
|
||||||
auth_tx: tx.clone().into_authenticated().unwrap(),
|
|
||||||
};
|
|
||||||
sequencer.mempool.push_item(tx_mempool_original);
|
|
||||||
let current_height = sequencer
|
let current_height = sequencer
|
||||||
.produce_new_block_with_mempool_transactions()
|
.produce_new_block_with_mempool_transactions()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@ -800,10 +560,7 @@ mod tests {
|
|||||||
assert_eq!(block.transactions, vec![tx.clone()]);
|
assert_eq!(block.transactions, vec![tx.clone()]);
|
||||||
|
|
||||||
// Add same transaction should fail
|
// Add same transaction should fail
|
||||||
let tx_mempool_replay = MempoolTransaction {
|
sequencer.mempool.push_item(tx);
|
||||||
auth_tx: tx.into_authenticated().unwrap(),
|
|
||||||
};
|
|
||||||
sequencer.mempool.push_item(tx_mempool_replay);
|
|
||||||
let current_height = sequencer
|
let current_height = sequencer
|
||||||
.produce_new_block_with_mempool_transactions()
|
.produce_new_block_with_mempool_transactions()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|||||||
@ -1,20 +0,0 @@
|
|||||||
use common::{merkle_tree_public::TreeHashType, transaction::AuthenticatedTransaction};
|
|
||||||
use mempool::mempoolitem::MemPoolItem;
|
|
||||||
|
|
||||||
pub struct MempoolTransaction {
|
|
||||||
pub auth_tx: AuthenticatedTransaction,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<AuthenticatedTransaction> for MempoolTransaction {
|
|
||||||
fn from(auth_tx: AuthenticatedTransaction) -> Self {
|
|
||||||
Self { auth_tx }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MemPoolItem for MempoolTransaction {
|
|
||||||
type Identifier = TreeHashType;
|
|
||||||
|
|
||||||
fn identifier(&self) -> Self::Identifier {
|
|
||||||
*self.auth_tx.hash()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,314 +0,0 @@
|
|||||||
use accounts::account_core::address::AccountAddress;
|
|
||||||
use anyhow::Result;
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
||||||
pub(crate) struct AccountPublicData {
|
|
||||||
pub balance: u64,
|
|
||||||
pub address: AccountAddress,
|
|
||||||
nonce: u64,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AccountPublicData {
|
|
||||||
pub fn new(address: AccountAddress) -> Self {
|
|
||||||
Self {
|
|
||||||
balance: 0,
|
|
||||||
nonce: 0,
|
|
||||||
address,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new_with_balance(address: AccountAddress, balance: u64) -> Self {
|
|
||||||
Self {
|
|
||||||
balance,
|
|
||||||
address,
|
|
||||||
nonce: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct SequencerAccountsStore {
|
|
||||||
accounts: HashMap<AccountAddress, AccountPublicData>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SequencerAccountsStore {
|
|
||||||
pub fn new(initial_accounts: &[(AccountAddress, u64)]) -> Self {
|
|
||||||
let mut accounts = HashMap::new();
|
|
||||||
|
|
||||||
for (account_addr, balance) in initial_accounts {
|
|
||||||
accounts.insert(
|
|
||||||
*account_addr,
|
|
||||||
AccountPublicData::new_with_balance(*account_addr, *balance),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Self { accounts }
|
|
||||||
}
|
|
||||||
|
|
||||||
///Register new account in accounts store
|
|
||||||
///
|
|
||||||
///Starts with zero public balance
|
|
||||||
pub fn register_account(&mut self, account_addr: AccountAddress) {
|
|
||||||
self.accounts
|
|
||||||
.insert(account_addr, AccountPublicData::new(account_addr));
|
|
||||||
}
|
|
||||||
|
|
||||||
///Check, if `account_addr` present in account store
|
|
||||||
pub fn contains_account(&self, account_addr: &AccountAddress) -> bool {
|
|
||||||
self.accounts.contains_key(account_addr)
|
|
||||||
}
|
|
||||||
|
|
||||||
///Check `account_addr` balance,
|
|
||||||
///
|
|
||||||
///returns 0, if account address not found
|
|
||||||
pub fn get_account_balance(&self, account_addr: &AccountAddress) -> u64 {
|
|
||||||
self.accounts
|
|
||||||
.get(account_addr)
|
|
||||||
.map(|acc| acc.balance)
|
|
||||||
.unwrap_or(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_account_nonce(&self, account_addr: &AccountAddress) -> u64 {
|
|
||||||
self.accounts
|
|
||||||
.get(account_addr)
|
|
||||||
.map(|acc| acc.nonce)
|
|
||||||
.unwrap_or(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
///Update `account_addr` balance,
|
|
||||||
///
|
|
||||||
/// returns 0, if account address not found, otherwise returns previous balance
|
|
||||||
///
|
|
||||||
/// Also, if account was not previously found, sets it with zero balance
|
|
||||||
pub fn set_account_balance(&mut self, account_addr: &AccountAddress, new_balance: u64) -> u64 {
|
|
||||||
let acc_data = self.accounts.get_mut(account_addr);
|
|
||||||
|
|
||||||
if let Some(acc_data) = acc_data {
|
|
||||||
let old_balance = acc_data.balance;
|
|
||||||
|
|
||||||
acc_data.balance = new_balance;
|
|
||||||
|
|
||||||
old_balance
|
|
||||||
} else {
|
|
||||||
self.register_account(*account_addr);
|
|
||||||
|
|
||||||
let acc = self.accounts.get_mut(account_addr).unwrap();
|
|
||||||
|
|
||||||
acc.balance = new_balance;
|
|
||||||
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
///Update `account_addr` nonce,
|
|
||||||
///
|
|
||||||
/// Returns previous nonce
|
|
||||||
pub fn increase_nonce(&mut self, account_addr: &AccountAddress) -> u64 {
|
|
||||||
if let Some(acc_data) = self.accounts.get_mut(account_addr) {
|
|
||||||
let old_nonce = acc_data.nonce;
|
|
||||||
acc_data.nonce += 1;
|
|
||||||
old_nonce
|
|
||||||
} else {
|
|
||||||
self.register_account(*account_addr);
|
|
||||||
self.increase_nonce(account_addr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
///Remove account from storage
|
|
||||||
///
|
|
||||||
/// Fails, if `balance` is != 0
|
|
||||||
///
|
|
||||||
/// Returns `Option<AccountAddress>` which is `None` if `account_addr` vere not present in store
|
|
||||||
pub fn unregister_account(
|
|
||||||
&mut self,
|
|
||||||
account_addr: AccountAddress,
|
|
||||||
) -> Result<Option<AccountAddress>> {
|
|
||||||
if self.get_account_balance(&account_addr) == 0 {
|
|
||||||
Ok(self.accounts.remove(&account_addr).map(|data| data.address))
|
|
||||||
} else {
|
|
||||||
anyhow::bail!("Chain consistency violation: It is forbidden to remove account with nonzero balance");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
///Number of accounts present in store
|
|
||||||
pub fn len(&self) -> usize {
|
|
||||||
self.accounts.len()
|
|
||||||
}
|
|
||||||
|
|
||||||
///Is accounts store empty
|
|
||||||
pub fn is_empty(&self) -> bool {
|
|
||||||
self.accounts.is_empty()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for SequencerAccountsStore {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::new(&[])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_zero_balance_account_data_creation() {
|
|
||||||
let new_acc = AccountPublicData::new([1; 32]);
|
|
||||||
|
|
||||||
assert_eq!(new_acc.balance, 0);
|
|
||||||
assert_eq!(new_acc.address, [1; 32]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_zero_nonce_account_data_creation() {
|
|
||||||
let new_acc = AccountPublicData::new([1; 32]);
|
|
||||||
|
|
||||||
assert_eq!(new_acc.nonce, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_non_zero_balance_account_data_creation() {
|
|
||||||
let new_acc = AccountPublicData::new_with_balance([1; 32], 10);
|
|
||||||
|
|
||||||
assert_eq!(new_acc.balance, 10);
|
|
||||||
assert_eq!(new_acc.address, [1; 32]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_zero_nonce_account_data_creation_with_balance() {
|
|
||||||
let new_acc = AccountPublicData::new_with_balance([1; 32], 10);
|
|
||||||
|
|
||||||
assert_eq!(new_acc.nonce, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn default_account_sequencer_store() {
|
|
||||||
let seq_acc_store = SequencerAccountsStore::default();
|
|
||||||
|
|
||||||
assert!(seq_acc_store.accounts.is_empty());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn account_sequencer_store_register_acc() {
|
|
||||||
let mut seq_acc_store = SequencerAccountsStore::default();
|
|
||||||
|
|
||||||
seq_acc_store.register_account([1; 32]);
|
|
||||||
|
|
||||||
assert!(seq_acc_store.contains_account(&[1; 32]));
|
|
||||||
|
|
||||||
let acc_balance = seq_acc_store.get_account_balance(&[1; 32]);
|
|
||||||
|
|
||||||
assert_eq!(acc_balance, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn account_sequencer_store_unregister_acc_not_present() {
|
|
||||||
let mut seq_acc_store = SequencerAccountsStore::default();
|
|
||||||
|
|
||||||
seq_acc_store.register_account([1; 32]);
|
|
||||||
|
|
||||||
let rem_res = seq_acc_store.unregister_account([2; 32]).unwrap();
|
|
||||||
|
|
||||||
assert!(rem_res.is_none());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn account_sequencer_store_unregister_acc_not_zero_balance() {
|
|
||||||
let mut seq_acc_store = SequencerAccountsStore::new(&[([1; 32], 12), ([2; 32], 100)]);
|
|
||||||
|
|
||||||
let rem_res = seq_acc_store.unregister_account([1; 32]);
|
|
||||||
|
|
||||||
assert!(rem_res.is_err());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn account_sequencer_store_unregister_acc() {
|
|
||||||
let mut seq_acc_store = SequencerAccountsStore::default();
|
|
||||||
|
|
||||||
seq_acc_store.register_account([1; 32]);
|
|
||||||
|
|
||||||
assert!(seq_acc_store.contains_account(&[1; 32]));
|
|
||||||
|
|
||||||
seq_acc_store.unregister_account([1; 32]).unwrap().unwrap();
|
|
||||||
|
|
||||||
assert!(!seq_acc_store.contains_account(&[1; 32]));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn account_sequencer_store_with_preset_accounts_1() {
|
|
||||||
let seq_acc_store = SequencerAccountsStore::new(&[([1; 32], 12), ([2; 32], 100)]);
|
|
||||||
|
|
||||||
assert!(seq_acc_store.contains_account(&[1; 32]));
|
|
||||||
assert!(seq_acc_store.contains_account(&[2; 32]));
|
|
||||||
|
|
||||||
let acc_balance = seq_acc_store.get_account_balance(&[1; 32]);
|
|
||||||
|
|
||||||
assert_eq!(acc_balance, 12);
|
|
||||||
|
|
||||||
let acc_balance = seq_acc_store.get_account_balance(&[2; 32]);
|
|
||||||
|
|
||||||
assert_eq!(acc_balance, 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn account_sequencer_store_with_preset_accounts_2() {
|
|
||||||
let seq_acc_store =
|
|
||||||
SequencerAccountsStore::new(&[([6; 32], 120), ([7; 32], 15), ([8; 32], 10)]);
|
|
||||||
|
|
||||||
assert!(seq_acc_store.contains_account(&[6; 32]));
|
|
||||||
assert!(seq_acc_store.contains_account(&[7; 32]));
|
|
||||||
assert!(seq_acc_store.contains_account(&[8; 32]));
|
|
||||||
|
|
||||||
let acc_balance = seq_acc_store.get_account_balance(&[6; 32]);
|
|
||||||
|
|
||||||
assert_eq!(acc_balance, 120);
|
|
||||||
|
|
||||||
let acc_balance = seq_acc_store.get_account_balance(&[7; 32]);
|
|
||||||
|
|
||||||
assert_eq!(acc_balance, 15);
|
|
||||||
|
|
||||||
let acc_balance = seq_acc_store.get_account_balance(&[8; 32]);
|
|
||||||
|
|
||||||
assert_eq!(acc_balance, 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn account_sequencer_store_fetch_unknown_account() {
|
|
||||||
let seq_acc_store =
|
|
||||||
SequencerAccountsStore::new(&[([6; 32], 120), ([7; 32], 15), ([8; 32], 10)]);
|
|
||||||
|
|
||||||
let acc_balance = seq_acc_store.get_account_balance(&[9; 32]);
|
|
||||||
|
|
||||||
assert_eq!(acc_balance, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn account_sequencer_store_is_empty_test() {
|
|
||||||
let seq_acc_store = SequencerAccountsStore::default();
|
|
||||||
|
|
||||||
assert!(seq_acc_store.is_empty());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn account_sequencer_store_set_balance_to_unknown_account() {
|
|
||||||
let mut seq_acc_store = SequencerAccountsStore::default();
|
|
||||||
|
|
||||||
let ret = seq_acc_store.set_account_balance(&[1; 32], 100);
|
|
||||||
|
|
||||||
assert_eq!(ret, 0);
|
|
||||||
assert!(seq_acc_store.contains_account(&[1; 32]));
|
|
||||||
assert_eq!(seq_acc_store.get_account_balance(&[1; 32]), 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_increase_nonce() {
|
|
||||||
let mut account_store = SequencerAccountsStore::default();
|
|
||||||
let address = [1; 32];
|
|
||||||
let first_nonce = account_store.increase_nonce(&address);
|
|
||||||
assert_eq!(first_nonce, 0);
|
|
||||||
let second_nonce = account_store.increase_nonce(&address);
|
|
||||||
assert_eq!(second_nonce, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,7 +1,7 @@
|
|||||||
use std::{collections::HashMap, path::Path};
|
use std::{collections::HashMap, path::Path};
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use common::{block::Block, merkle_tree_public::TreeHashType, transaction::Transaction};
|
use common::{block::Block, merkle_tree_public::TreeHashType};
|
||||||
use storage::RocksDBIO;
|
use storage::RocksDBIO;
|
||||||
|
|
||||||
pub struct SequecerBlockStore {
|
pub struct SequecerBlockStore {
|
||||||
@ -51,12 +51,12 @@ impl SequecerBlockStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the transaction corresponding to the given hash, if it exists in the blockchain.
|
/// Returns the transaction corresponding to the given hash, if it exists in the blockchain.
|
||||||
pub fn get_transaction_by_hash(&self, hash: TreeHashType) -> Option<Transaction> {
|
pub fn get_transaction_by_hash(&self, hash: TreeHashType) -> Option<nssa::PublicTransaction> {
|
||||||
let block_id = self.tx_hash_to_block_map.get(&hash);
|
let block_id = self.tx_hash_to_block_map.get(&hash);
|
||||||
let block = block_id.map(|&id| self.get_block_at_id(id));
|
let block = block_id.map(|&id| self.get_block_at_id(id));
|
||||||
if let Some(Ok(block)) = block {
|
if let Some(Ok(block)) = block {
|
||||||
for transaction in block.transactions.into_iter() {
|
for transaction in block.transactions.into_iter() {
|
||||||
if transaction.body().hash() == hash {
|
if transaction.hash() == hash {
|
||||||
return Some(transaction);
|
return Some(transaction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -69,13 +69,14 @@ fn block_to_transactions_map(block: &Block) -> HashMap<TreeHashType, u64> {
|
|||||||
block
|
block
|
||||||
.transactions
|
.transactions
|
||||||
.iter()
|
.iter()
|
||||||
.map(|transaction| (transaction.body().hash(), block.block_id))
|
.map(|transaction| (transaction.hash(), block.block_id))
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use tempfile::tempdir;
|
use tempfile::tempdir;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -88,22 +89,21 @@ mod tests {
|
|||||||
prev_block_hash: [0; 32],
|
prev_block_hash: [0; 32],
|
||||||
hash: [1; 32],
|
hash: [1; 32],
|
||||||
transactions: vec![],
|
transactions: vec![],
|
||||||
data: vec![],
|
|
||||||
};
|
};
|
||||||
// Start an empty node store
|
// Start an empty node store
|
||||||
let mut node_store =
|
let mut node_store =
|
||||||
SequecerBlockStore::open_db_with_genesis(path, Some(genesis_block)).unwrap();
|
SequecerBlockStore::open_db_with_genesis(path, Some(genesis_block)).unwrap();
|
||||||
|
|
||||||
let tx = common::test_utils::produce_dummy_empty_transaction();
|
let tx = common::test_utils::produce_dummy_empty_transaction();
|
||||||
let block = common::test_utils::produce_dummy_block(1, None, vec![tx.clone()], vec![]);
|
let block = common::test_utils::produce_dummy_block(1, None, vec![tx.clone()]);
|
||||||
|
|
||||||
// Try retrieve a tx that's not in the chain yet.
|
// Try retrieve a tx that's not in the chain yet.
|
||||||
let retrieved_tx = node_store.get_transaction_by_hash(tx.body().hash());
|
let retrieved_tx = node_store.get_transaction_by_hash(tx.hash());
|
||||||
assert_eq!(None, retrieved_tx);
|
assert_eq!(None, retrieved_tx);
|
||||||
// Add the block with the transaction
|
// Add the block with the transaction
|
||||||
node_store.put_block_at_id(block).unwrap();
|
node_store.put_block_at_id(block).unwrap();
|
||||||
// Try again
|
// Try again
|
||||||
let retrieved_tx = node_store.get_transaction_by_hash(tx.body().hash());
|
let retrieved_tx = node_store.get_transaction_by_hash(tx.hash());
|
||||||
assert_eq!(Some(tx), retrieved_tx);
|
assert_eq!(Some(tx), retrieved_tx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,25 +1,17 @@
|
|||||||
use std::{collections::HashSet, path::Path};
|
use std::path::Path;
|
||||||
|
|
||||||
use accounts_store::SequencerAccountsStore;
|
|
||||||
use block_store::SequecerBlockStore;
|
use block_store::SequecerBlockStore;
|
||||||
use common::{
|
use common::block::HashableBlockData;
|
||||||
block::HashableBlockData,
|
use nssa::{self, Address};
|
||||||
merkle_tree_public::merkle_tree::{PublicTransactionMerkleTree, UTXOCommitmentsMerkleTree},
|
|
||||||
nullifier::UTXONullifier,
|
|
||||||
};
|
|
||||||
use rand::{rngs::OsRng, RngCore};
|
use rand::{rngs::OsRng, RngCore};
|
||||||
|
|
||||||
use crate::config::AccountInitialData;
|
use crate::config::AccountInitialData;
|
||||||
|
|
||||||
pub mod accounts_store;
|
|
||||||
pub mod block_store;
|
pub mod block_store;
|
||||||
|
|
||||||
pub struct SequecerChainStore {
|
pub struct SequecerChainStore {
|
||||||
pub acc_store: SequencerAccountsStore,
|
pub state: nssa::V01State,
|
||||||
pub block_store: SequecerBlockStore,
|
pub block_store: SequecerBlockStore,
|
||||||
pub nullifier_store: HashSet<UTXONullifier>,
|
|
||||||
pub utxo_commitments_store: UTXOCommitmentsMerkleTree,
|
|
||||||
pub pub_tx_store: PublicTransactionMerkleTree,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SequecerChainStore {
|
impl SequecerChainStore {
|
||||||
@ -29,7 +21,7 @@ impl SequecerChainStore {
|
|||||||
is_genesis_random: bool,
|
is_genesis_random: bool,
|
||||||
initial_accounts: &[AccountInitialData],
|
initial_accounts: &[AccountInitialData],
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let init_accs: Vec<_> = initial_accounts
|
let init_accs: Vec<(Address, u128)> = initial_accounts
|
||||||
.iter()
|
.iter()
|
||||||
.map(|acc_data| {
|
.map(|acc_data| {
|
||||||
(
|
(
|
||||||
@ -42,10 +34,7 @@ impl SequecerChainStore {
|
|||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let acc_store = SequencerAccountsStore::new(&init_accs);
|
let state = nssa::V01State::new_with_genesis_accounts(&init_accs);
|
||||||
let nullifier_store = HashSet::new();
|
|
||||||
let utxo_commitments_store = UTXOCommitmentsMerkleTree::new(vec![]);
|
|
||||||
let pub_tx_store = PublicTransactionMerkleTree::new(vec![]);
|
|
||||||
|
|
||||||
let mut data = [0; 32];
|
let mut data = [0; 32];
|
||||||
let mut prev_block_hash = [0; 32];
|
let mut prev_block_hash = [0; 32];
|
||||||
@ -59,7 +48,6 @@ impl SequecerChainStore {
|
|||||||
block_id: genesis_id,
|
block_id: genesis_id,
|
||||||
prev_block_id: genesis_id.saturating_sub(1),
|
prev_block_id: genesis_id.saturating_sub(1),
|
||||||
transactions: vec![],
|
transactions: vec![],
|
||||||
data: data.to_vec(),
|
|
||||||
prev_block_hash,
|
prev_block_hash,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -73,12 +61,6 @@ impl SequecerChainStore {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
Self {
|
Self { state, block_store }
|
||||||
acc_store,
|
|
||||||
block_store,
|
|
||||||
nullifier_store,
|
|
||||||
utxo_commitments_store,
|
|
||||||
pub_tx_store,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,6 +14,7 @@ actix-cors.workspace = true
|
|||||||
futures.workspace = true
|
futures.workspace = true
|
||||||
hex.workspace = true
|
hex.workspace = true
|
||||||
tempfile.workspace = true
|
tempfile.workspace = true
|
||||||
|
base64.workspace = true
|
||||||
|
|
||||||
actix-web.workspace = true
|
actix-web.workspace = true
|
||||||
tokio.workspace = true
|
tokio.workspace = true
|
||||||
@ -32,3 +33,6 @@ path = "../storage"
|
|||||||
|
|
||||||
[dependencies.common]
|
[dependencies.common]
|
||||||
path = "../common"
|
path = "../common"
|
||||||
|
|
||||||
|
[dependencies.nssa]
|
||||||
|
path = "../nssa"
|
||||||
|
|||||||
@ -1,8 +1,11 @@
|
|||||||
use actix_web::Error as HttpError;
|
use actix_web::Error as HttpError;
|
||||||
|
use base64::{engine::general_purpose, Engine};
|
||||||
|
use nssa;
|
||||||
use sequencer_core::config::AccountInitialData;
|
use sequencer_core::config::AccountInitialData;
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
|
||||||
use common::{
|
use common::{
|
||||||
|
block::HashableBlockData,
|
||||||
merkle_tree_public::TreeHashType,
|
merkle_tree_public::TreeHashType,
|
||||||
rpc_primitives::{
|
rpc_primitives::{
|
||||||
errors::RpcError,
|
errors::RpcError,
|
||||||
@ -17,14 +20,13 @@ use common::{
|
|||||||
|
|
||||||
use common::rpc_primitives::requests::{
|
use common::rpc_primitives::requests::{
|
||||||
GetBlockDataRequest, GetBlockDataResponse, GetGenesisIdRequest, GetGenesisIdResponse,
|
GetBlockDataRequest, GetBlockDataResponse, GetGenesisIdRequest, GetGenesisIdResponse,
|
||||||
GetLastBlockRequest, GetLastBlockResponse, HelloRequest, HelloResponse, RegisterAccountRequest,
|
GetLastBlockRequest, GetLastBlockResponse, HelloRequest, HelloResponse, SendTxRequest,
|
||||||
RegisterAccountResponse, SendTxRequest, SendTxResponse,
|
SendTxResponse,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{respond, types::err_rpc::RpcErr, JsonHandler};
|
use super::{respond, types::err_rpc::RpcErr, JsonHandler};
|
||||||
|
|
||||||
pub const HELLO: &str = "hello";
|
pub const HELLO: &str = "hello";
|
||||||
pub const REGISTER_ACCOUNT: &str = "register_account";
|
|
||||||
pub const SEND_TX: &str = "send_tx";
|
pub const SEND_TX: &str = "send_tx";
|
||||||
pub const GET_BLOCK: &str = "get_block";
|
pub const GET_BLOCK: &str = "get_block";
|
||||||
pub const GET_GENESIS: &str = "get_genesis";
|
pub const GET_GENESIS: &str = "get_genesis";
|
||||||
@ -66,29 +68,15 @@ impl JsonHandler {
|
|||||||
respond(helperstruct)
|
respond(helperstruct)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn process_register_account_request(&self, request: Request) -> Result<Value, RpcErr> {
|
|
||||||
let acc_req = RegisterAccountRequest::parse(Some(request.params))?;
|
|
||||||
|
|
||||||
{
|
|
||||||
let mut acc_store = self.sequencer_state.lock().await;
|
|
||||||
|
|
||||||
acc_store.register_account(acc_req.address);
|
|
||||||
}
|
|
||||||
|
|
||||||
let helperstruct = RegisterAccountResponse {
|
|
||||||
status: SUCCESS.to_string(),
|
|
||||||
};
|
|
||||||
|
|
||||||
respond(helperstruct)
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn process_send_tx(&self, request: Request) -> Result<Value, RpcErr> {
|
async fn process_send_tx(&self, request: Request) -> Result<Value, RpcErr> {
|
||||||
let send_tx_req = SendTxRequest::parse(Some(request.params))?;
|
let send_tx_req = SendTxRequest::parse(Some(request.params))?;
|
||||||
|
let tx = nssa::PublicTransaction::from_bytes(&send_tx_req.transaction)
|
||||||
|
.map_err(|e| RpcError::serialization_error(&e.to_string()))?;
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut state = self.sequencer_state.lock().await;
|
let mut state = self.sequencer_state.lock().await;
|
||||||
|
|
||||||
state.push_tx_into_mempool_pre_check(send_tx_req.transaction)?;
|
state.push_tx_into_mempool_pre_check(tx)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let helperstruct = SendTxResponse {
|
let helperstruct = SendTxResponse {
|
||||||
@ -110,7 +98,9 @@ impl JsonHandler {
|
|||||||
.get_block_at_id(get_block_req.block_id)?
|
.get_block_at_id(get_block_req.block_id)?
|
||||||
};
|
};
|
||||||
|
|
||||||
let helperstruct = GetBlockDataResponse { block };
|
let helperstruct = GetBlockDataResponse {
|
||||||
|
block: HashableBlockData::from(block).to_bytes(),
|
||||||
|
};
|
||||||
|
|
||||||
respond(helperstruct)
|
respond(helperstruct)
|
||||||
}
|
}
|
||||||
@ -164,13 +154,16 @@ impl JsonHandler {
|
|||||||
let get_account_req = GetAccountBalanceRequest::parse(Some(request.params))?;
|
let get_account_req = GetAccountBalanceRequest::parse(Some(request.params))?;
|
||||||
let address_bytes = hex::decode(get_account_req.address)
|
let address_bytes = hex::decode(get_account_req.address)
|
||||||
.map_err(|_| RpcError::invalid_params("invalid hex".to_string()))?;
|
.map_err(|_| RpcError::invalid_params("invalid hex".to_string()))?;
|
||||||
let address = address_bytes
|
let address = nssa::Address::new(
|
||||||
.try_into()
|
address_bytes
|
||||||
.map_err(|_| RpcError::invalid_params("invalid length".to_string()))?;
|
.try_into()
|
||||||
|
.map_err(|_| RpcError::invalid_params("invalid length".to_string()))?,
|
||||||
|
);
|
||||||
|
|
||||||
let balance = {
|
let balance = {
|
||||||
let state = self.sequencer_state.lock().await;
|
let state = self.sequencer_state.lock().await;
|
||||||
state.store.acc_store.get_account_balance(&address)
|
let account = state.store.state.get_account_by_address(&address);
|
||||||
|
account.balance
|
||||||
};
|
};
|
||||||
|
|
||||||
let helperstruct = GetAccountBalanceResponse { balance };
|
let helperstruct = GetAccountBalanceResponse { balance };
|
||||||
@ -190,16 +183,22 @@ impl JsonHandler {
|
|||||||
|
|
||||||
let transaction = {
|
let transaction = {
|
||||||
let state = self.sequencer_state.lock().await;
|
let state = self.sequencer_state.lock().await;
|
||||||
state.store.block_store.get_transaction_by_hash(hash)
|
state
|
||||||
|
.store
|
||||||
|
.block_store
|
||||||
|
.get_transaction_by_hash(hash)
|
||||||
|
.map(|tx| tx.to_bytes())
|
||||||
|
};
|
||||||
|
let base64_encoded = transaction.map(|tx| general_purpose::STANDARD.encode(tx));
|
||||||
|
let helperstruct = GetTransactionByHashResponse {
|
||||||
|
transaction: base64_encoded,
|
||||||
};
|
};
|
||||||
let helperstruct = GetTransactionByHashResponse { transaction };
|
|
||||||
respond(helperstruct)
|
respond(helperstruct)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn process_request_internal(&self, request: Request) -> Result<Value, RpcErr> {
|
pub async fn process_request_internal(&self, request: Request) -> Result<Value, RpcErr> {
|
||||||
match request.method.as_ref() {
|
match request.method.as_ref() {
|
||||||
HELLO => self.process_temp_hello(request).await,
|
HELLO => self.process_temp_hello(request).await,
|
||||||
REGISTER_ACCOUNT => self.process_register_account_request(request).await,
|
|
||||||
SEND_TX => self.process_send_tx(request).await,
|
SEND_TX => self.process_send_tx(request).await,
|
||||||
GET_BLOCK => self.process_get_block_data(request).await,
|
GET_BLOCK => self.process_get_block_data(request).await,
|
||||||
GET_GENESIS => self.process_get_genesis(request).await,
|
GET_GENESIS => self.process_get_genesis(request).await,
|
||||||
@ -217,10 +216,9 @@ mod tests {
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::{rpc_handler, JsonHandler};
|
use crate::{rpc_handler, JsonHandler};
|
||||||
use common::{
|
use base64::{engine::general_purpose, Engine};
|
||||||
rpc_primitives::RpcPollingConfig,
|
use common::rpc_primitives::RpcPollingConfig;
|
||||||
transaction::{SignaturePrivateKey, Transaction, TransactionBody},
|
|
||||||
};
|
|
||||||
use sequencer_core::{
|
use sequencer_core::{
|
||||||
config::{AccountInitialData, SequencerConfig},
|
config::{AccountInitialData, SequencerConfig},
|
||||||
SequencerCore,
|
SequencerCore,
|
||||||
@ -233,13 +231,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![
|
||||||
13, 150, 223, 204, 65, 64, 25, 56, 12, 157, 222, 12, 211, 220, 229, 170, 201, 15, 181,
|
27, 132, 197, 86, 123, 18, 100, 64, 153, 93, 62, 213, 170, 186, 5, 101, 215, 30, 24,
|
||||||
68, 59, 248, 113, 16, 135, 65, 174, 175, 222, 85, 42, 215,
|
52, 96, 72, 25, 255, 156, 23, 245, 233, 213, 221, 7, 143,
|
||||||
];
|
];
|
||||||
|
|
||||||
let acc2_addr = vec![
|
let acc2_addr = vec![
|
||||||
151, 72, 112, 233, 190, 141, 10, 192, 138, 168, 59, 63, 199, 167, 166, 134, 41, 29,
|
77, 75, 108, 209, 54, 16, 50, 202, 155, 210, 174, 185, 217, 0, 170, 77, 69, 217, 234,
|
||||||
135, 50, 80, 138, 186, 152, 179, 96, 128, 243, 156, 44, 243, 100,
|
216, 10, 201, 66, 51, 116, 196, 81, 167, 37, 77, 7, 102,
|
||||||
];
|
];
|
||||||
|
|
||||||
let initial_acc1 = AccountInitialData {
|
let initial_acc1 = AccountInitialData {
|
||||||
@ -266,31 +264,32 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn json_handler_for_tests() -> (JsonHandler, Vec<AccountInitialData>) {
|
fn components_for_tests() -> (
|
||||||
|
JsonHandler,
|
||||||
|
Vec<AccountInitialData>,
|
||||||
|
nssa::PublicTransaction,
|
||||||
|
) {
|
||||||
let config = sequencer_config_for_tests();
|
let config = sequencer_config_for_tests();
|
||||||
|
|
||||||
let mut sequencer_core = SequencerCore::start_from_config(config);
|
let mut sequencer_core = SequencerCore::start_from_config(config);
|
||||||
|
|
||||||
let initial_accounts = sequencer_core.sequencer_config.initial_accounts.clone();
|
let initial_accounts = sequencer_core.sequencer_config.initial_accounts.clone();
|
||||||
|
|
||||||
let tx_body = TransactionBody {
|
let signing_key = nssa::PrivateKey::try_new([1; 32]).unwrap();
|
||||||
tx_kind: common::transaction::TxKind::Shielded,
|
let balance_to_move = 10;
|
||||||
execution_input: Default::default(),
|
let tx = common::test_utils::create_transaction_native_token_transfer(
|
||||||
execution_output: Default::default(),
|
[
|
||||||
utxo_commitments_spent_hashes: Default::default(),
|
27, 132, 197, 86, 123, 18, 100, 64, 153, 93, 62, 213, 170, 186, 5, 101, 215, 30,
|
||||||
utxo_commitments_created_hashes: Default::default(),
|
24, 52, 96, 72, 25, 255, 156, 23, 245, 233, 213, 221, 7, 143,
|
||||||
nullifier_created_hashes: Default::default(),
|
],
|
||||||
execution_proof_private: Default::default(),
|
0,
|
||||||
encoded_data: Default::default(),
|
[2; 32],
|
||||||
ephemeral_pub_key: Default::default(),
|
balance_to_move,
|
||||||
commitment: Default::default(),
|
signing_key,
|
||||||
tweak: Default::default(),
|
);
|
||||||
secret_r: Default::default(),
|
|
||||||
sc_addr: Default::default(),
|
sequencer_core
|
||||||
};
|
.push_tx_into_mempool_pre_check(tx.clone())
|
||||||
let tx = Transaction::new(tx_body, SignaturePrivateKey::from_slice(&[1; 32]).unwrap());
|
.unwrap();
|
||||||
|
|
||||||
sequencer_core.push_tx_into_mempool_pre_check(tx).unwrap();
|
|
||||||
sequencer_core
|
sequencer_core
|
||||||
.produce_new_block_with_mempool_transactions()
|
.produce_new_block_with_mempool_transactions()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@ -303,6 +302,7 @@ mod tests {
|
|||||||
sequencer_state: sequencer_core,
|
sequencer_state: sequencer_core,
|
||||||
},
|
},
|
||||||
initial_accounts,
|
initial_accounts,
|
||||||
|
tx,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -329,7 +329,7 @@ mod tests {
|
|||||||
|
|
||||||
#[actix_web::test]
|
#[actix_web::test]
|
||||||
async fn test_get_account_balance_for_non_existent_account() {
|
async fn test_get_account_balance_for_non_existent_account() {
|
||||||
let (json_handler, _) = json_handler_for_tests();
|
let (json_handler, _, _) = components_for_tests();
|
||||||
let request = serde_json::json!({
|
let request = serde_json::json!({
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
"method": "get_account_balance",
|
"method": "get_account_balance",
|
||||||
@ -351,7 +351,7 @@ mod tests {
|
|||||||
|
|
||||||
#[actix_web::test]
|
#[actix_web::test]
|
||||||
async fn test_get_account_balance_for_invalid_hex() {
|
async fn test_get_account_balance_for_invalid_hex() {
|
||||||
let (json_handler, _) = json_handler_for_tests();
|
let (json_handler, _, _) = components_for_tests();
|
||||||
let request = serde_json::json!({
|
let request = serde_json::json!({
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
"method": "get_account_balance",
|
"method": "get_account_balance",
|
||||||
@ -374,7 +374,7 @@ mod tests {
|
|||||||
|
|
||||||
#[actix_web::test]
|
#[actix_web::test]
|
||||||
async fn test_get_account_balance_for_invalid_length() {
|
async fn test_get_account_balance_for_invalid_length() {
|
||||||
let (json_handler, _) = json_handler_for_tests();
|
let (json_handler, _, _) = components_for_tests();
|
||||||
let request = serde_json::json!({
|
let request = serde_json::json!({
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
"method": "get_account_balance",
|
"method": "get_account_balance",
|
||||||
@ -397,7 +397,7 @@ mod tests {
|
|||||||
|
|
||||||
#[actix_web::test]
|
#[actix_web::test]
|
||||||
async fn test_get_account_balance_for_existing_account() {
|
async fn test_get_account_balance_for_existing_account() {
|
||||||
let (json_handler, initial_accounts) = json_handler_for_tests();
|
let (json_handler, initial_accounts, _) = components_for_tests();
|
||||||
|
|
||||||
let acc1_addr = initial_accounts[0].addr.clone();
|
let acc1_addr = initial_accounts[0].addr.clone();
|
||||||
|
|
||||||
@ -411,7 +411,7 @@ mod tests {
|
|||||||
"id": 1,
|
"id": 1,
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
"result": {
|
"result": {
|
||||||
"balance": 10000
|
"balance": 10000 - 10
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -422,7 +422,7 @@ mod tests {
|
|||||||
|
|
||||||
#[actix_web::test]
|
#[actix_web::test]
|
||||||
async fn test_get_transaction_by_hash_for_non_existent_hash() {
|
async fn test_get_transaction_by_hash_for_non_existent_hash() {
|
||||||
let (json_handler, _) = json_handler_for_tests();
|
let (json_handler, _, _) = components_for_tests();
|
||||||
let request = serde_json::json!({
|
let request = serde_json::json!({
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
"method": "get_transaction_by_hash",
|
"method": "get_transaction_by_hash",
|
||||||
@ -444,7 +444,7 @@ mod tests {
|
|||||||
|
|
||||||
#[actix_web::test]
|
#[actix_web::test]
|
||||||
async fn test_get_transaction_by_hash_for_invalid_hex() {
|
async fn test_get_transaction_by_hash_for_invalid_hex() {
|
||||||
let (json_handler, _) = json_handler_for_tests();
|
let (json_handler, _, _) = components_for_tests();
|
||||||
let request = serde_json::json!({
|
let request = serde_json::json!({
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
"method": "get_transaction_by_hash",
|
"method": "get_transaction_by_hash",
|
||||||
@ -468,7 +468,7 @@ mod tests {
|
|||||||
|
|
||||||
#[actix_web::test]
|
#[actix_web::test]
|
||||||
async fn test_get_transaction_by_hash_for_invalid_length() {
|
async fn test_get_transaction_by_hash_for_invalid_length() {
|
||||||
let (json_handler, _) = json_handler_for_tests();
|
let (json_handler, _, _) = components_for_tests();
|
||||||
let request = serde_json::json!({
|
let request = serde_json::json!({
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
"method": "get_transaction_by_hash",
|
"method": "get_transaction_by_hash",
|
||||||
@ -492,11 +492,14 @@ mod tests {
|
|||||||
|
|
||||||
#[actix_web::test]
|
#[actix_web::test]
|
||||||
async fn test_get_transaction_by_hash_for_existing_transaction() {
|
async fn test_get_transaction_by_hash_for_existing_transaction() {
|
||||||
let (json_handler, _) = json_handler_for_tests();
|
let (json_handler, _, tx) = components_for_tests();
|
||||||
|
let tx_hash_hex = hex::encode(tx.hash());
|
||||||
|
let expected_base64_encoded = general_purpose::STANDARD.encode(tx.to_bytes());
|
||||||
|
|
||||||
let request = serde_json::json!({
|
let request = serde_json::json!({
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
"method": "get_transaction_by_hash",
|
"method": "get_transaction_by_hash",
|
||||||
"params": { "hash": "2c69b9639bcf8d58509204e18f1d5962029bf26840915f2bf2bb434501ad3c38"},
|
"params": { "hash": tx_hash_hex},
|
||||||
"id": 1
|
"id": 1
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -504,28 +507,9 @@ mod tests {
|
|||||||
"id": 1,
|
"id": 1,
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
"result": {
|
"result": {
|
||||||
"transaction": {
|
"transaction": expected_base64_encoded,
|
||||||
"body": {
|
|
||||||
"commitment": [],
|
|
||||||
"encoded_data": [],
|
|
||||||
"ephemeral_pub_key": [],
|
|
||||||
"execution_input": [],
|
|
||||||
"execution_output": [],
|
|
||||||
"execution_proof_private": "",
|
|
||||||
"nullifier_created_hashes": [],
|
|
||||||
"sc_addr": "",
|
|
||||||
"secret_r": vec![0; 32],
|
|
||||||
"tweak": "0".repeat(64),
|
|
||||||
"tx_kind": "Shielded",
|
|
||||||
"utxo_commitments_created_hashes": [],
|
|
||||||
"utxo_commitments_spent_hashes": [],
|
|
||||||
},
|
|
||||||
"public_key": "3056301006072A8648CE3D020106052B8104000A034200041B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F70BEAF8F588B541507FED6A642C5AB42DFDF8120A7F639DE5122D47A69A8E8D1",
|
|
||||||
"signature": "D75783642EA6E7D5E13AE8CCD3C2D3F82728C0A778A80C9F2976C739CD9F7F3F240B0532954D87761DE299A6CB9E6606295786BA5D0F5CACAB3F3626724528B1"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let response = call_rpc_handler_with_json(json_handler, request).await;
|
let response = call_rpc_handler_with_json(json_handler, request).await;
|
||||||
|
|
||||||
assert_eq!(response, expected_response);
|
assert_eq!(response, expected_response);
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
use std::{path::Path, sync::Arc};
|
use std::{path::Path, sync::Arc};
|
||||||
|
|
||||||
use common::block::Block;
|
use common::block::{Block, HashableBlockData};
|
||||||
use error::DbError;
|
use error::DbError;
|
||||||
use rocksdb::{
|
use rocksdb::{
|
||||||
BoundColumnFamily, ColumnFamilyDescriptor, DBWithThreadMode, MultiThreaded, Options,
|
BoundColumnFamily, ColumnFamilyDescriptor, DBWithThreadMode, MultiThreaded, Options,
|
||||||
@ -242,12 +242,7 @@ impl RocksDBIO {
|
|||||||
.put_cf(
|
.put_cf(
|
||||||
&cf_block,
|
&cf_block,
|
||||||
block.block_id.to_be_bytes(),
|
block.block_id.to_be_bytes(),
|
||||||
serde_json::to_vec(&block).map_err(|serr| {
|
HashableBlockData::from(block).to_bytes(),
|
||||||
DbError::serde_cast_message(
|
|
||||||
serr,
|
|
||||||
Some("Block Serialization failed".to_string()),
|
|
||||||
)
|
|
||||||
})?,
|
|
||||||
)
|
)
|
||||||
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
|
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -261,9 +256,7 @@ impl RocksDBIO {
|
|||||||
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
|
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
|
||||||
|
|
||||||
if let Some(data) = res {
|
if let Some(data) = res {
|
||||||
Ok(serde_json::from_slice::<Block>(&data).map_err(|serr| {
|
Ok(HashableBlockData::from_bytes(&data).into())
|
||||||
DbError::serde_cast_message(serr, Some("Block Deserialization failed".to_string()))
|
|
||||||
})?)
|
|
||||||
} else {
|
} else {
|
||||||
Err(DbError::db_interaction_error(
|
Err(DbError::db_interaction_error(
|
||||||
"Block on this id not found".to_string(),
|
"Block on this id not found".to_string(),
|
||||||
|
|||||||
@ -18,7 +18,7 @@ reqwest.workspace = true
|
|||||||
thiserror.workspace = true
|
thiserror.workspace = true
|
||||||
tokio.workspace = true
|
tokio.workspace = true
|
||||||
tempfile.workspace = true
|
tempfile.workspace = true
|
||||||
risc0-zkvm = { git = "https://github.com/risc0/risc0.git", branch = "release-2.3" }
|
risc0-zkvm = "2.3.1"
|
||||||
hex.workspace = true
|
hex.workspace = true
|
||||||
actix-rt.workspace = true
|
actix-rt.workspace = true
|
||||||
clap.workspace = true
|
clap.workspace = true
|
||||||
@ -35,6 +35,9 @@ path = "../utxo"
|
|||||||
[dependencies.zkvm]
|
[dependencies.zkvm]
|
||||||
path = "../zkvm"
|
path = "../zkvm"
|
||||||
|
|
||||||
|
[dependencies.nssa]
|
||||||
|
path = "../nssa"
|
||||||
|
|
||||||
[dependencies.common]
|
[dependencies.common]
|
||||||
path = "../common"
|
path = "../common"
|
||||||
|
|
||||||
|
|||||||
@ -1,8 +1,9 @@
|
|||||||
use accounts::account_core::{address::AccountAddress, Account};
|
use accounts::account_core::Account;
|
||||||
|
use nssa::Address;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
pub struct WalletAccountsStore {
|
pub struct WalletAccountsStore {
|
||||||
pub accounts: HashMap<AccountAddress, Account>,
|
pub accounts: HashMap<Address, Account>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WalletAccountsStore {
|
impl WalletAccountsStore {
|
||||||
@ -16,7 +17,7 @@ impl WalletAccountsStore {
|
|||||||
self.accounts.insert(account.address, account);
|
self.accounts.insert(account.address, account);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unregister_account(&mut self, account_addr: AccountAddress) {
|
pub fn unregister_account(&mut self, account_addr: Address) {
|
||||||
self.accounts.remove(&account_addr);
|
self.accounts.remove(&account_addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -82,7 +83,7 @@ mod tests {
|
|||||||
let mut store = WalletAccountsStore::new();
|
let mut store = WalletAccountsStore::new();
|
||||||
|
|
||||||
let account_addr: [u8; 32] = pad_to_32("nonexistent".to_string().as_bytes());
|
let account_addr: [u8; 32] = pad_to_32("nonexistent".to_string().as_bytes());
|
||||||
store.unregister_account(account_addr);
|
store.unregister_account(Address::new(account_addr));
|
||||||
|
|
||||||
assert!(store.accounts.is_empty());
|
assert!(store.accounts.is_empty());
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,9 @@
|
|||||||
use std::collections::{BTreeMap, HashMap};
|
use std::collections::{BTreeMap, HashMap};
|
||||||
|
|
||||||
use accounts::account_core::{address::AccountAddress, Account};
|
use accounts::account_core::Account;
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use common::merkle_tree_public::merkle_tree::UTXOCommitmentsMerkleTree;
|
use common::merkle_tree_public::merkle_tree::UTXOCommitmentsMerkleTree;
|
||||||
|
use nssa::Address;
|
||||||
use sc_core::public_context::PublicSCContext;
|
use sc_core::public_context::PublicSCContext;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
@ -37,7 +38,7 @@ impl From<AccMap> for HashMap<[u8; 32], Account> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct WalletChainStore {
|
pub struct WalletChainStore {
|
||||||
pub acc_map: HashMap<AccountAddress, Account>,
|
pub acc_map: HashMap<Address, Account>,
|
||||||
pub utxo_commitments_store: UTXOCommitmentsMerkleTree,
|
pub utxo_commitments_store: UTXOCommitmentsMerkleTree,
|
||||||
pub wallet_config: WalletConfig,
|
pub wallet_config: WalletConfig,
|
||||||
}
|
}
|
||||||
@ -54,7 +55,7 @@ impl WalletChainStore {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn produce_context(&self, caller: AccountAddress) -> PublicSCContext {
|
pub fn produce_context(&self, caller: Address) -> PublicSCContext {
|
||||||
let mut account_masks = BTreeMap::new();
|
let mut account_masks = BTreeMap::new();
|
||||||
|
|
||||||
for (acc_addr, acc) in &self.acc_map {
|
for (acc_addr, acc) in &self.acc_map {
|
||||||
@ -80,78 +81,12 @@ mod tests {
|
|||||||
|
|
||||||
fn create_initial_accounts() -> Vec<Account> {
|
fn create_initial_accounts() -> Vec<Account> {
|
||||||
let initial_acc1 = serde_json::from_str(r#"{
|
let initial_acc1 = serde_json::from_str(r#"{
|
||||||
"address": [
|
"address": "1b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f",
|
||||||
244,
|
|
||||||
55,
|
|
||||||
238,
|
|
||||||
205,
|
|
||||||
74,
|
|
||||||
115,
|
|
||||||
179,
|
|
||||||
192,
|
|
||||||
65,
|
|
||||||
186,
|
|
||||||
166,
|
|
||||||
169,
|
|
||||||
221,
|
|
||||||
45,
|
|
||||||
6,
|
|
||||||
57,
|
|
||||||
200,
|
|
||||||
65,
|
|
||||||
195,
|
|
||||||
70,
|
|
||||||
118,
|
|
||||||
252,
|
|
||||||
206,
|
|
||||||
100,
|
|
||||||
215,
|
|
||||||
250,
|
|
||||||
72,
|
|
||||||
230,
|
|
||||||
19,
|
|
||||||
71,
|
|
||||||
217,
|
|
||||||
249
|
|
||||||
],
|
|
||||||
"balance": 100,
|
"balance": 100,
|
||||||
"nonce": 0,
|
"nonce": 0,
|
||||||
"key_holder": {
|
"key_holder": {
|
||||||
"nullifer_public_key": "03A340BECA9FAAB444CED0140681D72EA1318B5C611704FEE017DA9836B17DB718",
|
"nullifer_public_key": "03A340BECA9FAAB444CED0140681D72EA1318B5C611704FEE017DA9836B17DB718",
|
||||||
"pub_account_signing_key": [
|
"pub_account_signing_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],
|
||||||
244,
|
|
||||||
88,
|
|
||||||
134,
|
|
||||||
61,
|
|
||||||
35,
|
|
||||||
209,
|
|
||||||
229,
|
|
||||||
101,
|
|
||||||
85,
|
|
||||||
35,
|
|
||||||
140,
|
|
||||||
140,
|
|
||||||
192,
|
|
||||||
226,
|
|
||||||
83,
|
|
||||||
83,
|
|
||||||
190,
|
|
||||||
189,
|
|
||||||
110,
|
|
||||||
8,
|
|
||||||
89,
|
|
||||||
127,
|
|
||||||
147,
|
|
||||||
142,
|
|
||||||
157,
|
|
||||||
204,
|
|
||||||
51,
|
|
||||||
109,
|
|
||||||
189,
|
|
||||||
92,
|
|
||||||
144,
|
|
||||||
68
|
|
||||||
],
|
|
||||||
"top_secret_key_holder": {
|
"top_secret_key_holder": {
|
||||||
"secret_spending_key": "7BC46784DB1BC67825D8F029436846712BFDF9B5D79EA3AB11D39A52B9B229D4"
|
"secret_spending_key": "7BC46784DB1BC67825D8F029436846712BFDF9B5D79EA3AB11D39A52B9B229D4"
|
||||||
},
|
},
|
||||||
@ -165,78 +100,12 @@ mod tests {
|
|||||||
}"#).unwrap();
|
}"#).unwrap();
|
||||||
|
|
||||||
let initial_acc2 = serde_json::from_str(r#"{
|
let initial_acc2 = serde_json::from_str(r#"{
|
||||||
"address": [
|
"address": "4d4b6cd1361032ca9bd2aeb9d900aa4d45d9ead80ac9423374c451a7254d0766",
|
||||||
72,
|
|
||||||
169,
|
|
||||||
70,
|
|
||||||
237,
|
|
||||||
1,
|
|
||||||
96,
|
|
||||||
35,
|
|
||||||
157,
|
|
||||||
25,
|
|
||||||
15,
|
|
||||||
83,
|
|
||||||
18,
|
|
||||||
52,
|
|
||||||
206,
|
|
||||||
202,
|
|
||||||
63,
|
|
||||||
48,
|
|
||||||
59,
|
|
||||||
173,
|
|
||||||
76,
|
|
||||||
78,
|
|
||||||
7,
|
|
||||||
254,
|
|
||||||
229,
|
|
||||||
28,
|
|
||||||
45,
|
|
||||||
194,
|
|
||||||
79,
|
|
||||||
6,
|
|
||||||
89,
|
|
||||||
58,
|
|
||||||
85
|
|
||||||
],
|
|
||||||
"balance": 200,
|
"balance": 200,
|
||||||
"nonce": 0,
|
"nonce": 0,
|
||||||
"key_holder": {
|
"key_holder": {
|
||||||
"nullifer_public_key": "02172F50274DE67C4087C344F5D58E11DF761D90285B095060E0994FAA6BCDE271",
|
"nullifer_public_key": "02172F50274DE67C4087C344F5D58E11DF761D90285B095060E0994FAA6BCDE271",
|
||||||
"pub_account_signing_key": [
|
"pub_account_signing_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],
|
||||||
136,
|
|
||||||
105,
|
|
||||||
9,
|
|
||||||
53,
|
|
||||||
180,
|
|
||||||
145,
|
|
||||||
64,
|
|
||||||
5,
|
|
||||||
235,
|
|
||||||
174,
|
|
||||||
62,
|
|
||||||
211,
|
|
||||||
206,
|
|
||||||
116,
|
|
||||||
185,
|
|
||||||
24,
|
|
||||||
214,
|
|
||||||
62,
|
|
||||||
244,
|
|
||||||
64,
|
|
||||||
224,
|
|
||||||
59,
|
|
||||||
120,
|
|
||||||
150,
|
|
||||||
30,
|
|
||||||
249,
|
|
||||||
160,
|
|
||||||
46,
|
|
||||||
189,
|
|
||||||
254,
|
|
||||||
47,
|
|
||||||
244
|
|
||||||
],
|
|
||||||
"top_secret_key_holder": {
|
"top_secret_key_holder": {
|
||||||
"secret_spending_key": "80A186737C8D38B4288A03F0F589957D9C040D79C19F3E0CC4BA80F8494E5179"
|
"secret_spending_key": "80A186737C8D38B4288A03F0F589957D9C040D79C19F3E0CC4BA80F8494E5179"
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
use std::{fs::File, io::BufReader, path::PathBuf, str::FromStr};
|
use std::{fs::File, io::BufReader, path::PathBuf, str::FromStr};
|
||||||
|
|
||||||
use accounts::account_core::Account;
|
use anyhow::Result;
|
||||||
use anyhow::{anyhow, Result};
|
use nssa::{address::HexString, Address};
|
||||||
|
|
||||||
use crate::{config::WalletConfig, HOME_DIR_ENV_VAR};
|
use crate::{config::WalletConfig, HOME_DIR_ENV_VAR};
|
||||||
|
|
||||||
@ -20,10 +20,8 @@ pub fn fetch_config() -> Result<WalletConfig> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//ToDo: Replace with structures conversion in future
|
//ToDo: Replace with structures conversion in future
|
||||||
pub fn produce_account_addr_from_hex(hex_str: String) -> Result<[u8; 32]> {
|
pub fn produce_account_addr_from_hex(hex_str: String) -> Result<Address> {
|
||||||
hex::decode(hex_str)?
|
Ok(HexString::try_from(hex_str.as_str())?.into())
|
||||||
.try_into()
|
|
||||||
.map_err(|_| anyhow!("Failed conversion to 32 bytes"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
///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`
|
||||||
|
|||||||
@ -1,19 +1,17 @@
|
|||||||
use std::{fs::File, io::Write, path::PathBuf, sync::Arc};
|
use std::{fs::File, io::Write, path::PathBuf, sync::Arc};
|
||||||
|
|
||||||
use common::{
|
use common::{
|
||||||
execution_input::PublicNativeTokenSend,
|
|
||||||
sequencer_client::{json::SendTxResponse, SequencerClient},
|
sequencer_client::{json::SendTxResponse, SequencerClient},
|
||||||
transaction::Transaction,
|
|
||||||
ExecutionFailureKind,
|
ExecutionFailureKind,
|
||||||
};
|
};
|
||||||
|
|
||||||
use accounts::account_core::{address::AccountAddress, Account};
|
use accounts::account_core::Account;
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use chain_storage::WalletChainStore;
|
use chain_storage::WalletChainStore;
|
||||||
use common::transaction::TransactionBody;
|
|
||||||
use config::WalletConfig;
|
use config::WalletConfig;
|
||||||
use log::info;
|
use log::info;
|
||||||
use sc_core::proofs_circuits::pedersen_commitment_vec;
|
use nssa::Address;
|
||||||
|
use tokio::sync::RwLock;
|
||||||
|
|
||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
|
|
||||||
@ -56,7 +54,7 @@ impl WalletCore {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn create_new_account(&mut self) -> AccountAddress {
|
pub async fn create_new_account(&mut self) -> Address {
|
||||||
let account = Account::new();
|
let account = Account::new();
|
||||||
account.log();
|
account.log();
|
||||||
|
|
||||||
@ -69,54 +67,38 @@ impl WalletCore {
|
|||||||
|
|
||||||
pub async fn send_public_native_token_transfer(
|
pub async fn send_public_native_token_transfer(
|
||||||
&self,
|
&self,
|
||||||
from: AccountAddress,
|
from: Address,
|
||||||
nonce: u64,
|
nonce: u128,
|
||||||
to: AccountAddress,
|
to: Address,
|
||||||
balance_to_move: u64,
|
balance_to_move: u128,
|
||||||
) -> Result<SendTxResponse, ExecutionFailureKind> {
|
) -> Result<SendTxResponse, ExecutionFailureKind> {
|
||||||
let public_context = self.storage.produce_context(from);
|
{
|
||||||
|
let read_guard = self.storage.read().await;
|
||||||
let (tweak, secret_r, commitment) = pedersen_commitment_vec(
|
|
||||||
//Will not panic, as public context is serializable
|
|
||||||
public_context.produce_u64_list_from_context().unwrap(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let sc_addr = hex::encode([0; 32]);
|
|
||||||
|
|
||||||
let tx: TransactionBody =
|
|
||||||
sc_core::transaction_payloads_tools::create_public_transaction_payload(
|
|
||||||
serde_json::to_vec(&PublicNativeTokenSend {
|
|
||||||
from,
|
|
||||||
nonce,
|
|
||||||
to,
|
|
||||||
balance_to_move,
|
|
||||||
})
|
|
||||||
.unwrap(),
|
|
||||||
commitment,
|
|
||||||
tweak,
|
|
||||||
secret_r,
|
|
||||||
sc_addr,
|
|
||||||
);
|
|
||||||
tx.log();
|
|
||||||
|
|
||||||
let account = self.storage.acc_map.get(&from);
|
|
||||||
|
|
||||||
if let Some(account) = account {
|
if let Some(account) = account {
|
||||||
let key_to_sign_transaction = account.key_holder.get_pub_account_signing_key();
|
let key_to_sign_transaction = account.key_holder.get_pub_account_signing_key();
|
||||||
|
|
||||||
let signed_transaction = Transaction::new(tx, key_to_sign_transaction);
|
if let Some(account) = account {
|
||||||
|
let addresses = vec![from, to];
|
||||||
|
let nonces = vec![nonce];
|
||||||
|
let program_id = nssa::program::Program::authenticated_transfer_program().id();
|
||||||
|
let message = nssa::public_transaction::Message::try_new(
|
||||||
|
program_id,
|
||||||
|
addresses,
|
||||||
|
nonces,
|
||||||
|
balance_to_move,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
Ok(self.sequencer_client.send_tx(signed_transaction).await?)
|
let signing_key = account.key_holder.get_pub_account_signing_key();
|
||||||
} else {
|
let witness_set =
|
||||||
Err(ExecutionFailureKind::AmountMismatchError)
|
nssa::public_transaction::WitnessSet::for_message(&message, &[signing_key]);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
///Helperfunction to increment nonces for all given accounts
|
let tx = nssa::PublicTransaction::new(message, witness_set);
|
||||||
fn increment_nonces(&mut self, accounts_to_increment_nonces: &[AccountAddress]) {
|
|
||||||
for acc_addr in accounts_to_increment_nonces {
|
Ok(self.sequencer_client.send_tx(tx).await?)
|
||||||
if let Some(acc) = self.storage.acc_map.get_mut(acc_addr) {
|
} else {
|
||||||
acc.nonce += 1;
|
Err(ExecutionFailureKind::AmountMismatchError)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -158,15 +140,15 @@ pub enum Command {
|
|||||||
///from - valid 32 byte hex string
|
///from - valid 32 byte hex string
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
from: String,
|
from: String,
|
||||||
///nonce - u64 integer
|
///nonce - u128 integer
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
nonce: u64,
|
nonce: u128,
|
||||||
///to - valid 32 byte hex string
|
///to - valid 32 byte hex string
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
to: String,
|
to: String,
|
||||||
///amount - amount of balance to move
|
///amount - amount of balance to move
|
||||||
#[arg(long)]
|
#[arg(long)]
|
||||||
amount: u64,
|
amount: u128,
|
||||||
},
|
},
|
||||||
///Dump accounts at destination
|
///Dump accounts at destination
|
||||||
DumpAccountsOnDisc {
|
DumpAccountsOnDisc {
|
||||||
|
|||||||
@ -12,7 +12,7 @@ serde.workspace = true
|
|||||||
thiserror.workspace = true
|
thiserror.workspace = true
|
||||||
rand.workspace = true
|
rand.workspace = true
|
||||||
|
|
||||||
risc0-zkvm = { git = "https://github.com/risc0/risc0.git", branch = "release-2.3" }
|
risc0-zkvm = "2.3.1"
|
||||||
test-methods = { path = "test_methods" }
|
test-methods = { path = "test_methods" }
|
||||||
|
|
||||||
[dependencies.accounts]
|
[dependencies.accounts]
|
||||||
@ -24,6 +24,9 @@ path = "../utxo"
|
|||||||
[dependencies.common]
|
[dependencies.common]
|
||||||
path = "../common"
|
path = "../common"
|
||||||
|
|
||||||
|
[dependencies.nssa]
|
||||||
|
path = "../nssa"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
cuda = ["risc0-zkvm/cuda"]
|
cuda = ["risc0-zkvm/cuda"]
|
||||||
default = []
|
default = []
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
use accounts::account_core::address::AccountAddress;
|
|
||||||
use common::ExecutionFailureKind;
|
use common::ExecutionFailureKind;
|
||||||
|
use nssa::Address;
|
||||||
use rand::{rngs::OsRng, RngCore};
|
use rand::{rngs::OsRng, RngCore};
|
||||||
use risc0_zkvm::{default_executor, default_prover, sha::Digest, ExecutorEnv, Receipt};
|
use risc0_zkvm::{default_executor, default_prover, sha::Digest, ExecutorEnv, Receipt};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
@ -35,7 +35,7 @@ pub fn gas_limits_check<INP: Serialize>(
|
|||||||
#[allow(clippy::result_large_err)]
|
#[allow(clippy::result_large_err)]
|
||||||
pub fn prove_mint_utxo(
|
pub fn prove_mint_utxo(
|
||||||
amount_to_mint: u128,
|
amount_to_mint: u128,
|
||||||
owner: AccountAddress,
|
owner: Address,
|
||||||
) -> Result<(UTXO, Receipt), ExecutionFailureKind> {
|
) -> Result<(UTXO, Receipt), ExecutionFailureKind> {
|
||||||
let mut builder = ExecutorEnv::builder();
|
let mut builder = ExecutorEnv::builder();
|
||||||
|
|
||||||
@ -63,7 +63,10 @@ pub fn prove_mint_utxo(
|
|||||||
.map_err(ExecutionFailureKind::prove_error)?
|
.map_err(ExecutionFailureKind::prove_error)?
|
||||||
.receipt;
|
.receipt;
|
||||||
|
|
||||||
let digest: UTXOPayload = receipt.journal.decode()?;
|
let digest: UTXOPayload = receipt
|
||||||
|
.journal
|
||||||
|
.decode()
|
||||||
|
.map_err(|e| ExecutionFailureKind::DecodeError(e.to_string()))?;
|
||||||
|
|
||||||
Ok((UTXO::create_utxo_from_payload(digest), receipt))
|
Ok((UTXO::create_utxo_from_payload(digest), receipt))
|
||||||
}
|
}
|
||||||
@ -71,8 +74,8 @@ pub fn prove_mint_utxo(
|
|||||||
#[allow(clippy::result_large_err)]
|
#[allow(clippy::result_large_err)]
|
||||||
pub fn prove_send_utxo(
|
pub fn prove_send_utxo(
|
||||||
spent_utxo: UTXO,
|
spent_utxo: UTXO,
|
||||||
owners_parts: Vec<(u128, AccountAddress)>,
|
owners_parts: Vec<(u128, Address)>,
|
||||||
) -> Result<(Vec<(UTXO, AccountAddress)>, Receipt), ExecutionFailureKind> {
|
) -> Result<(Vec<(UTXO, Address)>, Receipt), ExecutionFailureKind> {
|
||||||
let cumulative_spent = owners_parts.iter().fold(0, |acc, item| acc + item.0);
|
let cumulative_spent = owners_parts.iter().fold(0, |acc, item| acc + item.0);
|
||||||
|
|
||||||
if cumulative_spent != spent_utxo.amount {
|
if cumulative_spent != spent_utxo.amount {
|
||||||
@ -110,7 +113,10 @@ pub fn prove_send_utxo(
|
|||||||
.map_err(ExecutionFailureKind::prove_error)?
|
.map_err(ExecutionFailureKind::prove_error)?
|
||||||
.receipt;
|
.receipt;
|
||||||
|
|
||||||
let digest: Vec<(UTXOPayload, AccountAddress)> = receipt.journal.decode()?;
|
let digest: Vec<(UTXOPayload, Address)> = receipt
|
||||||
|
.journal
|
||||||
|
.decode()
|
||||||
|
.map_err(|e| ExecutionFailureKind::DecodeError(e.to_string()))?;
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
digest
|
digest
|
||||||
@ -125,7 +131,7 @@ pub fn prove_send_utxo(
|
|||||||
pub fn prove_send_utxo_multiple_assets_one_receiver(
|
pub fn prove_send_utxo_multiple_assets_one_receiver(
|
||||||
spent_utxos: Vec<UTXO>,
|
spent_utxos: Vec<UTXO>,
|
||||||
number_to_send: usize,
|
number_to_send: usize,
|
||||||
receiver: AccountAddress,
|
receiver: Address,
|
||||||
) -> Result<(Vec<UTXO>, Vec<UTXO>, Receipt), ExecutionFailureKind> {
|
) -> Result<(Vec<UTXO>, Vec<UTXO>, Receipt), ExecutionFailureKind> {
|
||||||
if number_to_send > spent_utxos.len() {
|
if number_to_send > spent_utxos.len() {
|
||||||
return Err(ExecutionFailureKind::AmountMismatchError);
|
return Err(ExecutionFailureKind::AmountMismatchError);
|
||||||
@ -158,7 +164,10 @@ pub fn prove_send_utxo_multiple_assets_one_receiver(
|
|||||||
.map_err(ExecutionFailureKind::prove_error)?
|
.map_err(ExecutionFailureKind::prove_error)?
|
||||||
.receipt;
|
.receipt;
|
||||||
|
|
||||||
let digest: (Vec<UTXOPayload>, Vec<UTXOPayload>) = receipt.journal.decode()?;
|
let digest: (Vec<UTXOPayload>, Vec<UTXOPayload>) = receipt
|
||||||
|
.journal
|
||||||
|
.decode()
|
||||||
|
.map_err(|e| ExecutionFailureKind::DecodeError(e.to_string()))?;
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
digest
|
digest
|
||||||
@ -177,17 +186,17 @@ pub fn prove_send_utxo_multiple_assets_one_receiver(
|
|||||||
|
|
||||||
#[allow(clippy::result_large_err)]
|
#[allow(clippy::result_large_err)]
|
||||||
pub fn prove_send_utxo_shielded(
|
pub fn prove_send_utxo_shielded(
|
||||||
owner: AccountAddress,
|
owner: Address,
|
||||||
amount: u128,
|
amount: u128,
|
||||||
owners_parts: Vec<(u128, AccountAddress)>,
|
owners_parts: Vec<(u128, Address)>,
|
||||||
) -> Result<(Vec<(UTXO, AccountAddress)>, Receipt), ExecutionFailureKind> {
|
) -> Result<(Vec<(UTXO, Address)>, Receipt), ExecutionFailureKind> {
|
||||||
let cumulative_spent = owners_parts.iter().fold(0, |acc, item| acc + item.0);
|
let cumulative_spent = owners_parts.iter().fold(0, |acc, item| acc + item.0);
|
||||||
|
|
||||||
if cumulative_spent != amount {
|
if cumulative_spent != amount {
|
||||||
return Err(ExecutionFailureKind::AmountMismatchError);
|
return Err(ExecutionFailureKind::AmountMismatchError);
|
||||||
}
|
}
|
||||||
|
|
||||||
let temp_utxo_to_spend = UTXO::new(owner, vec![], amount, true);
|
let temp_utxo_to_spend = UTXO::new(*owner.value(), vec![], amount, true);
|
||||||
let utxo_payload = temp_utxo_to_spend.into_payload();
|
let utxo_payload = temp_utxo_to_spend.into_payload();
|
||||||
|
|
||||||
let mut builder = ExecutorEnv::builder();
|
let mut builder = ExecutorEnv::builder();
|
||||||
@ -220,7 +229,10 @@ pub fn prove_send_utxo_shielded(
|
|||||||
.map_err(ExecutionFailureKind::prove_error)?
|
.map_err(ExecutionFailureKind::prove_error)?
|
||||||
.receipt;
|
.receipt;
|
||||||
|
|
||||||
let digest: Vec<(UTXOPayload, AccountAddress)> = receipt.journal.decode()?;
|
let digest: Vec<(UTXOPayload, Address)> = receipt
|
||||||
|
.journal
|
||||||
|
.decode()
|
||||||
|
.map_err(|e| ExecutionFailureKind::DecodeError(e.to_string()))?;
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
digest
|
digest
|
||||||
@ -234,8 +246,8 @@ pub fn prove_send_utxo_shielded(
|
|||||||
#[allow(clippy::result_large_err)]
|
#[allow(clippy::result_large_err)]
|
||||||
pub fn prove_send_utxo_deshielded(
|
pub fn prove_send_utxo_deshielded(
|
||||||
spent_utxo: UTXO,
|
spent_utxo: UTXO,
|
||||||
owners_parts: Vec<(u128, AccountAddress)>,
|
owners_parts: Vec<(u128, Address)>,
|
||||||
) -> Result<(Vec<(u128, AccountAddress)>, Receipt), ExecutionFailureKind> {
|
) -> Result<(Vec<(u128, Address)>, Receipt), ExecutionFailureKind> {
|
||||||
let cumulative_spent = owners_parts.iter().fold(0, |acc, item| acc + item.0);
|
let cumulative_spent = owners_parts.iter().fold(0, |acc, item| acc + item.0);
|
||||||
|
|
||||||
if cumulative_spent != spent_utxo.amount {
|
if cumulative_spent != spent_utxo.amount {
|
||||||
@ -273,7 +285,10 @@ pub fn prove_send_utxo_deshielded(
|
|||||||
.map_err(ExecutionFailureKind::prove_error)?
|
.map_err(ExecutionFailureKind::prove_error)?
|
||||||
.receipt;
|
.receipt;
|
||||||
|
|
||||||
let digest: Vec<(UTXOPayload, AccountAddress)> = receipt.journal.decode()?;
|
let digest: Vec<(UTXOPayload, Address)> = receipt
|
||||||
|
.journal
|
||||||
|
.decode()
|
||||||
|
.map_err(|e| ExecutionFailureKind::DecodeError(e.to_string()))?;
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
digest
|
digest
|
||||||
@ -288,7 +303,7 @@ pub fn prove_send_utxo_deshielded(
|
|||||||
pub fn prove_mint_utxo_multiple_assets(
|
pub fn prove_mint_utxo_multiple_assets(
|
||||||
amount_to_mint: u128,
|
amount_to_mint: u128,
|
||||||
number_of_assets: usize,
|
number_of_assets: usize,
|
||||||
owner: AccountAddress,
|
owner: Address,
|
||||||
) -> Result<(Vec<UTXO>, Receipt), ExecutionFailureKind> {
|
) -> Result<(Vec<UTXO>, Receipt), ExecutionFailureKind> {
|
||||||
let mut builder = ExecutorEnv::builder();
|
let mut builder = ExecutorEnv::builder();
|
||||||
|
|
||||||
@ -313,7 +328,10 @@ pub fn prove_mint_utxo_multiple_assets(
|
|||||||
.map_err(ExecutionFailureKind::prove_error)?
|
.map_err(ExecutionFailureKind::prove_error)?
|
||||||
.receipt;
|
.receipt;
|
||||||
|
|
||||||
let digest: Vec<UTXOPayload> = receipt.journal.decode()?;
|
let digest: Vec<UTXOPayload> = receipt
|
||||||
|
.journal
|
||||||
|
.decode()
|
||||||
|
.map_err(|e| ExecutionFailureKind::DecodeError(e.to_string()))?;
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
digest
|
digest
|
||||||
@ -326,7 +344,7 @@ pub fn prove_mint_utxo_multiple_assets(
|
|||||||
|
|
||||||
pub fn execute_mint_utxo(
|
pub fn execute_mint_utxo(
|
||||||
amount_to_mint: u128,
|
amount_to_mint: u128,
|
||||||
owner: AccountAddress,
|
owner: Address,
|
||||||
randomness: [u8; 32],
|
randomness: [u8; 32],
|
||||||
) -> anyhow::Result<UTXO> {
|
) -> anyhow::Result<UTXO> {
|
||||||
let mut builder = ExecutorEnv::builder();
|
let mut builder = ExecutorEnv::builder();
|
||||||
@ -348,8 +366,8 @@ pub fn execute_mint_utxo(
|
|||||||
|
|
||||||
pub fn execute_send_utxo(
|
pub fn execute_send_utxo(
|
||||||
spent_utxo: UTXO,
|
spent_utxo: UTXO,
|
||||||
owners_parts: Vec<(u128, AccountAddress)>,
|
owners_parts: Vec<(u128, Address)>,
|
||||||
) -> anyhow::Result<(UTXO, Vec<(UTXO, AccountAddress)>)> {
|
) -> anyhow::Result<(UTXO, Vec<(UTXO, Address)>)> {
|
||||||
let mut builder = ExecutorEnv::builder();
|
let mut builder = ExecutorEnv::builder();
|
||||||
|
|
||||||
let utxo_payload = spent_utxo.into_payload();
|
let utxo_payload = spent_utxo.into_payload();
|
||||||
@ -372,7 +390,7 @@ pub fn execute_send_utxo(
|
|||||||
|
|
||||||
let receipt = executor.execute(env, test_methods::SEND_UTXO_ELF)?;
|
let receipt = executor.execute(env, test_methods::SEND_UTXO_ELF)?;
|
||||||
|
|
||||||
let digest: (UTXOPayload, Vec<(UTXOPayload, AccountAddress)>) = receipt.journal.decode()?;
|
let digest: (UTXOPayload, Vec<(UTXOPayload, Address)>) = receipt.journal.decode()?;
|
||||||
|
|
||||||
Ok((
|
Ok((
|
||||||
UTXO::create_utxo_from_payload(digest.0),
|
UTXO::create_utxo_from_payload(digest.0),
|
||||||
@ -554,29 +572,29 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_execute_mint_utxo() {
|
fn test_execute_mint_utxo() {
|
||||||
let owner = AccountAddress::default();
|
let owner = Address::default();
|
||||||
let amount = 123456789;
|
let amount = 123456789;
|
||||||
let mut randomness = [0u8; 32];
|
let mut randomness = [0u8; 32];
|
||||||
OsRng.fill_bytes(&mut randomness);
|
OsRng.fill_bytes(&mut randomness);
|
||||||
|
|
||||||
let utxo_exec = execute_mint_utxo(amount, owner, randomness).expect("execution failed");
|
let utxo_exec = execute_mint_utxo(amount, owner, randomness).expect("execution failed");
|
||||||
assert_eq!(utxo_exec.amount, amount);
|
assert_eq!(utxo_exec.amount, amount);
|
||||||
assert_eq!(utxo_exec.owner, owner);
|
assert_eq!(utxo_exec.owner, *owner.value());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_prove_mint_utxo() {
|
fn test_prove_mint_utxo() {
|
||||||
let owner = AccountAddress::default();
|
let owner = Address::default();
|
||||||
let amount = 123456789;
|
let amount = 123456789;
|
||||||
|
|
||||||
let (utxo, _) = prove_mint_utxo(amount, owner).expect("proof failed");
|
let (utxo, _) = prove_mint_utxo(amount, owner).expect("proof failed");
|
||||||
assert_eq!(utxo.amount, amount);
|
assert_eq!(utxo.amount, amount);
|
||||||
assert_eq!(utxo.owner, owner);
|
assert_eq!(utxo.owner, *owner.value());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_prove_send_utxo() {
|
fn test_prove_send_utxo() {
|
||||||
let owner = AccountAddress::default();
|
let owner = Address::default();
|
||||||
let amount = 100;
|
let amount = 100;
|
||||||
let (input_utxo, _) = prove_mint_utxo(amount, owner).expect("mint failed");
|
let (input_utxo, _) = prove_mint_utxo(amount, owner).expect("mint failed");
|
||||||
|
|
||||||
@ -590,7 +608,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_prove_send_utxo_deshielded() {
|
fn test_prove_send_utxo_deshielded() {
|
||||||
let owner = AccountAddress::default();
|
let owner = Address::default();
|
||||||
let amount = 100;
|
let amount = 100;
|
||||||
let (utxo, _) = prove_mint_utxo(amount, owner).unwrap();
|
let (utxo, _) = prove_mint_utxo(amount, owner).unwrap();
|
||||||
let parts = vec![(60, owner), (40, owner)];
|
let parts = vec![(60, owner), (40, owner)];
|
||||||
@ -604,7 +622,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_prove_send_utxo_shielded() {
|
fn test_prove_send_utxo_shielded() {
|
||||||
let owner = AccountAddress::default();
|
let owner = Address::default();
|
||||||
let amount = 100;
|
let amount = 100;
|
||||||
let parts = vec![(60, owner), (40, owner)];
|
let parts = vec![(60, owner), (40, owner)];
|
||||||
|
|
||||||
@ -617,8 +635,8 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_prove_send_utxo_multiple_assets_one_receiver() {
|
fn test_prove_send_utxo_multiple_assets_one_receiver() {
|
||||||
let owner = AccountAddress::default();
|
let owner = Address::default();
|
||||||
let receiver = AccountAddress::default();
|
let receiver = Address::default();
|
||||||
|
|
||||||
let utxos = vec![
|
let utxos = vec![
|
||||||
prove_mint_utxo(100, owner).unwrap().0,
|
prove_mint_utxo(100, owner).unwrap().0,
|
||||||
|
|||||||
@ -4,7 +4,7 @@ version = "0.1.0"
|
|||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
risc0-build = { git = "https://github.com/risc0/risc0.git", branch = "release-2.3" }
|
risc0-build = { version = "2.3.1" }
|
||||||
|
|
||||||
[package.metadata.risc0]
|
[package.metadata.risc0]
|
||||||
methods = ["guest"]
|
methods = ["guest"]
|
||||||
|
|||||||
449
zkvm/test_methods/guest/Cargo.lock
generated
449
zkvm/test_methods/guest/Cargo.lock
generated
@ -14,6 +14,12 @@ dependencies = [
|
|||||||
"zerocopy",
|
"zerocopy",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "allocator-api2"
|
||||||
|
version = "0.2.21"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyhow"
|
name = "anyhow"
|
||||||
version = "1.0.93"
|
version = "1.0.93"
|
||||||
@ -22,21 +28,24 @@ checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ark-bn254"
|
name = "ark-bn254"
|
||||||
version = "0.4.0"
|
version = "0.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a22f4561524cd949590d78d7d4c5df8f592430d221f7f3c9497bbafd8972120f"
|
checksum = "d69eab57e8d2663efa5c63135b2af4f396d66424f88954c21104125ab6b3e6bc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ark-ec",
|
"ark-ec",
|
||||||
"ark-ff",
|
"ark-ff",
|
||||||
|
"ark-r1cs-std",
|
||||||
"ark-std",
|
"ark-std",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ark-crypto-primitives"
|
name = "ark-crypto-primitives"
|
||||||
version = "0.4.0"
|
version = "0.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1f3a13b34da09176a8baba701233fdffbaa7c1b1192ce031a3da4e55ce1f1a56"
|
checksum = "1e0c292754729c8a190e50414fd1a37093c786c709899f29c9f7daccecfa855e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"ahash",
|
||||||
|
"ark-crypto-primitives-macros",
|
||||||
"ark-ec",
|
"ark-ec",
|
||||||
"ark-ff",
|
"ark-ff",
|
||||||
"ark-relations",
|
"ark-relations",
|
||||||
@ -46,74 +55,91 @@ dependencies = [
|
|||||||
"blake2",
|
"blake2",
|
||||||
"derivative",
|
"derivative",
|
||||||
"digest",
|
"digest",
|
||||||
|
"fnv",
|
||||||
|
"merlin",
|
||||||
"sha2",
|
"sha2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ark-ec"
|
name = "ark-crypto-primitives-macros"
|
||||||
version = "0.4.2"
|
version = "0.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba"
|
checksum = "e7e89fe77d1f0f4fe5b96dfc940923d88d17b6a773808124f21e764dfb063c6a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.87",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ark-ec"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "43d68f2d516162846c1238e755a7c4d131b892b70cc70c471a8e3ca3ed818fce"
|
||||||
|
dependencies = [
|
||||||
|
"ahash",
|
||||||
"ark-ff",
|
"ark-ff",
|
||||||
"ark-poly",
|
"ark-poly",
|
||||||
"ark-serialize",
|
"ark-serialize",
|
||||||
"ark-std",
|
"ark-std",
|
||||||
"derivative",
|
"educe",
|
||||||
"hashbrown 0.13.2",
|
"fnv",
|
||||||
|
"hashbrown",
|
||||||
"itertools",
|
"itertools",
|
||||||
|
"num-bigint",
|
||||||
|
"num-integer",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"zeroize",
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ark-ff"
|
name = "ark-ff"
|
||||||
version = "0.4.2"
|
version = "0.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba"
|
checksum = "a177aba0ed1e0fbb62aa9f6d0502e9b46dad8c2eab04c14258a1212d2557ea70"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ark-ff-asm",
|
"ark-ff-asm",
|
||||||
"ark-ff-macros",
|
"ark-ff-macros",
|
||||||
"ark-serialize",
|
"ark-serialize",
|
||||||
"ark-std",
|
"ark-std",
|
||||||
"derivative",
|
"arrayvec",
|
||||||
"digest",
|
"digest",
|
||||||
|
"educe",
|
||||||
"itertools",
|
"itertools",
|
||||||
"num-bigint",
|
"num-bigint",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"paste",
|
"paste",
|
||||||
"rustc_version",
|
|
||||||
"zeroize",
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ark-ff-asm"
|
name = "ark-ff-asm"
|
||||||
version = "0.4.2"
|
version = "0.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348"
|
checksum = "62945a2f7e6de02a31fe400aa489f0e0f5b2502e69f95f853adb82a96c7a6b60"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"quote",
|
"quote",
|
||||||
"syn 1.0.109",
|
"syn 2.0.87",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ark-ff-macros"
|
name = "ark-ff-macros"
|
||||||
version = "0.4.2"
|
version = "0.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565"
|
checksum = "09be120733ee33f7693ceaa202ca41accd5653b779563608f1234f78ae07c4b3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"num-bigint",
|
"num-bigint",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 1.0.109",
|
"syn 2.0.87",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ark-groth16"
|
name = "ark-groth16"
|
||||||
version = "0.4.0"
|
version = "0.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "20ceafa83848c3e390f1cbf124bc3193b3e639b3f02009e0e290809a501b95fc"
|
checksum = "88f1d0f3a534bb54188b8dcc104307db6c56cdae574ddc3212aec0625740fc7e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ark-crypto-primitives",
|
"ark-crypto-primitives",
|
||||||
"ark-ec",
|
"ark-ec",
|
||||||
@ -126,22 +152,41 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ark-poly"
|
name = "ark-poly"
|
||||||
version = "0.4.2"
|
version = "0.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d320bfc44ee185d899ccbadfa8bc31aab923ce1558716e1997a1e74057fe86bf"
|
checksum = "579305839da207f02b89cd1679e50e67b4331e2f9294a57693e5051b7703fe27"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"ahash",
|
||||||
"ark-ff",
|
"ark-ff",
|
||||||
"ark-serialize",
|
"ark-serialize",
|
||||||
"ark-std",
|
"ark-std",
|
||||||
"derivative",
|
"educe",
|
||||||
"hashbrown 0.13.2",
|
"fnv",
|
||||||
|
"hashbrown",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ark-r1cs-std"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "941551ef1df4c7a401de7068758db6503598e6f01850bdb2cfdb614a1f9dbea1"
|
||||||
|
dependencies = [
|
||||||
|
"ark-ec",
|
||||||
|
"ark-ff",
|
||||||
|
"ark-relations",
|
||||||
|
"ark-std",
|
||||||
|
"educe",
|
||||||
|
"num-bigint",
|
||||||
|
"num-integer",
|
||||||
|
"num-traits",
|
||||||
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ark-relations"
|
name = "ark-relations"
|
||||||
version = "0.4.0"
|
version = "0.5.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "00796b6efc05a3f48225e59cb6a2cda78881e7c390872d5786aaf112f31fb4f0"
|
checksum = "ec46ddc93e7af44bcab5230937635b06fb5744464dd6a7e7b083e80ebd274384"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ark-ff",
|
"ark-ff",
|
||||||
"ark-std",
|
"ark-std",
|
||||||
@ -151,32 +196,33 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ark-serialize"
|
name = "ark-serialize"
|
||||||
version = "0.4.2"
|
version = "0.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5"
|
checksum = "3f4d068aaf107ebcd7dfb52bc748f8030e0fc930ac8e360146ca54c1203088f7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ark-serialize-derive",
|
"ark-serialize-derive",
|
||||||
"ark-std",
|
"ark-std",
|
||||||
|
"arrayvec",
|
||||||
"digest",
|
"digest",
|
||||||
"num-bigint",
|
"num-bigint",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ark-serialize-derive"
|
name = "ark-serialize-derive"
|
||||||
version = "0.4.2"
|
version = "0.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea"
|
checksum = "213888f660fddcca0d257e88e54ac05bca01885f258ccdf695bafd77031bb69d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 1.0.109",
|
"syn 2.0.87",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ark-snark"
|
name = "ark-snark"
|
||||||
version = "0.4.0"
|
version = "0.5.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "84d3cc6833a335bb8a600241889ead68ee89a3cf8448081fb7694c0fe503da63"
|
checksum = "d368e2848c2d4c129ce7679a7d0d2d612b6a274d3ea6a13bad4445d61b381b88"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ark-ff",
|
"ark-ff",
|
||||||
"ark-relations",
|
"ark-relations",
|
||||||
@ -186,20 +232,32 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ark-std"
|
name = "ark-std"
|
||||||
version = "0.4.0"
|
version = "0.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185"
|
checksum = "246a225cc6131e9ee4f24619af0f19d67761fff15d7ccc22e42b80846e69449a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"rand",
|
"rand",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "arrayvec"
|
||||||
|
version = "0.7.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "autocfg"
|
name = "autocfg"
|
||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bit-vec"
|
||||||
|
version = "0.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "1.3.2"
|
version = "1.3.2"
|
||||||
@ -261,18 +319,18 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytemuck"
|
name = "bytemuck"
|
||||||
version = "1.19.0"
|
version = "1.23.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8334215b81e418a0a7bdb8ef0849474f40bb10c8b71f1c4ed315cff49f32494d"
|
checksum = "5c76a5792e44e4abe34d3abf15636779261d45a7450612059293d1d2cfc63422"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytemuck_derive",
|
"bytemuck_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytemuck_derive"
|
name = "bytemuck_derive"
|
||||||
version = "1.8.0"
|
version = "1.8.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bcfcc3cd946cb52f0bbfdbbcfa2f4e24f75ebb6c0e1002f7c25904fada18b9ec"
|
checksum = "3fa76293b4f7bb636ab88fd78228235b5248b4d05cc589aed610f954af5d7c7a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@ -297,6 +355,15 @@ version = "0.2.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
|
checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cobs"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1"
|
||||||
|
dependencies = [
|
||||||
|
"thiserror",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "const-oid"
|
name = "const-oid"
|
||||||
version = "0.9.6"
|
version = "0.9.6"
|
||||||
@ -360,6 +427,27 @@ dependencies = [
|
|||||||
"syn 1.0.109",
|
"syn 1.0.109",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "derive_more"
|
||||||
|
version = "2.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678"
|
||||||
|
dependencies = [
|
||||||
|
"derive_more-impl",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "derive_more-impl"
|
||||||
|
version = "2.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.87",
|
||||||
|
"unicode-xid",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "digest"
|
name = "digest"
|
||||||
version = "0.10.7"
|
version = "0.10.7"
|
||||||
@ -378,6 +466,18 @@ version = "1.2.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2"
|
checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "educe"
|
||||||
|
version = "0.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1d7bc049e1bd8cdeb31b68bbd586a9464ecf9f3944af3958a7a9d0f8b9799417"
|
||||||
|
dependencies = [
|
||||||
|
"enum-ordinalize",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.87",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "either"
|
name = "either"
|
||||||
version = "1.13.0"
|
version = "1.13.0"
|
||||||
@ -390,12 +490,50 @@ version = "0.7.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4445909572dbd556c457c849c4ca58623d84b27c8fff1e74b0b4227d8b90d17b"
|
checksum = "4445909572dbd556c457c849c4ca58623d84b27c8fff1e74b0b4227d8b90d17b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "embedded-io"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "embedded-io"
|
||||||
|
version = "0.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "enum-ordinalize"
|
||||||
|
version = "4.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fea0dcfa4e54eeb516fe454635a95753ddd39acda650ce703031c6973e315dd5"
|
||||||
|
dependencies = [
|
||||||
|
"enum-ordinalize-derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "enum-ordinalize-derive"
|
||||||
|
version = "4.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0d28318a75d4aead5c4db25382e8ef717932d0346600cacae6357eb5941bc5ff"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.87",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "equivalent"
|
name = "equivalent"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fnv"
|
||||||
|
version = "1.0.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "foreign-types"
|
name = "foreign-types"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
@ -441,16 +579,19 @@ checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"libc",
|
"libc",
|
||||||
"wasi",
|
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "getrandom"
|
||||||
version = "0.13.2"
|
version = "0.3.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e"
|
checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ahash",
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"r-efi",
|
||||||
|
"wasi 0.14.2+wasi-0.2.4",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -458,6 +599,9 @@ name = "hashbrown"
|
|||||||
version = "0.15.1"
|
version = "0.15.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3"
|
checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3"
|
||||||
|
dependencies = [
|
||||||
|
"allocator-api2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hex"
|
name = "hex"
|
||||||
@ -471,6 +615,12 @@ version = "0.4.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46"
|
checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "include_bytes_aligned"
|
||||||
|
version = "0.1.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4ee796ad498c8d9a1d68e477df8f754ed784ef875de1414ebdaf169f70a6a784"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "2.6.0"
|
version = "2.6.0"
|
||||||
@ -478,14 +628,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da"
|
checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"equivalent",
|
"equivalent",
|
||||||
"hashbrown 0.15.1",
|
"hashbrown",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itertools"
|
name = "itertools"
|
||||||
version = "0.10.5"
|
version = "0.13.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
|
checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"either",
|
"either",
|
||||||
]
|
]
|
||||||
@ -496,6 +646,24 @@ version = "1.0.14"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674"
|
checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "keccak"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654"
|
||||||
|
dependencies = [
|
||||||
|
"cpufeatures",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lazy_static"
|
||||||
|
version = "1.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||||
|
dependencies = [
|
||||||
|
"spin",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.162"
|
version = "0.2.162"
|
||||||
@ -529,6 +697,18 @@ version = "2.7.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "merlin"
|
||||||
|
version = "3.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "58c38e2799fc0978b65dfff8023ec7843e2330bb462f19198840b34b6582397d"
|
||||||
|
dependencies = [
|
||||||
|
"byteorder",
|
||||||
|
"keccak",
|
||||||
|
"rand_core",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "metal"
|
name = "metal"
|
||||||
version = "0.29.0"
|
version = "0.29.0"
|
||||||
@ -544,6 +724,12 @@ dependencies = [
|
|||||||
"paste",
|
"paste",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "no_std_strings"
|
||||||
|
version = "0.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a5b0c77c1b780822bc749a33e39aeb2c07584ab93332303babeabb645298a76e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-bigint"
|
name = "num-bigint"
|
||||||
version = "0.4.6"
|
version = "0.4.6"
|
||||||
@ -599,6 +785,18 @@ version = "0.2.15"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff"
|
checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "postcard"
|
||||||
|
version = "1.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24"
|
||||||
|
dependencies = [
|
||||||
|
"cobs",
|
||||||
|
"embedded-io 0.4.0",
|
||||||
|
"embedded-io 0.6.1",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ppv-lite86"
|
name = "ppv-lite86"
|
||||||
version = "0.2.20"
|
version = "0.2.20"
|
||||||
@ -635,6 +833,12 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "r-efi"
|
||||||
|
version = "5.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rand"
|
name = "rand"
|
||||||
version = "0.8.5"
|
version = "0.8.5"
|
||||||
@ -663,22 +867,44 @@ checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "risc0-binfmt"
|
name = "risc0-binfmt"
|
||||||
version = "1.2.0-alpha.1"
|
version = "2.0.2"
|
||||||
source = "git+https://github.com/risc0/risc0.git#cc8e628638530815fa8b9ac840543c720ec402e8"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "62eb7025356a233c1bc267c458a2ce56fcfc89b136d813c8a77be14ef1eaf2b1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"borsh",
|
"borsh",
|
||||||
|
"derive_more",
|
||||||
"elf",
|
"elf",
|
||||||
|
"lazy_static",
|
||||||
|
"postcard",
|
||||||
"risc0-zkp",
|
"risc0-zkp",
|
||||||
"risc0-zkvm-platform",
|
"risc0-zkvm-platform",
|
||||||
|
"semver",
|
||||||
"serde",
|
"serde",
|
||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "risc0-circuit-keccak"
|
||||||
|
version = "3.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0094af5a57b020388a03bdd3834959c7d62723f1687be81414ade25104d93263"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"bytemuck",
|
||||||
|
"paste",
|
||||||
|
"risc0-binfmt",
|
||||||
|
"risc0-circuit-recursion",
|
||||||
|
"risc0-core",
|
||||||
|
"risc0-zkp",
|
||||||
|
"tracing",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "risc0-circuit-recursion"
|
name = "risc0-circuit-recursion"
|
||||||
version = "1.2.0-alpha.1"
|
version = "3.0.0"
|
||||||
source = "git+https://github.com/risc0/risc0.git#cc8e628638530815fa8b9ac840543c720ec402e8"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "76ebded45c902c2b6939924a1cddd1d06b5d1d4ad1531e8798ebfee78f9c038d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
@ -691,32 +917,38 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "risc0-circuit-rv32im"
|
name = "risc0-circuit-rv32im"
|
||||||
version = "1.2.0-alpha.1"
|
version = "3.0.0"
|
||||||
source = "git+https://github.com/risc0/risc0.git#cc8e628638530815fa8b9ac840543c720ec402e8"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "15030849f8356f01f23c74b37dbfa4283100b594eb634109993e9e005ef45f64"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"metal",
|
"bit-vec",
|
||||||
|
"bytemuck",
|
||||||
|
"derive_more",
|
||||||
|
"paste",
|
||||||
"risc0-binfmt",
|
"risc0-binfmt",
|
||||||
"risc0-core",
|
"risc0-core",
|
||||||
"risc0-zkp",
|
"risc0-zkp",
|
||||||
"risc0-zkvm-platform",
|
|
||||||
"serde",
|
"serde",
|
||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "risc0-core"
|
name = "risc0-core"
|
||||||
version = "1.2.0-alpha.1"
|
version = "2.0.0"
|
||||||
source = "git+https://github.com/risc0/risc0.git#cc8e628638530815fa8b9ac840543c720ec402e8"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "317bbf70a8750b64d4fd7a2bdc9d7d5f30d8bb305cae486962c797ef35c8d08e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
|
"bytemuck_derive",
|
||||||
"rand_core",
|
"rand_core",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "risc0-groth16"
|
name = "risc0-groth16"
|
||||||
version = "1.2.0-alpha.1"
|
version = "2.0.2"
|
||||||
source = "git+https://github.com/risc0/risc0.git#cc8e628638530815fa8b9ac840543c720ec402e8"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7cf5d0b673d5fc67a89147c2e9c53134707dcc8137a43d1ef06b4ff68e99b74f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"ark-bn254",
|
"ark-bn254",
|
||||||
@ -733,10 +965,21 @@ dependencies = [
|
|||||||
"stability",
|
"stability",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "risc0-zkos-v1compat"
|
||||||
|
version = "2.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f76c479b69d1987cb54ac72dcc017197296fdcd6daf78fafc10cbbd3a167a7de"
|
||||||
|
dependencies = [
|
||||||
|
"include_bytes_aligned",
|
||||||
|
"no_std_strings",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "risc0-zkp"
|
name = "risc0-zkp"
|
||||||
version = "1.2.0-alpha.1"
|
version = "2.0.2"
|
||||||
source = "git+https://github.com/risc0/risc0.git#cc8e628638530815fa8b9ac840543c720ec402e8"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a287e9cd6d7b3b38eeb49c62090c46a1935922309fbd997a9143ed8c43c8f3cb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"blake2",
|
"blake2",
|
||||||
@ -753,24 +996,29 @@ dependencies = [
|
|||||||
"risc0-zkvm-platform",
|
"risc0-zkvm-platform",
|
||||||
"serde",
|
"serde",
|
||||||
"sha2",
|
"sha2",
|
||||||
|
"stability",
|
||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "risc0-zkvm"
|
name = "risc0-zkvm"
|
||||||
version = "1.2.0-alpha.1"
|
version = "2.3.1"
|
||||||
source = "git+https://github.com/risc0/risc0.git#cc8e628638530815fa8b9ac840543c720ec402e8"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9684b333c1c5d83f29ce2a92314ccfafd9d8cdfa6c4e19c07b97015d2f1eb9d0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"borsh",
|
"borsh",
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
"getrandom",
|
"derive_more",
|
||||||
|
"getrandom 0.2.15",
|
||||||
"hex",
|
"hex",
|
||||||
"risc0-binfmt",
|
"risc0-binfmt",
|
||||||
|
"risc0-circuit-keccak",
|
||||||
"risc0-circuit-recursion",
|
"risc0-circuit-recursion",
|
||||||
"risc0-circuit-rv32im",
|
"risc0-circuit-rv32im",
|
||||||
"risc0-core",
|
"risc0-core",
|
||||||
"risc0-groth16",
|
"risc0-groth16",
|
||||||
|
"risc0-zkos-v1compat",
|
||||||
"risc0-zkp",
|
"risc0-zkp",
|
||||||
"risc0-zkvm-platform",
|
"risc0-zkvm-platform",
|
||||||
"rrs-lib",
|
"rrs-lib",
|
||||||
@ -783,11 +1031,14 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "risc0-zkvm-platform"
|
name = "risc0-zkvm-platform"
|
||||||
version = "1.2.0-alpha.1"
|
version = "2.0.3"
|
||||||
source = "git+https://github.com/risc0/risc0.git#cc8e628638530815fa8b9ac840543c720ec402e8"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cae9cb2c2f6cab2dfa395ea6e2576713929040c7fb0c5f4150d13e1119d18686"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
"getrandom",
|
"cfg-if",
|
||||||
|
"getrandom 0.2.15",
|
||||||
|
"getrandom 0.3.3",
|
||||||
"libm",
|
"libm",
|
||||||
"stability",
|
"stability",
|
||||||
]
|
]
|
||||||
@ -802,15 +1053,6 @@ dependencies = [
|
|||||||
"paste",
|
"paste",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rustc_version"
|
|
||||||
version = "0.4.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
|
|
||||||
dependencies = [
|
|
||||||
"semver",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ryu"
|
name = "ryu"
|
||||||
version = "1.0.18"
|
version = "1.0.18"
|
||||||
@ -822,6 +1064,9 @@ name = "semver"
|
|||||||
version = "1.0.23"
|
version = "1.0.23"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
|
checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
@ -866,6 +1111,12 @@ dependencies = [
|
|||||||
"digest",
|
"digest",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "spin"
|
||||||
|
version = "0.9.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "stability"
|
name = "stability"
|
||||||
version = "0.2.1"
|
version = "0.2.1"
|
||||||
@ -913,6 +1164,26 @@ dependencies = [
|
|||||||
"serde_json",
|
"serde_json",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thiserror"
|
||||||
|
version = "2.0.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
|
||||||
|
dependencies = [
|
||||||
|
"thiserror-impl",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thiserror-impl"
|
||||||
|
version = "2.0.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.87",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml_datetime"
|
name = "toml_datetime"
|
||||||
version = "0.6.8"
|
version = "0.6.8"
|
||||||
@ -984,6 +1255,12 @@ version = "1.0.13"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
|
checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-xid"
|
||||||
|
version = "0.2.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "valuable"
|
name = "valuable"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@ -1002,6 +1279,15 @@ version = "0.11.0+wasi-snapshot-preview1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasi"
|
||||||
|
version = "0.14.2+wasi-0.2.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3"
|
||||||
|
dependencies = [
|
||||||
|
"wit-bindgen-rt",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winnow"
|
name = "winnow"
|
||||||
version = "0.6.20"
|
version = "0.6.20"
|
||||||
@ -1011,6 +1297,15 @@ dependencies = [
|
|||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wit-bindgen-rt"
|
||||||
|
version = "0.39.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.6.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerocopy"
|
name = "zerocopy"
|
||||||
version = "0.7.35"
|
version = "0.7.35"
|
||||||
|
|||||||
@ -7,9 +7,7 @@ edition = "2021"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
serde_json = "1.0.81"
|
serde_json = "1.0.81"
|
||||||
risc0-zkvm = { git = "https://github.com/risc0/risc0.git", default-features = false, features = [
|
risc0-zkvm = { version = "2.3.1", default-features = false, features = ['std'] }
|
||||||
"std",
|
|
||||||
] }
|
|
||||||
|
|
||||||
[dependencies.serde]
|
[dependencies.serde]
|
||||||
features = ["derive"]
|
features = ["derive"]
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user