library_blockchain/
blockchain.rs1
2
3use serde::Serialize;
4
5use super::*;
6use crate::transaction::Put;
7
8use crate::transaction::IO;
9use std::collections::HashSet;
10
11
12
13#[derive(Debug,Serialize)]
16pub struct Blockchain {
17 pub blocks: Vec<Block >,
18 unspent_outputs: HashSet<Hash>,
19}
20
21impl Default for Blockchain {
22 fn default() -> Self {
23 Blockchain {
24 blocks: vec![],
25 unspent_outputs: HashSet::new(),
26 }
27 }
28}
29impl Blockchain {
30 pub fn new() -> Self {
31 Blockchain {
32 blocks: vec![],
33 unspent_outputs: HashSet::new(),
34 }
35 }
36
37 pub fn blockchain_update_with_block(&mut self, block: Block ) -> Result<&Vec<Block>, CustomError> {
42 let i = &self.blocks.len();
43
44 if block.index != *i as u32 {
45 return Err(CustomError::BlockValidation(
46 BlockValidationError::MismatchedIndex,
47 ));
48
49 } else if !block::blockchain_check_difficulty(&block.hash(), block.difficulty) {
50 return Err(CustomError::BlockValidation(
51 BlockValidationError::InvalidHash,
52 ));
53 } else if *i != 0 {
54 let prev_block = &self.blocks[i - 1];
56 if block.timestamp <= prev_block.timestamp {
57 return Err(CustomError::BlockValidation(
58 BlockValidationError::AchronologicalTimestamp,
59 ));
60 } else if block.prev_block_hash != prev_block.hash {
61 return Err(CustomError::BlockValidation(
62 BlockValidationError::MismatchedPreviousHash,
63 ));
64 }
65 } else {
66 if block.prev_block_hash != vec![0; 32] {
68 return Err(CustomError::BlockValidation(
69 BlockValidationError::InvalidGenesisBlockFormat,
70 ));
71 }
72 }
73
74 if let Some((coinbase, option_transactions)) = block.transactions.split_first() {
75 if !coinbase.is_coinbase() {
76 return Err(CustomError::BlockValidation(
77 BlockValidationError::InvalidCoinbaseTransaction,
78 ));
79 }
80
81 let mut block_spent: HashSet<Hash> = HashSet::new();
82 let mut block_created: HashSet<Hash> = HashSet::new();
83 let mut total_fee = 0;
84
85 for transaction in option_transactions {
86 let input_hashes = transaction.returns_closure_io_hash(&IO::Input);
87 let output_hashes = transaction.returns_closure_io_hash(&IO::Output);
88
89 if !(&input_hashes() - &self.unspent_outputs).is_empty()
97 || !(&input_hashes() & &block_spent).is_empty()
98 {
99 if *i==0 {
100 return Err(CustomError::BlockValidation(
104 BlockValidationError::InvalidInput
105 ));
106 }
107 }
108
109 let input_value = transaction.returns_closure_io(&IO::Input);
110 let output_value = transaction.returns_closure_io(&IO::Output);
111
112 if &output_value() > &input_value() {
113 return Err(CustomError::BlockValidation(
114 BlockValidationError::InsufficientInputValue,
115 ));
116 }
117
118 let fee = &input_value() - &output_value();
119
120 total_fee += fee;
121
122 block_spent.extend(input_hashes());
123 block_created.extend(output_hashes());
124 }
125
126 let coinbase_output_value = coinbase.returns_closure_io(&IO::Output);
127
128 if coinbase_output_value() < total_fee {
129 return Err(CustomError::BlockValidation(
130 BlockValidationError::InvalidCoinbaseTransactionFee,
131 ));
132 } else {
133 let coinbase_output_hashes = coinbase.returns_closure_io_hash(&IO::Output);
134 block_created.extend(coinbase_output_hashes());
135 }
136
137 self.unspent_outputs
138 .retain(|output| !block_spent.contains(output));
139 self.unspent_outputs.extend(block_created);
140 }
141 println!("**BlOcKcHaIn SiGnAls:**\n{:?}\n", &block);
142 let _ = &self.blocks.push(block);
143
144 Ok(&self.blocks)
145 }
146}