From 6197878157c81c8a1b66bc512f00765c176fb181 Mon Sep 17 00:00:00 2001 From: narodnik Date: Sat, 7 May 2022 10:28:01 +0200 Subject: [PATCH] create proper state transition function --- bin/daod/demo/main.py | 60 ++++++++++++++++++++++++++++++++++++++----- src/node/state.rs | 6 +++++ 2 files changed, 59 insertions(+), 7 deletions(-) diff --git a/bin/daod/demo/main.py b/bin/daod/demo/main.py index 1450f2a4e..25d529987 100644 --- a/bin/daod/demo/main.py +++ b/bin/daod/demo/main.py @@ -3,6 +3,53 @@ from classnamespace import ClassNamespace from crypto import pallas_curve, ff_hash from tx import TransactionBuilder +class State: + + def __init__(self): + self.all_coins = set() + self.nullifiers = set() + + def is_valid_merkle(self, all_coins): + return all_coins.issubset(self.all_coins) + + def nullifier_exists(self, nullifier): + return nullifier in self.nullifiers + + def apply(self, update): + self.nullifiers = self.nullifiers.union(update.nullifiers) + + for coin, enc_note in zip(update.coins, update.enc_notes): + self.all_coins.add(coin) + + # Try to decrypt notes here + print(f"Received {enc_note.value} DRK") + +def state_transition(state, tx): + for input in tx.clear_inputs: + pk = input.signature_public + # Check pk is correct + + for input in tx.inputs: + if not state.is_valid_merkle(input.revealed.all_coins): + print(f"invalid merkle root", file=sys.stderr) + return None + + nullifier = input.revealed.nullifier + if state.nullifier_exists(nullifier): + print(f"duplicate nullifier found", file=sys.stderr) + return None + + is_verify, reason = tx.verify() + if not is_verify: + print(f"tx verify failed: {reason}", file=sys.stderr) + return None + + update = ClassNamespace() + update.nullifiers = [input.revealed.nullifier for input in tx.inputs] + update.coins = [output.revealed.coin for output in tx.outputs] + update.enc_notes = [output.enc_note for output in tx.outputs] + return update + def main(argv): ec = pallas_curve() @@ -19,10 +66,10 @@ def main(argv): builder.add_output(initial_supply, token_id, public) tx = builder.build() - is_verify, reason = tx.verify() - if not is_verify: - print(f"tx verify failed: {reason}", file=sys.stderr) + state = State() + if (update := state_transition(state, tx)) is None: return -1 + state.apply(update) assert len(tx.outputs) > 0 note = tx.outputs[0].enc_note @@ -36,7 +83,7 @@ def main(argv): note.coin_blind ) assert coin == tx.outputs[0].mint_proof.get_revealed().coin - all_coins = [coin] + all_coins = set([coin]) builder = TransactionBuilder(ec) builder.add_input(all_coins, secret, note) @@ -50,10 +97,9 @@ def main(argv): tx = builder.build() - is_verify, reason = tx.verify() - if not is_verify: - print(f"tx2 verify failed: {reason}", file=sys.stderr) + if (update := state_transition(state, tx)) is None: return -1 + state.apply(update) return 0 diff --git a/src/node/state.rs b/src/node/state.rs index db00823a5..5ec979385 100644 --- a/src/node/state.rs +++ b/src/node/state.rs @@ -56,6 +56,7 @@ pub fn state_transition(state: &S, tx: Transaction) -> VerifyRe debug!(target: "state_transition", "Iterate clear_inputs"); for (i, input) in tx.clear_inputs.iter().enumerate() { let pk = &input.signature_public; + // TODO: this depends on the token ID if !state.is_valid_cashier_public_key(pk) && !state.is_valid_faucet_public_key(pk) { error!(target: "state_transition", "Invalid pubkey for clear input: {:?}", pk); return Err(VerifyFailed::InvalidCashierOrFaucetKey(i)) @@ -167,6 +168,11 @@ impl State { let own_coin = OwnCoin { coin, note, secret: *secret, nullifier, leaf_position }; + // FIXME: BUG check values inside the note are correct + // We need to hash them all and check them against the coin + // for them to be accepted. + // Don't trust - verify. + wallet.put_own_coin(own_coin, tokenlist.clone()).await?; if let Some(ch) = notify.clone() {