ソースを参照

return specific errors for VerifyFailed

narodnik 5 年 前
コミット
ec78bf9ac9
4 ファイル変更64 行追加17 行削除
  1. 37 5
      src/bin/tx.rs
  2. 11 1
      src/error.rs
  3. 1 0
      src/lib.rs
  4. 15 11
      src/tx.rs

+ 37 - 5
src/bin/tx.rs

@@ -16,8 +16,33 @@ use sapvi::crypto::{
 };
 use sapvi::error::{Error, Result};
 use sapvi::serial::{Decodable, Encodable, VarInt};
+use sapvi::state::{state_transition, ProgramState, StateUpdates};
 use sapvi::tx;
 
+struct MemoryState {
+    mint_pvk: groth16::PreparedVerifyingKey<Bls12>,
+    spend_pvk: groth16::PreparedVerifyingKey<Bls12>,
+    cashier_public: jubjub::SubgroupPoint
+}
+
+impl ProgramState for MemoryState {
+    fn is_valid_cashier_public_key(&self, public: &jubjub::SubgroupPoint) -> bool {
+        public == &self.cashier_public
+    }
+
+    fn mint_pvk(&self) -> &groth16::PreparedVerifyingKey<Bls12> {
+        &self.mint_pvk
+    }
+    fn spend_pvk(&self) -> &groth16::PreparedVerifyingKey<Bls12> {
+        &self.spend_pvk
+    }
+}
+
+impl MemoryState {
+    fn apply(updates: StateUpdates) {
+    }
+}
+
 fn main() {
     // Auto create trusted ceremony parameters if they don't exist
     if !Path::new("mint.params").exists() {
@@ -38,6 +63,12 @@ fn main() {
     // This is their public key
     let cashier_public = zcash_primitives::constants::SPENDING_KEY_GENERATOR * cashier_secret;
 
+    let state = MemoryState {
+        mint_pvk,
+        spend_pvk,
+        cashier_public
+    };
+
     // Wallet 1 creates a secret key
     let secret = jubjub::Fr::random(&mut OsRng);
     // This is their public key
@@ -79,12 +110,13 @@ fn main() {
     }
     // Now we receive the tx data
     let note = {
+        let txx = tx::Transaction::decode(&tx_data[..]).unwrap();
         let tx = tx::Transaction::decode(&tx_data[..]).unwrap();
-        // Check the public key in the clear inputs
-        // It should be a valid public key for the cashier
-        assert_eq!(tx.clear_inputs[0].signature_public, cashier_public);
+
+        let update = state_transition(&state, txx).expect("step 2 state transition failed");
+
         // Check the tx verifies correctly
-        assert!(tx.verify(&mint_pvk, &spend_pvk));
+        //assert!(tx.verify(&mint_pvk, &spend_pvk));
         // Add the new coins to the merkle tree
         tree.append(Coin::new(tx.outputs[0].revealed.coin))
             .expect("append merkle");
@@ -172,6 +204,6 @@ fn main() {
     // Verify it's valid
     {
         let tx = tx::Transaction::decode(&tx_data[..]).unwrap();
-        assert!(tx.verify(&mint_pvk, &spend_pvk));
+        //assert!(tx.verify(&mint_pvk, &spend_pvk));
     }
 }

+ 11 - 1
src/error.rs

@@ -1,9 +1,10 @@
 use std::fmt;
+use rusqlite;
 
 use crate::net::error::NetError;
 use crate::service::ServicesError;
+use crate::state;
 use crate::vm::ZKVMError;
-use rusqlite;
 
 pub type Result<T> = std::result::Result<T, Error>;
 
@@ -46,6 +47,7 @@ pub enum Error {
     NoteDecryptionFailed,
     ServicesError(ServicesError),
     ZMQError(zeromq::ZmqError),
+    VerifyFailed(state::VerifyFailed),
 }
 
 impl std::error::Error for Error {}
@@ -92,6 +94,7 @@ impl fmt::Display for Error {
             Error::NoteDecryptionFailed => f.write_str("Unable to decrypt mint note"),
             Error::ServicesError(ref err) => write!(f, "Services error: {}", err),
             Error::ZMQError(ref err) => write!(f, "zmq error: {}", err),
+            Error::VerifyFailed(ref err) => write!(f, "Verify failed: {}", err),
         }
     }
 }
@@ -174,3 +177,10 @@ impl From<std::string::FromUtf8Error> for Error {
         Error::Utf8Error
     }
 }
+
+impl From<state::VerifyFailed> for Error {
+    fn from(err: state::VerifyFailed) -> Error {
+        Error::VerifyFailed(err)
+    }
+}
+

+ 1 - 0
src/lib.rs

@@ -16,6 +16,7 @@ pub mod net;
 pub mod rpc;
 pub mod serial;
 pub mod service;
+pub mod state;
 pub mod system;
 pub mod tx;
 pub mod vm;

+ 15 - 11
src/tx.rs

@@ -17,6 +17,7 @@ use crate::crypto::{
 use crate::error::{Error, Result};
 use crate::impl_vec;
 use crate::serial::{Decodable, Encodable, VarInt};
+use crate::state;
 
 pub struct TransactionBuilder {
     pub clear_inputs: Vec<TransactionBuilderClearInputInfo>,
@@ -267,43 +268,46 @@ impl Transaction {
         &self,
         mint_pvk: &groth16::PreparedVerifyingKey<Bls12>,
         spend_pvk: &groth16::PreparedVerifyingKey<Bls12>,
-    ) -> bool {
+    ) -> std::result::Result<(), state::VerifyFailed> {
         let mut valcom_total = jubjub::SubgroupPoint::identity();
         for input in &self.clear_inputs {
             valcom_total += Self::compute_value_commit(input.value, &input.valcom_blind);
         }
-        for input in &self.inputs {
+        for (i, input) in self.inputs.iter().enumerate() {
             if !verify_spend_proof(spend_pvk, &input.spend_proof, &input.revealed) {
-                return false;
+                return Err(state::VerifyFailed::SpendProof(i));
             }
             valcom_total += &input.revealed.value_commit;
         }
-        for output in &self.outputs {
+        for (i, output) in self.outputs.iter().enumerate() {
             if !verify_mint_proof(mint_pvk, &output.mint_proof, &output.revealed) {
-                println!("mint fail");
-                return false;
+                return Err(state::VerifyFailed::SpendProof(i));
             }
             valcom_total -= &output.revealed.value_commit;
         }
 
+        if valcom_total != jubjub::SubgroupPoint::identity() {
+            return Err(state::VerifyFailed::MissingFunds);
+        }
+
         // Verify signatures
         let mut unsigned_tx_data = vec![];
         self.encode_without_signature(&mut unsigned_tx_data)
             .expect("TODO handle this");
-        for input in &self.clear_inputs {
+        for (i, input) in self.clear_inputs.iter().enumerate() {
             let public = schnorr::PublicKey(input.signature_public.clone());
             if !public.verify(&unsigned_tx_data[..], &input.signature) {
-                return false;
+                return Err(state::VerifyFailed::ClearInputSignature(i));
             }
         }
-        for input in &self.inputs {
+        for (i, input) in self.inputs.iter().enumerate() {
             let public = schnorr::PublicKey(input.revealed.signature_public.clone());
             if !public.verify(&unsigned_tx_data[..], &input.signature) {
-                return false;
+                return Err(state::VerifyFailed::InputSignature(i));
             }
         }
 
-        valcom_total == jubjub::SubgroupPoint::identity()
+            Ok(())
     }
 }