Make cashierd compile.

This commit is contained in:
parazyd
2021-11-30 17:36:10 +01:00
parent 113a257227
commit cde8b6d7e2
9 changed files with 294 additions and 418 deletions

View File

@@ -5,21 +5,24 @@ use async_std::sync::{Arc, Mutex};
use async_trait::async_trait;
use clap::clap_app;
use easy_parallel::Parallel;
use log::debug;
use incrementalmerkletree::bridgetree::BridgeTree;
use log::{debug, info};
use pasta_curves::pallas;
use serde_json::{json, Value};
use drk::{
blockchain::{rocks::columns, Rocks, RocksColumn},
circuit::{MintContract, SpendContract},
cli::{CashierdConfig, Config},
client::{Client, State},
crypto::{mint_proof::MintProofKeys, schnorr, spend_proof::SpendProofKeys},
client::Client,
crypto::{merkle_node::MerkleNode, proof::VerifyingKey, schnorr},
rpc::{
jsonrpc::{error as jsonerr, response as jsonresp, ErrorCode::*, JsonRequest, JsonResult},
rpcserver::{listen_and_serve, RequestHandler, RpcServerConfig},
},
serial::{deserialize, serialize},
service::{bridge, bridge::Bridge},
state::State,
types::DrkTokenId,
util::{expand_path, generate_id, join_config_path, parse::truncate, NetworkName},
wallet::{cashierdb::TokenKey, CashierDb, WalletDb},
@@ -342,13 +345,13 @@ impl Cashierd {
cashier_public = addr.public;
} else {
let cashier_secret = schnorr::SecretKey::random();
cashier_public = cashier_secret.public_key();
cashier_public = cashier_secret.public_key().inner();
self.cashier_wallet
.put_withdraw_keys(
&address,
&cashier_public,
&cashier_secret,
&cashier_secret.inner(),
&network,
&token_id,
mint_address.into(),
@@ -669,15 +672,19 @@ async fn start(
let rocks = Rocks::new(expand_path(&config.database_path.clone())?.as_path())?;
let mint_proof_keys = MintProofKeys::initialize();
let spend_proof_keys = SpendProofKeys::initialize();
/*
let mint_pk = ProvingKey::build(11, MintContract::default());
let spend_pk = ProvingKey::build(11, SpendContract::default());
*/
info!("Building verifying key for the mint contract...");
let mint_vk = VerifyingKey::build(11, MintContract::default());
info!("Building verifying key for the spend contract...");
let spend_vk = VerifyingKey::build(11, SpendContract::default());
let client = Client::new(
rocks.clone(),
(config.gateway_protocol_url.parse()?, config.gateway_publisher_url.parse()?),
client_wallet.clone(),
mint_proof_keys,
spend_proof_keys,
)
.await?;
@@ -694,13 +701,13 @@ async fn start(
tree: BridgeTree::<MerkleNode, 32>::new(100),
merkle_roots,
nullifiers,
mint_vk: mint_proof_keys.vk,
spend_vk: spend_proof_keys.vk,
mint_vk,
spend_vk,
public_keys: cashier_public_keys,
}));
if get_address_flag {
println!("Public Key: {}", cashier_public_str);
info!("Public Key: {}", cashier_public_str);
return Ok(())
};
@@ -750,7 +757,7 @@ async fn main() -> Result<()> {
config.client_wallet_password.clone(),
)?;
client_wallet.remove_own_coins()?;
client_wallet.remove_own_coins().await?;
let wallet = CashierDb::new(
expand_path(&config.cashier_wallet_path)?.as_path(),
@@ -764,7 +771,7 @@ async fn main() -> Result<()> {
std::fs::remove_dir_all(path)?;
}
println!("Wallet got updated successfully.");
info!("Wallet got updated successfully.");
return Ok(())
}

View File

@@ -99,7 +99,7 @@ impl MemoryState {
fn main() -> Result<()> {
let cashier_signature_secret = schnorr::SecretKey::random();
let cashier_signature_public = cashier_secret.public_key();
let cashier_signature_public = cashier_signature_secret.public_key();
let keypair = Keypair::random(&mut OsRng);

View File

@@ -1,2 +1,5 @@
pub mod mint_contract;
pub mod spend_contract;
pub use mint_contract::MintContract;
pub use spend_contract::SpendContract;

View File

@@ -1,26 +1,24 @@
use async_std::sync::{Arc, Mutex};
use incrementalmerkletree::bridgetree::BridgeTree;
use log::{debug, info};
use incrementalmerkletree::Tree;
use log::{debug, info, warn};
use pasta_curves::pallas;
use smol::Executor;
use url::Url;
use crate::{
blockchain::{rocks::columns, Rocks, RocksColumn, Slab},
crypto::{
coin::Coin, merkle_node::MerkleNode, mint_proof::MintProofKeys, nullifier::Nullifier,
proof::VerifyingKey, schnorr, spend_proof::SpendProofKeys,
},
serial::{serialize, Encodable},
crypto::{coin::Coin, merkle_node::MerkleNode, schnorr, util::mod_r_p},
serial::{serialize, Decodable, Encodable},
service::GatewayClient,
state::{state_transition, ProgramState},
state::{state_transition, State},
tx,
wallet::{Keypair, WalletPtr},
wallet::{CashierDbPtr, Keypair, WalletPtr},
Result,
};
#[derive(Debug, Clone, thiserror::Error)]
pub enum ClientFailed {
#[error("here is no enough value {0}")]
#[error("Here is not enough value {0}")]
NotEnoughValue(u64),
#[error("Invalid Address {0}")]
InvalidAddress(String),
@@ -46,12 +44,24 @@ pub enum ClientFailed {
VerifyError(String),
}
pub type ClientResult<T> = std::result::Result<T, ClientFailed>;
impl From<super::error::Error> for ClientFailed {
fn from(err: super::error::Error) -> ClientFailed {
ClientFailed::ClientError(err.to_string())
}
}
impl From<crate::state::VerifyFailed> for ClientFailed {
fn from(err: crate::state::VerifyFailed) -> ClientFailed {
ClientFailed::VerifyError(err.to_string())
}
}
pub struct Client {
main_keypair: Keypair,
pub main_keypair: Keypair,
gateway: GatewayClient,
wallet: WalletPtr,
mint_proof_keys: MintProofKeys,
spend_proof_keys: SpendProofKeys,
}
impl Client {
@@ -59,70 +69,69 @@ impl Client {
rocks: Arc<Rocks>,
gateway_addrs: (Url, Url),
wallet: WalletPtr,
mint_proof_keys: MintProofKeys,
spend_proof_keys: SpendProofKeys,
) -> Result<Self> {
wallet.init_db()?;
wallet.init_db().await?;
// Generate a new keypair if we don't have any.
if wallet.get_keypairs()?.is_empty() {
wallet.key_gen()?;
if wallet.get_keypairs().await?.is_empty() {
wallet.key_gen().await?;
}
// TODO: Think about multiple keypairs.
let main_keypair = wallet.get_keypairs()?[0].clone();
// TODO: Think about multiple keypairs
let main_keypair = wallet.get_keypairs().await?[0].clone();
info!("Main keypair: {}", bs58::encode(&serialize(&main_keypair.public)).into_string());
let slabstore = RocksColumn::<columns::Slabs>::new(rocks);
debug!("Creating GatewayClient");
let slabstore = RocksColumn::<columns::Slabs>::new(rocks);
let gateway = GatewayClient::new(gateway_addrs.0, gateway_addrs.1, slabstore)?;
let client = Client { main_keypair, gateway, wallet, mint_proof_keys, spend_proof_keys };
let client = Client { main_keypair, gateway, wallet };
Ok(client)
}
pub async fn start(&mut self) -> Result<()> {
self.gateway.start().await?;
Ok(())
self.gateway.start().await
}
async fn build_slab_from_tx(
&mut self,
pub_key: pallas::Point,
pubkey: pallas::Point,
value: u64,
token_id: pallas::Base,
clear_input: bool,
state: Arc<Mutex<State>>,
) -> ClientResult<Vec<Coin>> {
debug!(target: "CLIENT", "Start build slab from tx");
debug!("Start build slab from tx");
let mut clear_inputs: Vec<tx::TransactionBuilderClearInputInfo> = vec![];
let mut inputs: Vec<tx::TransactionBuilderInputInfo> = vec![];
let mut outputs: Vec<tx::TransactionBuilderOutputInfo> = vec![];
let mut coins: Vec<Coin> = vec![];
if clear_input {
let signature_secret = self.main_keypair.private;
// TODO: FIXME:
let base_secret = self.main_keypair.private;
let signature_secret = schnorr::SecretKey(mod_r_p(base_secret));
let input = tx::TransactionBuilderClearInputInfo { value, token_id, signature_secret };
clear_inputs.push(input);
} else {
debug!(target: "CLIENT", "Start build inputs");
let mut inputs_value: u64 = 0;
let own_coins = self.wallet.get_own_coins()?;
debug!("Start build inputs");
let mut inputs_value = 0_u64;
let state_m = state.lock().await;
let own_coins = self.wallet.get_own_coins().await?;
for own_coin in own_coins.iter() {
if inputs_value >= value {
break
}
let witness = &own_coin.witness;
let merkle_path = witness.path().unwrap();
let node = MerkleNode(own_coin.coin.inner());
let (leaf_position, merkle_path) = state_m.tree.authentication_path(&node).unwrap();
// TODO: What is this counting? Is it everything or does it know to separate
// different tokens?
inputs_value += own_coin.note.value;
let input = tx::TransactionBuilderInputInfo {
leaf_position,
merkle_path,
secret: own_coin.secret,
note: own_coin.note.clone(),
@@ -146,157 +155,90 @@ impl Client {
});
}
debug!(target: "CLIENT", "End build inputs");
debug!("End build inputs");
}
outputs.push(tx::TransactionBuilderOutputInfo { value, token_id, public: pub_key });
outputs.push(tx::TransactionBuilderOutputInfo { value, token_id, public: pubkey });
let builder = tx::TransactionBuilder { clear_inputs, inputs, outputs };
let tx: tx::Transaction;
let mut tx_data = vec![];
{
tx = builder.build()?;
tx.encode(&mut tx_data).expect("encode tx");
}
tx = builder.build()?;
tx.encode(&mut tx_data).expect("encode tx");
let slab = Slab::new(tx_data);
debug!("End build slab from tx");
debug!(target: "CLIENT", "End build slab from tx");
// check if it's valid before send it to gateway
// Check if it's valid before sending to gateway
let state = &*state.lock().await;
state_transition(state, tx)?;
self.gateway.put_slab(slab).await?;
Ok(coins)
}
pub async fn send(
&mut self,
pub_key: pallas::Point,
pubkey: pallas::Point,
amount: u64,
token_id: pallas::Base,
clear_input: bool,
state: Arc<Mutex<State>>,
) -> ClientResult<()> {
debug!(target: "CLIENT", "Start send {}", amount);
// TODO: TOKEN debug
debug!("Start send {}", amount);
if amount == 0 {
return Err(ClientFailed::InvalidAmount(amount as u64))
return Err(ClientFailed::InvalidAmount(0))
}
let coins = self.build_slab_from_tx(pub_key, amount, token_id, clear_input, state).await?;
let coins = self.build_slab_from_tx(pubkey, amount, token_id, clear_input, state).await?;
for coin in coins.iter() {
self.wallet.confirm_spend_coin(coin)?;
self.wallet.confirm_spend_coin(coin).await?;
}
debug!(target: "CLIENT", "End send {}", amount);
debug!("End send {}", amount);
Ok(())
}
pub async fn transfer(
&mut self,
token_id: pallas::Base,
pub_key: pallas::Point,
amount: u64,
async fn update_state(
secret_keys: Vec<pallas::Base>,
slab: &Slab,
state: Arc<Mutex<State>>,
) -> ClientResult<()> {
debug!(target: "CLIENT", "Start transfer {}", amount);
let token_id_exists = self.wallet.token_id_exists(&token_id)?;
if token_id_exists {
self.send(pub_key, amount, token_id, false, state).await?;
} else {
return Err(ClientFailed::NotEnoughValue(amount))
}
debug!(target: "CLIENT", "End transfer {}", amount);
wallet: WalletPtr,
notify: Option<async_channel::Sender<(pallas::Point, u64)>>,
) -> Result<()> {
debug!("Build tx from slab and update the state");
let tx = tx::Transaction::decode(&slab.get_payload()[..])?;
let st = &*state.lock().await;
let update = state_transition(st, tx)?;
let mut st = state.lock().await;
st.apply(update, secret_keys, notify, wallet).await?;
Ok(())
}
}
pub struct State {
// The entire merkle tree state
pub tree: BridgeTree<MerkleNode, 32>,
// List of all previous and the current merkle roots
// This is the hashed value of all the children.
pub merkle_roots: RocksColumn<columns::MerkleRoots>,
// Nullifiers prevent double spending
pub nullifiers: RocksColumn<columns::Nullifiers>,
// Mint verifying key used by ZK
pub mint_vk: VerifyingKey,
// Spend verifying key used by ZK
pub spend_vk: VerifyingKey,
// List of cashier public keys
pub public_keys: Vec<pallas::Point>,
}
impl ProgramState for State {
fn is_valid_cashier_public_key(&self, public: &schnorr::PublicKey) -> bool {
debug!(target: "CLIENT STATE", "Check if it is valid cashier public key");
self.public_keys.contains(public)
}
fn is_valid_merkle(&self, merkle_root: &MerkleNode) -> bool {
debug!(target: "CLIENT STATE", "Check if it is valid merkle");
if let Ok(mr) = self.merkle_roots.key_exist(*merkle_root) {
return mr
}
false
}
fn nullifier_exists(&self, nullifier: &Nullifier) -> bool {
debug!(target: "CLIENT STATE", "Check if nullifier exists");
if let Ok(nl) = self.nullifiers.key_exist(nullifier.to_bytes()) {
return nl
}
false
}
fn mint_vk(&self) -> &VerifyingKey {
&self.mint_vk
}
fn spend_vk(&self) -> &VerifyingKey {
&self.spend_vk
}
}
/*
impl Client {
pub async fn connect_to_subscriber_from_cashier(
&self,
state: Arc<Mutex<State>>,
cashier_wallet: CashierDbPtr,
notify: async_channel::Sender<(jubjub::SubgroupPoint, u64)>,
notify: async_channel::Sender<(pallas::Point, u64)>,
executor: Arc<Executor<'_>>,
) -> Result<()> {
// start subscribing
debug!(target: "CLIENT", "Start subscriber for cashier");
let gateway_slabs_sub: GatewaySlabsSubscriber =
self.gateway.start_subscriber(executor.clone()).await?;
debug!("Start subscriber for cashier");
let gateway_slabs_sub = self.gateway.start_subscriber(executor.clone()).await?;
let secret_key = self.main_keypair.private;
let wallet = self.wallet.clone();
//let task: smol::Task<Result<()>> = executor.spawn(async move {
let task: smol::Task<Result<()>> = executor.spawn(async move {
loop {
let slab = gateway_slabs_sub.recv().await?;
debug!("Received new slab");
debug!(target: "CLIENT", "Received new slab");
let mut secret_keys: Vec<jubjub::Fr> = vec![secret_key];
let mut withdraw_keys = cashier_wallet.get_withdraw_private_keys()?;
let mut secret_keys: Vec<pallas::Base> = vec![secret_key];
let mut withdraw_keys = cashier_wallet.get_withdraw_private_keys().await?;
secret_keys.append(&mut withdraw_keys);
let update_state = Self::update_state(
@@ -306,246 +248,16 @@ impl Client {
wallet.clone(),
Some(notify.clone()),
)
.await;
.await;
if let Err(e) = update_state {
warn!("Update state: {}", e.to_string());
continue;
warn!("Update state: {}", e);
continue
}
}
});
task.detach();
Ok(())
}
pub async fn connect_to_subscriber(
&self,
state: Arc<Mutex<State>>,
executor: Arc<Executor<'_>>,
) -> Result<()> {
// start subscribing
debug!(target: "CLIENT", "Start subscriber");
let gateway_slabs_sub: GatewaySlabsSubscriber =
self.gateway.start_subscriber(executor.clone()).await?;
let secret_key = self.main_keypair.private;
let wallet = self.wallet.clone();
let task: smol::Task<Result<()>> = executor.spawn(async move {
loop {
let slab = gateway_slabs_sub.recv().await?;
debug!(target: "CLIENT", "Received new slab");
let update_state = Self::update_state(
vec![secret_key],
&slab,
state.clone(),
wallet.clone(),
None,
)
.await;
if let Err(e) = update_state {
warn!("Update state: {}", e.to_string());
continue;
}
}
});
task.detach();
Ok(())
}
async fn update_state(
secret_keys: Vec<jubjub::Fr>,
slab: &Slab,
state: Arc<Mutex<State>>,
wallet: WalletPtr,
notify: Option<async_channel::Sender<(jubjub::SubgroupPoint, u64)>>,
) -> Result<()> {
debug!(target: "CLIENT", "Build tx from slab and update the state");
let tx = tx::Transaction::decode(&slab.get_payload()[..])?;
let update: StateUpdate;
{
let state = &*state.lock().await;
update = state_transition(state, tx)?;
}
let mut state = state.lock().await;
state
.apply(update, secret_keys.clone(), notify, wallet)
.await?;
Ok(())
}
pub fn init_db(&self) -> Result<()> {
self.wallet.init_db()
}
pub fn get_own_coins(&self) -> Result<Vec<OwnCoin>> {
self.wallet.get_own_coins()
}
pub fn confirm_spend_coin(&self, coin: &Coin) -> Result<()> {
self.wallet.confirm_spend_coin(coin)
}
pub fn key_gen(&self) -> Result<()> {
self.wallet.key_gen()
}
pub fn get_balances(&self) -> Result<Balances> {
self.wallet.get_balances()
}
pub fn token_id_exists(&self, token_id: &jubjub::Fr) -> Result<bool> {
self.wallet.token_id_exists(token_id)
}
pub fn get_token_id(&self) -> Result<Vec<jubjub::Fr>> {
self.wallet.get_token_id()
}
}
pub struct State {
// The entire merkle tree state
pub tree: CommitmentTree<MerkleNode>,
// List of all previous and the current merkle roots
// This is the hashed value of all the children.
pub merkle_roots: RocksColumn<columns::MerkleRoots>,
// Nullifiers prevent double spending
pub nullifiers: RocksColumn<columns::Nullifiers>,
// Mint verifying key used by ZK
pub mint_pvk: groth16::PreparedVerifyingKey<Bls12>,
// Spend verifying key used by ZK
pub spend_pvk: groth16::PreparedVerifyingKey<Bls12>,
// List of cashier public keys
pub public_keys: Vec<jubjub::SubgroupPoint>,
}
impl State {
pub async fn apply(
&mut self,
update: StateUpdate,
secret_keys: Vec<jubjub::Fr>,
notify: Option<async_channel::Sender<(jubjub::SubgroupPoint, u64)>>,
wallet: WalletPtr,
) -> Result<()> {
// Extend our list of nullifiers with the ones from the update
debug!(target: "CLIENT STATE", "Extend nullifiers");
for nullifier in update.nullifiers {
self.nullifiers.put(nullifier, vec![] as Vec<u8>)?;
}
debug!(target: "CLIENT STATE", "Update merkle tree and witness ");
// Update merkle tree and witnesses
for (coin, enc_note) in update.coins.into_iter().zip(update.enc_notes.iter()) {
// Add the new coins to the merkle tree
let node = MerkleNode::from_coin(&coin);
self.tree.append(node).expect("Append to merkle tree");
debug!(target: "CLIENT STATE", "Keep track of all merkle roots");
// Keep track of all merkle roots that have existed
self.merkle_roots.put(self.tree.root(), vec![] as Vec<u8>)?;
debug!(target: "CLIENT STATE", "Update witness");
// Also update all the coin witnesses
let mut updated_witnesses = wallet.get_witnesses()?;
updated_witnesses.iter_mut().for_each(|(_, witness)| {
witness.append(node).expect("Append to witness");
});
wallet.update_witnesses(updated_witnesses)?;
debug!(target: "CLIENT STATE", "iterate over secret_keys to decrypt note");
for secret in secret_keys.iter() {
if let Some(note) = Self::try_decrypt_note(enc_note, *secret) {
// We need to keep track of the witness for this coin.
// This allows us to prove inclusion of the coin in the merkle tree with ZK.
// Just as we update the merkle tree with every new coin, so we do the same with
// the witness.
// Derive the current witness from the current tree.
// This is done right after we add our coin to the tree (but before any other
// coins are added)
// Make a new witness for this coin
let witness = IncrementalWitness::from_tree(&self.tree);
let mut nullifier = [0; 32];
nullifier.copy_from_slice(
Blake2sParams::new()
.hash_length(32)
.personal(zcash_primitives::constants::PRF_NF_PERSONALIZATION)
.to_state()
.update(&secret.to_bytes())
.update(&note.serial.to_bytes())
.finalize()
.as_bytes(),
);
let nullifier = Nullifier::new(nullifier);
let own_coin = OwnCoin {
coin: coin.clone(),
note: note.clone(),
secret: *secret,
witness: witness.clone(),
nullifier,
};
wallet.put_own_coins(own_coin)?;
let pub_key = zcash_primitives::constants::SPENDING_KEY_GENERATOR * secret;
debug!(target: "CLIENT STATE", "Received a coin: amount {} ", note.value);
debug!(target: "CLIENT STATE", "Send a notification");
if let Some(ch) = notify.clone() {
ch.send((pub_key, note.value)).await?
}
}
}
}
Ok(())
}
fn try_decrypt_note(ciphertext: &EncryptedNote, secret: jubjub::Fr) -> Option<Note> {
match ciphertext.decrypt(&secret) {
// ... and return the decrypted note for this coin.
Ok(note) => Some(note),
// We weren't able to decrypt the note with our key.
Err(_) => None,
}
}
}
*/
impl From<super::error::Error> for ClientFailed {
fn from(err: super::error::Error) -> ClientFailed {
ClientFailed::ClientError(err.to_string())
}
}
impl From<crate::state::VerifyFailed> for ClientFailed {
fn from(err: crate::state::VerifyFailed) -> ClientFailed {
ClientFailed::VerifyError(err.to_string())
}
}
pub type ClientResult<T> = std::result::Result<T, ClientFailed>;

View File

@@ -19,11 +19,9 @@ impl Coin {
self.0.to_bytes()
}
/*
pub(crate) fn inner(&self) -> pallas::Base {
self.0
}
*/
}
impl Encodable for Coin {

View File

@@ -1,5 +1,9 @@
use std::io;
use halo2_gadgets::primitives::{
poseidon,
poseidon::{ConstantLength, P128Pow5T3},
};
use pasta_curves::{arithmetic::FieldExt, pallas};
use crate::{
@@ -11,6 +15,12 @@ use crate::{
pub struct Nullifier(pub(crate) pallas::Base);
impl Nullifier {
pub fn new(secret: pallas::Base, serial: pallas::Base) -> Self {
let nullifier = [secret, serial];
let nullifier = poseidon::Hash::init(P128Pow5T3, ConstantLength::<2>).hash(nullifier);
Nullifier(nullifier)
}
pub fn from_bytes(bytes: &[u8; 32]) -> Self {
pallas::Base::from_bytes(bytes).map(Nullifier).unwrap()
}

View File

@@ -36,6 +36,10 @@ impl SecretKey {
let public_key = OrchardFixedBases::SpendAuthG.generator() * self.0;
PublicKey(public_key)
}
pub fn inner(&self) -> pallas::Scalar {
self.0
}
}
#[derive(PartialEq)]
@@ -67,6 +71,10 @@ impl PublicKey {
OrchardFixedBases::SpendAuthG.generator() * signature.response - self.0 * challenge ==
signature.commit
}
pub fn inner(&self) -> pallas::Point {
self.0
}
}
impl Encodable for PublicKey {

View File

@@ -1,18 +1,30 @@
use halo2_gadgets::ecc::FixedPoints;
use incrementalmerkletree::{bridgetree::BridgeTree, Frontier, Tree};
use log::debug;
use pasta_curves::pallas;
use crate::{
blockchain::{rocks::columns, RocksColumn},
crypto::{
coin::Coin, merkle_node::MerkleNode, note::EncryptedNote, nullifier::Nullifier,
proof::VerifyingKey, schnorr,
coin::Coin,
constants::OrchardFixedBases,
merkle_node::MerkleNode,
note::{EncryptedNote, Note},
nullifier::Nullifier,
proof::VerifyingKey,
schnorr,
util::mod_r_p,
OwnCoin,
},
tx::Transaction,
wallet::WalletPtr,
Result,
};
pub trait ProgramState {
fn is_valid_cashier_public_key(&self, public: &schnorr::PublicKey) -> bool;
fn is_valid_merkle(&self, merkle: &MerkleNode) -> bool;
fn nullifier_exists(&self, nullifier: &Nullifier) -> bool;
fn mint_vk(&self) -> &VerifyingKey;
fn spend_vk(&self) -> &VerifyingKey;
}
@@ -102,3 +114,114 @@ pub fn state_transition<S: ProgramState>(state: &S, tx: Transaction) -> VerifyRe
Ok(StateUpdate { nullifiers, coins, enc_notes })
}
pub struct State {
/// The entire Merkle tree state
pub tree: BridgeTree<MerkleNode, 32>,
/// List of all previous and the current merkle roots.
/// This is the hashed value of all the children.
pub merkle_roots: RocksColumn<columns::MerkleRoots>,
/// Nullifiers prevent double-spending
pub nullifiers: RocksColumn<columns::Nullifiers>,
/// List of Cashier public keys
pub public_keys: Vec<pallas::Point>,
/// Verifying key for the Mint contract
pub mint_vk: VerifyingKey,
/// Verifying key for the Spend contract
pub spend_vk: VerifyingKey,
}
impl State {
pub async fn apply(
&mut self,
update: StateUpdate,
secret_keys: Vec<pallas::Base>,
notify: Option<async_channel::Sender<(pallas::Point, u64)>>,
wallet: WalletPtr,
) -> Result<()> {
// Extend our list of nullifiers with the ones from the update.
debug!("Extend nullifiers");
for nullifier in update.nullifiers {
self.nullifiers.put(nullifier, vec![] as Vec<u8>)?;
}
debug!("Update Merkle tree and witness");
for (coin, enc_note) in update.coins.into_iter().zip(update.enc_notes.iter()) {
// Add the new coins to the Merkle tree
let node = MerkleNode(coin.0);
self.tree.append(&node);
// Keep track of all Merkle roots that have existed
self.merkle_roots.put(self.tree.root(), vec![] as Vec<u8>)?;
for secret in secret_keys.iter() {
if let Some(note) = State::try_decrypt_note(enc_note, *secret) {
// TODO: What to do with witnesses?
self.tree.witness();
let nullifier = Nullifier::new(*secret, note.serial);
let own_coin = OwnCoin {
coin: coin.clone(),
note: note.clone(),
secret: *secret,
// witness: witness.clone(),
nullifier,
};
wallet.put_own_coins(own_coin).await?;
// TODO: Place somewhere proper
let pubkey = OrchardFixedBases::NullifierK.generator() * mod_r_p(*secret);
debug!("Received a coin: amount {}", note.value);
debug!("Send a notification");
if let Some(ch) = notify.clone() {
ch.send((pubkey, note.value)).await?;
}
}
}
}
debug!("apply() exiting successfully");
Ok(())
}
fn try_decrypt_note(ciphertext: &EncryptedNote, secret: pallas::Base) -> Option<Note> {
match ciphertext.decrypt(&secret) {
Ok(note) => Some(note),
Err(_) => None,
}
}
}
impl ProgramState for State {
// TODO: Proper keypair type
fn is_valid_cashier_public_key(&self, public: &schnorr::PublicKey) -> bool {
debug!("Check if it is a valid cashier public key");
self.public_keys.contains(&public.inner())
}
fn is_valid_merkle(&self, merkle_root: &MerkleNode) -> bool {
debug!("Check if it is valid merkle");
if let Ok(mr) = self.merkle_roots.key_exist(merkle_root.clone()) {
return mr
}
false
}
fn nullifier_exists(&self, nullifier: &Nullifier) -> bool {
debug!("Check if nullifier exists");
if let Ok(nl) = self.nullifiers.key_exist(nullifier.to_bytes()) {
return nl
}
false
}
fn mint_vk(&self) -> &VerifyingKey {
&self.mint_vk
}
fn spend_vk(&self) -> &VerifyingKey {
&self.spend_vk
}
}

View File

@@ -1,5 +1,6 @@
use std::{path::Path, sync::Arc};
use std::path::Path;
use async_std::sync::{Arc, Mutex};
use log::{debug, error, info};
use pasta_curves::arithmetic::Field;
use rand::rngs::OsRng;
@@ -46,7 +47,7 @@ impl Balances {
}
pub struct WalletDb {
pub conn: Connection,
pub conn: Mutex<Connection>,
}
impl WalletApi for WalletDb {}
@@ -63,25 +64,27 @@ impl WalletDb {
conn.pragma_update(None, "key", &password)?;
info!(target: "WALLETDB", "Opened connection at path: {:?}", path);
Ok(Arc::new(Self { conn }))
Ok(Arc::new(Self { conn: Mutex::new(conn) }))
}
pub fn init_db(&self) -> Result<()> {
pub async fn init_db(&self) -> Result<()> {
debug!(target: "WALLETDB", "Initialize...");
let contents = include_str!("../../sql/schema.sql");
Ok(self.conn.execute_batch(contents)?)
let conn = self.conn.lock().await;
Ok(conn.execute_batch(contents)?)
}
pub fn key_gen(&self) -> Result<()> {
pub async fn key_gen(&self) -> Result<()> {
debug!(target: "WALLETDB", "Attempting to generate keys...");
let mut stmt = self.conn.prepare("SELECT * FROM keys WHERE key_id > ?")?;
let conn = self.conn.lock().await;
let mut stmt = conn.prepare("SELECT * FROM keys WHERE key_id > ?")?;
let key_check = stmt.exists(params!["0"])?;
if !key_check {
let secret = DrkSecretKey::random(&mut OsRng);
let public = derive_public_key(secret);
self.put_keypair(&public, &secret)?;
self.put_keypair(&public, &secret).await?;
return Ok(())
}
@@ -89,12 +92,17 @@ impl WalletDb {
Err(Error::from(ClientFailed::KeyExists))
}
pub fn put_keypair(&self, key_public: &DrkPublicKey, key_private: &DrkSecretKey) -> Result<()> {
pub async fn put_keypair(
&self,
key_public: &DrkPublicKey,
key_private: &DrkSecretKey,
) -> Result<()> {
debug!(target: "WALLETDB", "put_keypair()");
let key_public = serial::serialize(key_public);
let key_private = serial::serialize(key_private);
self.conn.execute(
let conn = self.conn.lock().await;
conn.execute(
"INSERT INTO keys(key_public, key_private) VALUES (?1, ?2)",
params![key_public, key_private],
)?;
@@ -102,9 +110,10 @@ impl WalletDb {
Ok(())
}
pub fn get_keypairs(&self) -> Result<Vec<Keypair>> {
pub async fn get_keypairs(&self) -> Result<Vec<Keypair>> {
debug!(target: "WALLETDB", "Returning keypairs...");
let mut stmt = self.conn.prepare("SELECT * FROM keys")?;
let conn = self.conn.lock().await;
let mut stmt = conn.prepare("SELECT * FROM keys")?;
// this just gets the first key. maybe we should randomize this
let key_iter = stmt.query_map([], |row| Ok((row.get(1)?, row.get(2)?)))?;
@@ -122,11 +131,12 @@ impl WalletDb {
Ok(keypairs)
}
pub fn get_own_coins(&self) -> Result<OwnCoins> {
pub async fn get_own_coins(&self) -> Result<OwnCoins> {
debug!(target: "WALLETDB", "Get own coins");
let is_spent = 0;
let mut coins = self.conn.prepare("SELECT * FROM coins WHERE is_spent = :is_spent ;")?;
let conn = self.conn.lock().await;
let mut coins = conn.prepare("SELECT * FROM coins WHERE is_spent = :is_spent ;")?;
let rows = coins.query_map(&[(":is_spent", &is_spent)], |row| {
Ok((
@@ -178,7 +188,7 @@ impl WalletDb {
Ok(own_coins)
}
pub fn put_own_coins(&self, own_coin: OwnCoin) -> Result<()> {
pub async fn put_own_coins(&self, own_coin: OwnCoin) -> Result<()> {
debug!(target: "WALLETDB", "Put own coins");
let coin = self.get_value_serialized(&own_coin.coin.to_bytes())?;
let serial = self.get_value_serialized(&own_coin.note.serial)?;
@@ -191,7 +201,8 @@ impl WalletDb {
let is_spent = 0;
let nullifier = self.get_value_serialized(&own_coin.nullifier)?;
self.conn.execute(
let conn = self.conn.lock().await;
conn.execute(
"INSERT OR REPLACE INTO coins
(coin, serial, value, token_id, coin_blind,
valcom_blind, witness, secret, is_spent, nullifier)
@@ -215,18 +226,20 @@ impl WalletDb {
Ok(())
}
pub fn remove_own_coins(&self) -> Result<()> {
pub async fn remove_own_coins(&self) -> Result<()> {
debug!(target: "WALLETDB", "Remove own coins");
let _rows = self.conn.execute("DROP TABLE coins;", [])?;
let conn = self.conn.lock().await;
let _rows = conn.execute("DROP TABLE coins;", [])?;
Ok(())
}
pub fn confirm_spend_coin(&self, coin: &Coin) -> Result<()> {
pub async fn confirm_spend_coin(&self, coin: &Coin) -> Result<()> {
debug!(target: "WALLETDB", "Confirm spend coin");
let is_spent = 1;
let coin = self.get_value_serialized(coin)?;
self.conn.execute(
let conn = self.conn.lock().await;
conn.execute(
"UPDATE coins
SET is_spent = ?1
WHERE coin = ?2 ;",
@@ -284,11 +297,12 @@ impl WalletDb {
}
*/
pub fn get_balances(&self) -> Result<Balances> {
pub async fn get_balances(&self) -> Result<Balances> {
debug!(target: "WALLETDB", "Get token and balances...");
let is_spent = 0;
let mut stmt = self.conn.prepare(
let conn = self.conn.lock().await;
let mut stmt = conn.prepare(
"SELECT value, token_id, nullifier FROM coins WHERE is_spent = :is_spent ;",
)?;
@@ -309,12 +323,12 @@ impl WalletDb {
Ok(balances)
}
pub fn get_token_id(&self) -> Result<Vec<DrkTokenId>> {
pub async fn get_token_id(&self) -> Result<Vec<DrkTokenId>> {
debug!(target: "WALLETDB", "Get token ID...");
let is_spent = 0;
let mut stmt =
self.conn.prepare("SELECT token_id FROM coins WHERE is_spent = :is_spent ;")?;
let conn = self.conn.lock().await;
let mut stmt = conn.prepare("SELECT token_id FROM coins WHERE is_spent = :is_spent ;")?;
let rows = stmt.query_map(&[(":is_spent", &is_spent)], |row| row.get(0))?;
@@ -329,21 +343,22 @@ impl WalletDb {
Ok(token_ids)
}
pub fn token_id_exists(&self, token_id: &DrkTokenId) -> Result<bool> {
pub async fn token_id_exists(&self, token_id: &DrkTokenId) -> Result<bool> {
debug!(target: "WALLETDB", "Check tokenID exists");
let is_spent = 0;
let id = self.get_value_serialized(token_id)?;
let mut stmt =
self.conn.prepare("SELECT * FROM coins WHERE token_id = ? AND is_spent = ? ;")?;
let conn = self.conn.lock().await;
let mut stmt = conn.prepare("SELECT * FROM coins WHERE token_id = ? AND is_spent = ? ;")?;
let id_check = stmt.exists(params![id, is_spent])?;
Ok(id_check)
}
pub fn test_wallet(&self) -> Result<()> {
let mut stmt = self.conn.prepare("SELECT * FROM keys")?;
pub async fn test_wallet(&self) -> Result<()> {
let conn = self.conn.lock().await;
let mut stmt = conn.prepare("SELECT * FROM keys")?;
let _rows = stmt.query([])?;
Ok(())
}