ソースを参照

annotate entrypoint.rs and format

x 3 年 前
コミット
88b3bb1dfd
7 ファイル変更118 行追加180 行削除
  1. 3 1
      .gitignore
  2. 0 1
      src/client/mod.rs
  3. 22 36
      src/client/set_v1.rs
  4. 47 67
      src/entrypoint.rs
  5. 8 18
      src/model.rs
  6. 33 45
      tests/harness.rs
  7. 5 12
      tests/integration.rs

+ 3 - 1
.gitignore

@@ -1,2 +1,4 @@
-map_contract.wasm
+*.wasm
 proof/*.zk.bin
+target/
+

+ 0 - 1
src/client/mod.rs

@@ -28,4 +28,3 @@
 
 /// `Map::Set` API
 pub mod set_v1;
-

+ 22 - 36
src/client/set_v1.rs

@@ -18,22 +18,13 @@
  */
 
 use darkfi::{
-    zk::{
-        halo2::Value,
-        Proof,
-        ProvingKey,
-        ZkCircuit,
-        Witness
-    },
+    zk::{halo2::Value, Proof, ProvingKey, Witness, ZkCircuit},
     zkas::ZkBinary,
     Result,
 };
 
 use darkfi_sdk::{
-    crypto::{
-        poseidon_hash,
-        SecretKey,
-    },
+    crypto::{poseidon_hash, SecretKey},
     pasta::pallas,
 };
 
@@ -44,13 +35,13 @@ use rand::rngs::OsRng;
 use crate::model::SetParamsV1;
 
 pub struct SetCallBuilder {
-    pub secret:     SecretKey,
-    pub lock:       pallas::Base,
-    pub car:        pallas::Base,
-    pub key:        pallas::Base,
-    pub value:      pallas::Base,
-    pub zkbin:      ZkBinary,
-    pub prove_key:  ProvingKey,
+    pub secret: SecretKey,
+    pub lock: pallas::Base,
+    pub car: pallas::Base,
+    pub key: pallas::Base,
+    pub value: pallas::Base,
+    pub zkbin: ZkBinary,
+    pub prove_key: ProvingKey,
 }
 
 pub struct SetCallDebris {
@@ -63,45 +54,40 @@ impl SetCallBuilder {
     pub fn build(&self) -> Result<SetCallDebris> {
         debug!("Building Map::SetV1 contract call");
 
-        let params = SetParamsV1 { 
+        let params = SetParamsV1 {
             // !!!!private computation done in rust!!!!
-            account: poseidon_hash([self.secret.inner()]), 
-            lock :self.lock,
-            car :self.car,
+            account: poseidon_hash([self.secret.inner()]),
+            lock: self.lock,
+            car: self.car,
             key: self.key,
             value: self.value,
         };
 
-        Ok(
-            SetCallDebris {
-                params: params.clone(),
-                proofs: vec![self.create_set_proof(params.clone())?],
-                signature_secrets: vec![self.secret],
+        Ok(SetCallDebris {
+            params: params.clone(),
+            proofs: vec![self.create_set_proof(params.clone())?],
+            signature_secrets: vec![self.secret],
         })
     }
 
-    pub fn create_set_proof(
-        &self,
-        public_inputs: SetParamsV1
-    ) -> Result<Proof> {
+    pub fn create_set_proof(&self, public_inputs: SetParamsV1) -> Result<Proof> {
         debug!("Creating map set proof");
 
-        let witness       = vec![
+        let witness = vec![
             Witness::Base(Value::known(self.secret.inner())),
             Witness::Base(Value::known(self.car)),
             Witness::Base(Value::known(self.lock)),
             Witness::Base(Value::known(self.key)),
             Witness::Base(Value::known(self.value)),
         ];
-        let circuit       = ZkCircuit::new(witness, self.zkbin.clone());
-        let proof         = Proof::create(
+        let circuit = ZkCircuit::new(witness, self.zkbin.clone());
+        let proof = Proof::create(
             &self.prove_key,
             &[circuit],
             &public_inputs.to_vec(),
-            &mut OsRng
+            &mut OsRng,
         )?;
 
         Ok(proof)
     }
 }
-

+ 47 - 67
src/entrypoint.rs

@@ -18,38 +18,27 @@
  */
 
 use crate::{
-    ContractFunction,
-    MAP_CONTRACT_ENTRIES_TREE,
-    MAP_CONTRACT_ZKAS_SET_NS,
-    error::MapError
+    error::MapError, ContractFunction, MAP_CONTRACT_ENTRIES_TREE, MAP_CONTRACT_ZKAS_SET_NS,
 };
 
 use darkfi_sdk::{
-    crypto::{ContractId, PublicKey, poseidon_hash},
+    crypto::{poseidon_hash, ContractId, PublicKey},
+    db::{db_get, db_init, db_lookup, db_set, zkas_db_set},
     error::{ContractError, ContractResult},
     msg,
     pasta::pallas,
-    ContractCall,
     util::set_return_data,
-    db::{db_init, db_lookup, db_set, zkas_db_set, db_get},
+    ContractCall,
 };
 
-use darkfi_serial::{
-    serialize,
-    deserialize,
-    Encodable,
-    WriteExt
-};
+use darkfi_serial::{deserialize, serialize, Encodable, WriteExt};
 
-use crate::model::{
-    SetParamsV1,
-    SetUpdateV1,
-};
+use crate::model::{SetParamsV1, SetUpdateV1};
 
 // A macro defining the 4 entrypoints
 // init:     called during (re)deployment
 // metadata: called during contract message call, first
-// exec:     second 
+// exec:     second
 // apply:    last
 darkfi_sdk::define_contract!(
     init:     init_contract,
@@ -58,7 +47,6 @@ darkfi_sdk::define_contract!(
     metadata: get_metadata
 );
 
-
 // init takes:
 // - the contract ID given by the runtime
 // - a payload in the form of a slice of bytes
@@ -83,10 +71,10 @@ fn init_contract(cid: ContractId, _ix: &[u8]) -> ContractResult {
     if db_lookup(cid, MAP_CONTRACT_ENTRIES_TREE).is_err() {
         // "Under the hood" are comments for the studious ones about how
         // something works in its implementation.
-        // 
+        //
         // Under the hood: db_init is only allowed callable inside init.
         // https://github.com/darkrenaissance/darkfi/blob/35405831e366eaa74522ab14645a5a05ce5cfa1e/src/runtime/import/db.rs#L55-L58
-        // 
+        //
         // Under the hood: cid must match the contract ID of this contract
         // https://github.com/darkrenaissance/darkfi/blob/35405831e366eaa74522ab14645a5a05ce5cfa1e/src/runtime/import/db.rs#L105-L108
         db_init(cid, MAP_CONTRACT_ENTRIES_TREE)?;
@@ -112,10 +100,8 @@ fn get_metadata(_cid: ContractId, ix: &[u8]) -> ContractResult {
 
     // Match on the first byte to select the function
     match ContractFunction::try_from(self_.data[0])? {
-
         // When the first byte is matched as `Set`
         ContractFunction::Set => {
-
             // Deserialize contract call, excluding the first byte
             let params: SetParamsV1 = deserialize(&self_.data[1..])?;
 
@@ -123,36 +109,31 @@ fn get_metadata(_cid: ContractId, ix: &[u8]) -> ContractResult {
             // a vector of public keys and
             // a vector of (zkas namespace, public inputs)
             let signature_pubkeys: Vec<PublicKey> = vec![];
-            let mut zk_public_inputs: Vec<(String, Vec<pallas::Base>)>
-                = vec![];
-
-            zk_public_inputs.push((
-                MAP_CONTRACT_ZKAS_SET_NS.to_string(),
-                params.to_vec(),
-            ));
-    
+            let mut zk_public_inputs: Vec<(String, Vec<pallas::Base>)> = vec![];
+
+            zk_public_inputs.push((MAP_CONTRACT_ZKAS_SET_NS.to_string(), params.to_vec()));
+
             // Encode the two vectors into one vector
             let mut metadata = vec![];
             zk_public_inputs.encode(&mut metadata)?;
             signature_pubkeys.encode(&mut metadata)?;
 
             // Return data to the host using an import
-            // 
-	    // Under the hood: metadata is invoked here
+            //
+            // Under the hood: metadata is invoked here
             // https://github.com/darkrenaissance/darkfi/blob/35405831e366eaa74522ab14645a5a05ce5cfa1e/src/consensus/validator.rs#L1045C1-L1045C1
             //
-	    // Under the hood: The metadata is return here 
+            // Under the hood: The metadata is returned here
             // https://github.com/darkrenaissance/darkfi/blob/35405831e366eaa74522ab14645a5a05ce5cfa1e/src/runtime/import/util.rs#L43
             set_return_data(&metadata)?;
 
-
             Ok(())
-
         }
-
     }
 }
 
+/// Taking call_idx and calls, `set_return_data` a state update to
+/// return to the host **to be applied in `process_update()`.
 fn process_instruction(cid: ContractId, ix: &[u8]) -> ContractResult {
     let (call_idx, calls): (u32, Vec<ContractCall>) = deserialize(ix)?;
     if call_idx >= calls.len() as u32 {
@@ -162,32 +143,40 @@ fn process_instruction(cid: ContractId, ix: &[u8]) -> ContractResult {
 
     match ContractFunction::try_from(ix[0])? {
         ContractFunction::Set => {
-            msg!("processing SET");
-            let params: SetParamsV1 = 
-                deserialize(&calls[call_idx as usize].data[1..])?;
+            let params: SetParamsV1 = deserialize(&calls[call_idx as usize].data[1..])?;
+
+            // Calculating the slot
+            // If the prover wants to set a top-level name,
+            // i.e. in the canonical root name registry,
+            // then slot = poseidon_hash(0, key)
             let slot = if params.car == pallas::Base::one() {
                 poseidon_hash([pallas::Base::zero(), params.key])
+            // else slot = poseidon_hash(account, key).
+            // That is, if you don't have the account's secret,
+            // you cannot write to the same slot assuming second preimage
+            // resistance.
             } else {
                 poseidon_hash([params.account, params.key])
             };
 
-            // Question being answered by this block of code:
-            // is this slot locked?
+            // Check if this slot is locked.
+            // Allow only setting unlocked slot.
             let db = db_lookup(cid, MAP_CONTRACT_ENTRIES_TREE)?;
             match db_get(db, &serialize(&slot))? {
-                None => msg!("[SET] slot has no value"),
+                None => {}
                 Some(lock) => {
                     if deserialize(&lock)? {
-                        return Err(MapError::Locked.into())
+                        return Err(MapError::Locked.into());
                     }
                 }
             };
+
             msg!("[SET] slot  = {:?}", slot);
             msg!("[SET] car   = {:?}", params.car);
             msg!("[SET] lock  = {:?}", params.lock);
             msg!("[SET] value = {:?}", params.value);
 
-
+            // Prepare the return data for the host.
             let update = SetUpdateV1 {
                 slot,
                 lock: params.lock,
@@ -196,47 +185,38 @@ fn process_instruction(cid: ContractId, ix: &[u8]) -> ContractResult {
             let mut update_data = vec![];
             update_data.write_u8(ContractFunction::Set as u8)?;
             let _ = update.encode(&mut update_data)?;
+
+            // Setting the return data for the host.
+            // Under the hood: https://github.com/darkrenaissance/darkfi/blob/35405831e366eaa74522ab14645a5a05ce5cfa1e/src/runtime/import/util.rs#L43
             set_return_data(&update_data)?;
-            msg!("[SET] State update set!");
 
             Ok(())
         }
     }
 }
 
-fn process_update(
-    cid: ContractId,
-    update_data: &[u8]
-) -> ContractResult {
+/// Taking the cid and the update data set in `process_instruction`,
+/// write to the relevant databases.
+/// In particular, set in db MAP_CONTRACT_ENTRIES_TREE:
+/// * slot     = lock
+/// * slot + 1 = value
+fn process_update(cid: ContractId, update_data: &[u8]) -> ContractResult {
     match ContractFunction::try_from(update_data[0])? {
         ContractFunction::Set => {
             let update: SetUpdateV1 = deserialize(&update_data[1..])?;
 
-            msg!("[SET] serialized_slot     = {:?}",
-                 &serialize(&update.slot));
-            msg!("[SET] serialized_slot + 1 = {:?}",
-                 &serialize(&(update.slot.add(&pallas::Base::one()))));
-            msg!("[SET] serialized_lock    = {:?}",
-                 &serialize(&update.lock));
-            msg!("[SET] serialized_value    = {:?}",
-                 &serialize(&update.value));
-
             // key(slot)     = lock
             // key(slot + 1) = value
             let db = db_lookup(cid, MAP_CONTRACT_ENTRIES_TREE)?;
-            db_set(
-                db,
-                &serialize(&update.slot),
-                &serialize(&update.lock),
-            ).unwrap();
+            db_set(db, &serialize(&update.slot), &serialize(&update.lock)).unwrap();
             db_set(
                 db,
                 &serialize(&(update.slot.add(&pallas::Base::one()))),
                 &serialize(&update.value),
-            ).unwrap();
+            )
+            .unwrap();
 
             Ok(())
-        },
+        }
     }
 }
-

+ 8 - 18
src/model.rs

@@ -1,35 +1,25 @@
 use darkfi_sdk::pasta::pallas;
 
-use darkfi_serial::{
-    SerialDecodable, 
-    SerialEncodable
-};
+use darkfi_serial::{SerialDecodable, SerialEncodable};
 
 #[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
 pub struct SetParamsV1 {
     pub account: pallas::Base,
-    pub lock:    pallas::Base,
-    pub car:     pallas::Base,
-    pub key:     pallas::Base,
-    pub value:   pallas::Base,
+    pub lock: pallas::Base,
+    pub car: pallas::Base,
+    pub key: pallas::Base,
+    pub value: pallas::Base,
 }
 
 impl SetParamsV1 {
     pub fn to_vec(&self) -> Vec<pallas::Base> {
-        vec![
-            self.account,
-            self.lock,
-            self.car,
-            self.key,
-            self.value,
-        ]
+        vec![self.account, self.lock, self.car, self.key, self.value]
     }
 }
 
 #[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
 pub struct SetUpdateV1 {
-    pub slot:  pallas::Base,
-    pub lock:  pallas::Base,
+    pub slot: pallas::Base,
+    pub lock: pallas::Base,
     pub value: pallas::Base,
 }
-

+ 33 - 45
tests/harness.rs

@@ -21,12 +21,8 @@ use std::collections::HashMap;
 
 use darkfi::{
     consensus::{
-        ValidatorState,
-        ValidatorStatePtr,
-        TESTNET_BOOTSTRAP_TIMESTAMP,
-        TESTNET_GENESIS_HASH_BYTES,
-        TESTNET_GENESIS_TIMESTAMP,
-        TESTNET_INITIAL_DISTRIBUTION,
+        ValidatorState, ValidatorStatePtr, TESTNET_BOOTSTRAP_TIMESTAMP, TESTNET_GENESIS_HASH_BYTES,
+        TESTNET_GENESIS_TIMESTAMP, TESTNET_INITIAL_DISTRIBUTION,
     },
     runtime::vm_runtime::SMART_CONTRACT_ZKAS_DB_NAME,
     tx::Transaction,
@@ -36,14 +32,7 @@ use darkfi::{
     Result,
 };
 use darkfi_sdk::{
-    crypto::{
-        Keypair,
-        MerkleTree,
-        PublicKey,
-        SecretKey,
-        DARK_TOKEN_ID,
-        MAP_CONTRACT_ID
-    },
+    crypto::{Keypair, MerkleTree, PublicKey, SecretKey, DARK_TOKEN_ID, MAP_CONTRACT_ID},
     pasta::pallas,
     ContractCall,
 };
@@ -51,11 +40,7 @@ use darkfi_serial::{deserialize, serialize, Encodable};
 use log::info;
 use rand::rngs::OsRng;
 
-use darkfi_map_contract::{
-    model::SetParamsV1,
-    client::set_v1::SetCallBuilder,
-    ContractFunction,
-};
+use darkfi_map_contract::{client::set_v1::SetCallBuilder, model::SetParamsV1, ContractFunction};
 
 pub const MAP_CONTRACT_ZKAS_SET_NS_V1: &str = "Set_V1";
 
@@ -86,10 +71,7 @@ pub struct Wallet {
 }
 
 impl Wallet {
-    async fn new(
-        keypair: Keypair,
-        faucet_pubkeys: &[PublicKey]
-        ) -> Result<Self> {
+    async fn new(keypair: Keypair, faucet_pubkeys: &[PublicKey]) -> Result<Self> {
         let wallet = WalletDb::new("sqlite::memory:", "foo").await?;
         let sled_db = sled::Config::new().temporary(true).open()?;
 
@@ -108,11 +90,15 @@ impl Wallet {
 
         let merkle_tree = MerkleTree::new(100);
 
-        Ok(Self { keypair, state, merkle_tree, wallet, })
+        Ok(Self {
+            keypair,
+            state,
+            merkle_tree,
+            wallet,
+        })
     }
 }
 
-
 pub struct MapTestHarness {
     pub faucet: Wallet,
     pub alice: Wallet,
@@ -129,10 +115,8 @@ impl MapTestHarness {
         let alice = Wallet::new(alice_kp, &faucet_pubkeys).await?;
 
         // Get the zkas circuits and build proving keys
-        let alice_sled = 
-            alice.state.read().await.blockchain.sled_db.clone();
-        let db_handle =
-            alice.state.read().await.blockchain.contracts.lookup(
+        let alice_sled = alice.state.read().await.blockchain.sled_db.clone();
+        let db_handle = alice.state.read().await.blockchain.contracts.lookup(
             &alice_sled,
             &MAP_CONTRACT_ID,
             SMART_CONTRACT_ZKAS_DB_NAME,
@@ -142,10 +126,8 @@ impl MapTestHarness {
         let mut proving_keys = HashMap::new();
         macro_rules! mkpk {
             ($ns:expr) => {
-                let zkas_bytes =
-                    db_handle.get(&serialize(&$ns))?.unwrap();
-                let (zkbin, _): (Vec<u8>, Vec<u8>) =
-                                 deserialize(&zkas_bytes)?;
+                let zkas_bytes = db_handle.get(&serialize(&$ns))?.unwrap();
+                let (zkbin, _): (Vec<u8>, Vec<u8>) = deserialize(&zkas_bytes)?;
                 let zkbin = ZkBinary::decode(&zkbin)?;
                 let witnesses = empty_witnesses(&zkbin);
                 let circuit = ZkCircuit::new(witnesses, zkbin.clone());
@@ -155,7 +137,11 @@ impl MapTestHarness {
         }
         mkpk!(MAP_CONTRACT_ZKAS_SET_NS_V1);
 
-        Ok(Self { faucet, alice, proving_keys })
+        Ok(Self {
+            faucet,
+            alice,
+            proving_keys,
+        })
     }
 
     pub fn set(
@@ -166,10 +152,7 @@ impl MapTestHarness {
         key: pallas::Base,
         value: pallas::Base,
     ) -> Result<(Transaction, SetParamsV1)> {
-        let (prove_key, zkbin) = 
-            self.proving_keys.get(
-                &MAP_CONTRACT_ZKAS_SET_NS_V1
-                ).unwrap();   
+        let (prove_key, zkbin) = self.proving_keys.get(&MAP_CONTRACT_ZKAS_SET_NS_V1).unwrap();
         let debris = SetCallBuilder {
             zkbin: zkbin.clone(),
             prove_key: prove_key.clone(),
@@ -177,21 +160,26 @@ impl MapTestHarness {
             lock: lock.clone(),
             car: car.clone(),
             key: key.clone(),
-            value: value.clone()
-        }.build()?;
+            value: value.clone(),
+        }
+        .build()?;
 
         let mut data = vec![ContractFunction::Set as u8];
         debris.params.encode(&mut data)?;
-        let calls = vec![
-            ContractCall { contract_id: *MAP_CONTRACT_ID, data: data }
-        ];
+        let calls = vec![ContractCall {
+            contract_id: *MAP_CONTRACT_ID,
+            data: data,
+        }];
         let proofs = vec![debris.proofs];
 
-        let mut tx = Transaction { calls, proofs, signatures: vec![] };
+        let mut tx = Transaction {
+            calls,
+            proofs,
+            signatures: vec![],
+        };
         let sigs = tx.create_sigs(&mut OsRng, &debris.signature_secrets)?;
         tx.signatures = vec![sigs];
 
         Ok((tx, debris.params))
     }
 }
-

+ 5 - 12
tests/integration.rs

@@ -16,25 +16,18 @@
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-
-use std::time::Instant;
 use darkfi::Result;
+use darkfi_map_contract::MAP_CONTRACT_ENTRIES_TREE;
 use darkfi_sdk::{
-    crypto::{
-        poseidon_hash,
-        Keypair,
-        MerkleNode,
-        Nullifier,
-        MAP_CONTRACT_ID
-    },
+    crypto::{poseidon_hash, Keypair, MerkleNode, Nullifier, MAP_CONTRACT_ID},
     incrementalmerkletree::Tree,
     pasta::pallas,
     // db::{db_lookup, db_get} link error?
 };
-use log::{info, debug};
-use rand::rngs::OsRng;
-use darkfi_map_contract::MAP_CONTRACT_ENTRIES_TREE;
 use darkfi_serial::{deserialize, serialize};
+use log::{debug, info};
+use rand::rngs::OsRng;
+use std::time::Instant;
 
 mod harness;
 use harness::{init_logger, MapTestHarness};