main.rs 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2023 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::{sync::Arc, time::Instant};
  19. use darkfi::{util::time::Timestamp, Result};
  20. use darkfi_sdk::{
  21. crypto::MerkleTree,
  22. pasta::{group::ff::FromUniformBytes, pallas},
  23. };
  24. use darkfi_serial::{async_trait, Encodable, SerialDecodable, SerialEncodable};
  25. use randomx::{RandomXCache, RandomXDataset, RandomXFlags, RandomXVM};
  26. const GENESIS: &[u8] = b"genesis";
  27. const DIFFICULTY: usize = 1;
  28. const HASH_LEN: usize = 32;
  29. #[derive(SerialEncodable, SerialDecodable)]
  30. struct Transaction(Vec<u8>);
  31. impl Transaction {
  32. fn hash(&self) -> Result<blake2b_simd::Hash> {
  33. let mut hasher = blake2b_simd::Params::new().hash_length(HASH_LEN).to_state();
  34. self.encode(&mut hasher)?;
  35. Ok(hasher.finalize())
  36. }
  37. }
  38. #[derive(SerialEncodable, SerialDecodable)]
  39. struct BlockHeader {
  40. nonce: u32,
  41. previous_hash: blake2b_simd::Hash,
  42. timestamp: Timestamp,
  43. txtree: MerkleTree,
  44. }
  45. #[derive(SerialEncodable, SerialDecodable)]
  46. struct Block {
  47. header: BlockHeader,
  48. transactions: Vec<Transaction>,
  49. }
  50. impl Block {
  51. fn hash(&self) -> Result<blake2b_simd::Hash> {
  52. let mut len = 0;
  53. let mut hasher = blake2b_simd::Params::new().hash_length(HASH_LEN).to_state();
  54. len += self.header.encode(&mut hasher)?;
  55. len += self.header.txtree.root(0).unwrap().encode(&mut hasher)?;
  56. len += self.transactions.len().encode(&mut hasher)?;
  57. len.encode(&mut hasher)?;
  58. Ok(hasher.finalize())
  59. }
  60. fn insert_tx(&mut self, tx: &Transaction) -> Result<()> {
  61. let mut buf = [0u8; 64];
  62. buf[..HASH_LEN].copy_from_slice(tx.hash()?.as_bytes());
  63. let leaf = pallas::Base::from_uniform_bytes(&buf);
  64. self.header.txtree.append(leaf.into());
  65. Ok(())
  66. }
  67. }
  68. fn main() -> Result<()> {
  69. // Construct the genesis block
  70. let genesis_hash =
  71. blake2b_simd::Params::new().hash_length(HASH_LEN).to_state().update(GENESIS).finalize();
  72. let mut genesis_block = Block {
  73. header: BlockHeader {
  74. nonce: 0,
  75. previous_hash: genesis_hash,
  76. timestamp: Timestamp::current_time(),
  77. txtree: MerkleTree::new(100),
  78. },
  79. transactions: vec![],
  80. };
  81. let genesis_tx = Transaction(vec![1, 3, 3, 7]);
  82. genesis_block.insert_tx(&genesis_tx)?;
  83. // Get initial PoW input
  84. let pow_input = genesis_block.hash()?;
  85. // This is single-threaded mining, but check darkrenaissance/RandomX/examples/
  86. // for multi-threaded ops.
  87. let miner_setup = Instant::now();
  88. let flags = RandomXFlags::default() | RandomXFlags::FULLMEM;
  89. let dataset = Arc::new(RandomXDataset::new(flags, pow_input.as_bytes(), 1).unwrap());
  90. let vm = RandomXVM::new_fast(flags, &dataset).unwrap();
  91. // The miner creates a block
  92. let mut miner_block = Block {
  93. header: BlockHeader {
  94. nonce: 0,
  95. previous_hash: genesis_block.hash()?,
  96. timestamp: Timestamp::current_time(),
  97. txtree: MerkleTree::new(100),
  98. },
  99. transactions: vec![],
  100. };
  101. let tx0 = Transaction(vec![0, 3, 1, 2]);
  102. let tx1 = Transaction(vec![1, 2, 1, 0]);
  103. miner_block.insert_tx(&tx0)?;
  104. miner_block.insert_tx(&tx1)?;
  105. println!("Miner setup time: {:?}", miner_setup.elapsed());
  106. // Melt the CPU
  107. let mining_time = Instant::now();
  108. loop {
  109. let out_hash = vm.hash(miner_block.hash()?.as_bytes());
  110. let mut success = true;
  111. for i in 0..DIFFICULTY {
  112. if out_hash[i] != 0x00 {
  113. success = false;
  114. }
  115. }
  116. if success {
  117. break
  118. }
  119. miner_block.header.nonce += 1;
  120. }
  121. println!("Mining time: {:?}", mining_time.elapsed());
  122. // Verify
  123. let verifier_setup = Instant::now();
  124. let flags = RandomXFlags::default();
  125. let cache = RandomXCache::new(flags, pow_input.as_bytes()).unwrap();
  126. let vm = RandomXVM::new(flags, &cache).unwrap();
  127. println!("Verifier setup time: {:?}", verifier_setup.elapsed());
  128. let verification_time = Instant::now();
  129. let out_hash = vm.hash(miner_block.hash()?.as_bytes());
  130. for i in 0..DIFFICULTY {
  131. assert!(out_hash[i] == 0x00);
  132. }
  133. println!("Verification time: {:?}", verification_time.elapsed());
  134. Ok(())
  135. }