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

blockchain: proof of work data enum added

skoupidi 1 год назад
Родитель
Сommit
b054d403de

+ 1 - 1
bin/darkfid/genesis_block_localnet

@@ -1 +1 @@
-AYa7rEMKSzoYLxJbN6SG6cSGu/o02E70pmtKI+XwxiWxAAAAAH0JGmgAAAAAAAAAAAAAAAA7PNtvmfHqHEnjNnAS1ULkbCEM4uIYpCgNuv5kw2ETCMPjhlzo1AEcT03pj4ZfNZRxh9AwSl4slZFTeM+H5fyGAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+AYa7rEMKSzoYLxJbN6SG6cSGu/o02E70pmtKI+XwxiWxAAAAAD5GG2gAAAAAAAAAAAAAAAA7PNtvmfHqHEnjNnAS1ULkbCEM4uIYpCgNuv5kw2ETCMPjhlzo1AEcT03pj4ZfNZRxh9AwSl4slZFTeM+H5fyGAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

+ 1 - 1
bin/darkfid/genesis_block_mainnet

@@ -1 +1 @@
-AYa7rEMKSzoYLxJbN6SG6cSGu/o02E70pmtKI+XwxiWxAAAAAK0JGmgAAAAAAAAAAAAAAAA7PNtvmfHqHEnjNnAS1ULkbCEM4uIYpCgNuv5kw2ETCMPjhlzo1AEcT03pj4ZfNZRxh9AwSl4slZFTeM+H5fyGAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+AYa7rEMKSzoYLxJbN6SG6cSGu/o02E70pmtKI+XwxiWxAAAAAE9GG2gAAAAAAAAAAAAAAAA7PNtvmfHqHEnjNnAS1ULkbCEM4uIYpCgNuv5kw2ETCMPjhlzo1AEcT03pj4ZfNZRxh9AwSl4slZFTeM+H5fyGAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

+ 1 - 1
bin/darkfid/genesis_block_testnet

@@ -1 +1 @@
-AYa7rEMKSzoYLxJbN6SG6cSGu/o02E70pmtKI+XwxiWxAAAAAKEJGmgAAAAAAAAAAAAAAAA7PNtvmfHqHEnjNnAS1ULkbCEM4uIYpCgNuv5kw2ETCMPjhlzo1AEcT03pj4ZfNZRxh9AwSl4slZFTeM+H5fyGAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
+AYa7rEMKSzoYLxJbN6SG6cSGu/o02E70pmtKI+XwxiWxAAAAAEhGG2gAAAAAAAAAAAAAAAA7PNtvmfHqHEnjNnAS1ULkbCEM4uIYpCgNuv5kw2ETCMPjhlzo1AEcT03pj4ZfNZRxh9AwSl4slZFTeM+H5fyGAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

+ 2 - 2
bin/darkfid/src/proto/protocol_sync.rs

@@ -107,7 +107,7 @@ pub struct HeaderSyncResponse {
 impl_p2p_message!(
     HeaderSyncResponse,
     "headersyncresponse",
-    2341,
+    8192, // We leave some headroom for merge mining data
     1,
     PROTOCOL_SYNC_METERING_CONFIGURATION
 );
@@ -221,7 +221,7 @@ pub struct ForkHeadersResponse {
 impl_p2p_message!(
     ForkHeadersResponse,
     "forkheadersresponse",
-    2341,
+    8192, // We leave some headroom for merge mining data
     1,
     PROTOCOL_SYNC_METERING_CONFIGURATION
 );

+ 5 - 5
bin/darkfid/src/tests/metering.rs

@@ -33,9 +33,9 @@ fn darkfid_protocols_metering() {
     const U32_LEN: usize = 4;
     const VARINT_LEN: usize = 1;
     const HEADER_HASH_LEN: usize = 32;
-    // Header = U8_LEN + HEADER_HASH_LEN + U32_LEN + U64_LEN + U64_LEN + (U8_LEN * 32) + STATE_HASH_LEN =
-    // 1 + 32 + 4 + 8 + 8 + (1 * 32) = 53 + 32 + 32 = 117
-    const HEADER_LEN: usize = 117;
+    // Header = U8_LEN + HEADER_HASH_LEN + U32_LEN + U64_LEN + U64_LEN + (U8_LEN * 32) + STATE_HASH_LEN + ENUM_LEN =
+    // 1 + 32 + 4 + 8 + 8 + (1 * 32) + 1 = 53 + 32 + 32 + 1 = 118
+    const HEADER_LEN: usize = 118;
 
     // Generate a dummy `Header`.
     // Its bytes vector length is constant.
@@ -103,7 +103,7 @@ fn darkfid_protocols_metering() {
     // Based on length size/type, this can add from 1(u8) to 8(u64) bytes.
     // Since `BATCH` is 20, its `VarInt` will be represented as a u8,
     // adding an extra byte.
-    // Length = (BATCH * HEADER_LEN) + VARINT_LEN = (20 * 117) + 1 = 2340 + 1 = 2341
+    // Length = (BATCH * HEADER_LEN) + VARINT_LEN = (20 * 118) + 1 = 2360 + 1 = 2361
     assert_eq!(serialize(&header_sync_response).len(), (BATCH * HEADER_LEN) + VARINT_LEN);
 
     // Protocol sync `SyncRequest` is limited by `BATCH` so it has a
@@ -158,7 +158,7 @@ fn darkfid_protocols_metering() {
     // constant max bytes length limit.
     let fork_headers_response = ForkHeadersResponse { headers: vec![header; BATCH] };
     // Don't forget the extra byte from `Vec` length.
-    // Length = (BATCH * HEADER_LEN) + VARINT_LEN = (20 * 117) + 1 = 2340 + 1 = 2341
+    // Length = (BATCH * HEADER_LEN) + VARINT_LEN = (20 * 118) + 1 = 2360 + 1 = 2361
     assert_eq!(serialize(&fork_headers_response).len(), (BATCH * HEADER_LEN) + VARINT_LEN);
 
     // Protocol sync `ForkProposalsRequest` is limited by `BATCH` so it has a

+ 4 - 0
bin/explorer/explorerd/src/service/blocks.rs

@@ -51,6 +51,8 @@ pub struct BlockRecord {
     pub transactions_root: String,
     /// Contracts states Monotree(SMT) root this block commits to
     pub state_root: String,
+    /// Block Proof of Work type
+    pub pow_data: String,
     /// Block producer signature
     pub signature: Signature,
 }
@@ -67,6 +69,7 @@ impl BlockRecord {
             JsonValue::Number(self.nonce as f64),
             JsonValue::String(self.transactions_root.clone()),
             JsonValue::String(self.state_root.clone()),
+            JsonValue::String(self.pow_data.clone()),
             JsonValue::String(format!("{:?}", self.signature)),
         ])
     }
@@ -83,6 +86,7 @@ impl From<&BlockInfo> for BlockRecord {
             nonce: block.header.nonce,
             transactions_root: block.header.transactions_root.to_string(),
             state_root: blake3::Hash::from_bytes(block.header.state_root).to_string(),
+            pow_data: format!("{:?}", block.header.pow_data),
             signature: block.signature,
         }
     }

+ 1 - 0
doc/src/arch/consensus.md

@@ -262,6 +262,7 @@ the tx in Bitcoin with the most outputs has 2501.
 | `nonce`             | `u64`      | The block's nonce value                                  |
 | `transactions_root` | `[u8; 32]` | Merkle tree root of the block's transactions hashes      |
 | `state_root`        | `[u8; 32]` | Contracts states Monotree(SMT) root the block commits to |
+| `pow_data`          | `Enum`     | Block Proof of Work type                                 |
 
 ## Block
 

+ 53 - 9
src/blockchain/header_store.rs

@@ -24,7 +24,7 @@ use darkfi_sdk::{
     monotree::{Hash as StateHash, EMPTY_HASH},
 };
 #[cfg(feature = "async-serial")]
-use darkfi_serial::async_trait;
+use darkfi_serial::{async_trait, FutAsyncWriteExt};
 use darkfi_serial::{deserialize, serialize, Encodable, SerialDecodable, SerialEncodable};
 use sled_overlay::{
     serial::{parse_record, parse_u32_key_record},
@@ -33,10 +33,20 @@ use sled_overlay::{
 
 use crate::{util::time::Timestamp, Error, Result};
 
-use super::SledDbOverlayPtr;
+use super::{monero::MoneroPowData, SledDbOverlayPtr};
 
-#[derive(Copy, Clone, Debug, Eq, PartialEq, SerialEncodable, SerialDecodable)]
-// We have to introduce a type rather than using an alias so we can restrict API access
+/// Struct representing the Proof of Work used in a block.
+#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
+#[allow(clippy::large_enum_variant)]
+pub enum PowData {
+    /// Native Darkfi PoW
+    Darkfi,
+    /// Monero merge mining PoW
+    Monero(MoneroPowData),
+}
+
+#[derive(Clone, Copy, Debug, Eq, PartialEq, SerialEncodable, SerialDecodable)]
+// We have to introduce a type rather than using an alias so we can restrict API access.
 pub struct HeaderHash(pub [u8; 32]);
 
 impl HeaderHash {
@@ -69,7 +79,7 @@ impl fmt::Display for HeaderHash {
 }
 
 /// This struct represents a tuple of the form (version, previous, height, timestamp, nonce, merkle_tree).
-#[derive(Debug, Clone, PartialEq, Eq, SerialEncodable, SerialDecodable)]
+#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
 pub struct Header {
     /// Block version
     pub version: u8,
@@ -85,17 +95,31 @@ pub struct Header {
     pub transactions_root: MerkleNode,
     /// Contracts states Monotree(SMT) root this block commits to
     pub state_root: StateHash,
+    /// Block Proof of Work type
+    pub pow_data: PowData,
 }
 
 impl Header {
+    /// Generates a new header with default transactions and state root,
+    /// using Darkfi native Proof of Work data.
     pub fn new(previous: HeaderHash, height: u32, timestamp: Timestamp, nonce: u64) -> Self {
         let version = block_version(height);
         let transactions_root = MerkleTree::new(1).root(0).unwrap();
         let state_root = *EMPTY_HASH;
-        Self { version, previous, height, timestamp, nonce, transactions_root, state_root }
+        let pow_data = PowData::Darkfi;
+        Self {
+            version,
+            previous,
+            height,
+            timestamp,
+            nonce,
+            transactions_root,
+            state_root,
+            pow_data,
+        }
     }
 
-    /// Compute the header's hash
+    /// Compute the header's hash.
     pub fn hash(&self) -> HeaderHash {
         let mut hasher = blake3::Hasher::new();
 
@@ -106,10 +130,28 @@ impl Header {
 
         HeaderHash(hasher.finalize().into())
     }
+
+    /// Compute the header's template hash, which excludes its Proof of Work data.
+    pub fn template_hash(&self) -> HeaderHash {
+        let mut hasher = blake3::Hasher::new();
+
+        // Blake3 hasher .update() method never fails.
+        // This call returns a Result due to how the Write trait is specified.
+        // Calling unwrap() here should be safe.
+        self.version.encode(&mut hasher).expect("blake3 hasher");
+        self.previous.encode(&mut hasher).expect("blake3 hasher");
+        self.height.encode(&mut hasher).expect("blake3 hasher");
+        self.timestamp.encode(&mut hasher).expect("blake3 hasher");
+        self.nonce.encode(&mut hasher).expect("blake3 hasher");
+        self.transactions_root.encode(&mut hasher).expect("blake3 hasher");
+        self.state_root.encode(&mut hasher).expect("blake3 hasher");
+
+        HeaderHash(hasher.finalize().into())
+    }
 }
 
 impl Default for Header {
-    /// Represents the genesis header on current timestamp
+    /// Represents the genesis header on current timestamp.
     fn default() -> Self {
         Header::new(
             HeaderHash::new(blake3::hash(b"Let there be dark!").into()),
@@ -123,7 +165,7 @@ impl Default for Header {
 impl fmt::Display for Header {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         let s = format!(
-            "{} {{\n\t{}: {}\n\t{}: {}\n\t{}: {}\n\t{}: {}\n\t{}: {}\n\t{}: {}\n\t{}: {}\n\t{}: {}\n}}",
+            "{} {{\n\t{}: {}\n\t{}: {}\n\t{}: {}\n\t{}: {}\n\t{}: {}\n\t{}: {}\n\t{}: {}\n\t{}: {}\n\t{}: {:?}\n}}",
             "Header",
             "Hash",
             self.hash(),
@@ -141,6 +183,8 @@ impl fmt::Display for Header {
             self.transactions_root,
             "State Root",
             blake3::Hash::from_bytes(self.state_root),
+            "Proof of Work data",
+            self.pow_data,
         );
 
         write!(f, "{}", s)

+ 20 - 1
src/blockchain/monero/mod.rs

@@ -16,7 +16,10 @@
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-use std::io::{self, Cursor, Error, Read, Write};
+use std::{
+    fmt,
+    io::{self, Cursor, Error, Read, Write},
+};
 
 #[cfg(feature = "async-serial")]
 use darkfi_serial::{async_trait, AsyncDecodable, AsyncEncodable, AsyncRead, AsyncWrite};
@@ -62,6 +65,22 @@ pub struct MoneroPowData {
     pub aux_chain_merkle_proof: MerkleProof,
 }
 
+impl fmt::Debug for MoneroPowData {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let mut digest = [0u8; 32];
+        self.coinbase_tx_hasher.clone().finalize(&mut digest);
+        f.debug_struct("MoneroPowData")
+            .field("header", &self.header)
+            .field("randomx_key", &self.randomx_key)
+            .field("transaction_count", &self.transaction_count)
+            .field("merkle_root", &self.merkle_root)
+            .field("coinbase_merkle_proof", &self.coinbase_merkle_proof)
+            .field("coinbase_tx_extra", &self.coinbase_tx_extra)
+            .field("aux_chain_merkle_proof", &self.aux_chain_merkle_proof)
+            .finish()
+    }
+}
+
 impl Encodable for MoneroPowData {
     fn encode<S: Write>(&self, s: &mut S) -> io::Result<usize> {
         let mut n = 0;

+ 1 - 0
src/validator/pow.rs

@@ -266,6 +266,7 @@ impl PoWModule {
     }
 
     /// Verify provided block corresponds to next mine target.
+    // TODO: Verify depending on block Proof of Work data
     pub fn verify_block_hash(&self, block: &BlockInfo) -> Result<()> {
         let verifier_setup = Instant::now();
 

+ 8 - 2
src/validator/verification.rs

@@ -36,8 +36,8 @@ use smol::io::Cursor;
 
 use crate::{
     blockchain::{
-        block_store::append_tx_to_merkle_tree, BlockInfo, Blockchain, BlockchainOverlayPtr,
-        HeaderHash,
+        block_store::append_tx_to_merkle_tree, header_store::PowData, BlockInfo, Blockchain,
+        BlockchainOverlayPtr, HeaderHash,
     },
     error::TxVerifyFailed,
     runtime::vm_runtime::Runtime,
@@ -75,6 +75,12 @@ pub async fn verify_genesis_block(
         return Err(Error::BlockIsInvalid(block_hash))
     }
 
+    // Block must use Darkfi native Proof of Work data
+    match block.header.pow_data {
+        PowData::Darkfi => { /* do nothing */ }
+        _ => return Err(Error::BlockIsInvalid(block_hash)),
+    }
+
     // Verify transactions vector contains at least one(producers) transaction
     if block.txs.is_empty() {
         return Err(Error::BlockContainsNoTransactions(block_hash))