block.rs 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  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::fmt;
  19. use darkfi_sdk::{
  20. crypto::{MerkleNode, MerkleTree},
  21. pasta::pallas,
  22. };
  23. use darkfi_serial::{async_trait, serialize, SerialDecodable, SerialEncodable};
  24. use super::{
  25. constants::{BLOCK_MAGIC_BYTES, BLOCK_VERSION},
  26. LeadInfo,
  27. };
  28. use crate::{impl_p2p_message, net::Message, tx::Transaction, util::time::Timestamp};
  29. /// This struct represents a tuple of the form (version, previous, epoch, slot, timestamp, merkle_root).
  30. #[derive(Debug, Clone, PartialEq, Eq, SerialEncodable, SerialDecodable)]
  31. pub struct Header {
  32. /// Block version
  33. pub version: u8,
  34. /// Previous block hash
  35. pub previous: blake3::Hash,
  36. /// Epoch
  37. pub epoch: u64,
  38. /// Slot UID
  39. pub slot: u64,
  40. /// Block creation timestamp
  41. pub timestamp: Timestamp,
  42. /// Root of the transaction hashes merkle tree
  43. pub root: MerkleNode,
  44. }
  45. impl Header {
  46. pub fn new(
  47. previous: blake3::Hash,
  48. epoch: u64,
  49. slot: u64,
  50. timestamp: Timestamp,
  51. root: MerkleNode,
  52. ) -> Self {
  53. let version = BLOCK_VERSION;
  54. Self { version, previous, epoch, slot, timestamp, root }
  55. }
  56. /// Generate the genesis block.
  57. pub fn genesis_header(genesis_ts: Timestamp, genesis_data: blake3::Hash) -> Self {
  58. let tree = MerkleTree::new(100);
  59. let root = tree.root(0).unwrap();
  60. Self::new(genesis_data, 0, 0, genesis_ts, root)
  61. }
  62. /// Calculate the header hash
  63. pub fn headerhash(&self) -> blake3::Hash {
  64. blake3::hash(&serialize(self))
  65. }
  66. }
  67. impl Default for Header {
  68. fn default() -> Self {
  69. Header::new(
  70. blake3::hash(b""),
  71. 0,
  72. 0,
  73. Timestamp::current_time(),
  74. MerkleNode::from(pallas::Base::zero()),
  75. )
  76. }
  77. }
  78. /// This struct represents a tuple of the form (`magic`, `header`, `counter`, `txs`, `lead_info`).
  79. /// The header and transactions are stored as hashes, serving as pointers to
  80. /// the actual data in the sled database.
  81. #[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
  82. pub struct Block {
  83. /// Block magic bytes
  84. pub magic: [u8; 4],
  85. /// Block header
  86. pub header: blake3::Hash,
  87. /// Trasaction hashes
  88. pub txs: Vec<blake3::Hash>,
  89. /// Lead Info
  90. pub lead_info: LeadInfo,
  91. }
  92. impl_p2p_message!(Block, "block");
  93. impl Block {
  94. pub fn new(
  95. previous: blake3::Hash,
  96. epoch: u64,
  97. slot: u64,
  98. txs: Vec<blake3::Hash>,
  99. root: MerkleNode,
  100. lead_info: LeadInfo,
  101. ) -> Self {
  102. let magic = BLOCK_MAGIC_BYTES;
  103. let timestamp = Timestamp::current_time();
  104. let header = Header::new(previous, epoch, slot, timestamp, root);
  105. let header = header.headerhash();
  106. Self { magic, header, txs, lead_info }
  107. }
  108. /// Generate the genesis block.
  109. pub fn genesis_block(genesis_ts: Timestamp, genesis_data: blake3::Hash) -> Self {
  110. let magic = BLOCK_MAGIC_BYTES;
  111. let header = Header::genesis_header(genesis_ts, genesis_data);
  112. let header = header.headerhash();
  113. let lead_info = LeadInfo::default();
  114. Self { magic, header, txs: vec![], lead_info }
  115. }
  116. /// Calculate the block hash
  117. pub fn blockhash(&self) -> blake3::Hash {
  118. blake3::hash(&serialize(self))
  119. }
  120. }
  121. /// Auxiliary structure used for blockchain syncing.
  122. #[derive(Debug, SerialEncodable, SerialDecodable)]
  123. pub struct BlockOrder {
  124. /// Slot UID
  125. pub slot: u64,
  126. /// Block headerhash of that slot
  127. pub block: blake3::Hash,
  128. }
  129. impl_p2p_message!(BlockOrder, "blockorder");
  130. /// Structure representing full block data.
  131. #[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
  132. pub struct BlockInfo {
  133. /// BlockInfo magic bytes
  134. pub magic: [u8; 4],
  135. /// Block header data
  136. pub header: Header,
  137. /// Transactions payload
  138. pub txs: Vec<Transaction>,
  139. /// Lead Info,
  140. pub lead_info: LeadInfo,
  141. }
  142. impl Default for BlockInfo {
  143. fn default() -> Self {
  144. let magic = BLOCK_MAGIC_BYTES;
  145. Self { magic, header: Header::default(), txs: vec![], lead_info: LeadInfo::default() }
  146. }
  147. }
  148. impl_p2p_message!(BlockInfo, "blockinfo");
  149. impl BlockInfo {
  150. pub fn new(header: Header, txs: Vec<Transaction>, lead_info: LeadInfo) -> Self {
  151. let magic = BLOCK_MAGIC_BYTES;
  152. Self { magic, header, txs, lead_info }
  153. }
  154. /// Calculate the block hash
  155. pub fn blockhash(&self) -> blake3::Hash {
  156. let block: Block = self.clone().into();
  157. block.blockhash()
  158. }
  159. }
  160. impl From<BlockInfo> for Block {
  161. fn from(block_info: BlockInfo) -> Self {
  162. let txs = block_info.txs.iter().map(|x| blake3::hash(&serialize(x))).collect();
  163. Self {
  164. magic: block_info.magic,
  165. header: block_info.header.headerhash(),
  166. txs,
  167. lead_info: block_info.lead_info,
  168. }
  169. }
  170. }
  171. /// Auxiliary structure used for blockchain syncing
  172. #[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
  173. pub struct BlockResponse {
  174. /// Response blocks.
  175. pub blocks: Vec<BlockInfo>,
  176. }
  177. impl_p2p_message!(BlockResponse, "blockresponse");
  178. /// This struct represents a block proposal, used for consensus.
  179. #[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
  180. pub struct BlockProposal {
  181. /// Block hash
  182. pub hash: blake3::Hash,
  183. /// Block header hash
  184. pub header: blake3::Hash,
  185. /// Block data
  186. pub block: BlockInfo,
  187. }
  188. impl BlockProposal {
  189. #[allow(clippy::too_many_arguments)]
  190. pub fn new(header: Header, txs: Vec<Transaction>, lead_info: LeadInfo) -> Self {
  191. let block = BlockInfo::new(header, txs, lead_info);
  192. let hash = block.blockhash();
  193. let header = block.header.headerhash();
  194. Self { hash, header, block }
  195. }
  196. }
  197. impl PartialEq for BlockProposal {
  198. fn eq(&self, other: &Self) -> bool {
  199. self.hash == other.hash &&
  200. self.header == other.header &&
  201. self.block.header == other.block.header &&
  202. self.block.txs == other.block.txs
  203. }
  204. }
  205. impl fmt::Display for BlockProposal {
  206. fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
  207. formatter.write_fmt(format_args!(
  208. "BlockProposal {{ leader public key: {}, hash: {}, header: {}, epoch: {}, slot: {}, txs: {} }}",
  209. self.block.lead_info.public_key,
  210. self.hash,
  211. self.header,
  212. self.block.header.epoch,
  213. self.block.header.slot,
  214. self.block.txs.len()
  215. ))
  216. }
  217. }
  218. impl_p2p_message!(BlockProposal, "proposal");
  219. impl From<BlockProposal> for BlockInfo {
  220. fn from(block: BlockProposal) -> BlockInfo {
  221. block.block
  222. }
  223. }