Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Testing multiple note insertions #19

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Nargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ compiler_version = ">=0.18.0"

[dependencies]
aztec = { git = "https://github.com/AztecProtocol/aztec-packages/", tag = "aztec-packages-v0.62.0", directory = "noir-projects/aztec-nr/aztec" }
value_note = { git="https://github.com/AztecProtocol/aztec-packages/", tag="aztec-packages-v0.62.0", directory="noir-projects/aztec-nr/value-note" }
26 changes: 24 additions & 2 deletions src/main.nr
Original file line number Diff line number Diff line change
@@ -1,19 +1,26 @@
mod test;
mod types;
use dep::aztec::macros::aztec;

#[aztec]
contract EasyPrivateVoting {
use crate::types::shared_note::{SHARED_NOTE_LEN, SharedNote};
use dep::aztec::{
encrypted_logs::encrypted_note_emission::encode_and_encrypt_note,
keys::getters::get_public_keys,
macros::{functions::{initializer, internal, private, public}, storage::storage},
oracle::random::random,
};
use dep::aztec::prelude::{AztecAddress, Map, PublicMutable, SharedImmutable};
use dep::aztec::prelude::{AztecAddress, Map, PrivateSet, PublicMutable, SharedImmutable};
use dep::value_note::value_note::ValueNote;

#[storage]
struct Storage<Context> {
admin: PublicMutable<AztecAddress, Context>, // admin can end vote
tally: Map<Field, PublicMutable<Field, Context>, Context>, // we will store candidate as key and number of votes as value
vote_ended: PublicMutable<bool, Context>, // vote_ended is boolean
active_at_block: SharedImmutable<u32, Context>, // when people can start voting
set: PrivateSet<SharedNote, Context>,
}

#[public]
Expand All @@ -27,7 +34,7 @@ contract EasyPrivateVoting {

#[private]
// annotation to mark function as private and expose private context
fn cast_vote(candidate: Field) {
fn cast_vote(candidate: Field, bob: AztecAddress, charlie: AztecAddress) {
let msg_sender_npk_m_hash = get_public_keys(context.msg_sender()).npk_m.hash();

let secret = context.request_nsk_app(msg_sender_npk_m_hash); // get secret key of caller of function
Expand All @@ -36,6 +43,21 @@ contract EasyPrivateVoting {
EasyPrivateVoting::at(context.this_address()).add_to_tally_public(candidate).enqueue(
&mut context,
);
//
let mut shared_note = SharedNote::new(context.msg_sender(), bob, random());
let owner_ovpk = get_public_keys(context.msg_sender()).ovpk_m;

let n = storage.set.insert(&mut shared_note);

n.emit(encode_and_encrypt_note(
&mut context,
owner_ovpk,
context.msg_sender(),
context.msg_sender(),
));

n.emit(encode_and_encrypt_note(&mut context, owner_ovpk, bob, context.msg_sender()));
n.emit(encode_and_encrypt_note(&mut context, owner_ovpk, charlie, context.msg_sender()));
}

#[public]
Expand Down
41 changes: 30 additions & 11 deletions src/test/first.nr
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
use crate::test::utils;

use dep::aztec::test::{helpers::{cheatcodes, test_environment::TestEnvironment}};
use dep::aztec::protocol_types::storage::map::derive_storage_slot_in_map;
use dep::aztec::hash::compute_secret_hash;
use dep::aztec::note::note_getter::{MAX_NOTES_PER_PAGE, view_notes};
use dep::aztec::note::note_viewer_options::NoteViewerOptions;
use dep::aztec::hash::compute_secret_hash;
use dep::aztec::protocol_types::storage::map::derive_storage_slot_in_map;
use dep::aztec::test::helpers::{cheatcodes, test_environment::TestEnvironment};

use dep::aztec::{oracle::{execution::{get_block_number, get_contract_address}, storage::storage_read}};
use dep::aztec::oracle::{
execution::{get_block_number, get_contract_address},
storage::storage_read,
};

use crate::EasyPrivateVoting;

Expand Down Expand Up @@ -60,11 +63,16 @@ unconstrained fn test_fail_end_vote_by_non_admin() {
unconstrained fn test_cast_vote() {
let (env, voting_contract_address, _) = utils::setup();
let alice = env.create_account();
let bob = env.create_account();
let charlie = env.create_account();

env.impersonate(alice);

let candidate = 1;
env.advance_block_by(6);
EasyPrivateVoting::at(voting_contract_address).cast_vote(candidate).call(&mut env.private());
EasyPrivateVoting::at(voting_contract_address).cast_vote(candidate, bob, charlie).call(
&mut env.private(),
);

// Read vote count from storage
let block_number = get_block_number();
Expand All @@ -80,16 +88,21 @@ unconstrained fn test_cast_vote_with_separate_accounts() {
let (env, voting_contract_address, _) = utils::setup();
let alice = env.create_account();
let bob = env.create_account();
let charlie = env.create_account();

let candidate = 101;

env.impersonate(alice);
env.advance_block_by(1);
EasyPrivateVoting::at(voting_contract_address).cast_vote(candidate).call(&mut env.private());
EasyPrivateVoting::at(voting_contract_address).cast_vote(candidate, bob, charlie).call(
&mut env.private(),
);

env.impersonate(bob);
env.advance_block_by(1);
EasyPrivateVoting::at(voting_contract_address).cast_vote(candidate).call(&mut env.private());
EasyPrivateVoting::at(voting_contract_address).cast_vote(candidate, bob, charlie).call(
&mut env.private(),
);

// Read vote count from storage
let block_number = get_block_number();
Expand All @@ -104,14 +117,20 @@ unconstrained fn test_cast_vote_with_separate_accounts() {
unconstrained fn test_fail_vote_twice() {
let (env, voting_contract_address, _) = utils::setup();
let alice = env.create_account();
let bob = env.create_account();
let charlie = env.create_account();

let candidate = 101;

env.impersonate(alice);
env.advance_block_by(1);
EasyPrivateVoting::at(voting_contract_address).cast_vote(candidate).call(&mut env.private());
EasyPrivateVoting::at(voting_contract_address).cast_vote(candidate, bob, charlie).call(
&mut env.private(),
);

// Vote again as alice
env.advance_block_by(1);
EasyPrivateVoting::at(voting_contract_address).cast_vote(candidate).call(&mut env.private());
EasyPrivateVoting::at(voting_contract_address).cast_vote(candidate, bob, charlie).call(
&mut env.private(),
);
}
21 changes: 16 additions & 5 deletions src/test/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ describe("Voting", () => {
pxe = await setupSandbox();

wallets = await getInitialTestAccountsWallets(pxe);

accounts = wallets.map(w => w.getCompleteAddress())
})

Expand Down Expand Up @@ -63,20 +64,30 @@ describe("Voting", () => {

it("It casts a vote", async () => {
const candidate = new Fr(1)
const [deployerWallet, bobWallet, charlieWallet] = wallets; // using first account as deployer and second as bob

const contract = await EasyPrivateVotingContract.deploy(deployerWallet, deployerWallet.getAddress()).send().deployed();
const receipt = await contract.methods.cast_vote(candidate, bobWallet.getAddress(), charlieWallet.getAddress()).send().wait({ debug: true });

console.log(receipt);
const { visibleIncomingNotes, visibleOutgoingNotes } = receipt.debugInfo!
console.log("Visible Incoming Notes:");
console.log(visibleIncomingNotes);
console.log("Visible Outgoing Notes:");
console.log(visibleOutgoingNotes);

const contract = await EasyPrivateVotingContract.deploy(wallets[0], accounts[0].address).send().deployed();
const tx = await contract.methods.cast_vote(candidate).send().wait();
let count = await contract.methods.get_vote(candidate).simulate();
expect(count).toBe(1n);
}, 300_000)

it("It should fail when trying to vote twice", async () => {
const candidate = new Fr(1)
const [deployerWallet, bobWallet, charlieWallet] = wallets; // using first account as deployer and second as bob

const contract = await EasyPrivateVotingContract.deploy(wallets[0], accounts[0].address).send().deployed();
await contract.methods.cast_vote(candidate).send().wait();
const contract = await EasyPrivateVotingContract.deploy(deployerWallet, deployerWallet.getAddress()).send().deployed();
await contract.methods.cast_vote(candidate, bobWallet.getAddress(), charlieWallet.getAddress()).send().wait();

const secondVoteReceipt = await contract.methods.cast_vote(candidate).send().getReceipt();
const secondVoteReceipt = await contract.methods.cast_vote(candidate, bobWallet.getAddress(), charlieWallet.getAddress()).send().getReceipt();
expect(secondVoteReceipt).toEqual(
expect.objectContaining({
status: TxStatus.DROPPED,
Expand Down
1 change: 1 addition & 0 deletions src/types.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
mod shared_note;
64 changes: 64 additions & 0 deletions src/types/shared_note.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
use dep::aztec::{
context::PrivateContext,
macros::notes::note,
note::{
note_header::NoteHeader, note_interface::NullifiableNote,
utils::compute_note_hash_for_nullify,
},
prelude::AztecAddress,
protocol_types::{
constants::GENERATOR_INDEX__NOTE_NULLIFIER,
hash::poseidon2_hash_with_separator,
traits::{Deserialize, Serialize},
},
};

/// @member alice: the user who shares the note
/// @member bob: the user who the note is shared with
/// @member shared_nullifier_key: the key used to nullify the note
#[note]
#[derive(Serialize, Deserialize)]
pub struct SharedNote {
alice: AztecAddress, // msg_sender
bob: AztecAddress, // inputted by msg_sender
shared_nullifier_key: Field, // oracle::random
}

/// @notice Declare the length of the note.
global SHARED_NOTE_LEN: Field = 4;

impl SharedNote {
pub fn new(alice: AztecAddress, bob: AztecAddress, shared_nullifier_key: Field) -> Self {
SharedNote { alice, bob, shared_nullifier_key, header: NoteHeader::empty() }
}
}

impl Eq for SharedNote {
fn eq(self, other: SharedNote) -> bool {
self.alice.eq(other.alice)
& self.bob.eq(other.bob)
& self.shared_nullifier_key.eq(other.shared_nullifier_key)
}
}

impl NullifiableNote for SharedNote {
fn compute_nullifier(
self,
context: &mut PrivateContext,
note_hash_for_nullify: Field,
) -> Field {
// let note_hash_for_nullify = compute_note_hash_for_nullify(self);
poseidon2_hash_with_separator(
[self.shared_nullifier_key],
GENERATOR_INDEX__NOTE_NULLIFIER as Field,
)
}

unconstrained fn compute_nullifier_without_context(self) -> Field {
// let note_hash_for_nullify = compute_note_hash_for_nullify(self);
poseidon2_hash_with_separator(
[self.shared_nullifier_key],
GENERATOR_INDEX__NOTE_NULLIFIER as Field,
)
}
}