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

darkfid: optional mining reward spend hook and user data added

skoupidi 2 лет назад
Родитель
Сommit
109b902b01

+ 1 - 0
Cargo.lock

@@ -2206,6 +2206,7 @@ version = "0.4.1"
 dependencies = [
 dependencies = [
  "async-trait",
  "async-trait",
  "blake3 1.5.1",
  "blake3 1.5.1",
+ "bs58",
  "darkfi",
  "darkfi",
  "darkfi-contract-test-harness",
  "darkfi-contract-test-harness",
  "darkfi-sdk",
  "darkfi-sdk",

+ 2 - 1
bin/darkfid/Cargo.toml

@@ -10,7 +10,7 @@ edition = "2021"
 
 
 [dependencies]
 [dependencies]
 # Darkfi
 # Darkfi
-darkfi = {path = "../../", features = ["async-daemonize"]}
+darkfi = {path = "../../", features = ["async-daemonize", "bs58"]}
 darkfi_money_contract = {path = "../../src/contract/money"}
 darkfi_money_contract = {path = "../../src/contract/money"}
 darkfi-contract-test-harness = {path = "../../src/contract/test-harness"}
 darkfi-contract-test-harness = {path = "../../src/contract/test-harness"}
 darkfi-sdk = {path = "../../src/sdk"}
 darkfi-sdk = {path = "../../src/sdk"}
@@ -18,6 +18,7 @@ darkfi-serial = {path = "../../src/serial"}
 
 
 # Misc
 # Misc
 blake3 = "1.5.1"
 blake3 = "1.5.1"
+bs58 = "0.5.1"
 log = "0.4.21"
 log = "0.4.21"
 num-bigint = "0.4.5"
 num-bigint = "0.4.5"
 rand = "0.8.5"
 rand = "0.8.5"

+ 18 - 0
bin/darkfid/darkfid_config.toml

@@ -40,6 +40,12 @@ miner = true
 # replace with your own one.
 # replace with your own one.
 recipient = "5ZHfYpt4mpJcwBNxfEyxLzeFJUEeoePs5NQ5jVEgHrMf"
 recipient = "5ZHfYpt4mpJcwBNxfEyxLzeFJUEeoePs5NQ5jVEgHrMf"
 
 
+# Optional contract spend hook to use in the mining reward
+#spend_hook = "YOUR_SPEND_HOOK_HERE"
+
+# Optional user data to use in the mining reward
+#user_data = "YOUR_USER_DATA_HERE"
+
 # Skip syncing process and start node right away
 # Skip syncing process and start node right away
 skip_sync = true
 skip_sync = true
 
 
@@ -132,6 +138,12 @@ miner = false
 # Wallet address to receive mining rewards.
 # Wallet address to receive mining rewards.
 #recipient = "YOUR_WALLET_ADDRESS_HERE"
 #recipient = "YOUR_WALLET_ADDRESS_HERE"
 
 
+# Optional contract spend hook to use in the mining reward
+#spend_hook = "YOUR_SPEND_HOOK_HERE"
+
+# Optional user data to use in the mining reward
+#user_data = "YOUR_USER_DATA_HERE"
+
 # Skip syncing process and start node right away
 # Skip syncing process and start node right away
 skip_sync = false
 skip_sync = false
 
 
@@ -228,6 +240,12 @@ miner = false
 # Wallet address to receive mining rewards.
 # Wallet address to receive mining rewards.
 #recipient = "YOUR_WALLET_ADDRESS_HERE"
 #recipient = "YOUR_WALLET_ADDRESS_HERE"
 
 
+# Optional contract spend hook to use in the mining reward
+#spend_hook = "YOUR_SPEND_HOOK_HERE"
+
+# Optional user data to use in the mining reward
+#user_data = "YOUR_USER_DATA_HERE"
+
 # Skip syncing process and start node right away
 # Skip syncing process and start node right away
 skip_sync = false
 skip_sync = false
 
 

+ 17 - 6
bin/darkfid/src/main.rs

@@ -136,6 +136,14 @@ pub struct BlockchainNetwork {
     /// Wallet address to receive mining rewards
     /// Wallet address to receive mining rewards
     pub recipient: Option<String>,
     pub recipient: Option<String>,
 
 
+    #[structopt(long)]
+    /// Optional contract spend hook to use in the mining reward
+    pub spend_hook: Option<String>,
+
+    #[structopt(long)]
+    /// Optional user data to use in the mining reward
+    pub user_data: Option<String>,
+
     #[structopt(long)]
     #[structopt(long)]
     /// Skip syncing process and start node right away
     /// Skip syncing process and start node right away
     pub skip_sync: bool,
     pub skip_sync: bool,
@@ -341,13 +349,16 @@ async fn realmain(args: Args, ex: Arc<smol::Executor<'static>>) -> Result<()> {
     consensus_task.clone().start(
     consensus_task.clone().start(
         consensus_init_task(
         consensus_init_task(
             darkfid.clone(),
             darkfid.clone(),
-            ConsensusInitTaskConfig::new(
-                blockchain_config.skip_sync,
-                blockchain_config.checkpoint_height,
-                blockchain_config.checkpoint, blockchain_config.miner,
-                blockchain_config.recipient,
+            ConsensusInitTaskConfig {
+                skip_sync: blockchain_config.skip_sync,
+                checkpoint_height: blockchain_config.checkpoint_height,
+                checkpoint: blockchain_config.checkpoint,
+                miner: blockchain_config.miner,
+                recipient: blockchain_config.recipient,
+                spend_hook: blockchain_config.spend_hook,
+                user_data: blockchain_config.user_data,
                 bootstrap,
                 bootstrap,
-            ),
+            },
             ex.clone(),
             ex.clone(),
         ),
         ),
         |res| async move {
         |res| async move {

+ 52 - 28
bin/darkfid/src/task/consensus.rs

@@ -25,36 +25,28 @@ use darkfi::{
     util::{encoding::base64, time::Timestamp},
     util::{encoding::base64, time::Timestamp},
     Error, Result,
     Error, Result,
 };
 };
-use darkfi_sdk::crypto::PublicKey;
+use darkfi_sdk::{
+    crypto::{FuncId, PublicKey},
+    pasta::{group::ff::PrimeField, pallas},
+};
 use darkfi_serial::serialize_async;
 use darkfi_serial::serialize_async;
 use log::{error, info};
 use log::{error, info};
 
 
 use crate::{
 use crate::{
-    task::{garbage_collect_task, miner_task, sync_task},
+    task::{garbage_collect_task, miner::MinerRewardsRecipientConfig, miner_task, sync_task},
     Darkfid,
     Darkfid,
 };
 };
 
 
-/// Auxiliary structure representing node consesus init task configuration
+/// Auxiliary structure representing node consensus init task configuration
 pub struct ConsensusInitTaskConfig {
 pub struct ConsensusInitTaskConfig {
-    skip_sync: bool,
-    checkpoint_height: Option<u32>,
-    checkpoint: Option<String>,
-    miner: bool,
-    recipient: Option<String>,
-    bootstrap: u64,
-}
-
-impl ConsensusInitTaskConfig {
-    pub fn new(
-        skip_sync: bool,
-        checkpoint_height: Option<u32>,
-        checkpoint: Option<String>,
-        miner: bool,
-        recipient: Option<String>,
-        bootstrap: u64,
-    ) -> Self {
-        Self { skip_sync, checkpoint_height, checkpoint, miner, recipient, bootstrap }
-    }
+    pub skip_sync: bool,
+    pub checkpoint_height: Option<u32>,
+    pub checkpoint: Option<String>,
+    pub miner: bool,
+    pub recipient: Option<String>,
+    pub spend_hook: Option<String>,
+    pub user_data: Option<String>,
+    pub bootstrap: u64,
 }
 }
 
 
 /// Sync the node consensus state and start the corresponding task, based on node type.
 /// Sync the node consensus state and start the corresponding task, based on node type.
@@ -97,15 +89,41 @@ pub async fn consensus_init_task(
         None
         None
     };
     };
 
 
-    // Grab rewards recipient public key(address) if node is a miner
-    let recipient = if config.miner {
+    // Grab rewards recipient public key(address) if node is a miner,
+    // along with configured spend hook and user data.
+    let recipient_config = if config.miner {
         if config.recipient.is_none() {
         if config.recipient.is_none() {
             return Err(Error::ParseFailed("Recipient address missing"))
             return Err(Error::ParseFailed("Recipient address missing"))
         }
         }
-        match PublicKey::from_str(config.recipient.as_ref().unwrap()) {
-            Ok(address) => Some(address),
+        let recipient = match PublicKey::from_str(config.recipient.as_ref().unwrap()) {
+            Ok(address) => address,
             Err(_) => return Err(Error::InvalidAddress),
             Err(_) => return Err(Error::InvalidAddress),
-        }
+        };
+
+        let spend_hook = match config.spend_hook {
+            Some(s) => match FuncId::from_str(&s) {
+                Ok(s) => Some(s),
+                Err(_) => return Err(Error::ParseFailed("Invalid spend hook")),
+            },
+            None => None,
+        };
+
+        let user_data = match config.user_data {
+            Some(u) => {
+                let bytes: [u8; 32] = match bs58::decode(&u).into_vec()?.try_into() {
+                    Ok(b) => b,
+                    Err(_) => return Err(Error::ParseFailed("Invalid user data")),
+                };
+
+                match pallas::Base::from_repr(bytes).into() {
+                    Some(v) => Some(v),
+                    None => return Err(Error::ParseFailed("Invalid user data")),
+                }
+            }
+            None => None,
+        };
+
+        Some(MinerRewardsRecipientConfig { recipient, spend_hook, user_data })
     } else {
     } else {
         None
         None
     };
     };
@@ -113,7 +131,13 @@ pub async fn consensus_init_task(
     // Gracefully handle network disconnections
     // Gracefully handle network disconnections
     loop {
     loop {
         let result = if config.miner {
         let result = if config.miner {
-            miner_task(node.clone(), recipient.unwrap(), config.skip_sync, ex.clone()).await
+            miner_task(
+                node.clone(),
+                recipient_config.as_ref().unwrap(),
+                config.skip_sync,
+                ex.clone(),
+            )
+            .await
         } else {
         } else {
             replicator_task(node.clone(), ex.clone()).await
             replicator_task(node.clone(), ex.clone()).await
         };
         };

+ 20 - 13
bin/darkfid/src/task/miner.rs

@@ -36,7 +36,7 @@ use darkfi_money_contract::{
     client::pow_reward_v1::PoWRewardCallBuilder, MoneyFunction, MONEY_CONTRACT_ZKAS_MINT_NS_V1,
     client::pow_reward_v1::PoWRewardCallBuilder, MoneyFunction, MONEY_CONTRACT_ZKAS_MINT_NS_V1,
 };
 };
 use darkfi_sdk::{
 use darkfi_sdk::{
-    crypto::{poseidon_hash, PublicKey, SecretKey, MONEY_CONTRACT_ID},
+    crypto::{poseidon_hash, FuncId, PublicKey, SecretKey, MONEY_CONTRACT_ID},
     pasta::pallas,
     pasta::pallas,
     ContractCall,
     ContractCall,
 };
 };
@@ -48,6 +48,13 @@ use smol::channel::{Receiver, Sender};
 
 
 use crate::{proto::ProposalMessage, task::garbage_collect_task, Darkfid};
 use crate::{proto::ProposalMessage, task::garbage_collect_task, Darkfid};
 
 
+/// Auxiliary structure representing node miner rewards recipient configuration
+pub struct MinerRewardsRecipientConfig {
+    pub recipient: PublicKey,
+    pub spend_hook: Option<FuncId>,
+    pub user_data: Option<pallas::Base>,
+}
+
 /// Async task used for participating in the PoW block production.
 /// Async task used for participating in the PoW block production.
 /// Miner initializes their setup and waits for next finalization,
 /// Miner initializes their setup and waits for next finalization,
 /// by listenning for new proposals from the network, for optimal
 /// by listenning for new proposals from the network, for optimal
@@ -60,7 +67,7 @@ use crate::{proto::ProposalMessage, task::garbage_collect_task, Darkfid};
 /// finishes, node triggers finallization check.
 /// finishes, node triggers finallization check.
 pub async fn miner_task(
 pub async fn miner_task(
     node: Arc<Darkfid>,
     node: Arc<Darkfid>,
-    recipient: PublicKey,
+    recipient_config: &MinerRewardsRecipientConfig,
     skip_sync: bool,
     skip_sync: bool,
     ex: Arc<smol::Executor<'static>>,
     ex: Arc<smol::Executor<'static>>,
 ) -> Result<()> {
 ) -> Result<()> {
@@ -158,7 +165,7 @@ pub async fn miner_task(
                 &node,
                 &node,
                 &extended_fork,
                 &extended_fork,
                 &mut secret,
                 &mut secret,
-                &recipient,
+                recipient_config,
                 &zkbin,
                 &zkbin,
                 &pk,
                 &pk,
                 &stop_signal,
                 &stop_signal,
@@ -262,7 +269,7 @@ async fn mine(
     node: &Darkfid,
     node: &Darkfid,
     extended_fork: &Fork,
     extended_fork: &Fork,
     secret: &mut SecretKey,
     secret: &mut SecretKey,
-    recipient: &PublicKey,
+    recipient_config: &MinerRewardsRecipientConfig,
     zkbin: &ZkBinary,
     zkbin: &ZkBinary,
     pk: &ProvingKey,
     pk: &ProvingKey,
     stop_signal: &Receiver<()>,
     stop_signal: &Receiver<()>,
@@ -270,7 +277,7 @@ async fn mine(
 ) -> Result<()> {
 ) -> Result<()> {
     smol::future::or(
     smol::future::or(
         wait_stop_signal(stop_signal),
         wait_stop_signal(stop_signal),
-        mine_next_block(node, extended_fork, secret, recipient, zkbin, pk, skip_sync),
+        mine_next_block(node, extended_fork, secret, recipient_config, zkbin, pk, skip_sync),
     )
     )
     .await
     .await
 }
 }
@@ -293,7 +300,7 @@ async fn mine_next_block(
     node: &Darkfid,
     node: &Darkfid,
     extended_fork: &Fork,
     extended_fork: &Fork,
     secret: &mut SecretKey,
     secret: &mut SecretKey,
-    recipient: &PublicKey,
+    recipient_config: &MinerRewardsRecipientConfig,
     zkbin: &ZkBinary,
     zkbin: &ZkBinary,
     pk: &ProvingKey,
     pk: &ProvingKey,
     skip_sync: bool,
     skip_sync: bool,
@@ -302,7 +309,7 @@ async fn mine_next_block(
     let (next_target, mut next_block) = generate_next_block(
     let (next_target, mut next_block) = generate_next_block(
         extended_fork,
         extended_fork,
         secret,
         secret,
-        recipient,
+        recipient_config,
         zkbin,
         zkbin,
         pk,
         pk,
         node.validator.consensus.module.read().await.target,
         node.validator.consensus.module.read().await.target,
@@ -343,7 +350,7 @@ async fn mine_next_block(
 async fn generate_next_block(
 async fn generate_next_block(
     extended_fork: &Fork,
     extended_fork: &Fork,
     secret: &mut SecretKey,
     secret: &mut SecretKey,
-    recipient: &PublicKey,
+    recipient_config: &MinerRewardsRecipientConfig,
     zkbin: &ZkBinary,
     zkbin: &ZkBinary,
     pk: &ProvingKey,
     pk: &ProvingKey,
     block_target: u32,
     block_target: u32,
@@ -368,7 +375,7 @@ async fn generate_next_block(
     *secret = SecretKey::from(next_secret);
     *secret = SecretKey::from(next_secret);
 
 
     // Generate reward transaction
     // Generate reward transaction
-    let tx = generate_transaction(next_block_height, fees, secret, recipient, zkbin, pk)?;
+    let tx = generate_transaction(next_block_height, fees, secret, recipient_config, zkbin, pk)?;
     txs.push(tx);
     txs.push(tx);
 
 
     // Generate the new header
     // Generate the new header
@@ -391,7 +398,7 @@ fn generate_transaction(
     block_height: u32,
     block_height: u32,
     fees: u64,
     fees: u64,
     secret: &SecretKey,
     secret: &SecretKey,
-    recipient: &PublicKey,
+    recipient_config: &MinerRewardsRecipientConfig,
     zkbin: &ZkBinary,
     zkbin: &ZkBinary,
     pk: &ProvingKey,
     pk: &ProvingKey,
 ) -> Result<Transaction> {
 ) -> Result<Transaction> {
@@ -400,9 +407,9 @@ fn generate_transaction(
         signature_public: PublicKey::from_secret(*secret),
         signature_public: PublicKey::from_secret(*secret),
         block_height,
         block_height,
         fees,
         fees,
-        recipient: Some(*recipient),
-        spend_hook: None,
-        user_data: None,
+        recipient: Some(recipient_config.recipient),
+        spend_hook: recipient_config.spend_hook,
+        user_data: recipient_config.user_data,
         mint_zkbin: zkbin.clone(),
         mint_zkbin: zkbin.clone(),
         mint_pk: pk.clone(),
         mint_pk: pk.clone(),
     }
     }

+ 6 - 0
contrib/localnet/darkfid-five-nodes/darkfid0.toml

@@ -34,6 +34,12 @@ miner = true
 # replace with your own one.
 # replace with your own one.
 recipient = "9vw6WznKk7xEFQwwXhJWMMdjUPi3cXL8NrFKQpKifG1U"
 recipient = "9vw6WznKk7xEFQwwXhJWMMdjUPi3cXL8NrFKQpKifG1U"
 
 
+# Optional contract spend hook to use in the mining reward
+#spend_hook = "YOUR_SPEND_HOOK_HERE"
+
+# Optional user data to use in the mining reward
+#user_data = "YOUR_USER_DATA_HERE"
+
 # Skip syncing process and start node right away
 # Skip syncing process and start node right away
 skip_sync = true
 skip_sync = true
 
 

+ 6 - 0
contrib/localnet/darkfid-five-nodes/darkfid1.toml

@@ -34,6 +34,12 @@ miner = true
 # replace with your own one.
 # replace with your own one.
 recipient = "9vw6WznKk7xEFQwwXhJWMMdjUPi3cXL8NrFKQpKifG1U"
 recipient = "9vw6WznKk7xEFQwwXhJWMMdjUPi3cXL8NrFKQpKifG1U"
 
 
+# Optional contract spend hook to use in the mining reward
+#spend_hook = "YOUR_SPEND_HOOK_HERE"
+
+# Optional user data to use in the mining reward
+#user_data = "YOUR_USER_DATA_HERE"
+
 # Skip syncing process and start node right away
 # Skip syncing process and start node right away
 skip_sync = false
 skip_sync = false
 
 

+ 6 - 0
contrib/localnet/darkfid-five-nodes/darkfid2.toml

@@ -34,6 +34,12 @@ miner = true
 # replace with your own one.
 # replace with your own one.
 recipient = "9vw6WznKk7xEFQwwXhJWMMdjUPi3cXL8NrFKQpKifG1U"
 recipient = "9vw6WznKk7xEFQwwXhJWMMdjUPi3cXL8NrFKQpKifG1U"
 
 
+# Optional contract spend hook to use in the mining reward
+#spend_hook = "YOUR_SPEND_HOOK_HERE"
+
+# Optional user data to use in the mining reward
+#user_data = "YOUR_USER_DATA_HERE"
+
 # Skip syncing process and start node right away
 # Skip syncing process and start node right away
 skip_sync = false
 skip_sync = false
 
 

+ 6 - 0
contrib/localnet/darkfid-five-nodes/darkfid3.toml

@@ -34,6 +34,12 @@ miner = true
 # replace with your own one.
 # replace with your own one.
 recipient = "9vw6WznKk7xEFQwwXhJWMMdjUPi3cXL8NrFKQpKifG1U"
 recipient = "9vw6WznKk7xEFQwwXhJWMMdjUPi3cXL8NrFKQpKifG1U"
 
 
+# Optional contract spend hook to use in the mining reward
+#spend_hook = "YOUR_SPEND_HOOK_HERE"
+
+# Optional user data to use in the mining reward
+#user_data = "YOUR_USER_DATA_HERE"
+
 # Skip syncing process and start node right away
 # Skip syncing process and start node right away
 skip_sync = false
 skip_sync = false
 
 

+ 6 - 0
contrib/localnet/darkfid-five-nodes/darkfid4.toml

@@ -34,6 +34,12 @@ miner = true
 # replace with your own one.
 # replace with your own one.
 recipient = "9vw6WznKk7xEFQwwXhJWMMdjUPi3cXL8NrFKQpKifG1U"
 recipient = "9vw6WznKk7xEFQwwXhJWMMdjUPi3cXL8NrFKQpKifG1U"
 
 
+# Optional contract spend hook to use in the mining reward
+#spend_hook = "YOUR_SPEND_HOOK_HERE"
+
+# Optional user data to use in the mining reward
+#user_data = "YOUR_USER_DATA_HERE"
+
 # Skip syncing process and start node right away
 # Skip syncing process and start node right away
 skip_sync = false
 skip_sync = false
 
 

+ 6 - 0
contrib/localnet/darkfid-single-node/darkfid.toml

@@ -37,6 +37,12 @@ miner = true
 # replace with your own one.
 # replace with your own one.
 recipient = "9vw6WznKk7xEFQwwXhJWMMdjUPi3cXL8NrFKQpKifG1U"
 recipient = "9vw6WznKk7xEFQwwXhJWMMdjUPi3cXL8NrFKQpKifG1U"
 
 
+# Optional contract spend hook to use in the mining reward
+#spend_hook = "6iW9nywZYvyhcM7P1iLwYkh92rvYtREDsC8hgqf2GLuT"
+
+# Optional user data to use in the mining reward
+#user_data = "YOUR_USER_DATA_HERE"
+
 # Skip syncing process and start node right away
 # Skip syncing process and start node right away
 skip_sync = true
 skip_sync = true
 
 

+ 6 - 0
contrib/localnet/darkfid-small/darkfid0.toml

@@ -34,6 +34,12 @@ miner = true
 # replace with your own one.
 # replace with your own one.
 recipient = "9vw6WznKk7xEFQwwXhJWMMdjUPi3cXL8NrFKQpKifG1U"
 recipient = "9vw6WznKk7xEFQwwXhJWMMdjUPi3cXL8NrFKQpKifG1U"
 
 
+# Optional contract spend hook to use in the mining reward
+#spend_hook = "YOUR_SPEND_HOOK_HERE"
+
+# Optional user data to use in the mining reward
+#user_data = "YOUR_USER_DATA_HERE"
+
 # Skip syncing process and start node right away
 # Skip syncing process and start node right away
 skip_sync = true
 skip_sync = true
 
 

+ 6 - 0
contrib/localnet/darkfid-small/darkfid1.toml

@@ -42,6 +42,12 @@ miner = true
 # replace with your own one.
 # replace with your own one.
 recipient = "9vw6WznKk7xEFQwwXhJWMMdjUPi3cXL8NrFKQpKifG1U"
 recipient = "9vw6WznKk7xEFQwwXhJWMMdjUPi3cXL8NrFKQpKifG1U"
 
 
+# Optional contract spend hook to use in the mining reward
+#spend_hook = "YOUR_SPEND_HOOK_HERE"
+
+# Optional user data to use in the mining reward
+#user_data = "YOUR_USER_DATA_HERE"
+
 # Skip syncing process and start node right away
 # Skip syncing process and start node right away
 skip_sync = false
 skip_sync = false