mirror of
https://github.com/darkrenaissance/darkfi.git
synced 2026-01-09 14:48:08 -05:00
contract/dao: Rewrite integration test using the test harness.
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -1641,6 +1641,7 @@ dependencies = [
|
||||
"bs58",
|
||||
"chacha20poly1305",
|
||||
"darkfi",
|
||||
"darkfi-contract-test-harness",
|
||||
"darkfi-money-contract",
|
||||
"darkfi-sdk",
|
||||
"darkfi-serial",
|
||||
|
||||
@@ -27,10 +27,10 @@ rand = { version = "0.8.5", optional = true }
|
||||
[dev-dependencies]
|
||||
async-std = {version = "1.12.0", features = ["attributes"]}
|
||||
darkfi = {path = "../../../", features = ["tx", "blockchain"]}
|
||||
darkfi-money-contract = { path = "../money", features = ["client", "no-entrypoint"] }
|
||||
darkfi-money-contract = {path = "../money", features = ["client", "no-entrypoint"]}
|
||||
simplelog = "0.12.1"
|
||||
sled = "0.34.7"
|
||||
#sqlx = {version = "0.6.3", features = ["runtime-async-std-rustls", "sqlite"]}
|
||||
darkfi-contract-test-harness = {path = "../test-harness"}
|
||||
|
||||
# We need to disable random using "custom" which makes the crate a noop
|
||||
# so the wasm32-unknown-unknown target is enabled.
|
||||
|
||||
@@ -32,7 +32,7 @@ use darkfi::{
|
||||
};
|
||||
|
||||
use super::{DaoInfo, DaoProposalInfo};
|
||||
use crate::model::{DaoBlindAggregateVote, DaoExecParams};
|
||||
use crate::model::{DaoBlindAggregateVote, DaoExecParams, DaoProposalBulla};
|
||||
|
||||
pub struct DaoExecCall {
|
||||
pub proposal: DaoProposalInfo,
|
||||
@@ -85,14 +85,14 @@ impl DaoExecCall {
|
||||
self.dao.bulla_blind,
|
||||
]);
|
||||
|
||||
let proposal_bulla = poseidon_hash::<6>([
|
||||
let proposal_bulla = DaoProposalBulla::from(poseidon_hash::<6>([
|
||||
proposal_dest_x,
|
||||
proposal_dest_y,
|
||||
proposal_amount,
|
||||
self.proposal.token_id.inner(),
|
||||
dao_bulla,
|
||||
self.proposal.blind,
|
||||
]);
|
||||
]));
|
||||
|
||||
let coin_0 = poseidon_hash::<7>([
|
||||
proposal_dest_x,
|
||||
@@ -157,7 +157,7 @@ impl DaoExecCall {
|
||||
|
||||
debug!(target: "dao", "proposal_bulla: {:?}", proposal_bulla);
|
||||
let public_inputs = vec![
|
||||
proposal_bulla,
|
||||
proposal_bulla.inner(),
|
||||
coin_0,
|
||||
coin_1,
|
||||
*yes_vote_commit_coords.x(),
|
||||
|
||||
@@ -34,7 +34,7 @@ use darkfi::{
|
||||
Result,
|
||||
};
|
||||
|
||||
use crate::model::{DaoProposeParams, DaoProposeParamsInput};
|
||||
use crate::model::{DaoProposalBulla, DaoProposeParams, DaoProposeParamsInput};
|
||||
|
||||
use super::DaoInfo;
|
||||
|
||||
@@ -195,14 +195,14 @@ impl DaoProposeCall {
|
||||
|
||||
let dao_leaf_position: u64 = self.dao_leaf_position.into();
|
||||
|
||||
let proposal_bulla = poseidon_hash::<6>([
|
||||
let proposal_bulla = DaoProposalBulla::from(poseidon_hash::<6>([
|
||||
proposal_dest_x,
|
||||
proposal_dest_y,
|
||||
proposal_amount,
|
||||
self.proposal.token_id.inner(),
|
||||
dao_bulla,
|
||||
self.proposal.blind,
|
||||
]);
|
||||
]));
|
||||
|
||||
let prover_witnesses = vec![
|
||||
// Proposers total number of gov tokens
|
||||
@@ -231,7 +231,7 @@ impl DaoProposeCall {
|
||||
let public_inputs = vec![
|
||||
token_commit,
|
||||
self.dao_merkle_root.inner(),
|
||||
proposal_bulla,
|
||||
proposal_bulla.inner(),
|
||||
*total_funds_coords.x(),
|
||||
*total_funds_coords.y(),
|
||||
];
|
||||
|
||||
@@ -36,7 +36,7 @@ use darkfi::{
|
||||
};
|
||||
|
||||
use super::{DaoInfo, DaoProposalInfo};
|
||||
use crate::model::{DaoVoteParams, DaoVoteParamsInput};
|
||||
use crate::model::{DaoProposalBulla, DaoVoteParams, DaoVoteParamsInput};
|
||||
|
||||
#[derive(SerialEncodable, SerialDecodable)]
|
||||
pub struct DaoVoteNote {
|
||||
@@ -196,14 +196,14 @@ impl DaoVoteCall {
|
||||
self.dao.bulla_blind,
|
||||
]);
|
||||
|
||||
let proposal_bulla = poseidon_hash::<6>([
|
||||
let proposal_bulla = DaoProposalBulla::from(poseidon_hash::<6>([
|
||||
proposal_dest_x,
|
||||
proposal_dest_y,
|
||||
proposal_amount,
|
||||
self.proposal.token_id.inner(),
|
||||
dao_bulla,
|
||||
self.proposal.blind,
|
||||
]);
|
||||
]));
|
||||
|
||||
let vote_option = self.vote_option as u64;
|
||||
assert!(vote_option == 0 || vote_option == 1);
|
||||
@@ -243,7 +243,7 @@ impl DaoVoteCall {
|
||||
|
||||
let public_inputs = vec![
|
||||
token_commit,
|
||||
proposal_bulla,
|
||||
proposal_bulla.inner(),
|
||||
// this should be a value commit??
|
||||
*yes_vote_commit_coords.x(),
|
||||
*yes_vote_commit_coords.y(),
|
||||
|
||||
@@ -55,7 +55,7 @@ pub(crate) fn dao_exec_get_metadata(
|
||||
zk_public_inputs.push((
|
||||
DAO_CONTRACT_ZKAS_DAO_EXEC_NS.to_string(),
|
||||
vec![
|
||||
params.proposal,
|
||||
params.proposal.inner(),
|
||||
params.coin_0.inner(),
|
||||
params.coin_1.inner(),
|
||||
*yes_vote_coords.x(),
|
||||
@@ -110,8 +110,11 @@ pub(crate) fn dao_exec_process_instruction(
|
||||
// Checks
|
||||
// ======
|
||||
// 1. Check coins in MoneyTransfer are the same as our coin 0 and coin 1
|
||||
if mt_params.outputs[0].coin != params.coin_0 ||
|
||||
mt_params.outputs[1].coin != params.coin_1 ||
|
||||
// * outputs[0] is the change returned to DAO
|
||||
// * outputs[1] is the value being sent to the recipient
|
||||
// (This is how it's done in the client API of Money::Transfer)
|
||||
if mt_params.outputs[0].coin != params.coin_1 ||
|
||||
mt_params.outputs[1].coin != params.coin_0 ||
|
||||
mt_params.outputs.len() != 2
|
||||
{
|
||||
msg!("[Dao::Exec] Error: Coin commitments mismatch");
|
||||
|
||||
@@ -85,7 +85,7 @@ pub(crate) fn dao_propose_get_metadata(
|
||||
vec![
|
||||
params.token_commit,
|
||||
params.dao_merkle_root.inner(),
|
||||
params.proposal_bulla,
|
||||
params.proposal_bulla.inner(),
|
||||
*total_funds_coords.x(),
|
||||
*total_funds_coords.y(),
|
||||
],
|
||||
|
||||
@@ -90,7 +90,7 @@ pub(crate) fn dao_vote_get_metadata(
|
||||
DAO_CONTRACT_ZKAS_DAO_VOTE_MAIN_NS.to_string(),
|
||||
vec![
|
||||
params.token_commit,
|
||||
params.proposal_bulla,
|
||||
params.proposal_bulla.inner(),
|
||||
*yes_vote_commit_coords.x(),
|
||||
*yes_vote_commit_coords.y(),
|
||||
*all_vote_commit_coords.x(),
|
||||
|
||||
@@ -57,12 +57,6 @@ pub mod entrypoint;
|
||||
/// Client API for interaction with this smart contract
|
||||
pub mod client;
|
||||
|
||||
// TODO: Delete these and use the proper API
|
||||
#[cfg(feature = "client")]
|
||||
pub mod money_client;
|
||||
#[cfg(feature = "client")]
|
||||
pub mod wallet_cache;
|
||||
|
||||
// These are the different sled trees that will be created
|
||||
pub const DAO_CONTRACT_DB_INFO_TREE: &str = "dao_info";
|
||||
pub const DAO_CONTRACT_DB_DAO_BULLAS: &str = "dao_bullas";
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use core::str::FromStr;
|
||||
|
||||
use darkfi_money_contract::model::Coin;
|
||||
use darkfi_sdk::{
|
||||
crypto::{note::AeadEncryptedNote, pasta_prelude::*, MerkleNode, Nullifier, PublicKey},
|
||||
@@ -51,11 +53,53 @@ impl DaoBulla {
|
||||
}
|
||||
}
|
||||
|
||||
use core::str::FromStr;
|
||||
impl std::hash::Hash for DaoBulla {
|
||||
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
|
||||
state.write(&self.to_bytes());
|
||||
}
|
||||
}
|
||||
|
||||
darkfi_sdk::fp_from_bs58!(DaoBulla);
|
||||
darkfi_sdk::fp_to_bs58!(DaoBulla);
|
||||
darkfi_sdk::ty_from_fp!(DaoBulla);
|
||||
|
||||
/// A `DaoProposalBulla` represented in the state
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, SerialEncodable, SerialDecodable)]
|
||||
pub struct DaoProposalBulla(pallas::Base);
|
||||
|
||||
impl DaoProposalBulla {
|
||||
/// Reference the raw inner base field element
|
||||
pub fn inner(&self) -> pallas::Base {
|
||||
self.0
|
||||
}
|
||||
|
||||
/// Create a `DaoBulla` object from given bytes, erroring if the
|
||||
/// input bytes are noncanonical.
|
||||
pub fn from_bytes(x: [u8; 32]) -> Result<Self, ContractError> {
|
||||
match pallas::Base::from_repr(x).into() {
|
||||
Some(v) => Ok(Self(v)),
|
||||
None => Err(ContractError::IoError(
|
||||
"Failed to instantiate DaoProposalBulla from bytes".to_string(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert the `DaoBulla` type into 32 raw bytes
|
||||
pub fn to_bytes(&self) -> [u8; 32] {
|
||||
self.0.to_repr()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::hash::Hash for DaoProposalBulla {
|
||||
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
|
||||
state.write(&self.to_bytes());
|
||||
}
|
||||
}
|
||||
|
||||
darkfi_sdk::fp_from_bs58!(DaoProposalBulla);
|
||||
darkfi_sdk::fp_to_bs58!(DaoProposalBulla);
|
||||
darkfi_sdk::ty_from_fp!(DaoProposalBulla);
|
||||
|
||||
/// Parameters for `Dao::Mint`
|
||||
#[derive(Debug, Copy, Clone, SerialEncodable, SerialDecodable)]
|
||||
pub struct DaoMintParams {
|
||||
@@ -80,7 +124,7 @@ pub struct DaoProposeParams {
|
||||
/// Token ID commitment for the proposal
|
||||
pub token_commit: pallas::Base,
|
||||
/// Bulla of the DAO proposal
|
||||
pub proposal_bulla: pallas::Base,
|
||||
pub proposal_bulla: DaoProposalBulla,
|
||||
/// Encrypted note
|
||||
pub note: AeadEncryptedNote,
|
||||
/// Inputs for the proposal
|
||||
@@ -102,7 +146,7 @@ pub struct DaoProposeParamsInput {
|
||||
#[derive(Debug, Copy, Clone, SerialEncodable, SerialDecodable)]
|
||||
pub struct DaoProposeUpdate {
|
||||
/// Minted proposal bulla
|
||||
pub proposal_bulla: pallas::Base,
|
||||
pub proposal_bulla: DaoProposalBulla,
|
||||
/// Snapshotted Merkle root in the Money state
|
||||
pub snapshot_root: MerkleNode,
|
||||
}
|
||||
@@ -124,7 +168,7 @@ pub struct DaoVoteParams {
|
||||
/// Token commitment for the vote inputs
|
||||
pub token_commit: pallas::Base,
|
||||
/// Proposal bulla being voted on
|
||||
pub proposal_bulla: pallas::Base,
|
||||
pub proposal_bulla: DaoProposalBulla,
|
||||
/// Commitment for yes votes
|
||||
pub yes_vote_commit: pallas::Point,
|
||||
/// Encrypted note
|
||||
@@ -150,7 +194,7 @@ pub struct DaoVoteParamsInput {
|
||||
#[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
|
||||
pub struct DaoVoteUpdate {
|
||||
/// The proposal bulla being voted on
|
||||
pub proposal_bulla: pallas::Base,
|
||||
pub proposal_bulla: DaoProposalBulla,
|
||||
/// The updated proposal metadata
|
||||
pub proposal_metadata: DaoProposalMetadata,
|
||||
/// Vote nullifiers,
|
||||
@@ -188,7 +232,7 @@ impl Default for DaoBlindAggregateVote {
|
||||
#[derive(Debug, Copy, Clone, SerialEncodable, SerialDecodable)]
|
||||
pub struct DaoExecParams {
|
||||
/// The proposal bulla
|
||||
pub proposal: pallas::Base,
|
||||
pub proposal: DaoProposalBulla,
|
||||
/// The output coin for the proposal recipient
|
||||
pub coin_0: Coin,
|
||||
/// The output coin for the change returned to DAO
|
||||
@@ -203,5 +247,5 @@ pub struct DaoExecParams {
|
||||
#[derive(Debug, Copy, Clone, SerialEncodable, SerialDecodable)]
|
||||
pub struct DaoExecUpdate {
|
||||
/// The proposal bulla
|
||||
pub proposal: pallas::Base,
|
||||
pub proposal: DaoProposalBulla,
|
||||
}
|
||||
|
||||
@@ -1,227 +0,0 @@
|
||||
/* This file is part of DarkFi (https://dark.fi)
|
||||
*
|
||||
* Copyright (C) 2020-2023 Dyne.org foundation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
//! TODO: This file should be deleted and the API from money::client
|
||||
//! should be used directly.
|
||||
|
||||
use darkfi::{
|
||||
zk::{Proof, ProvingKey},
|
||||
zkas::ZkBinary,
|
||||
Result,
|
||||
};
|
||||
use darkfi_sdk::{
|
||||
bridgetree,
|
||||
crypto::{
|
||||
note::AeadEncryptedNote, pasta_prelude::*, MerkleNode, PublicKey, SecretKey, TokenId,
|
||||
ValueBlind,
|
||||
},
|
||||
pasta::pallas,
|
||||
};
|
||||
|
||||
use rand::rngs::OsRng;
|
||||
|
||||
use darkfi_money_contract::{
|
||||
client::{
|
||||
transfer_v1::{
|
||||
create_transfer_burn_proof, create_transfer_mint_proof, TransactionBuilderInputInfo,
|
||||
TransactionBuilderOutputInfo,
|
||||
},
|
||||
MoneyNote,
|
||||
},
|
||||
model::{ClearInput, Input, MoneyTransferParamsV1, Output},
|
||||
};
|
||||
|
||||
pub struct TransferCall {
|
||||
pub clear_inputs: Vec<TransferClearInput>,
|
||||
pub inputs: Vec<TransferInput>,
|
||||
pub outputs: Vec<TransferOutput>,
|
||||
}
|
||||
|
||||
pub struct TransferClearInput {
|
||||
pub value: u64,
|
||||
pub token_id: TokenId,
|
||||
pub signature_secret: SecretKey,
|
||||
}
|
||||
|
||||
pub struct TransferInput {
|
||||
pub leaf_position: bridgetree::Position,
|
||||
pub merkle_path: Vec<MerkleNode>,
|
||||
pub secret: SecretKey,
|
||||
pub note: MoneyNote,
|
||||
pub user_data_blind: pallas::Base,
|
||||
pub value_blind: ValueBlind,
|
||||
pub signature_secret: SecretKey,
|
||||
}
|
||||
|
||||
pub struct TransferOutput {
|
||||
pub value: u64,
|
||||
pub token_id: TokenId,
|
||||
pub public: PublicKey,
|
||||
pub serial: pallas::Base,
|
||||
pub spend_hook: pallas::Base,
|
||||
pub user_data: pallas::Base,
|
||||
}
|
||||
|
||||
impl TransferCall {
|
||||
fn compute_remainder_blind(
|
||||
clear_inputs: &[ClearInput],
|
||||
input_blinds: &[ValueBlind],
|
||||
output_blinds: &[ValueBlind],
|
||||
) -> ValueBlind {
|
||||
let mut total = ValueBlind::zero();
|
||||
|
||||
for input in clear_inputs {
|
||||
total += input.value_blind;
|
||||
}
|
||||
|
||||
for input_blind in input_blinds {
|
||||
total += input_blind;
|
||||
}
|
||||
|
||||
for output_blind in output_blinds {
|
||||
total -= output_blind;
|
||||
}
|
||||
|
||||
total
|
||||
}
|
||||
|
||||
pub fn make(
|
||||
self,
|
||||
mint_zkbin: &ZkBinary,
|
||||
mint_pk: &ProvingKey,
|
||||
burn_zkbin: &ZkBinary,
|
||||
burn_pk: &ProvingKey,
|
||||
) -> Result<(MoneyTransferParamsV1, Vec<Proof>)> {
|
||||
assert!(self.clear_inputs.len() + self.inputs.len() > 0);
|
||||
|
||||
let mut clear_inputs = vec![];
|
||||
let token_blind = ValueBlind::random(&mut OsRng);
|
||||
for input in &self.clear_inputs {
|
||||
let signature_public = PublicKey::from_secret(input.signature_secret);
|
||||
let value_blind = ValueBlind::random(&mut OsRng);
|
||||
|
||||
let clear_input = ClearInput {
|
||||
value: input.value,
|
||||
token_id: input.token_id,
|
||||
value_blind,
|
||||
token_blind,
|
||||
signature_public,
|
||||
};
|
||||
clear_inputs.push(clear_input);
|
||||
}
|
||||
|
||||
let mut proofs = vec![];
|
||||
let mut inputs = vec![];
|
||||
let mut input_blinds = vec![];
|
||||
|
||||
for input in self.inputs {
|
||||
let value_blind = input.value_blind;
|
||||
input_blinds.push(value_blind);
|
||||
|
||||
// FIXME: Just an API hack
|
||||
let _input = TransactionBuilderInputInfo {
|
||||
leaf_position: input.leaf_position,
|
||||
merkle_path: input.merkle_path,
|
||||
secret: input.secret,
|
||||
note: input.note,
|
||||
};
|
||||
|
||||
let (proof, revealed) = create_transfer_burn_proof(
|
||||
burn_zkbin,
|
||||
burn_pk,
|
||||
&_input,
|
||||
value_blind,
|
||||
token_blind,
|
||||
input.user_data_blind,
|
||||
input.signature_secret,
|
||||
)?;
|
||||
|
||||
proofs.push(proof);
|
||||
|
||||
let input = Input {
|
||||
value_commit: revealed.value_commit,
|
||||
token_commit: revealed.token_commit,
|
||||
nullifier: revealed.nullifier,
|
||||
merkle_root: revealed.merkle_root,
|
||||
spend_hook: revealed.spend_hook,
|
||||
user_data_enc: revealed.user_data_enc,
|
||||
signature_public: revealed.signature_public,
|
||||
};
|
||||
inputs.push(input);
|
||||
}
|
||||
|
||||
let mut outputs = vec![];
|
||||
let mut output_blinds = vec![];
|
||||
// This value_blind calc assumes there will always be at least a single output
|
||||
assert!(!self.outputs.is_empty());
|
||||
|
||||
for (i, output) in self.outputs.iter().enumerate() {
|
||||
let value_blind = if i == self.outputs.len() - 1 {
|
||||
Self::compute_remainder_blind(&clear_inputs, &input_blinds, &output_blinds)
|
||||
} else {
|
||||
ValueBlind::random(&mut OsRng)
|
||||
};
|
||||
output_blinds.push(value_blind);
|
||||
|
||||
let serial = output.serial;
|
||||
|
||||
// FIXME: This is a hack between the two APIs
|
||||
let _output = TransactionBuilderOutputInfo {
|
||||
value: output.value,
|
||||
token_id: output.token_id,
|
||||
public_key: output.public,
|
||||
};
|
||||
|
||||
let (proof, revealed) = create_transfer_mint_proof(
|
||||
mint_zkbin,
|
||||
mint_pk,
|
||||
&_output,
|
||||
value_blind,
|
||||
token_blind,
|
||||
serial,
|
||||
output.spend_hook,
|
||||
output.user_data,
|
||||
)?;
|
||||
|
||||
proofs.push(proof);
|
||||
|
||||
let note = MoneyNote {
|
||||
serial,
|
||||
value: output.value,
|
||||
token_id: output.token_id,
|
||||
spend_hook: output.spend_hook,
|
||||
user_data: output.user_data,
|
||||
value_blind,
|
||||
token_blind,
|
||||
memo: Vec::new(),
|
||||
};
|
||||
|
||||
let encrypted_note = AeadEncryptedNote::encrypt(¬e, &output.public, &mut OsRng)?;
|
||||
|
||||
let output = Output {
|
||||
value_commit: revealed.value_commit,
|
||||
token_commit: revealed.token_commit,
|
||||
coin: revealed.coin,
|
||||
note: encrypted_note,
|
||||
};
|
||||
outputs.push(output);
|
||||
}
|
||||
|
||||
Ok((MoneyTransferParamsV1 { clear_inputs, inputs, outputs }, proofs))
|
||||
}
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
/* This file is part of DarkFi (https://dark.fi)
|
||||
*
|
||||
* Copyright (C) 2020-2023 Dyne.org foundation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use darkfi_sdk::{
|
||||
bridgetree,
|
||||
crypto::{note::AeadEncryptedNote, pasta_prelude::Field, MerkleNode, MerkleTree, SecretKey},
|
||||
pasta::pallas,
|
||||
};
|
||||
|
||||
use darkfi_money_contract::{client::MoneyNote, model::Coin};
|
||||
|
||||
pub struct OwnCoin {
|
||||
pub coin: Coin,
|
||||
pub note: MoneyNote,
|
||||
pub leaf_position: bridgetree::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 Money Merkle tree state
|
||||
pub tree: MerkleTree,
|
||||
}
|
||||
|
||||
impl Default for WalletCache {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl WalletCache {
|
||||
pub fn new() -> Self {
|
||||
let mut tree = MerkleTree::new(100);
|
||||
tree.append(MerkleNode::from(pallas::Base::ZERO));
|
||||
let _ = tree.mark().unwrap();
|
||||
Self { cache: Vec::new(), tree }
|
||||
}
|
||||
|
||||
/// 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::take(own_coins)
|
||||
}
|
||||
}
|
||||
panic!("you forget to track() this secret!");
|
||||
}
|
||||
|
||||
pub fn try_decrypt_note(&mut self, coin: Coin, ciphertext: &AeadEncryptedNote) {
|
||||
// Add the new coins to the Merkle tree
|
||||
self.tree.append(MerkleNode::from(coin.inner()));
|
||||
|
||||
// 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.mark().expect("coin should be in tree");
|
||||
own_coins.push(OwnCoin { coin, note, leaf_position });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -53,7 +53,8 @@ async fn alice2alice_random_amounts() -> Result<()> {
|
||||
info!(target: "money", "[Faucet] ========================");
|
||||
info!(target: "money", "[Faucet] Building Alice's airdrop");
|
||||
info!(target: "money", "[Faucet] ========================");
|
||||
let (airdrop_tx, airdrop_params) = th.airdrop_native(ALICE_AIRDROP, Holder::Alice)?;
|
||||
let (airdrop_tx, airdrop_params) =
|
||||
th.airdrop_native(ALICE_AIRDROP, Holder::Alice, None, None, None, None)?;
|
||||
|
||||
info!(target: "money", "[Faucet] ==========================");
|
||||
info!(target: "money", "[Faucet] Executing Alice airdrop tx");
|
||||
@@ -151,7 +152,8 @@ async fn alice2alice_multiplecoins_random_amounts() -> Result<()> {
|
||||
info!(target: "money", "[Faucet] ===================================================");
|
||||
info!(target: "money", "[Faucet] Building Money::Mint params for Alice's mint for token {} and amount {}", i, amount);
|
||||
info!(target: "money", "[Faucet] ===================================================");
|
||||
let (mint_tx, mint_params) = th.token_mint(amount, Holder::Alice, Holder::Alice)?;
|
||||
let (mint_tx, mint_params) =
|
||||
th.token_mint(amount, Holder::Alice, Holder::Alice, None, None)?;
|
||||
|
||||
info!(target: "money", "[Faucet] =======================");
|
||||
info!(target: "money", "[Faucet] Executing Alice mint tx");
|
||||
|
||||
Reference in New Issue
Block a user