dao-example: remove WalletCache from money::State, now it's just used by the wallet.

This commit is contained in:
x
2022-11-05 12:34:01 +00:00
parent 5c98311c98
commit 38054cc751
3 changed files with 102 additions and 87 deletions

View File

@@ -16,70 +16,12 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
use darkfi::crypto::keypair::PublicKey;
use darkfi_sdk::crypto::{constants::MERKLE_DEPTH, MerkleNode, Nullifier};
use incrementalmerkletree::{bridgetree::BridgeTree, Tree};
use darkfi::crypto::{
coin::Coin,
keypair::{PublicKey, SecretKey},
};
use super::transfer;
use crate::note::EncryptedNote2;
use incrementalmerkletree::bridgetree::BridgeTree;
type MerkleTree = BridgeTree<MerkleNode, MERKLE_DEPTH>;
pub struct OwnCoin {
pub coin: Coin,
pub note: transfer::wallet::Note,
pub leaf_position: incrementalmerkletree::Position,
}
pub struct WalletCache {
// Normally this would be a HashMap, but SecretKey is not Hash-able
// TODO: This can be HashableBase
cache: Vec<(SecretKey, Vec<OwnCoin>)>,
}
impl WalletCache {
pub fn new() -> Self {
Self { cache: Vec::new() }
}
/// Must be called at the start to begin tracking received coins for this secret.
pub fn track(&mut self, secret: SecretKey) {
self.cache.push((secret, Vec::new()));
}
/// Get all coins received by this secret key
/// track() must be called on this secret before calling this or the function will panic.
pub fn get_received(&mut self, secret: &SecretKey) -> Vec<OwnCoin> {
for (other_secret, own_coins) in self.cache.iter_mut() {
if *secret == *other_secret {
// clear own_coins vec, and return current contents
return std::mem::replace(own_coins, Vec::new())
}
}
panic!("you forget to track() this secret!");
}
pub fn try_decrypt_note(
&mut self,
coin: Coin,
ciphertext: EncryptedNote2,
tree: &mut MerkleTree,
) {
// Loop through all our secret keys...
for (secret, own_coins) in self.cache.iter_mut() {
// .. attempt to decrypt the note ...
if let Ok(note) = ciphertext.decrypt(secret) {
let leaf_position = tree.witness().expect("coin should be in tree");
own_coins.push(OwnCoin { coin, note, leaf_position });
}
}
}
}
/// The state machine, held in memory.
pub struct State {
/// The entire Merkle tree state
@@ -95,8 +37,6 @@ pub struct State {
/// Public key of the faucet
pub faucet_signature_public: PublicKey,
pub wallet_cache: WalletCache,
}
impl State {
@@ -110,7 +50,6 @@ impl State {
nullifiers: vec![],
cashier_signature_public,
faucet_signature_public,
wallet_cache: WalletCache::new(),
})
}

View File

@@ -66,15 +66,13 @@ impl UpdateBase for Update {
state.nullifiers.append(&mut self.nullifiers);
//// Update merkle tree and witnesses
for (coin, enc_note) in self.coins.into_iter().zip(self.enc_notes.into_iter()) {
for coin in self.coins {
// Add the new coins to the Merkle tree
let node = MerkleNode::from(coin.0);
state.tree.append(&node);
// Keep track of all Merkle roots that have existed
state.merkle_roots.push(state.tree.root(0).unwrap());
state.wallet_cache.try_decrypt_note(coin, enc_note, &mut state.tree);
}
}
}

View File

@@ -21,7 +21,7 @@ use std::{
time::Instant,
};
use incrementalmerkletree::Tree;
use incrementalmerkletree::{bridgetree::BridgeTree, Tree};
use log::debug;
use pasta_curves::{
arithmetic::CurveAffine,
@@ -41,6 +41,7 @@ use darkfi::{
zk::circuit::{BurnContract, MintContract},
zkas::decoder::ZkBinary,
};
use darkfi_sdk::crypto::{constants::MERKLE_DEPTH, MerkleNode};
mod contract;
mod error;
@@ -49,9 +50,64 @@ mod util;
use crate::{
contract::{dao, example, money},
note::EncryptedNote2,
util::{sign, StateRegistry, Transaction, ZkContractTable},
};
type MerkleTree = BridgeTree<MerkleNode, MERKLE_DEPTH>;
pub struct OwnCoin {
pub coin: Coin,
pub note: money::transfer::wallet::Note,
pub leaf_position: incrementalmerkletree::Position,
}
pub struct WalletCache {
// Normally this would be a HashMap, but SecretKey is not Hash-able
// TODO: This can be HashableBase
cache: Vec<(SecretKey, Vec<OwnCoin>)>,
/// The entire Merkle tree state
tree: MerkleTree,
}
impl WalletCache {
pub fn new() -> Self {
Self { cache: Vec::new(), tree: MerkleTree::new(100) }
}
/// Must be called at the start to begin tracking received coins for this secret.
pub fn track(&mut self, secret: SecretKey) {
self.cache.push((secret, Vec::new()));
}
/// Get all coins received by this secret key
/// track() must be called on this secret before calling this or the function will panic.
pub fn get_received(&mut self, secret: &SecretKey) -> Vec<OwnCoin> {
for (other_secret, own_coins) in self.cache.iter_mut() {
if *secret == *other_secret {
// clear own_coins vec, and return current contents
return std::mem::replace(own_coins, Vec::new())
}
}
panic!("you forget to track() this secret!");
}
pub fn try_decrypt_note(&mut self, coin: Coin, ciphertext: &EncryptedNote2) {
// Add the new coins to the Merkle tree
let node = MerkleNode::from(coin.0);
self.tree.append(&node);
// Loop through all our secret keys...
for (secret, own_coins) in self.cache.iter_mut() {
// .. attempt to decrypt the note ...
if let Ok(note) = ciphertext.decrypt(secret) {
let leaf_position = self.tree.witness().expect("coin should be in tree");
own_coins.push(OwnCoin { coin, note, leaf_position });
}
}
}
}
// TODO: Anonymity leaks in this proof of concept:
//
// * Vote updates are linked to the proposal_bulla
@@ -199,6 +255,9 @@ async fn main() -> Result<()> {
let faucet_signature_secret = SecretKey::random(&mut OsRng);
let faucet_signature_public = PublicKey::from_secret(faucet_signature_secret);
// We use this to receive coins
let mut cache = WalletCache::new();
///////////////////////////////////////////////////
let money_state = money::state::State::new(cashier_signature_public, faucet_signature_public);
@@ -297,8 +356,7 @@ async fn main() -> Result<()> {
///////////////////////////////////////////////////
debug!(target: "demo", "Stage 2. Minting treasury token");
let state = states.lookup_mut::<money::State>(*money::CONTRACT_ID).unwrap();
state.wallet_cache.track(dao_keypair.secret);
cache.track(dao_keypair.secret);
//// Wallet
@@ -371,9 +429,22 @@ async fn main() -> Result<()> {
//// Wallet
// DAO reads the money received from the encrypted note
{
assert_eq!(tx.func_calls.len(), 1);
let func_call = &tx.func_calls[0];
let call_data = func_call.call_data.as_any();
assert_eq!((*call_data).type_id(), TypeId::of::<money::transfer::validate::CallData>());
let call_data = call_data.downcast_ref::<money::transfer::validate::CallData>().unwrap();
let state = states.lookup_mut::<money::State>(*money::CONTRACT_ID).unwrap();
let mut recv_coins = state.wallet_cache.get_received(&dao_keypair.secret);
for output in &call_data.outputs {
let coin = &output.revealed.coin;
let enc_note = &output.enc_note;
cache.try_decrypt_note(coin.clone(), enc_note);
}
}
let mut recv_coins = cache.get_received(&dao_keypair.secret);
assert_eq!(recv_coins.len(), 1);
let dao_recv_coin = recv_coins.pop().unwrap();
let treasury_note = dao_recv_coin.note;
@@ -413,10 +484,9 @@ async fn main() -> Result<()> {
// Hodler 3: the tiebreaker
let gov_keypair_3 = Keypair::random(&mut OsRng);
let state = states.lookup_mut::<money::State>(*money::CONTRACT_ID).unwrap();
state.wallet_cache.track(gov_keypair_1.secret);
state.wallet_cache.track(gov_keypair_2.secret);
state.wallet_cache.track(gov_keypair_3.secret);
cache.track(gov_keypair_1.secret);
cache.track(gov_keypair_2.secret);
cache.track(gov_keypair_3.secret);
let gov_keypairs = vec![gov_keypair_1, gov_keypair_2, gov_keypair_3];
@@ -502,13 +572,26 @@ async fn main() -> Result<()> {
tx.verify_sigs();
//// Wallet
{
assert_eq!(tx.func_calls.len(), 1);
let func_call = &tx.func_calls[0];
let call_data = func_call.call_data.as_any();
assert_eq!((*call_data).type_id(), TypeId::of::<money::transfer::validate::CallData>());
let call_data = call_data.downcast_ref::<money::transfer::validate::CallData>().unwrap();
for output in &call_data.outputs {
let coin = &output.revealed.coin;
let enc_note = &output.enc_note;
cache.try_decrypt_note(coin.clone(), enc_note);
}
}
let mut gov_recv = vec![None, None, None];
// Check that each person received one coin
for (i, key) in gov_keypairs.iter().enumerate() {
let gov_recv_coin = {
let state = states.lookup_mut::<money::State>(*money::CONTRACT_ID).unwrap();
let mut recv_coins = state.wallet_cache.get_received(&key.secret);
let mut recv_coins = cache.get_received(&key.secret);
assert_eq!(recv_coins.len(), 1);
let recv_coin = recv_coins.pop().unwrap();
let note = &recv_coin.note;
@@ -565,8 +648,7 @@ async fn main() -> Result<()> {
let user_keypair = Keypair::random(&mut OsRng);
let (money_leaf_position, money_merkle_path) = {
let state = states.lookup::<money::State>(*money::CONTRACT_ID).unwrap();
let tree = &state.tree;
let tree = &cache.tree;
let leaf_position = gov_recv[0].leaf_position;
let root = tree.root(0).unwrap();
let merkle_path = tree.authentication_path(leaf_position, &root).unwrap();
@@ -710,8 +792,7 @@ async fn main() -> Result<()> {
// User 1: YES
let (money_leaf_position, money_merkle_path) = {
let state = states.lookup::<money::State>(*money::CONTRACT_ID).unwrap();
let tree = &state.tree;
let tree = &cache.tree;
let leaf_position = gov_recv[0].leaf_position;
let root = tree.root(0).unwrap();
let merkle_path = tree.authentication_path(leaf_position, &root).unwrap();
@@ -802,8 +883,7 @@ async fn main() -> Result<()> {
// User 2: NO
let (money_leaf_position, money_merkle_path) = {
let state = states.lookup::<money::State>(*money::CONTRACT_ID).unwrap();
let tree = &state.tree;
let tree = &cache.tree;
let leaf_position = gov_recv[1].leaf_position;
let root = tree.root(0).unwrap();
let merkle_path = tree.authentication_path(leaf_position, &root).unwrap();
@@ -893,8 +973,7 @@ async fn main() -> Result<()> {
// User 3: YES
let (money_leaf_position, money_merkle_path) = {
let state = states.lookup::<money::State>(*money::CONTRACT_ID).unwrap();
let tree = &state.tree;
let tree = &cache.tree;
let leaf_position = gov_recv[2].leaf_position;
let root = tree.root(0).unwrap();
let merkle_path = tree.authentication_path(leaf_position, &root).unwrap();
@@ -1056,8 +1135,7 @@ async fn main() -> Result<()> {
let exec_signature_secret = SecretKey::random(&mut OsRng);
let (treasury_leaf_position, treasury_merkle_path) = {
let state = states.lookup::<money::State>(*money::CONTRACT_ID).unwrap();
let tree = &state.tree;
let tree = &cache.tree;
let leaf_position = dao_recv_coin.leaf_position;
let root = tree.root(0).unwrap();
let merkle_path = tree.authentication_path(leaf_position, &root).unwrap();