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

Have native contracts use 0 as "x" so it's not possible to produce signatures.

parazyd 3 лет назад
Родитель
Сommit
8710c13593

+ 2 - 4
bin/drk/src/rpc_blockchain.rs

@@ -41,9 +41,8 @@ use darkfi_money_contract::{
     MoneyFunction,
 };
 use darkfi_sdk::{
-    crypto::{poseidon_hash, ContractId, MerkleNode, Nullifier},
+    crypto::{contract_id::MONEY_CONTRACT_ID, poseidon_hash, ContractId, MerkleNode, Nullifier},
     incrementalmerkletree::Tree,
-    pasta::pallas,
 };
 use darkfi_serial::{deserialize, serialize};
 use serde_json::json;
@@ -134,8 +133,7 @@ impl Drk {
         let mut nullifiers: Vec<Nullifier> = vec![];
         let mut outputs: Vec<Output> = vec![];
 
-        // TODO: FIXME: This shouldn't be hardcoded here obviously.
-        let contract_id = ContractId::from(pallas::Base::from(u64::MAX - 420));
+        let contract_id = *MONEY_CONTRACT_ID;
 
         for (i, tx) in block.txs.iter().enumerate() {
             for (j, call) in tx.calls.iter().enumerate() {

+ 4 - 5
bin/drk/src/rpc_swap.rs

@@ -30,8 +30,9 @@ use darkfi_money_contract::{
 };
 use darkfi_sdk::{
     crypto::{
+        contract_id::MONEY_CONTRACT_ID,
         pedersen::{pedersen_commitment_base, pedersen_commitment_u64, ValueBlind},
-        poseidon_hash, ContractId, PublicKey, SecretKey, TokenId,
+        poseidon_hash, PublicKey, SecretKey, TokenId,
     },
     pasta::pallas,
     tx::ContractCall,
@@ -83,8 +84,7 @@ impl Drk {
         // We'll also need our Merkle tree
         let tree = self.wallet_tree().await?;
 
-        // TODO: FIXME: Do not hardcode the contract ID
-        let contract_id = ContractId::from(pallas::Base::from(u64::MAX - 420));
+        let contract_id = *MONEY_CONTRACT_ID;
 
         // Now we need to do a lookup for the zkas proof bincodes, and create
         // the circuit objects and proving keys so we can build the transaction.
@@ -170,8 +170,7 @@ impl Drk {
         // We'll also need our Merkle tree
         let tree = self.wallet_tree().await?;
 
-        // TODO: FIXME: Do not hardcode the contract ID
-        let contract_id = ContractId::from(pallas::Base::from(u64::MAX - 420));
+        let contract_id = *MONEY_CONTRACT_ID;
 
         // Now we need to do a lookup for the zkas proof bincodes, and create
         // the circuit objects and proving keys so we can build the transaction.

+ 2 - 4
bin/drk/src/rpc_transfer.rs

@@ -28,8 +28,7 @@ use darkfi_money_contract::{
     MoneyFunction, MONEY_CONTRACT_ZKAS_BURN_NS_V1, MONEY_CONTRACT_ZKAS_MINT_NS_V1,
 };
 use darkfi_sdk::{
-    crypto::{ContractId, Keypair, PublicKey, TokenId},
-    pasta::pallas,
+    crypto::{contract_id::MONEY_CONTRACT_ID, Keypair, PublicKey, TokenId},
     tx::ContractCall,
 };
 use darkfi_serial::Encodable;
@@ -77,8 +76,7 @@ impl Drk {
         let secrets = self.wallet_secrets().await?;
         let keypair = Keypair::new(secrets[0]);
 
-        // TODO: FIXME: Do not hardcode the contract ID
-        let contract_id = ContractId::from(pallas::Base::from(u64::MAX - 420));
+        let contract_id = *MONEY_CONTRACT_ID;
 
         // Now we need to do a lookup for the zkas proof bincodes, and create
         // the circuit objects and proving keys so we can build the transaction.

+ 7 - 6
bin/faucetd/src/main.rs

@@ -34,10 +34,13 @@ use darkfi_money_contract::{
     MoneyFunction, MONEY_CONTRACT_ZKAS_BURN_NS_V1, MONEY_CONTRACT_ZKAS_MINT_NS_V1,
 };
 use darkfi_sdk::{
-    crypto::{constants::MERKLE_DEPTH, ContractId, Keypair, MerkleNode, PublicKey, TokenId},
+    crypto::{
+        constants::MERKLE_DEPTH, contract_id::MONEY_CONTRACT_ID, Keypair, MerkleNode, PublicKey,
+        TokenId,
+    },
     db::SMART_CONTRACT_ZKAS_DB_NAME,
     incrementalmerkletree::bridgetree::BridgeTree,
-    pasta::{group::ff::PrimeField, pallas},
+    pasta::group::ff::PrimeField,
     tx::ContractCall,
 };
 use darkfi_serial::{deserialize, serialize, Encodable};
@@ -208,8 +211,7 @@ impl Faucetd {
         let proving_keys = Arc::new(RwLock::new(HashMap::new()));
 
         // For now we'll create the keys for the money contract
-        // FIXME: This shouldn't be hardcoded (see consensus/state.rs)
-        let cid = ContractId::from(pallas::Base::from(u64::MAX - 420));
+        let cid = *MONEY_CONTRACT_ID;
 
         // Do a lookup for the money contract's zkas database and fetch the circuits.
         let blockchain = { validator_state.read().await.blockchain.clone() };
@@ -405,8 +407,7 @@ impl Faucetd {
         };
         drop(map);
 
-        // FIXME: This hardcoded shit (see consensus/state.rs)
-        let cid = ContractId::from(pallas::Base::from(u64::MAX - 420));
+        let cid = *MONEY_CONTRACT_ID;
 
         let (mint_zkbin, mint_pk, burn_zkbin, burn_pk) = {
             let proving_keys_r = self.proving_keys.read().await;

+ 4 - 8
src/consensus/validator.rs

@@ -22,8 +22,9 @@ use async_std::sync::{Arc, RwLock};
 use darkfi_sdk::{
     crypto::{
         constants::MERKLE_DEPTH,
+        contract_id::MONEY_CONTRACT_ID,
         schnorr::{SchnorrPublic, SchnorrSecret},
-        ContractId, MerkleNode, PublicKey,
+        MerkleNode, PublicKey,
     },
     db::SMART_CONTRACT_ZKAS_DB_NAME,
     incrementalmerkletree::{bridgetree::BridgeTree, Tree},
@@ -137,14 +138,9 @@ impl ValidatorState {
         // whatever is necessary. This logic should be handled in the init function
         // of the actual contract, so make sure the native contracts handle this well.
 
-        // FIXME: This ID should be something that does not solve the pallas curve equation,
-        // and/or just hardcoded and forbidden in non-native contract deployment.
-        let money_contract_id = ContractId::from(pallas::Base::from(u64::MAX - 420));
         // The faucet pubkeys are pubkeys which are allowed to create clear inputs
         // in the money contract.
         let money_contract_deploy_payload = serialize(&faucet_pubkeys);
-
-        //let dao_contract_id = ContractId::from(pallas::Base::from(u64::MAX - 421));
         //let dao_contract_deploy_payload = vec![];
 
         // In this hashmap, we keep references to ZK proof verifying keys needed
@@ -154,13 +150,13 @@ impl ValidatorState {
         let native_contracts = vec![
             (
                 "Money Contract",
-                money_contract_id,
+                *MONEY_CONTRACT_ID,
                 include_bytes!("../contract/money/money_contract.wasm").to_vec(),
                 money_contract_deploy_payload,
             ),
             //(
             //    "DAO Contract",
-            //    dao_contract_id,
+            //    *DAO_CONTRACT_ID,
             //    include_bytes!("../contract/dao/dao_contract.wasm").to_vec(),
             //    dao_contract_deploy_payload,
             //),

+ 5 - 6
src/contract/dao/src/entrypoint.rs

@@ -17,7 +17,7 @@
  */
 
 use darkfi_sdk::{
-    crypto::{ContractId, MerkleNode, MerkleTree, PublicKey},
+    crypto::{contract_id::MONEY_CONTRACT_ID, ContractId, MerkleNode, MerkleTree, PublicKey},
     db::{db_contains_key, db_get, db_init, db_lookup, db_set, SMART_CONTRACT_ZKAS_DB_NAME},
     error::{ContractError, ContractResult},
     merkle::merkle_add,
@@ -177,7 +177,7 @@ fn process_instruction(cid: ContractId, ix: &[u8]) -> ContractResult {
             let params: DaoProposeParams = deserialize(&self_.data[1..])?;
 
             // Check the Merkle roots for the input coins are valid
-            let money_cid = ContractId::from(pallas::Base::from(u64::MAX - 420));
+            let money_cid = *MONEY_CONTRACT_ID;
             let coin_roots_db = db_lookup(money_cid, MONEY_CONTRACT_COIN_ROOTS_TREE)?;
             for input in &params.inputs {
                 if !db_contains_key(coin_roots_db, &serialize(&input.merkle_root))? {
@@ -209,7 +209,7 @@ fn process_instruction(cid: ContractId, ix: &[u8]) -> ContractResult {
         DaoFunction::Vote => {
             let params: DaoVoteParams = deserialize(&self_.data[1..])?;
 
-            let money_cid = ContractId::from(pallas::Base::from(u64::MAX - 420));
+            let money_cid = *MONEY_CONTRACT_ID;
 
             // Check proposal bulla exists
             let proposal_votes_db = db_lookup(cid, DAO_PROPOSAL_VOTES_TREE)?;
@@ -275,8 +275,7 @@ fn process_instruction(cid: ContractId, ix: &[u8]) -> ContractResult {
             assert!(call_idx == 1);
 
             // 3. First item should be a MoneyTransfer call
-            // FIXME: No hardcode of contract like this
-            assert!(call[0].contract_id == ContractId::from(pallas::Base::from(u64::MAX - 420)));
+            assert!(call[0].contract_id == *MONEY_CONTRACT_ID);
             assert!(call[0].data[0] == MoneyFunction::Transfer as u8);
 
             // 4. MoneyTransfer has exactly 2 outputs
@@ -536,7 +535,7 @@ fn get_metadata(cid: ContractId, ix: &[u8]) -> ContractResult {
                     *all_votes_coords.y(),
                     *input_value_coords.x(),
                     *input_value_coords.y(),
-                    pallas::Base::from(u64::MAX - 420), // <-- TODO: Should be money contract id?
+                    MONEY_CONTRACT_ID.inner(), // <-- TODO: Should be money contract id?
                     pallas::Base::zero(),
                     pallas::Base::zero(),
                 ],

+ 7 - 4
src/contract/money/tests/harness.rs

@@ -29,10 +29,13 @@ use darkfi::{
     Result,
 };
 use darkfi_sdk::{
-    crypto::{constants::MERKLE_DEPTH, ContractId, Keypair, MerkleNode, PublicKey, TokenId},
+    crypto::{
+        constants::MERKLE_DEPTH, contract_id::MONEY_CONTRACT_ID, ContractId, Keypair, MerkleNode,
+        PublicKey, TokenId,
+    },
     db::SMART_CONTRACT_ZKAS_DB_NAME,
     incrementalmerkletree::bridgetree::BridgeTree,
-    pasta::{group::ff::PrimeField, pallas},
+    pasta::group::ff::PrimeField,
     tx::ContractCall,
 };
 use darkfi_serial::{serialize, Encodable};
@@ -125,7 +128,7 @@ impl MoneyTestHarness {
         )
         .await?;
 
-        let money_contract_id = ContractId::from(pallas::Base::from(u64::MAX - 420));
+        let money_contract_id = *MONEY_CONTRACT_ID;
 
         let alice_sled = alice_state.read().await.blockchain.sled_db.clone();
         let db_handle = alice_state.read().await.blockchain.contracts.lookup(
@@ -199,7 +202,7 @@ impl MoneyTestHarness {
             true,
         )?;
 
-        let contract_id = ContractId::from(pallas::Base::from(u64::MAX - 420));
+        let contract_id = *MONEY_CONTRACT_ID;
 
         let mut data = vec![MoneyFunction::Transfer as u8];
         params.encode(&mut data)?;

+ 3 - 3
src/contract/money/tests/verification_bench.rs

@@ -20,7 +20,7 @@ use std::{env, str::FromStr};
 
 use darkfi::{tx::Transaction, Result};
 use darkfi_sdk::{
-    crypto::{poseidon_hash, ContractId, MerkleNode, Nullifier, TokenId},
+    crypto::{contract_id::MONEY_CONTRACT_ID, poseidon_hash, MerkleNode, Nullifier, TokenId},
     incrementalmerkletree::Tree,
     pasta::{group::ff::Field, pallas},
     tx::ContractCall,
@@ -57,7 +57,7 @@ async fn alice2alice_random_amounts() -> Result<()> {
 
     let mut th = MoneyTestHarness::new().await?;
     let token_id = TokenId::from(pallas::Base::random(&mut OsRng));
-    let contract_id = ContractId::from(pallas::Base::from(u64::MAX - 420));
+    let contract_id = *MONEY_CONTRACT_ID;
 
     let mut owncoins = vec![];
 
@@ -171,7 +171,7 @@ async fn alice2alice_random_amounts_multiplecoins() -> Result<()> {
 
     // Initialize harness
     let mut th = MoneyTestHarness::new().await?;
-    let contract_id = ContractId::from(pallas::Base::from(u64::MAX - 420));
+    let contract_id = *MONEY_CONTRACT_ID;
 
     // Generating 10 airdrop coins
     let mut token_ids = vec![];

+ 16 - 0
src/sdk/src/crypto/contract_id.rs

@@ -17,11 +17,27 @@
  */
 
 use darkfi_serial::{serialize, SerialDecodable, SerialEncodable};
+use lazy_static::lazy_static;
 use pasta_curves::{group::ff::PrimeField, pallas};
 
 use super::{poseidon_hash, PublicKey, SecretKey};
 use crate::error::ContractError;
 
+lazy_static! {
+    // The idea here is that 0 is not a valid x coordinate for any pallas point,
+    // therefore a signature cannot be produced for such IDs. This allows us to
+    // avoid hardcoding contract IDs for arbitrary contract deployments, because
+    // the contracts with 0 as their x coordinate can never have a valid signature.
+
+    /// Contract ID for the native money contract
+    pub static ref MONEY_CONTRACT_ID: ContractId =
+        ContractId::from(poseidon_hash([pallas::Base::zero(), pallas::Base::from(0)]));
+
+    /// Contract ID for the native DAO contract
+    pub static ref DAO_CONTRACT_ID: ContractId =
+        ContractId::from(poseidon_hash([pallas::Base::zero(), pallas::Base::from(1)]));
+}
+
 /// ContractId represents an on-chain identifier for a certain smart contract.
 #[derive(Copy, Clone, Debug, Eq, PartialEq, SerialEncodable, SerialDecodable)]
 pub struct ContractId(pallas::Base);