Explorar el Código

explorer: Add Monero header hash when PoWData is XMR

x hace 6 meses
padre
commit
eddb0245da

+ 2 - 0
Cargo.lock

@@ -2845,9 +2845,11 @@ dependencies = [
  "darkfi_money_contract",
  "easy-parallel",
  "hex",
+ "monero",
  "sled",
  "smol",
  "tapes",
+ "tiny-keccak",
  "tinyjson",
  "tracing",
  "url",

+ 3 - 0
bin/explorer/Cargo.toml

@@ -11,6 +11,9 @@ darkfi-sdk = {path = "../../src/sdk"}
 darkfi_money_contract = {path = "../../src/contract/money", features = ["no-entrypoint", "client"]}
 darkfi_deployooor_contract = {path = "../../src/contract/deployooor", features = ["no-entrypoint", "client"]}
 
+monero = "0.21.0"
+tiny-keccak = "2.0.2"
+
 async-channel = "2.5.0"
 async-trait = "0.1.89"
 easy-parallel = "3.3.1"

+ 1 - 0
bin/explorer/python/explorer.py

@@ -171,6 +171,7 @@ async def get_block_by_height(block_height: int):
         current_height=current_height,
         hashrate=format_hashrate(hashrate),
         block=block,
+        monero_hash=block["monero_hash"],
     )
 
 

+ 1 - 1
bin/explorer/python/rpc_client.py

@@ -173,7 +173,7 @@ class JsonRpcPool:
         """Create a new connection. Returns None if connection fails."""
         try:
             reader, writer = await asyncio.wait_for(
-                asyncio.open_connection(self.host, self.port),
+                asyncio.open_connection(self.host, self.port, limit=16*1024*1024),
                 timeout=self.connect_timeout
             )
             async with self._lock:

+ 5 - 1
bin/explorer/python/templates/block.html

@@ -131,7 +131,11 @@
           <tbody>
             <tr>
               <td class="info-label">Monero Block Hash</td>
-              <td><a href="https://localmonero.co/blocks/block/{{ monero_hash }}" target="_blank" class="hash hash-monero">{{ monero_hash }}</a></td>
+              {% if network == 'Testnet' %}
+              <td><a href="https://testnet.xmrchain.net/search?value={{ monero_hash }}" target="_blank" class="hash hash-monero">{{ monero_hash }}</a></td>
+              {% else %}
+              <td><a href="https://blocks.p2pool.observer/block/{{ monero_hash }}" target="_blank" class="hash hash-monero">{{ monero_hash }}</a></td>
+              {% endif %}
             </tr>
           </tbody>
         </table>

+ 1 - 1
bin/explorer/src/main.rs

@@ -237,7 +237,7 @@ impl Explorer {
         to_height: u64,
         ex: Arc<Executor<'_>>,
     ) -> Result<()> {
-        if from_height == to_height {
+        if from_height >= to_height {
             return Ok(())
         }
 

+ 32 - 2
bin/explorer/src/rpc.rs

@@ -30,6 +30,8 @@ use darkfi::{
 use darkfi_money_contract::MoneyFunction;
 use darkfi_sdk::crypto::contract_id::MONEY_CONTRACT_ID;
 use darkfi_serial::{deserialize_async, serialize_async};
+use monero::{consensus::encode::Encodable, VarInt};
+use tiny_keccak::{Hasher, Keccak};
 use tinyjson::JsonValue;
 
 use crate::{DifficultyIndex, Explorer};
@@ -189,15 +191,35 @@ struct ExplBlockInfo {
     difficulty: u64,
     cumulative: u64,
     powtype: String,
+    monero_hash: Option<String>,
     txs: Vec<TransactionInfo>,
     coinbase: CoinbaseInfo,
 }
 
 impl ExplBlockInfo {
     async fn new(block: &BlockInfo, diff: &DifficultyIndex) -> Self {
-        let powtype = match block.header.pow_data {
+        let mut monero_hash = None;
+        let powtype = match &block.header.pow_data {
             PowData::DarkFi => "DarkFi".to_string(),
-            PowData::Monero(_) => "Monero".to_string(),
+            PowData::Monero(powdata) => {
+                // Calculate the Monero block header hash
+                let mut blockhashing_blob = powdata.to_block_hashing_blob();
+                // Monero prefixes a VarInt of the blob len before getting the
+                // block hash but doesn't do this when getting the PoW hash :)
+                let mut header = vec![];
+                VarInt(blockhashing_blob.len() as u64).consensus_encode(&mut header).unwrap();
+                header.append(&mut blockhashing_blob);
+
+                let mut keccak = Keccak::v256();
+                keccak.update(&header);
+
+                let mut hash = [0u8; 32];
+                keccak.finalize(&mut hash);
+
+                monero_hash = Some(hex::encode(hash));
+
+                "Monero".to_string()
+            }
         };
 
         let mut txs = Vec::with_capacity(block.txs.len());
@@ -220,12 +242,19 @@ impl ExplBlockInfo {
             difficulty: diff.difficulty,
             cumulative: diff.cumulative,
             powtype,
+            monero_hash,
             txs,
             coinbase,
         }
     }
 
     fn to_json(&self) -> JsonValue {
+        let monero_hash = if let Some(hash) = &self.monero_hash {
+            JsonValue::String(hash.to_string())
+        } else {
+            JsonValue::Null
+        };
+
         JsonValue::Object(HashMap::from([
             ("height".to_string(), JsonValue::Number(self.height as f64)),
             ("hash".to_string(), JsonValue::String(self.hash.clone())),
@@ -239,6 +268,7 @@ impl ExplBlockInfo {
             ("difficulty".to_string(), JsonValue::Number(self.difficulty as f64)),
             ("cumulative".to_string(), JsonValue::Number(self.cumulative as f64)),
             ("powtype".to_string(), JsonValue::String(self.powtype.clone())),
+            ("monero_hash".to_string(), monero_hash),
             ("txs".to_string(), JsonValue::Array(self.txs.iter().map(|t| t.to_json()).collect())),
             ("coinbase".to_string(), self.coinbase.to_json()),
         ]))