mod.rs 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2025 Dyne.org foundation
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU Affero General Public License as
  7. * published by the Free Software Foundation, either version 3 of the
  8. * License, or (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU Affero General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Affero General Public License
  16. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. */
  18. use std::io::{self, Cursor, Error, Read, Write};
  19. use async_trait::async_trait;
  20. use darkfi_serial::{AsyncDecodable, AsyncEncodable, AsyncRead, AsyncWrite, Decodable, Encodable};
  21. use monero::{
  22. blockdata::transaction::RawExtraField,
  23. consensus::{Decodable as XmrDecodable, Encodable as XmrEncodable},
  24. cryptonote::hash::Hashable,
  25. util::ringct::{RctSigBase, RctType},
  26. BlockHeader, Hash,
  27. };
  28. use tiny_keccak::{Hasher, Keccak};
  29. mod merkle_proof;
  30. use merkle_proof::MerkleProof;
  31. mod keccak;
  32. use keccak::{keccak_from_bytes, keccak_to_bytes};
  33. mod utils;
  34. /// This struct represents all the Proof of Work information required
  35. /// for merge mining.
  36. #[derive(Clone)]
  37. pub struct MoneroPowData {
  38. /// Monero Header fields
  39. pub header: BlockHeader,
  40. /// RandomX VM key - length varies to a max len of 60.
  41. /// TODO: Implement a type, or use randomx_key[0] to define len.
  42. pub randomx_key: [u8; 64],
  43. /// The number of transactions included in this Monero block.
  44. /// This is used to produce the blockhashing_blob.
  45. pub transaction_count: u16,
  46. /// Transaction root
  47. pub merkle_root: Hash,
  48. /// Coinbase Merkle proof hashes
  49. pub coinbase_merkle_proof: MerkleProof,
  50. /// Incomplete hashed state of the coinbase transaction
  51. pub coinbase_tx_hasher: Keccak,
  52. /// Extra field of the coinbase
  53. pub coinbase_tx_extra: RawExtraField,
  54. /// Aux chain Merkle proof hashes
  55. pub aux_chain_merkle_proof: MerkleProof,
  56. }
  57. impl Encodable for MoneroPowData {
  58. fn encode<S: Write>(&self, s: &mut S) -> io::Result<usize> {
  59. let mut n = 0;
  60. n += self.header.consensus_encode(s)?;
  61. n += self.randomx_key.encode(s)?;
  62. n += self.transaction_count.encode(s)?;
  63. n += self.merkle_root.consensus_encode(s)?;
  64. n += self.coinbase_merkle_proof.encode(s)?;
  65. // This is an incomplete hasher. Dump it from memory
  66. // and write it down. We can restore it the same way.
  67. let buf = keccak_to_bytes(&self.coinbase_tx_hasher);
  68. n += buf.encode(s)?;
  69. n += self.coinbase_tx_extra.0.encode(s)?;
  70. n += self.aux_chain_merkle_proof.encode(s)?;
  71. Ok(n)
  72. }
  73. }
  74. #[async_trait]
  75. impl AsyncEncodable for MoneroPowData {
  76. async fn encode_async<S: AsyncWrite + Unpin + Send>(&self, s: &mut S) -> io::Result<usize> {
  77. let mut n = 0;
  78. let mut buf = vec![];
  79. self.header.consensus_encode(&mut buf)?;
  80. n += buf.encode_async(s).await?;
  81. n += self.randomx_key.encode_async(s).await?;
  82. n += self.transaction_count.encode_async(s).await?;
  83. let mut buf = vec![];
  84. self.merkle_root.consensus_encode(&mut buf)?;
  85. n += buf.encode_async(s).await?;
  86. n += self.coinbase_merkle_proof.encode_async(s).await?;
  87. // This is an incomplete hasher. Dump it from memory
  88. // and write it down. We can restore it the same way.
  89. let buf = keccak_to_bytes(&self.coinbase_tx_hasher);
  90. n += buf.encode_async(s).await?;
  91. n += self.coinbase_tx_extra.0.encode_async(s).await?;
  92. n += self.aux_chain_merkle_proof.encode_async(s).await?;
  93. Ok(n)
  94. }
  95. }
  96. #[async_trait]
  97. impl Decodable for MoneroPowData {
  98. fn decode<D: Read>(d: &mut D) -> io::Result<Self> {
  99. let header =
  100. BlockHeader::consensus_decode(d).map_err(|_| Error::other("Invalid XMR header"))?;
  101. let randomx_key: [u8; 64] = Decodable::decode(d)?;
  102. let transaction_count: u16 = Decodable::decode(d)?;
  103. let merkle_root =
  104. Hash::consensus_decode(d).map_err(|_| Error::other("Invamid XMR hash"))?;
  105. let coinbase_merkle_proof: MerkleProof = Decodable::decode(d)?;
  106. let buf: Vec<u8> = Decodable::decode(d)?;
  107. let coinbase_tx_hasher = keccak_from_bytes(&buf);
  108. let coinbase_tx_extra: Vec<u8> = Decodable::decode(d)?;
  109. let coinbase_tx_extra = RawExtraField(coinbase_tx_extra);
  110. let aux_chain_merkle_proof: MerkleProof = Decodable::decode(d)?;
  111. Ok(Self {
  112. header,
  113. randomx_key,
  114. transaction_count,
  115. merkle_root,
  116. coinbase_merkle_proof,
  117. coinbase_tx_hasher,
  118. coinbase_tx_extra,
  119. aux_chain_merkle_proof,
  120. })
  121. }
  122. }
  123. #[async_trait]
  124. impl AsyncDecodable for MoneroPowData {
  125. async fn decode_async<D: AsyncRead + Unpin + Send>(d: &mut D) -> io::Result<Self> {
  126. let buf: Vec<u8> = AsyncDecodable::decode_async(d).await?;
  127. let mut buf = Cursor::new(buf);
  128. let header = BlockHeader::consensus_decode(&mut buf)
  129. .map_err(|_| Error::other("Invalid XMR header"))?;
  130. let randomx_key: [u8; 64] = AsyncDecodable::decode_async(d).await?;
  131. let transaction_count: u16 = AsyncDecodable::decode_async(d).await?;
  132. let buf: Vec<u8> = AsyncDecodable::decode_async(d).await?;
  133. let mut buf = Cursor::new(buf);
  134. let merkle_root =
  135. Hash::consensus_decode(&mut buf).map_err(|_| Error::other("Invalid XMR hash"))?;
  136. let coinbase_merkle_proof: MerkleProof = AsyncDecodable::decode_async(d).await?;
  137. let buf: Vec<u8> = AsyncDecodable::decode_async(d).await?;
  138. let coinbase_tx_hasher = keccak_from_bytes(&buf);
  139. let coinbase_tx_extra: Vec<u8> = AsyncDecodable::decode_async(d).await?;
  140. let coinbase_tx_extra = RawExtraField(coinbase_tx_extra);
  141. let aux_chain_merkle_proof: MerkleProof = AsyncDecodable::decode_async(d).await?;
  142. Ok(Self {
  143. header,
  144. randomx_key,
  145. transaction_count,
  146. merkle_root,
  147. coinbase_merkle_proof,
  148. coinbase_tx_hasher,
  149. coinbase_tx_extra,
  150. aux_chain_merkle_proof,
  151. })
  152. }
  153. }
  154. impl MoneroPowData {
  155. /// Returns true if the coinbase Merkle proof produces the `merkle_root` hash.
  156. pub fn is_coinbase_valid_merkle_root(&self) -> bool {
  157. let mut finalised_prefix_keccak = self.coinbase_tx_hasher.clone();
  158. let mut encoder_extra_field = vec![];
  159. self.coinbase_tx_extra.consensus_encode(&mut encoder_extra_field).unwrap();
  160. finalised_prefix_keccak.update(&encoder_extra_field);
  161. let mut prefix_hash: [u8; 32] = [0; 32];
  162. finalised_prefix_keccak.finalize(&mut prefix_hash);
  163. let final_prefix_hash = Hash::from_slice(&prefix_hash);
  164. // let mut finalised_keccak = Keccak::v256();
  165. let rct_sig_base = RctSigBase {
  166. rct_type: RctType::Null,
  167. txn_fee: Default::default(),
  168. pseudo_outs: vec![],
  169. ecdh_info: vec![],
  170. out_pk: vec![],
  171. };
  172. let hashes = vec![final_prefix_hash, rct_sig_base.hash(), Hash::null()];
  173. let encoder_final: Vec<u8> =
  174. hashes.into_iter().flat_map(|h| Vec::from(&h.to_bytes()[..])).collect();
  175. let coinbase_hash = Hash::new(encoder_final);
  176. let merkle_root = self.coinbase_merkle_proof.calculate_root(&coinbase_hash);
  177. (self.merkle_root == merkle_root) && self.coinbase_merkle_proof.check_coinbase_path()
  178. }
  179. }