Преглед изворни кода

mmproxy/monero: Implement blocktemplate modification for merge mining

parazyd пре 2 година
родитељ
комит
3eed132fa4
3 измењених фајлова са 36 додато и 9 уклоњено
  1. 1 0
      Cargo.lock
  2. 1 0
      bin/darkfi-mmproxy/Cargo.toml
  3. 34 9
      bin/darkfi-mmproxy/src/monero.rs

+ 1 - 0
Cargo.lock

@@ -1761,6 +1761,7 @@ dependencies = [
  "darkfi-serial",
  "easy-parallel",
  "epee-encoding",
+ "hex",
  "log",
  "monero",
  "serde",

+ 1 - 0
bin/darkfi-mmproxy/Cargo.toml

@@ -21,6 +21,7 @@ monero = {version = "0.19.0", features = ["full"]}
 surf = "2.3.2"
 
 # Encoding
+hex = "0.4.3"
 url = "2.4.1"
 uuid = {version = "1.5.0", features = ["v4"]}
 

+ 34 - 9
bin/darkfi-mmproxy/src/monero.rs

@@ -29,6 +29,7 @@ use darkfi::{
     Error, Result,
 };
 use log::{debug, error};
+use monero::blockdata::transaction::{ExtraField, RawExtraField, SubField::MergeMining};
 
 use super::MiningProxy;
 
@@ -137,21 +138,30 @@ impl MiningProxy {
             return JsonError::new(InvalidParams, None, id).into()
         };
 
-        let Some(reserve_size) = params["reserve_size"].get::<f64>() else {
+        let Some(_reserve_size) = params["reserve_size"].get::<f64>() else {
             return JsonError::new(InvalidParams, None, id).into()
         };
 
+        // The MergeMining tag and anything else going into ExtraField should
+        // be done here, so we can pass the correct reserve_size.
+
+        // Create the Merge Mining Tag
+        let mm_tag = MergeMining(Some(monero::VarInt(32)), monero::Hash([0_u8; 32]));
+        let tx_extra: RawExtraField = ExtraField(vec![mm_tag]).into();
+        let reserve_size = tx_extra.0.len();
+
         // Create request
         let req = JsonRequest::new(
             "get_block_template",
             HashMap::from([
                 ("wallet_address".to_string(), (*wallet_address).clone().into()),
-                ("reserve_size".to_string(), (*reserve_size).into()),
+                ("reserve_size".to_string(), (reserve_size as f64).into()),
             ])
             .into(),
         );
 
-        let rep = match self.oneshot_request(req).await {
+        // Get block template from monerod
+        let mut rep = match self.oneshot_request(req).await {
             Ok(v) => v,
             Err(e) => {
                 error!(target: "rpc::monero::get_block_template", "{}", e);
@@ -159,15 +169,30 @@ impl MiningProxy {
             }
         };
 
-        // TODO: Now we have to modify the block template.
+        // Now we have to modify the block template:
         // * reserve_size has to be the size of the data we want to put in the block
         // * blocktemplate_blob has the reserved bytes, they're in the tx_extra field
-        //   of the coinbase tx, which is then hashed with other transactions into
-        //   merkle root hash which is what's in the blockhashing_blob
-        // * When blocktemplate_blob is modified, blockhashing_blob has to be updated too
-        // * The coinbase tx from monerod should be replaced with the one we create
-        //   containing the merged mining data/info
+        //   of the coinbase tx, which is then hashed with other txs into Merkle root
+        //   which is what's in the blockhashing_blob
+
+        // Deserialize the block template
+        let mut block_template = monero::consensus::deserialize::<monero::Block>(
+            &hex::decode(rep["result"]["blocktemplate_blob"].get::<String>().unwrap()).unwrap(),
+        )
+        .unwrap();
+
+        // Modify the coinbase tx
+        block_template.miner_tx.prefix.extra = tx_extra;
+
+        // Replace the blocktemplate blob
+        rep["result"]["blocktemplate_blob"] =
+            JsonValue::String(hex::encode(monero::consensus::serialize(&block_template)));
+
+        // Replace the blockhashing blob
+        rep["result"]["blockhashing_blob"] =
+            JsonValue::String(hex::encode(&block_template.serialize_hashable()));
 
+        // Pass the modified response to the client
         JsonResponse::new(rep, id).into()
     }