Просмотр исходного кода

create proper state transition function

narodnik 4 лет назад
Родитель
Сommit
6197878157
2 измененных файлов с 59 добавлено и 7 удалено
  1. 53 7
      bin/daod/demo/main.py
  2. 6 0
      src/node/state.rs

+ 53 - 7
bin/daod/demo/main.py

@@ -3,6 +3,53 @@ from classnamespace import ClassNamespace
 from crypto import pallas_curve, ff_hash
 from crypto import pallas_curve, ff_hash
 from tx import TransactionBuilder
 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):
 def main(argv):
     ec = pallas_curve()
     ec = pallas_curve()
 
 
@@ -19,10 +66,10 @@ def main(argv):
     builder.add_output(initial_supply, token_id, public)
     builder.add_output(initial_supply, token_id, public)
     tx = builder.build()
     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
         return -1
+    state.apply(update)
 
 
     assert len(tx.outputs) > 0
     assert len(tx.outputs) > 0
     note = tx.outputs[0].enc_note
     note = tx.outputs[0].enc_note
@@ -36,7 +83,7 @@ def main(argv):
         note.coin_blind
         note.coin_blind
     )
     )
     assert coin == tx.outputs[0].mint_proof.get_revealed().coin
     assert coin == tx.outputs[0].mint_proof.get_revealed().coin
-    all_coins = [coin]
+    all_coins = set([coin])
 
 
     builder = TransactionBuilder(ec)
     builder = TransactionBuilder(ec)
     builder.add_input(all_coins, secret, note)
     builder.add_input(all_coins, secret, note)
@@ -50,10 +97,9 @@ def main(argv):
 
 
     tx = builder.build()
     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
         return -1
+    state.apply(update)
 
 
     return 0
     return 0
 
 

+ 6 - 0
src/node/state.rs

@@ -56,6 +56,7 @@ pub fn state_transition<S: ProgramState>(state: &S, tx: Transaction) -> VerifyRe
     debug!(target: "state_transition", "Iterate clear_inputs");
     debug!(target: "state_transition", "Iterate clear_inputs");
     for (i, input) in tx.clear_inputs.iter().enumerate() {
     for (i, input) in tx.clear_inputs.iter().enumerate() {
         let pk = &input.signature_public;
         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) {
         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);
             error!(target: "state_transition", "Invalid pubkey for clear input: {:?}", pk);
             return Err(VerifyFailed::InvalidCashierOrFaucetKey(i))
             return Err(VerifyFailed::InvalidCashierOrFaucetKey(i))
@@ -167,6 +168,11 @@ impl State {
                     let own_coin =
                     let own_coin =
                         OwnCoin { coin, note, secret: *secret, nullifier, leaf_position };
                         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?;
                     wallet.put_own_coin(own_coin, tokenlist.clone()).await?;
 
 
                     if let Some(ch) = notify.clone() {
                     if let Some(ch) = notify.clone() {