1use ahash::AHashMap;
2use log::{debug, error, info, trace, warn};
3use num_derive::FromPrimitive;
4use num_traits::Zero;
5use rayon::prelude::*;
6use serde::{Deserialize, Serialize};
7use std::convert::TryInto;
8use std::fmt::{Display, Formatter};
9use std::io::{Error, ErrorKind};
10use std::ops::Rem;
11use std::{i128, mem};
12
13use crate::core::consensus::blockchain::Blockchain;
14use crate::core::consensus::burnfee::BurnFee;
15use crate::core::consensus::golden_ticket::GoldenTicket;
16use crate::core::consensus::hop::HOP_SIZE;
17use crate::core::consensus::merkle::MerkleTree;
18use crate::core::consensus::slip::{Slip, SlipType, SLIP_SIZE};
19use crate::core::consensus::transaction::{Transaction, TransactionType, TRANSACTION_SIZE};
20use crate::core::defs::{
21 BlockId, Currency, PeerIndex, PrintForLog, SaitoHash, SaitoPrivateKey, SaitoPublicKey,
22 SaitoSignature, SaitoUTXOSetKey, Timestamp, UtxoSet, BLOCK_FILE_EXTENSION,
23};
24use crate::core::io::storage::Storage;
25use crate::core::util::configuration::Configuration;
26use crate::core::util::crypto::{hash, sign, verify_signature};
27use crate::iterate;
28
29pub const BLOCK_HEADER_SIZE: usize = 389;
30
31#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
44pub struct ConsensusValues {
45 pub fee_transaction: Option<Transaction>,
47
48 pub st_num: u8,
50 pub st_index: Option<usize>,
52 pub it_num: u8,
54 pub it_index: Option<usize>,
56 pub ft_num: u8,
58 pub ft_index: Option<usize>,
60 pub gt_num: u8,
62 pub gt_index: Option<usize>,
64
65 pub total_fees: Currency,
67 pub total_fees_new: Currency,
69 pub total_fees_atr: Currency,
71 pub total_fees_cumulative: Currency,
73
74 pub avg_total_fees: Currency,
76 pub avg_total_fees_new: Currency,
78 pub avg_total_fees_atr: Currency,
80
81 pub total_bytes_new: u64,
83
84 pub total_payout_routing: Currency,
86 pub total_payout_mining: Currency,
88 pub total_payout_treasury: Currency,
90 pub total_payout_graveyard: Currency,
92 pub total_payout_atr: Currency,
94
95 pub avg_payout_routing: Currency,
97 pub avg_payout_mining: Currency,
99 pub avg_payout_treasury: Currency,
101 pub avg_payout_graveyard: Currency,
103 pub avg_payout_atr: Currency,
105
106 pub avg_fee_per_byte: Currency,
108
109 pub fee_per_byte: Currency,
111
112 pub burnfee: Currency,
114 pub difficulty: u64,
116
117 pub total_rebroadcast_slips: u64,
119 pub total_rebroadcast_nolan: Currency,
121 pub rebroadcasts: Vec<Transaction>,
123 pub rebroadcast_hash: [u8; 32],
125 pub avg_nolan_rebroadcast_per_block: Currency,
127
128 pub total_rebroadcast_fees_nolan: Currency,
129
130 pub total_rebroadcast_staking_payouts_nolan: Currency,
131
132 pub total_fees_paid_by_nonrebroadcast_atr_transactions: Currency,
133
134 pub expected_difficulty: u64,
135}
136
137impl Display for ConsensusValues {
138 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
139 writeln!(
140 f,
141 "ConsensusValues {{ fee_transaction: {:?}, st_num: {}, st_index: {:?}, it_num: {}, it_index: {:?}, ft_num: {}, ft_index: {:?}, gt_num: {}, gt_index: {:?}, total_fees: {}, total_fees_new: {}, total_fees_atr: {}, total_fees_cumulative: {}, avg_total_fees: {}, avg_total_fees_new: {}, avg_total_fees_atr: {}, total_bytes_new: {}, total_payout_routing: {}, total_payout_mining: {}, total_payout_treasury: {}, total_payout_graveyard: {}, total_payout_atr: {}, avg_payout_routing: {}, avg_payout_mining: {}, avg_payout_treasury: {}, avg_payout_graveyard: {}, avg_payout_atr: {}, avg_fee_per_byte: {}, fee_per_byte: {}, burnfee: {}, difficulty: {}, rebroadcasts: {:?}, total_rebroadcast_slips: {}, total_rebroadcast_nolan: {}, rebroadcast_hash: {:?}, avg_nolan_rebroadcast_per_block: {}, total_rebroadcast_fees_nolan: {}, total_rebroadcast_staking_payouts_nolan: {}, total_fees_paid_by_nonrebroadcast_atr_transactions: {}, expected_difficulty: {} }}",
142 self.fee_transaction,
143 self.st_num,
144 self.st_index,
145 self.it_num,
146 self.it_index,
147 self.ft_num,
148 self.ft_index,
149 self.gt_num,
150 self.gt_index,
151 self.total_fees,
152 self.total_fees_new,
153 self.total_fees_atr,
154 self.total_fees_cumulative,
155 self.avg_total_fees,
156 self.avg_total_fees_new,
157 self.avg_total_fees_atr,
158 self.total_bytes_new,
159 self.total_payout_routing,
160 self.total_payout_mining,
161 self.total_payout_treasury,
162 self.total_payout_graveyard,
163 self.total_payout_atr,
164 self.avg_payout_routing,
165 self.avg_payout_mining,
166 self.avg_payout_treasury,
167 self.avg_payout_graveyard,
168 self.avg_payout_atr,
169 self.avg_fee_per_byte,
170 self.fee_per_byte,
171 self.burnfee,
172 self.difficulty,
173 self.rebroadcasts.len(),
174 self.total_rebroadcast_slips,
175 self.total_rebroadcast_nolan,
176 self.rebroadcast_hash.to_hex(),
177 self.avg_nolan_rebroadcast_per_block,
178 self.total_rebroadcast_fees_nolan,
179 self.total_rebroadcast_staking_payouts_nolan,
180 self.total_fees_paid_by_nonrebroadcast_atr_transactions,
181 self.expected_difficulty)
182 }
183}
184
185impl ConsensusValues {
186 #[allow(clippy::too_many_arguments)]
187 pub fn new() -> ConsensusValues {
188 ConsensusValues {
189 fee_transaction: None,
190
191 st_num: 0,
192 st_index: None,
193 it_num: 0,
194 it_index: None,
195 ft_num: 0,
196 ft_index: None,
197 gt_num: 0,
198 gt_index: None,
199
200 total_fees: 5000,
201 total_fees_new: 0,
202 total_fees_atr: 0,
203 total_fees_cumulative: 0,
204
205 avg_total_fees: 0,
206 avg_total_fees_new: 0,
207 avg_total_fees_atr: 0,
208
209 total_bytes_new: 0,
210
211 total_payout_routing: 0,
212 total_payout_mining: 0,
213 total_payout_treasury: 0,
214 total_payout_graveyard: 0,
215 total_payout_atr: 0,
216
217 avg_payout_routing: 0,
218 avg_payout_mining: 0,
219 avg_payout_treasury: 0,
220 avg_payout_graveyard: 0,
221 avg_payout_atr: 0,
222
223 avg_fee_per_byte: 0,
224 fee_per_byte: 0,
225
226 burnfee: 1,
227 difficulty: 1,
228
229 rebroadcasts: vec![],
230 total_rebroadcast_slips: 0,
231 total_rebroadcast_nolan: 0,
232 rebroadcast_hash: [0; 32],
233 avg_nolan_rebroadcast_per_block: 0,
234
235 total_rebroadcast_fees_nolan: 0,
236
237 total_rebroadcast_staking_payouts_nolan: 0,
238
239 total_fees_paid_by_nonrebroadcast_atr_transactions: 0,
240
241 expected_difficulty: 0,
242 }
243 }
244}
245
246impl Default for ConsensusValues {
247 fn default() -> ConsensusValues {
248 ConsensusValues {
249 fee_transaction: None,
250
251 st_num: 0,
252 st_index: None,
253 it_num: 0,
254 it_index: None,
255 ft_num: 0,
256 ft_index: None,
257 gt_num: 0,
258 gt_index: None,
259
260 total_fees: 0,
261 total_fees_new: 0,
262 total_fees_atr: 0,
263 total_fees_cumulative: 0,
264
265 avg_total_fees: 0,
266 avg_total_fees_new: 0,
267 avg_total_fees_atr: 0,
268
269 total_bytes_new: 0,
270
271 total_payout_routing: 0,
272 total_payout_mining: 0,
273 total_payout_treasury: 0,
274 total_payout_graveyard: 0,
275 total_payout_atr: 0,
276
277 avg_payout_routing: 0,
278 avg_payout_mining: 0,
279 avg_payout_treasury: 0,
280 avg_payout_graveyard: 0,
281 avg_payout_atr: 0,
282
283 avg_fee_per_byte: 0,
284 fee_per_byte: 0,
285
286 burnfee: 1,
287 difficulty: 1,
288
289 rebroadcasts: vec![],
290 total_rebroadcast_slips: 0,
291 total_rebroadcast_nolan: 0,
292 rebroadcast_hash: [0; 32],
293 avg_nolan_rebroadcast_per_block: 0,
294 total_rebroadcast_fees_nolan: 0,
295
296 total_rebroadcast_staking_payouts_nolan: 0,
297
298 total_fees_paid_by_nonrebroadcast_atr_transactions: 0,
299
300 expected_difficulty: 0,
301 }
302 }
303}
304
305#[derive(Serialize, Deserialize, Debug, Copy, PartialEq, Clone, FromPrimitive)]
317pub enum BlockType {
318 Ghost = 0,
319 Header = 1,
320 Pruned = 2,
321 Full = 3,
322}
323
324#[serde_with::serde_as]
325#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
326pub struct Block {
327 pub id: BlockId,
335 pub timestamp: Timestamp,
336 pub previous_block_hash: [u8; 32],
337 #[serde_as(as = "[_; 33]")]
338 pub creator: [u8; 33],
339 pub merkle_root: [u8; 32],
340 #[serde_as(as = "[_; 64]")]
341 pub signature: [u8; 64],
342 pub graveyard: Currency,
343 pub treasury: Currency,
344
345 pub total_fees: Currency,
346 pub total_fees_new: Currency,
347 pub total_fees_atr: Currency,
348 pub total_fees_cumulative: Currency,
349 pub avg_total_fees: Currency,
350 pub avg_total_fees_new: Currency,
351 pub avg_total_fees_atr: Currency,
352 pub total_payout_routing: Currency,
353 pub total_payout_mining: Currency,
354 pub total_payout_treasury: Currency,
355 pub total_payout_graveyard: Currency,
356 pub total_payout_atr: Currency,
357 pub avg_payout_routing: Currency,
358 pub avg_payout_mining: Currency,
359 pub avg_payout_treasury: Currency,
360 pub avg_payout_graveyard: Currency,
361 pub avg_payout_atr: Currency,
362 pub avg_fee_per_byte: Currency,
363 pub fee_per_byte: Currency,
364 pub avg_nolan_rebroadcast_per_block: Currency,
365 pub burnfee: Currency,
366 pub difficulty: u64,
367 pub previous_block_unpaid: Currency,
368
369 pub transactions: Vec<Transaction>,
376
377 pub pre_hash: SaitoHash,
390 pub hash: SaitoHash,
392
393 pub total_work: Currency,
395 pub in_longest_chain: bool,
397 pub has_golden_ticket: bool,
399 pub has_issuance_transaction: bool,
401 pub issuance_transaction_index: u64,
403 pub has_fee_transaction: bool,
405 pub has_staking_transaction: bool,
406 pub golden_ticket_index: u64,
408 pub fee_transaction_index: u64,
410 pub total_rebroadcast_slips: u64,
412 pub total_rebroadcast_nolan: Currency,
414 pub rebroadcast_hash: [u8; 32],
416 pub block_type: BlockType,
418 pub cv: ConsensusValues,
419 #[serde(skip)]
421 pub slips_spent_this_block: AHashMap<SaitoUTXOSetKey, u64>,
422 #[serde(skip)]
423 pub created_hashmap_of_slips_spent_this_block: bool,
424 #[serde(skip)]
425 pub routed_from_peer: Option<PeerIndex>,
426 #[serde(skip)]
427 pub transaction_map: AHashMap<SaitoPublicKey, bool>,
428 #[serde(skip)]
429 pub force_loaded: bool,
430 pub safe_to_prune_transactions: bool,
432 pub has_checkpoint: bool,
434}
435
436impl Display for Block {
437 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
438 writeln!(
439 f,
440 "Block {{ id: {}, timestamp: {}, previous_block_hash: {:?}, creator: {:?}, merkle_root: {:?}, signature: {:?}, graveyard: {}, treasury: {}, total_fees: {}, total_fees_new: {}, total_fees_atr: {}, avg_total_fees: {}, avg_total_fees_new: {}, avg_total_fees_atr: {}, total_payout_routing: {}, total_payout_mining: {}, total_payout_treasury: {}, total_payout_graveyard: {}, total_payout_atr: {}, avg_payout_routing: {}, avg_payout_mining: {}, avg_payout_treasury: {}, avg_payout_graveyard: {}, avg_payout_atr: {}, avg_fee_per_byte: {}, fee_per_byte: {}, avg_nolan_rebroadcast_per_block: {}, burnfee: {}, difficulty: {}, previous_block_unpaid: {}, hash: {:?}, total_work: {}, in_longest_chain: {}, has_golden_ticket: {}, has_issuance_transaction: {}, issuance_transaction_index: {}, has_fee_transaction: {}, has_staking_transaction: {}, golden_ticket_index: {}, fee_transaction_index: {}, total_rebroadcast_slips: {}, total_rebroadcast_nolan: {}, rebroadcast_hash: {}, block_type: {:?}, cv: {}, routed_from_peer: {:?} ",
441 self.id,
442 self.timestamp,
443 self.previous_block_hash.to_hex(),
444 self.creator.to_base58(),
445 self.merkle_root.to_hex(),
446 self.signature.to_hex(),
447 self.graveyard,
448 self.treasury,
449 self.total_fees,
450 self.total_fees_new,
451 self.total_fees_atr,
452 self.avg_total_fees,
453 self.avg_total_fees_new,
454 self.avg_total_fees_atr,
455 self.total_payout_routing,
456 self.total_payout_mining,
457 self.total_payout_treasury,
458 self.total_payout_graveyard,
459 self.total_payout_atr,
460 self.avg_payout_routing,
461 self.avg_payout_mining,
462 self.avg_payout_treasury,
463 self.avg_payout_graveyard,
464 self.avg_payout_atr,
465 self.avg_fee_per_byte,
466 self.fee_per_byte,
467 self.avg_nolan_rebroadcast_per_block,
468 self.burnfee,
469 self.difficulty,
470 self.previous_block_unpaid,
471 self.hash.to_hex(),
472 self.total_work,
473 self.in_longest_chain,
474 self.has_golden_ticket,
475 self.has_issuance_transaction,
476 self.issuance_transaction_index,
477 self.has_fee_transaction,
478 self.has_staking_transaction,
479 self.golden_ticket_index,
480 self.fee_transaction_index,
481 self.total_rebroadcast_slips,
482 self.total_rebroadcast_nolan,
483 self.rebroadcast_hash.to_hex(),
484 self.block_type,
485 self.cv,
486 self.routed_from_peer,
487 ).unwrap();
488 writeln!(f, "}}")
493 }
494}
495
496impl Block {
497 #[allow(clippy::new_without_default)]
498 pub fn new() -> Block {
499 Block {
500 id: 0,
501 timestamp: 0,
502 previous_block_hash: [0; 32],
503 creator: [0; 33],
504 merkle_root: [0; 32],
505 signature: [0; 64],
506 graveyard: 0,
507 treasury: 0,
508 previous_block_unpaid: 0,
509 total_fees: 0,
510 total_fees_new: 0,
511 total_fees_atr: 0,
512 total_fees_cumulative: 0,
513 avg_total_fees: 0,
514 avg_total_fees_new: 0,
515 avg_total_fees_atr: 0,
516 total_payout_routing: 0,
517 total_payout_mining: 0,
518 total_payout_treasury: 0,
519 total_payout_graveyard: 0,
520 total_payout_atr: 0,
521 avg_payout_routing: 0,
522 avg_payout_mining: 0,
523 avg_payout_treasury: 0,
524 avg_payout_graveyard: 0,
525 avg_payout_atr: 0,
526 avg_fee_per_byte: 0,
527 fee_per_byte: 0,
528 burnfee: 0,
529 difficulty: 0,
530 avg_nolan_rebroadcast_per_block: 0,
531
532 transactions: vec![],
533 pre_hash: [0; 32],
534 hash: [0; 32],
535 total_work: 0,
536 in_longest_chain: false,
537 has_golden_ticket: false,
538 has_fee_transaction: false,
539 has_staking_transaction: false,
540 has_issuance_transaction: false,
541 issuance_transaction_index: 0,
542 golden_ticket_index: 0,
543 fee_transaction_index: 0,
544 total_rebroadcast_slips: 0,
545 total_rebroadcast_nolan: 0,
546 rebroadcast_hash: [0; 32],
548 block_type: BlockType::Full,
550 slips_spent_this_block: AHashMap::new(),
552 created_hashmap_of_slips_spent_this_block: false,
553 routed_from_peer: None,
554 transaction_map: Default::default(),
555 cv: ConsensusValues::default(),
556 force_loaded: false,
557 safe_to_prune_transactions: false,
558 has_checkpoint: false,
559 }
560 }
561
562 pub fn add_transaction(&mut self, tx: Transaction) {
563 self.transactions.push(tx);
564 }
565
566 pub async fn create(
570 transactions: &mut AHashMap<SaitoSignature, Transaction>,
571 previous_block_hash: SaitoHash,
572 blockchain: &Blockchain,
573 current_timestamp: Timestamp,
574 public_key: &SaitoPublicKey,
575 private_key: &SaitoPrivateKey,
576 golden_ticket: Option<Transaction>,
577 configs: &(dyn Configuration + Send + Sync),
578 storage: &Storage,
579 ) -> Result<Block, Error> {
580 debug!(
581 "Block::create : previous block hash : {:?}",
582 previous_block_hash.to_hex()
583 );
584
585 let mut previous_block_id = 0;
586 let mut _previous_block_timestamp = 0;
587 let mut previous_block_graveyard = 0;
588 let mut previous_block_treasury = 0;
589 let mut previous_block_total_fees = 0;
590 let mut _previous_block_avg_total_fees = 0;
591 let mut _previous_block_avg_total_fees_new = 0;
592 let mut _previous_block_avg_total_fees_atr = 0;
593 let mut _previous_block_avg_payout_routing = 0;
594 let mut _previous_block_avg_payout_mining = 0;
595 let mut _previous_block_avg_payout_treasury = 0;
596 let mut _previous_block_avg_payout_graveyard = 0;
597 let mut _previous_block_avg_payout_atr = 0;
598 let mut _previous_block_avg_fee_per_byte = 0;
599
600 if let Some(previous_block) = blockchain.blocks.get(&previous_block_hash) {
601 previous_block_id = previous_block.id;
602 previous_block_total_fees = previous_block.total_fees;
603 _previous_block_timestamp = previous_block.timestamp;
604 previous_block_graveyard = previous_block.graveyard;
605 previous_block_treasury = previous_block.treasury;
606 _previous_block_avg_total_fees = previous_block.avg_total_fees;
607 _previous_block_avg_total_fees_new = previous_block.avg_total_fees_new;
608 _previous_block_avg_total_fees_atr = previous_block.avg_total_fees_atr;
609 _previous_block_avg_payout_routing = previous_block.avg_payout_routing;
610 _previous_block_avg_payout_mining = previous_block.avg_payout_mining;
611 _previous_block_avg_payout_treasury = previous_block.avg_payout_treasury;
612 _previous_block_avg_payout_graveyard = previous_block.avg_payout_graveyard;
613 _previous_block_avg_payout_atr = previous_block.avg_payout_atr;
614 _previous_block_avg_fee_per_byte = previous_block.avg_fee_per_byte;
615 }
616
617 let mut block = Block::new();
621
622 block.id = previous_block_id + 1;
626 block.previous_block_hash = previous_block_hash;
627 block.timestamp = current_timestamp;
628 block.creator = *public_key;
629
630 if golden_ticket.is_some() {
634 block.previous_block_unpaid = 0;
635 } else {
636 block.previous_block_unpaid = previous_block_total_fees;
637 }
638
639 if let Some(gt) = golden_ticket {
643 block.transactions.push(gt);
644 }
645
646 block.transactions.reserve(transactions.len());
650 let iter = transactions.drain().map(|(_, tx)| tx);
651 block.transactions.extend(iter);
652 transactions.clear();
653
654 let mut cv: ConsensusValues = block
658 .generate_consensus_values(blockchain, storage, configs)
659 .await;
660 block.cv = cv.clone();
661
662 block.total_fees_new = cv.total_fees_new;
666
667 block.total_fees_atr = cv.total_fees_atr;
671
672 block.total_fees_cumulative = cv.total_fees_cumulative;
676
677 block.total_fees = block.total_fees_new + block.total_fees_atr;
681
682 block.avg_total_fees = cv.avg_total_fees;
686
687 block.avg_total_fees_new = cv.avg_total_fees_new;
691
692 block.avg_total_fees_atr = cv.avg_total_fees_atr;
696
697 block.total_payout_routing = cv.total_payout_routing;
701
702 block.total_payout_mining = cv.total_payout_mining;
706
707 block.total_payout_treasury = cv.total_payout_treasury;
711
712 block.total_payout_graveyard = cv.total_payout_graveyard;
716
717 block.total_payout_atr = cv.total_payout_atr;
721
722 block.avg_payout_routing = cv.avg_payout_routing;
726
727 block.avg_payout_mining = cv.avg_payout_mining;
731
732 block.avg_payout_treasury = cv.avg_payout_treasury;
736
737 block.avg_payout_graveyard = cv.avg_payout_graveyard;
741
742 block.avg_payout_atr = cv.avg_payout_atr;
746
747 block.avg_fee_per_byte = cv.avg_fee_per_byte;
751
752 block.fee_per_byte = cv.fee_per_byte;
756
757 block.avg_nolan_rebroadcast_per_block = cv.avg_nolan_rebroadcast_per_block;
761
762 block.burnfee = cv.burnfee;
766
767 block.difficulty = cv.difficulty;
771
772 block.treasury = previous_block_treasury + cv.total_payout_treasury - cv.total_payout_atr;
776
777 block.graveyard = previous_block_graveyard + cv.total_payout_graveyard;
781
782 let rlen = cv.rebroadcasts.len();
786
787 let _tx_hashes_generated = cv.rebroadcasts[0..rlen]
797 .iter_mut()
798 .enumerate()
799 .all(|(index, tx)| tx.generate(public_key, index as u64, block.id));
800
801 if rlen > 0 {
805 block.transactions.append(&mut cv.rebroadcasts);
806 }
807
808 if cv.fee_transaction.is_some() {
812 let mut fee_tx = cv.fee_transaction.unwrap();
813 let hash_for_signature: SaitoHash = hash(&fee_tx.serialize_for_signature());
814 fee_tx.hash_for_signature = Some(hash_for_signature);
815 fee_tx.sign(private_key);
816 block.add_transaction(fee_tx);
817 }
818
819 if !block.created_hashmap_of_slips_spent_this_block {
823 debug!(
824 "creating hashmap of slips spent this block : {}...",
825 block.id
826 );
827
828 for transaction in &block.transactions {
829 if transaction.transaction_type != TransactionType::Fee {
830 for input in transaction.from.iter() {
831 if input.amount == 0 {
832 continue;
833 }
834
835 let value = block
836 .slips_spent_this_block
837 .entry(input.get_utxoset_key())
838 .and_modify(|e| *e += 1)
839 .or_insert(1);
840
841 if *value > 1 && input.amount > 0 {
842 warn!(
843 "double-spend detected in block {} : {} in block.create()",
844 block.id, input
845 );
846 return Err(Error::new(
847 ErrorKind::InvalidData,
848 "double-spend detected",
849 ));
850 }
851 }
852 }
853 block.created_hashmap_of_slips_spent_this_block = true;
854 }
855 }
856 block.created_hashmap_of_slips_spent_this_block = true;
857
858 block.merkle_root = block.generate_merkle_root(configs.is_browser(), configs.is_spv_mode());
862
863 block.generate_pre_hash();
869 block.sign(private_key);
870
871 block.generate()?;
875
876 Ok(block)
877 }
878
879 pub async fn delete(&self, utxoset: &mut UtxoSet) -> bool {
883 for tx in &self.transactions {
884 tx.delete(utxoset).await;
885 }
886 true
887 }
888
889 pub fn deserialize_from_net(bytes: &[u8]) -> Result<Block, Error> {
927 if bytes.len() < BLOCK_HEADER_SIZE {
928 warn!(
929 "block buffer is smaller than header length. length : {:?}",
930 bytes.len()
931 );
932 return Err(Error::from(ErrorKind::InvalidData));
933 }
934 let transactions_len: u32 = u32::from_be_bytes(
935 bytes[0..4]
936 .try_into()
937 .or(Err(Error::from(ErrorKind::InvalidData)))?,
938 );
939 let id: u64 = u64::from_be_bytes(
940 bytes[4..12]
941 .try_into()
942 .or(Err(Error::from(ErrorKind::InvalidData)))?,
943 );
944 let timestamp: Timestamp = Timestamp::from_be_bytes(
945 bytes[12..20]
946 .try_into()
947 .or(Err(Error::from(ErrorKind::InvalidData)))?,
948 );
949 let previous_block_hash: SaitoHash = bytes[20..52]
950 .try_into()
951 .or(Err(Error::from(ErrorKind::InvalidData)))?;
952 let creator: SaitoPublicKey = bytes[52..85]
953 .try_into()
954 .or(Err(Error::from(ErrorKind::InvalidData)))?;
955 let merkle_root: SaitoHash = bytes[85..117]
956 .try_into()
957 .or(Err(Error::from(ErrorKind::InvalidData)))?;
958 let signature: SaitoSignature = bytes[117..181]
959 .try_into()
960 .or(Err(Error::from(ErrorKind::InvalidData)))?;
961
962 let graveyard: Currency = Currency::from_be_bytes(bytes[181..189].try_into().unwrap());
963 let treasury: Currency = Currency::from_be_bytes(bytes[189..197].try_into().unwrap());
964 let burnfee: Currency = Currency::from_be_bytes(bytes[197..205].try_into().unwrap());
965 let difficulty: u64 = u64::from_be_bytes(bytes[205..213].try_into().unwrap());
966 let avg_total_fees: Currency = Currency::from_be_bytes(bytes[213..221].try_into().unwrap()); let avg_fee_per_byte: Currency =
968 Currency::from_be_bytes(bytes[221..229].try_into().unwrap());
969 let avg_nolan_rebroadcast_per_block: Currency =
970 Currency::from_be_bytes(bytes[229..237].try_into().unwrap());
971 let previous_block_unpaid: Currency =
972 Currency::from_be_bytes(bytes[237..245].try_into().unwrap());
973 let avg_total_fees: Currency = Currency::from_be_bytes(bytes[245..253].try_into().unwrap());
974 let avg_total_fees_new: Currency =
975 Currency::from_be_bytes(bytes[253..261].try_into().unwrap());
976 let avg_total_fees_atr: Currency =
977 Currency::from_be_bytes(bytes[261..269].try_into().unwrap());
978 let avg_payout_routing: Currency =
979 Currency::from_be_bytes(bytes[269..277].try_into().unwrap());
980 let avg_payout_mining: Currency =
981 Currency::from_be_bytes(bytes[277..285].try_into().unwrap());
982 let avg_payout_treasury: Currency =
983 Currency::from_be_bytes(bytes[285..293].try_into().unwrap());
984 let avg_payout_graveyard: Currency =
985 Currency::from_be_bytes(bytes[293..301].try_into().unwrap());
986 let avg_payout_atr: Currency = Currency::from_be_bytes(bytes[301..309].try_into().unwrap());
987 let total_payout_routing: Currency =
988 Currency::from_be_bytes(bytes[309..317].try_into().unwrap());
989 let total_payout_mining: Currency =
990 Currency::from_be_bytes(bytes[317..325].try_into().unwrap());
991 let total_payout_treasury: Currency =
992 Currency::from_be_bytes(bytes[325..333].try_into().unwrap());
993 let total_payout_graveyard: Currency =
994 Currency::from_be_bytes(bytes[333..341].try_into().unwrap());
995 let total_payout_atr: Currency =
996 Currency::from_be_bytes(bytes[341..349].try_into().unwrap());
997 let total_fees: Currency = Currency::from_be_bytes(bytes[349..357].try_into().unwrap());
998 let total_fees_new: Currency = Currency::from_be_bytes(bytes[357..365].try_into().unwrap());
999 let total_fees_atr: Currency = Currency::from_be_bytes(bytes[365..373].try_into().unwrap());
1000 let fee_per_byte: Currency = Currency::from_be_bytes(bytes[373..381].try_into().unwrap());
1001 let total_fees_cumulative: Currency =
1002 Currency::from_be_bytes(bytes[381..389].try_into().unwrap());
1003
1004 let mut transactions = vec![];
1005 let mut start_of_transaction_data = BLOCK_HEADER_SIZE;
1006 for _n in 0..transactions_len {
1007 if bytes.len() < start_of_transaction_data + 16 {
1008 warn!(
1009 "block buffer is invalid to read transaction metadata. length : {:?}, end_of_tx_data : {:?}",
1010 bytes.len(),
1011 start_of_transaction_data+16
1012 );
1013 return Err(Error::from(ErrorKind::InvalidData));
1014 }
1015 let inputs_len: u32 = u32::from_be_bytes(
1016 bytes[start_of_transaction_data..start_of_transaction_data + 4]
1017 .try_into()
1018 .or(Err(Error::from(ErrorKind::InvalidData)))?,
1019 );
1020 let outputs_len: u32 = u32::from_be_bytes(
1021 bytes[start_of_transaction_data + 4..start_of_transaction_data + 8]
1022 .try_into()
1023 .or(Err(Error::from(ErrorKind::InvalidData)))?,
1024 );
1025 let message_len: usize = u32::from_be_bytes(
1026 bytes[start_of_transaction_data + 8..start_of_transaction_data + 12]
1027 .try_into()
1028 .or(Err(Error::from(ErrorKind::InvalidData)))?,
1029 ) as usize;
1030 let path_len: usize = u32::from_be_bytes(
1031 bytes[start_of_transaction_data + 12..start_of_transaction_data + 16]
1032 .try_into()
1033 .or(Err(Error::from(ErrorKind::InvalidData)))?,
1034 ) as usize;
1035 let total_len = inputs_len
1036 .checked_add(outputs_len)
1037 .ok_or(Error::from(ErrorKind::InvalidData))?;
1038 let end_of_transaction_data = start_of_transaction_data
1039 + TRANSACTION_SIZE
1040 + (total_len as usize * SLIP_SIZE)
1041 + message_len
1042 + path_len * HOP_SIZE;
1043
1044 if bytes.len() < end_of_transaction_data {
1045 warn!(
1046 "block buffer is invalid to read transaction data. length : {:?}, end of tx data : {:?}, tx_count : {:?}",
1047 bytes.len(), end_of_transaction_data, transactions_len
1048 );
1049 return Err(Error::from(ErrorKind::InvalidData));
1050 }
1051 let transaction = Transaction::deserialize_from_net(
1052 &bytes[start_of_transaction_data..end_of_transaction_data].to_vec(),
1053 )?;
1054 transactions.push(transaction);
1055 start_of_transaction_data = end_of_transaction_data;
1056 }
1057
1058 let mut block = Block::new();
1059 block.id = id;
1060 block.timestamp = timestamp;
1061 block.previous_block_hash = previous_block_hash;
1062 block.creator = creator;
1063 block.merkle_root = merkle_root;
1064 block.signature = signature;
1065 block.graveyard = graveyard;
1066 block.treasury = treasury;
1067 block.burnfee = burnfee;
1068 block.difficulty = difficulty;
1069 block.avg_total_fees = avg_total_fees;
1070 block.avg_fee_per_byte = avg_fee_per_byte;
1071 block.avg_nolan_rebroadcast_per_block = avg_nolan_rebroadcast_per_block;
1072 block.previous_block_unpaid = previous_block_unpaid;
1073 block.avg_total_fees = avg_total_fees;
1074 block.avg_total_fees_new = avg_total_fees_new;
1075 block.avg_total_fees_atr = avg_total_fees_atr;
1076 block.avg_payout_routing = avg_payout_routing;
1077 block.avg_payout_mining = avg_payout_mining;
1078 block.avg_payout_treasury = avg_payout_treasury;
1079 block.avg_payout_graveyard = avg_payout_graveyard;
1080 block.avg_payout_atr = avg_payout_atr;
1081 block.total_payout_routing = total_payout_routing;
1082 block.total_payout_mining = total_payout_mining;
1083 block.total_payout_treasury = total_payout_treasury;
1084 block.total_payout_graveyard = total_payout_graveyard;
1085 block.total_payout_atr = total_payout_atr;
1086 block.total_fees = total_fees;
1087 block.total_fees_new = total_fees_new;
1088 block.total_fees_atr = total_fees_atr;
1089 block.fee_per_byte = fee_per_byte;
1090 block.total_fees_cumulative = total_fees_cumulative;
1091
1092 block.transactions = transactions.to_vec();
1093
1094 if transactions_len == 0 && !(block.id == 1 && previous_block_hash == [0; 32]) {
1096 block.block_type = BlockType::Header;
1097 }
1098
1099 Ok(block)
1100 }
1101
1102 pub async fn downgrade_block_to_block_type(
1104 &mut self,
1105 block_type: BlockType,
1106 _is_spv: bool,
1107 ) -> bool {
1108 debug!(
1109 "downgrading BLOCK_ID {:?} to type : {:?}",
1110 self.id, block_type
1111 );
1112
1113 if self.block_type == block_type {
1114 return true;
1115 }
1116
1117 if block_type == BlockType::Pruned {
1121 self.transactions = vec![];
1122 self.block_type = BlockType::Pruned;
1123 return true;
1124 }
1125
1126 false
1127 }
1128
1129 pub fn find_winning_router(&self, random_number: SaitoHash) -> SaitoPublicKey {
1133 let winner_pubkey: SaitoPublicKey;
1134
1135 let x = primitive_types::U256::from_big_endian(&random_number);
1137 let y = self.total_fees;
1140
1141 if y == 0 {
1143 winner_pubkey = [0; 33];
1144 return winner_pubkey;
1145 }
1146
1147 let z = primitive_types::U256::from_big_endian(&y.to_be_bytes());
1148 let zy = x.rem(z);
1149 let winning_nolan: Currency = std::cmp::max(zy.low_u64(), 1);
1150
1151 let winning_tx_placeholder: Transaction;
1154
1155 let mut tx: Option<&Transaction> = None;
1160 for transaction in &self.transactions {
1161 if transaction.cumulative_fees >= winning_nolan {
1162 tx = Some(transaction);
1163 break;
1164 }
1165 }
1166
1167 if tx.is_none() {
1169 winner_pubkey = [0; 33];
1170 return winner_pubkey;
1171 }
1172
1173 let mut winning_tx = tx.unwrap();
1175
1176 if winning_tx.transaction_type == TransactionType::ATR {
1181 let tmptx = winning_tx.data.to_vec();
1182 winning_tx_placeholder =
1183 Transaction::deserialize_from_net(&tmptx).expect("buffer to be valid");
1184 winning_tx = &winning_tx_placeholder;
1185 } else {
1186 assert_ne!(
1187 winning_tx.cumulative_fees,
1188 Currency::zero(),
1189 "winning tx doesn't have fees {}",
1190 winning_tx
1191 );
1192 }
1193 winner_pubkey = winning_tx.get_winning_routing_node(hash(random_number.as_ref()));
1195 winner_pubkey
1196 }
1197
1198 pub fn generate(&mut self) -> Result<(), Error> {
1214 let creator_public_key = &self.creator;
1215
1216 self.total_rebroadcast_slips = 0;
1218 self.rebroadcast_hash = [0; 32];
1219
1220 let mut tx_index: u64 = 0;
1224 for tx in self.transactions.iter_mut() {
1225 tx.generate(creator_public_key, tx_index, self.id);
1226 if let TransactionType::SPV = tx.transaction_type {
1227 tx_index += tx.txs_replacements as u64;
1228 } else {
1229 tx_index += 1;
1230 }
1231 }
1232
1233 self.generate_transaction_hashmap();
1234
1235 if self.merkle_root == [0; 32] {
1236 self.merkle_root = self.generate_merkle_root(false, false);
1237 }
1238
1239 self.generate_pre_hash();
1240 self.generate_hash();
1241
1242 let mut cumulative_fees = 0;
1247 let mut total_work = 0;
1248
1249 let mut has_golden_ticket = false;
1250 let mut has_fee_transaction = false;
1251
1252 let mut has_issuance_transaction = false;
1253 let mut issuance_transaction_index = 0;
1254 let mut golden_ticket_index = 0;
1255 let mut fee_transaction_index = 0;
1256
1257 for i in 0..self.transactions.len() {
1266 let transaction = &mut self.transactions[i];
1267
1268 cumulative_fees = transaction.generate_cumulative_fees(cumulative_fees);
1269
1270 total_work += transaction.total_work_for_me;
1271
1272 if !self.created_hashmap_of_slips_spent_this_block
1282 && transaction.transaction_type != TransactionType::Fee
1283 {
1284 for input in transaction.from.iter() {
1285 if input.amount == 0 {
1286 continue;
1287 }
1288
1289 let value = self
1290 .slips_spent_this_block
1291 .entry(input.get_utxoset_key())
1292 .and_modify(|e| *e += 1)
1293 .or_insert(1);
1294 if *value > 1 && input.amount > 0 {
1295 warn!(
1296 "double-spend detected in block {} : {} in block.generate()",
1297 self.id, input
1298 );
1299 return Err(Error::new(ErrorKind::InvalidData, "double-spend detected"));
1300 }
1301 }
1302 self.created_hashmap_of_slips_spent_this_block = true;
1303 }
1304
1305 match transaction.transaction_type {
1307 TransactionType::Issuance => {
1308 has_issuance_transaction = true;
1309 issuance_transaction_index = i as u64;
1310 }
1311 TransactionType::Fee => {
1312 has_fee_transaction = true;
1313 fee_transaction_index = i as u64;
1314 }
1315 TransactionType::GoldenTicket => {
1316 has_golden_ticket = true;
1317 golden_ticket_index = i as u64;
1318 }
1319 TransactionType::ATR => {
1320 let mut vbytes: Vec<u8> = vec![];
1321 vbytes.extend(&self.rebroadcast_hash);
1322 vbytes.extend(&transaction.serialize_for_signature());
1323 self.rebroadcast_hash = hash(&vbytes);
1324
1325 for slip in transaction.to.iter() {
1326 if matches!(slip.slip_type, SlipType::ATR) {
1327 self.total_rebroadcast_slips += 1;
1328 }
1331 }
1332 }
1333 TransactionType::BlockStake => {
1334 self.has_staking_transaction = true;
1335 }
1336 _ => {}
1337 };
1338 }
1339 self.has_fee_transaction = has_fee_transaction;
1340 self.has_golden_ticket = has_golden_ticket;
1341 self.has_issuance_transaction = has_issuance_transaction;
1342 self.fee_transaction_index = fee_transaction_index;
1343 self.golden_ticket_index = golden_ticket_index;
1344 self.issuance_transaction_index = issuance_transaction_index;
1345 self.total_work = total_work;
1346
1347 Ok(())
1348 }
1349
1350 pub fn generate_hash(&mut self) -> SaitoHash {
1351 let hash_for_hash = hash(&self.serialize_for_hash());
1352 self.hash = hash_for_hash;
1353 hash_for_hash
1354 }
1355
1356 pub fn generate_merkle_root(&self, is_browser: bool, is_spv: bool) -> SaitoHash {
1357 if self.transactions.is_empty() && (is_browser || is_spv) {
1358 return self.merkle_root;
1359 }
1360
1361 let merkle_root_hash: SaitoHash;
1362 if let Some(tree) = MerkleTree::generate(&self.transactions) {
1363 merkle_root_hash = tree.get_root_hash();
1364 } else {
1365 merkle_root_hash = [0; 32];
1366 }
1367
1368 debug!(
1369 "generated the merkle root, Tx Count: {:?}, root = {:?}",
1370 self.transactions.len(),
1371 merkle_root_hash.to_hex()
1372 );
1373
1374 merkle_root_hash
1375 }
1376
1377 pub async fn generate_consensus_values(
1383 &self,
1384 blockchain: &Blockchain,
1385 storage: &Storage,
1386 configs: &(dyn Configuration + Send + Sync),
1387 ) -> ConsensusValues {
1388 let mut cv = ConsensusValues::new();
1392 let mut previous_block_treasury: Currency = 0;
1393 let mut previous_block_avg_nolan_rebroadcast_per_block: Currency = 0;
1394 let mut previous_block_avg_fee_per_byte: Currency = 0;
1395 let mut previous_block_avg_total_fees: Currency = 0;
1396 let mut previous_block_avg_total_fees_new: Currency = 0;
1397 let mut previous_block_avg_total_fees_atr: Currency = 0;
1398 let mut previous_block_avg_payout_routing: Currency = 0;
1399 let mut previous_block_avg_payout_mining: Currency = 0;
1400 let previous_block_avg_payout_treasury: Currency = 0;
1401 let previous_block_avg_payout_graveyard: Currency = 0;
1402 let previous_block_avg_payout_atr: Currency = 0;
1403 let mut total_number_of_non_fee_transactions = 0;
1404
1405 for (index, transaction) in self.transactions.iter().enumerate() {
1409 if transaction.is_fee_transaction() {
1420 cv.ft_num += 1;
1421 cv.ft_index = Some(index);
1422 } else {
1423 total_number_of_non_fee_transactions += 1;
1431 }
1432
1433 if (transaction.is_golden_ticket() || transaction.is_normal_transaction())
1434 && !transaction.is_atr_transaction()
1435 {
1436 cv.total_bytes_new += transaction.get_serialized_size() as u64;
1437 cv.total_fees_new += transaction.total_fees;
1438 }
1439
1440 if transaction.is_golden_ticket() {
1441 cv.gt_num += 1;
1442 cv.gt_index = Some(index);
1443 }
1444
1445 if transaction.is_staking_transaction() {
1446 cv.st_num += 1;
1447 cv.st_index = Some(index);
1448 }
1449
1450 if transaction.is_issuance_transaction() {
1451 cv.it_num += 1;
1452 cv.it_index = Some(index);
1453 }
1454 }
1455
1456 if let Some(previous_block) = blockchain.blocks.get(&self.previous_block_hash) {
1460 previous_block_treasury = previous_block.treasury;
1464 previous_block_avg_nolan_rebroadcast_per_block =
1465 previous_block.avg_nolan_rebroadcast_per_block;
1466 previous_block_avg_fee_per_byte = previous_block.avg_fee_per_byte;
1467 previous_block_avg_total_fees = previous_block.avg_total_fees;
1468 previous_block_avg_total_fees_new = previous_block.avg_total_fees_new;
1469 previous_block_avg_total_fees_atr = previous_block.avg_total_fees_atr;
1470 previous_block_avg_payout_routing = previous_block.avg_payout_routing;
1471 previous_block_avg_payout_mining = previous_block.avg_payout_mining;
1472
1473 cv.burnfee = BurnFee::calculate_burnfee_for_block(
1477 previous_block.burnfee,
1478 self.timestamp,
1479 previous_block.timestamp,
1480 configs.get_consensus_config().unwrap().heartbeat_interval,
1481 );
1482
1483 if cv.burnfee == 0 {
1484 cv.burnfee = 1;
1485 }
1486
1487 cv.difficulty = previous_block.difficulty;
1491 if previous_block.has_golden_ticket {
1492 if cv.gt_num > 0 {
1493 cv.difficulty += 1;
1494 }
1495 } else if cv.gt_num == 0 && cv.difficulty > 0 {
1496 cv.difficulty -= 1;
1497 }
1498 } else {
1499 cv.burnfee = self.burnfee;
1500 cv.difficulty = self.difficulty;
1501 }
1502
1503 cv.total_fees_cumulative = cv.total_fees_new;
1510
1511 if self.id > (configs.get_consensus_config().unwrap().genesis_period + 1) {
1520 if let Some(pruned_block_hash) = blockchain
1521 .blockring
1522 .get_longest_chain_block_hash_at_block_id(
1523 self.id - (configs.get_consensus_config().unwrap().genesis_period + 1),
1524 )
1525 {
1526 if let Some(pruned_block) = blockchain.blocks.get(&pruned_block_hash) {
1527 if let Ok(mut atr_block) = storage
1528 .load_block_from_disk(
1529 storage.generate_block_filepath(pruned_block).as_str(),
1530 )
1531 .await
1532 {
1533 atr_block.generate().unwrap();
1534 assert_ne!(
1535 atr_block.block_type,
1536 BlockType::Pruned,
1537 "block should be fetched fully before this"
1538 );
1539
1540 let total_utxo_staked =
1544 configs.get_consensus_config().unwrap().genesis_period
1545 * previous_block_avg_nolan_rebroadcast_per_block;
1546
1547 let expected_atr_payout = if total_utxo_staked > 0 {
1551 previous_block_treasury / total_utxo_staked
1552 } else {
1553 0
1554 };
1555
1556 let expected_atr_multiplier = 1 + expected_atr_payout;
1560
1561 for transaction in &atr_block.transactions {
1565 let mut outputs = vec![];
1566 let mut total_nolan_eligible_for_atr_payout: Currency = 0;
1567
1568 let mut i = 0;
1579
1580 while i < transaction.to.len() {
1581 let slip = &transaction.to[i];
1582
1583 if slip.slip_type == SlipType::Bound && i + 2 < transaction.to.len()
1587 {
1588 let slip1 = &transaction.to[i];
1589 let slip2 = &transaction.to[i + 1];
1590 let slip3 = &transaction.to[i + 2];
1591
1592 if slip2.slip_type != SlipType::Bound
1593 && slip3.slip_type == SlipType::Bound
1594 {
1595 if slip1.validate(&blockchain.utxoset)
1599 && slip2.validate(&blockchain.utxoset)
1600 && slip3.validate(&blockchain.utxoset)
1601 {
1602 trace!(
1603 "NFT group eligible: {}, {}, {}",
1604 slip1,
1605 slip2,
1606 slip3
1607 );
1608 outputs.push(slip1);
1609 outputs.push(slip2);
1610 outputs.push(slip3);
1611
1612 total_nolan_eligible_for_atr_payout += slip2.amount;
1616 }
1617
1618 i += 3;
1622 continue;
1623 }
1624 }
1625
1626 if slip.validate(&blockchain.utxoset) {
1630 trace!("Regular slip eligible: {}", slip);
1631 outputs.push(slip);
1632 total_nolan_eligible_for_atr_payout += slip.amount;
1633 }
1634
1635 i += 1;
1639 }
1640
1641 if !outputs.is_empty() {
1652 let tx_size = transaction.get_serialized_size() as u64;
1653 let atr_fee = tx_size * previous_block_avg_fee_per_byte;
1654
1655 let mut j = 0;
1656 while j < outputs.len() {
1657 let output = outputs[j];
1658
1659 let is_nft_triple = output.slip_type == SlipType::Bound
1664 && j + 2 < outputs.len()
1665 && outputs[j + 1].slip_type != SlipType::Bound
1666 && outputs[j + 2].slip_type == SlipType::Bound;
1667
1668 if is_nft_triple {
1669 let slip1 = outputs[j];
1673 let slip2 = outputs[j + 1];
1674 let slip3 = outputs[j + 2];
1675
1676 let atr_payout_for_slip =
1680 slip2.amount * expected_atr_multiplier;
1681 let surplus_payout_to_subtract_from_treasury =
1682 atr_payout_for_slip - slip2.amount;
1683 let atr_fee_for_slip = atr_fee;
1684
1685 if atr_payout_for_slip > atr_fee {
1686 cv.total_rebroadcast_nolan += slip2.amount;
1687 cv.total_rebroadcast_slips += 1;
1688
1689 let mut input1 = slip1.clone();
1693 let mut input2 = slip2.clone();
1694 let mut input3 = slip3.clone();
1695
1696 input2.amount = atr_payout_for_slip;
1700
1701 let mut output1 = slip1.clone();
1705 let mut output2 = slip2.clone();
1706 let mut output3 = slip3.clone();
1707
1708 output2.slip_type = SlipType::ATR;
1709 output2.amount = atr_payout_for_slip - atr_fee;
1710
1711 let rebroadcast_tx =
1715 Transaction::create_rebroadcast_bound_transaction(
1716 transaction,
1717 output1,
1718 input2.clone(),
1719 output3,
1720 );
1721
1722 cv.total_payout_atr +=
1723 surplus_payout_to_subtract_from_treasury;
1724 cv.total_fees_atr += atr_fee;
1725
1726 let mut vbytes = Vec::new();
1730 vbytes.extend(&cv.rebroadcast_hash);
1731 vbytes
1732 .extend(&rebroadcast_tx.serialize_for_signature());
1733 cv.rebroadcast_hash = hash(&vbytes);
1734
1735 cv.rebroadcasts.push(rebroadcast_tx);
1736 } else {
1737 cv.total_rebroadcast_nolan += slip2.amount;
1741 cv.total_fees_atr += slip2.amount;
1742 cv.total_fees_paid_by_nonrebroadcast_atr_transactions +=
1743 slip2.amount;
1744 trace!("we don't rebroadcast slip in tx - {:?} since atr_payout_for_slip = {:?} atr_fee = {:?} \n{}",transaction.hash_for_signature.unwrap().to_hex(),atr_payout_for_slip,atr_fee,output);
1745 }
1746
1747 j += 3;
1751 } else {
1752 let atr_payout_for_slip =
1756 output.amount * expected_atr_multiplier;
1757 let surplus_payout_to_subtract_from_treasury =
1758 atr_payout_for_slip - output.amount;
1759 let atr_fee_for_slip = atr_fee;
1760
1761 if atr_payout_for_slip > atr_fee {
1762 cv.total_rebroadcast_nolan += output.amount;
1763 cv.total_rebroadcast_slips += 1;
1764
1765 let mut slip = output.clone();
1769 slip.slip_type = SlipType::ATR;
1770 slip.amount = atr_payout_for_slip - atr_fee_for_slip;
1771
1772 let mut from_slip = output.clone();
1779 from_slip.amount = atr_payout_for_slip;
1780
1781 cv.total_payout_atr +=
1785 surplus_payout_to_subtract_from_treasury;
1786 cv.total_fees_atr += atr_fee_for_slip;
1787
1788 let rebroadcast_tx =
1792 Transaction::create_rebroadcast_transaction(
1793 transaction,
1794 slip,
1795 from_slip,
1796 );
1797
1798 let mut vbytes: Vec<u8> = vec![];
1802 vbytes.extend(&cv.rebroadcast_hash);
1803 vbytes
1804 .extend(&rebroadcast_tx.serialize_for_signature());
1805 cv.rebroadcast_hash = hash(&vbytes);
1806 cv.rebroadcasts.push(rebroadcast_tx);
1807 } else {
1808 cv.total_rebroadcast_nolan += output.amount;
1819 cv.total_fees_atr += output.amount;
1820 cv.total_fees_paid_by_nonrebroadcast_atr_transactions +=
1821 output.amount;
1822 trace!("we don't rebroadcast slip in tx - {:?} since atr_payout_for_slip = {:?} atr_fee = {:?} \n{}",transaction.hash_for_signature.unwrap().to_hex(),atr_payout_for_slip,atr_fee,output);
1823 }
1824
1825 j += 1;
1829 }
1830 }
1831 }
1832 }
1833
1834 cv.total_fees_cumulative = cv.total_fees_new + cv.total_fees_atr
1841 - cv.total_fees_paid_by_nonrebroadcast_atr_transactions;
1842
1843 if cv.total_payout_atr > (self.treasury as f64 * 0.05) as u64 {
1857 let max_total_payout = (self.treasury as f64 * 0.05) as u64;
1858 let unadjusted_total_nolan = cv.total_rebroadcast_nolan;
1859 let adjusted_atr_payout_multiplier =
1860 max_total_payout / unadjusted_total_nolan;
1861 let adjusted_output_multiplier = 1 + adjusted_atr_payout_multiplier;
1862 let _adjusted_total_rebroadcast_staking_payouts_nolan: Currency = 0;
1863 let _adjusted_total_rebroadcast_fees_nolan: Currency = 0;
1864
1865 cv.total_payout_atr = 0;
1873
1874 for rebroadcast_tx in &mut cv.rebroadcasts {
1875 if rebroadcast_tx.to.len() == 3
1888 && rebroadcast_tx.from.len() == 3
1889 && rebroadcast_tx.from[0].slip_type == SlipType::Bound
1890 && rebroadcast_tx.from[1].slip_type != SlipType::Bound
1891 && rebroadcast_tx.from[2].slip_type == SlipType::Bound
1892 {
1893 let input_amount = rebroadcast_tx.from[1].amount;
1894
1895 let new_output_amount =
1899 input_amount * adjusted_output_multiplier;
1900
1901 rebroadcast_tx.to[1].amount = new_output_amount;
1905
1906 cv.total_payout_atr += rebroadcast_tx.to[1].amount;
1907 cv.total_payout_atr -= input_amount;
1908 } else {
1909 let input_amount = rebroadcast_tx.from[0].amount;
1913 let new_output_amount =
1914 input_amount * adjusted_output_multiplier;
1915 rebroadcast_tx.to[0].amount = new_output_amount;
1916
1917 cv.total_payout_atr += rebroadcast_tx.to[0].amount;
1918 cv.total_payout_atr -= input_amount;
1919 }
1920 }
1921
1922 cv.total_fees_atr = 0;
1923 }
1924 } else {
1925 error!(
1926 "couldn't load block for ATR from disk. block hash : {:?}",
1927 pruned_block.hash.to_hex()
1928 );
1929 }
1930 } }
1932 } cv.total_fees = cv.total_fees_new + cv.total_fees_atr;
1938
1939 if cv.total_bytes_new > 0 {
1943 cv.fee_per_byte = cv.total_fees_new / cv.total_bytes_new as Currency;
1944 }
1945
1946 let adjustment = (previous_block_avg_fee_per_byte as i128 - cv.fee_per_byte as i128)
1950 / configs.get_consensus_config().unwrap().genesis_period as i128;
1951 cv.avg_fee_per_byte = (previous_block_avg_fee_per_byte as i128 - adjustment) as Currency;
1952
1953 let adjustment = (previous_block_avg_total_fees as i128 - cv.total_fees as i128)
1957 / configs.get_consensus_config().unwrap().genesis_period as i128;
1958 cv.avg_total_fees = (previous_block_avg_total_fees as i128 - adjustment) as Currency;
1959
1960 let adjustment = (previous_block_avg_total_fees_new as i128 - cv.total_fees_new as i128)
1964 / configs.get_consensus_config().unwrap().genesis_period as i128;
1965 cv.avg_total_fees_new =
1966 (previous_block_avg_total_fees_new as i128 - adjustment) as Currency;
1967
1968 let adjustment = (previous_block_avg_total_fees_atr as i128 - cv.total_fees_atr as i128)
1972 / configs.get_consensus_config().unwrap().genesis_period as i128;
1973 cv.avg_total_fees_atr =
1974 (previous_block_avg_total_fees_atr as i128 - adjustment) as Currency;
1975
1976 let adjustment = (previous_block_avg_nolan_rebroadcast_per_block as i128
1984 - cv.total_rebroadcast_nolan as i128)
1985 / configs.get_consensus_config().unwrap().genesis_period as i128;
1986 cv.avg_nolan_rebroadcast_per_block =
1987 (previous_block_avg_nolan_rebroadcast_per_block as i128 - adjustment) as Currency;
1988
1989 let mut miner_publickey: SaitoPublicKey = [0; 33];
1993 let mut miner_payout: Currency = 0;
1994 let mut router1_payout: Currency = 0;
1995 let mut router1_publickey: SaitoPublicKey = [0; 33];
1996 let mut router2_payout: Currency = 0;
1997 let mut router2_publickey: SaitoPublicKey = [0; 33];
1998 let mut treasury_contribution: Currency = 0;
1999 let mut graveyard_contribution: Currency = 0;
2000
2001 if let Some(gt_index) = cv.gt_index {
2005 let golden_ticket: GoldenTicket =
2009 GoldenTicket::deserialize_from_net(&self.transactions[gt_index].data);
2010 let mut next_random_number = hash(golden_ticket.random.as_ref());
2011
2012 if let Some(previous_block) = blockchain.blocks.get(&self.previous_block_hash) {
2016 debug!(
2017 "previous block : {:?}-{:?} exists!",
2018 previous_block.id,
2019 previous_block.hash.to_hex()
2020 );
2021
2022 let expected_miner_payout = previous_block.total_fees / 2;
2026 let maximum_miner_payout = (previous_block.avg_total_fees as f64 * 1.5) as u64;
2027 if expected_miner_payout > maximum_miner_payout {
2028 graveyard_contribution += expected_miner_payout - maximum_miner_payout;
2029 miner_payout = maximum_miner_payout;
2030 debug!(
2031 "block : {} miner payout set as maximum payout : {}. expected payout : {}",
2032 self.id, miner_payout, expected_miner_payout
2033 );
2034 } else {
2035 miner_payout = expected_miner_payout;
2036 debug!(
2037 "block : {} miner payout set as expected payout : {}. maximum payout : {}",
2038 self.id, miner_payout, maximum_miner_payout
2039 );
2040 }
2041 miner_publickey = golden_ticket.public_key;
2042
2043 let expected_router_payout = previous_block.total_fees - expected_miner_payout;
2047 let maximum_router_payout = (previous_block.avg_total_fees as f64 * 1.5) as u64;
2048 if expected_router_payout > maximum_router_payout {
2049 graveyard_contribution += expected_router_payout - maximum_router_payout;
2050 router1_payout = maximum_router_payout;
2051 debug!(
2052 "block : {} router1 payout set as maximum payout : {}. expected payout : {}",
2053 self.id, router1_payout, expected_router_payout
2054 );
2055 } else {
2056 router1_payout = expected_router_payout;
2057 debug!(
2058 "block : {} router1 payout set as expected payout : {}. maximum payout : {}",
2059 self.id, router1_payout, maximum_router_payout
2060 );
2061 }
2062 router1_publickey = previous_block.find_winning_router(next_random_number);
2063
2064 next_random_number = hash(next_random_number.as_ref());
2068 next_random_number = hash(next_random_number.as_ref());
2069
2070 if previous_block.has_golden_ticket {
2076 } else {
2080 if let Some(previous_previous_block) =
2084 blockchain.blocks.get(&previous_block.previous_block_hash)
2085 {
2086 let expected_treasury_contribution2 =
2095 previous_previous_block.total_fees / 2;
2096 let maximum_treasury_contribution2 =
2097 (previous_block.avg_total_fees as f64 * 1.5) as u64;
2098 if expected_treasury_contribution2 > maximum_treasury_contribution2 {
2099 treasury_contribution += maximum_treasury_contribution2;
2100 graveyard_contribution +=
2101 expected_treasury_contribution2 - maximum_treasury_contribution2;
2102 } else {
2103 treasury_contribution += expected_treasury_contribution2;
2104 }
2105
2106 let expected_router2_payout =
2110 previous_previous_block.total_fees - expected_treasury_contribution2;
2111 let maximum_router2_payout =
2113 (previous_block.avg_total_fees as f64 * 1.5) as u64;
2114 if expected_router2_payout > maximum_router2_payout {
2115 graveyard_contribution +=
2116 expected_router2_payout - maximum_router2_payout;
2117 router2_payout = maximum_router2_payout;
2118 } else {
2119 router2_payout = expected_router2_payout;
2120 }
2121 router2_publickey =
2122 previous_previous_block.find_winning_router(next_random_number);
2123
2124 next_random_number = hash(next_random_number.as_slice());
2128 next_random_number = hash(next_random_number.as_slice());
2129 }
2130 }
2131 } else {
2132 info!(
2133 "previous block : {:?} not found for block : {:?} at index : {:?}",
2134 self.previous_block_hash.to_hex(),
2135 self.hash.to_hex(),
2136 self.id
2137 );
2138 }
2139
2140 let mut slip_index = 0;
2144 let mut transaction = Transaction::default();
2145 transaction.transaction_type = TransactionType::Fee;
2146 transaction.timestamp = self.timestamp;
2147
2148 if miner_publickey != [0; 33] && miner_payout > 0 {
2149 let mut output = Slip::default();
2150 output.public_key = miner_publickey;
2151 output.amount = miner_payout;
2152 output.slip_type = SlipType::MinerOutput;
2153 output.slip_index = slip_index;
2154 output.tx_ordinal = total_number_of_non_fee_transactions + 1;
2155 output.block_id = self.id;
2156 transaction.add_to_slip(output.clone());
2157 slip_index += 1;
2158 } else {
2159 debug!(
2160 "miner_publickey is not set or payout is zero. Not adding to fee transaction"
2161 );
2162 }
2163
2164 if router1_payout > 0 {
2165 if router1_publickey != [0; 33] {
2166 let mut output = Slip::default();
2167 output.public_key = router1_publickey;
2168 output.amount = router1_payout;
2169 output.slip_type = SlipType::RouterOutput;
2170 output.slip_index = slip_index;
2171 output.tx_ordinal = total_number_of_non_fee_transactions + 1;
2172 output.block_id = self.id;
2173 transaction.add_to_slip(output.clone());
2174 slip_index += 1;
2175 } else {
2176 graveyard_contribution += router1_payout;
2177 }
2178 } else {
2179 debug!(
2180 "router1_publickey is not set or payout is zero. Not adding to fee transaction"
2181 );
2182 }
2183
2184 if router2_payout > 0 {
2185 if router2_publickey != [0; 33] {
2186 let mut output = Slip::default();
2187 output.public_key = router2_publickey;
2188 output.amount = router2_payout;
2189 output.slip_type = SlipType::RouterOutput;
2190 output.slip_index = slip_index;
2191 output.tx_ordinal = total_number_of_non_fee_transactions + 1;
2192 output.block_id = self.id;
2193 transaction.add_to_slip(output.clone());
2194 slip_index += 1;
2195 } else {
2196 graveyard_contribution += router2_payout;
2197 }
2198 } else {
2199 debug!(
2200 "router2_publickey is not set or payout is zero. Not adding to fee transaction"
2201 );
2202 }
2203
2204 cv.total_payout_mining = miner_payout;
2205 cv.total_payout_routing = router1_payout + router2_payout;
2206 cv.fee_transaction = Some(transaction);
2207 } else {
2208 if let Some(previous_block) = blockchain.blocks.get(&self.previous_block_hash) {
2213 if previous_block.has_golden_ticket {
2214 } else {
2216 if let Some(previous_previous_block) =
2219 blockchain.blocks.get(&previous_block.previous_block_hash)
2220 {
2221 graveyard_contribution += previous_block.previous_block_unpaid;
2222 }
2223 }
2224 }
2225 }
2226
2227 cv.total_payout_treasury = treasury_contribution;
2231 cv.total_payout_graveyard = graveyard_contribution;
2232
2233 let adjustment = (previous_block_avg_payout_routing as i128
2237 - cv.total_payout_routing as i128)
2238 / configs.get_consensus_config().unwrap().genesis_period as i128;
2239 cv.avg_payout_routing =
2240 (previous_block_avg_payout_routing as i128 - adjustment) as Currency;
2241
2242 let adjustment = (previous_block_avg_payout_mining as i128
2246 - cv.total_payout_mining as i128)
2247 / configs.get_consensus_config().unwrap().genesis_period as i128;
2248 cv.avg_payout_mining = (previous_block_avg_payout_mining as i128 - adjustment) as Currency;
2249
2250 let adjustment = (previous_block_avg_payout_treasury as i128
2254 - cv.total_payout_treasury as i128)
2255 / configs.get_consensus_config().unwrap().genesis_period as i128;
2256 cv.avg_payout_treasury =
2257 (previous_block_avg_payout_treasury as i128 - adjustment) as Currency;
2258
2259 let adjustment = (previous_block_avg_payout_graveyard as i128
2263 - cv.total_payout_graveyard as i128)
2264 / configs.get_consensus_config().unwrap().genesis_period as i128;
2265 cv.avg_payout_graveyard =
2266 (previous_block_avg_payout_graveyard as i128 - adjustment) as Currency;
2267
2268 let adjustment = (previous_block_avg_payout_atr as i128 - cv.total_payout_atr as i128)
2272 / configs.get_consensus_config().unwrap().genesis_period as i128;
2273 cv.avg_payout_atr = (previous_block_avg_payout_atr as i128 - adjustment) as Currency;
2274
2275 cv
2276 }
2277
2278 pub fn generate_pre_hash(&mut self) {
2279 self.pre_hash = hash(&self.serialize_for_signature());
2280 }
2281
2282 pub fn on_chain_reorganization(&mut self, utxoset: &mut UtxoSet, longest_chain: bool) -> bool {
2283 debug!(
2284 "block : on chain reorg : {:?} - {:?}",
2285 self.id,
2286 self.hash.to_hex()
2287 );
2288 for tx in &self.transactions {
2289 tx.on_chain_reorganization(utxoset, longest_chain);
2290 }
2291 self.in_longest_chain = longest_chain;
2292 true
2293 }
2294
2295 pub fn sign(&mut self, private_key: &SaitoPrivateKey) {
2299 self.signature = sign(&self.serialize_for_signature(), private_key);
2301 }
2302
2303 pub fn serialize_for_hash(&self) -> Vec<u8> {
2306 [
2307 self.previous_block_hash.as_slice(),
2308 self.pre_hash.as_slice(),
2309 ]
2310 .concat()
2311 }
2312
2313 pub fn serialize_for_signature(&self) -> Vec<u8> {
2318 [
2319 self.id.to_be_bytes().as_slice(),
2320 self.timestamp.to_be_bytes().as_slice(),
2321 self.previous_block_hash.as_slice(),
2322 self.creator.as_slice(),
2323 self.merkle_root.as_slice(),
2324 self.graveyard.to_be_bytes().as_slice(),
2325 self.treasury.to_be_bytes().as_slice(),
2326 self.burnfee.to_be_bytes().as_slice(),
2327 self.difficulty.to_be_bytes().as_slice(),
2328 self.avg_fee_per_byte.to_be_bytes().as_slice(),
2329 self.avg_nolan_rebroadcast_per_block
2330 .to_be_bytes()
2331 .as_slice(),
2332 self.previous_block_unpaid.to_be_bytes().as_slice(),
2333 self.avg_total_fees.to_be_bytes().as_slice(),
2334 self.avg_total_fees_new.to_be_bytes().as_slice(),
2335 self.avg_total_fees_atr.to_be_bytes().as_slice(),
2336 self.avg_payout_routing.to_be_bytes().as_slice(),
2337 self.avg_payout_mining.to_be_bytes().as_slice(),
2338 ]
2339 .concat()
2340 }
2341
2342 pub fn serialize_for_net(&self, block_type: BlockType) -> Vec<u8> {
2374 let mut tx_len_buffer: Vec<u8> = vec![];
2375
2376 if block_type == BlockType::Header {
2378 tx_len_buffer.extend(&0_u32.to_be_bytes());
2379 } else {
2380 tx_len_buffer.extend(&(self.transactions.iter().len() as u32).to_be_bytes());
2381 }
2382 let mut tx_buf = vec![];
2383 if block_type != BlockType::Header {
2384 tx_buf = iterate!(self.transactions, 10)
2386 .map(|transaction| transaction.serialize_for_net())
2387 .collect::<Vec<_>>()
2388 .concat();
2389 }
2390
2391 let buffer = [
2392 tx_len_buffer.as_slice(),
2393 self.id.to_be_bytes().as_slice(),
2394 self.timestamp.to_be_bytes().as_slice(),
2395 self.previous_block_hash.as_slice(),
2396 self.creator.as_slice(),
2397 self.merkle_root.as_slice(),
2398 self.signature.as_slice(),
2399 self.graveyard.to_be_bytes().as_slice(),
2400 self.treasury.to_be_bytes().as_slice(),
2401 self.burnfee.to_be_bytes().as_slice(),
2402 self.difficulty.to_be_bytes().as_slice(),
2403 self.avg_total_fees.to_be_bytes().as_slice(),
2404 self.avg_fee_per_byte.to_be_bytes().as_slice(),
2405 self.avg_nolan_rebroadcast_per_block
2406 .to_be_bytes()
2407 .as_slice(),
2408 self.previous_block_unpaid.to_be_bytes().as_slice(),
2409 self.avg_total_fees.to_be_bytes().as_slice(),
2410 self.avg_total_fees_new.to_be_bytes().as_slice(),
2411 self.avg_total_fees_atr.to_be_bytes().as_slice(),
2412 self.avg_payout_routing.to_be_bytes().as_slice(),
2413 self.avg_payout_mining.to_be_bytes().as_slice(),
2414 self.avg_payout_treasury.to_be_bytes().as_slice(),
2415 self.avg_payout_graveyard.to_be_bytes().as_slice(),
2416 self.avg_payout_atr.to_be_bytes().as_slice(),
2417 self.total_payout_routing.to_be_bytes().as_slice(),
2418 self.total_payout_mining.to_be_bytes().as_slice(),
2419 self.total_payout_treasury.to_be_bytes().as_slice(),
2420 self.total_payout_graveyard.to_be_bytes().as_slice(),
2421 self.total_payout_atr.to_be_bytes().as_slice(),
2422 self.total_fees.to_be_bytes().as_slice(),
2423 self.total_fees_new.to_be_bytes().as_slice(),
2424 self.total_fees_atr.to_be_bytes().as_slice(),
2425 self.fee_per_byte.to_be_bytes().as_slice(),
2426 self.total_fees_cumulative.to_be_bytes().as_slice(),
2427 tx_buf.as_slice(),
2428 ]
2429 .concat();
2430
2431 buffer
2432 }
2433
2434 pub async fn update_block_to_block_type(
2435 &mut self,
2436 block_type: BlockType,
2437 storage: &Storage,
2438 is_browser: bool,
2439 ) -> bool {
2440 if self.block_type == block_type {
2441 return true;
2442 }
2443
2444 if block_type == BlockType::Full {
2445 return self
2446 .upgrade_block_to_block_type(block_type, storage, is_browser)
2447 .await;
2448 }
2449
2450 if block_type == BlockType::Pruned {
2451 return self
2452 .downgrade_block_to_block_type(block_type, is_browser)
2453 .await;
2454 }
2455
2456 false
2457 }
2458
2459 pub async fn upgrade_block_to_block_type(
2463 &mut self,
2464 block_type: BlockType,
2465 storage: &Storage,
2466 is_spv: bool,
2467 ) -> bool {
2468 debug!(
2469 "upgrading block : {:?}-{:?} of type : {:?} to type : {:?}",
2470 self.id,
2471 self.hash.to_hex(),
2472 self.block_type,
2473 block_type
2474 );
2475 if self.block_type == block_type {
2476 trace!("block type is already {:?}", self.block_type);
2477 return true;
2478 }
2479
2480 if block_type == BlockType::Full {
2490 if is_spv {
2491 debug!("cannot upgrade block to full in spv mode");
2492 return false;
2493 }
2494 let new_block = storage
2495 .load_block_from_disk(storage.generate_block_filepath(self).as_str())
2496 .await;
2497 if new_block.is_err() {
2498 error!(
2499 "block not found in disk to upgrade : {:?}",
2500 self.hash.to_hex()
2501 );
2502 return false;
2503 }
2504 let mut new_block = new_block.unwrap();
2505
2506 debug!(
2507 "upgraded tx counts : {:?} vs {:?}",
2508 self.transactions.len(),
2509 new_block.transactions.len()
2510 );
2511 mem::swap(&mut new_block.transactions, &mut self.transactions);
2513
2514 if self.generate().is_err() {
2516 error!("failed to generate block after upgrade");
2517 return false;
2518 }
2519 self.block_type = BlockType::Full;
2520
2521 return true;
2522 }
2523
2524 false
2525 }
2526
2527 pub fn generate_lite_block(&self, keylist: Vec<SaitoPublicKey>) -> Block {
2528 debug!(
2529 "generating lite block for keys : {:?} for block : {:?}-{:?}",
2530 keylist.iter().map(hex::encode).collect::<Vec<String>>(),
2531 self.id,
2532 self.hash.to_hex()
2533 );
2534
2535 let mut pruned_txs: Vec<Transaction> = iterate!(&self.transactions, 10)
2536 .map(|tx| {
2537 if tx
2538 .from
2539 .iter()
2540 .any(|slip| keylist.contains(&slip.public_key))
2541 || tx.to.iter().any(|slip| keylist.contains(&slip.public_key))
2542 || tx.is_golden_ticket()
2543 {
2544 tx.clone()
2545 } else {
2546 Transaction {
2547 timestamp: tx.timestamp,
2548 from: vec![],
2549 to: vec![],
2550 data: vec![],
2551 transaction_type: TransactionType::SPV,
2552 txs_replacements: 1,
2553 signature: tx.signature,
2554 path: vec![],
2555 hash_for_signature: tx.hash_for_signature,
2556 total_in: 0,
2557 total_out: 0,
2558 total_fees: 0,
2559 total_work_for_me: 0,
2560 cumulative_fees: 0,
2561 }
2562 }
2563 })
2564 .collect();
2565
2566 let mut i = 0;
2567 while i + 1 < pruned_txs.len() {
2568 if pruned_txs[i].transaction_type == TransactionType::SPV
2569 && pruned_txs[i + 1].transaction_type == TransactionType::SPV
2570 && pruned_txs[i].txs_replacements == pruned_txs[i + 1].txs_replacements
2571 {
2572 pruned_txs[i].txs_replacements *= 2;
2573 let combined_hash = hash(
2574 &[
2575 pruned_txs[i].hash_for_signature.unwrap(),
2576 pruned_txs[i + 1].hash_for_signature.unwrap(),
2577 ]
2578 .concat(),
2579 );
2580 pruned_txs[i].hash_for_signature = Some(combined_hash);
2581 pruned_txs.remove(i + 1);
2582 } else {
2583 i += 2;
2584 }
2585 }
2586
2587 let mut block = Block::new();
2589
2590 block.transactions = pruned_txs;
2591 block.id = self.id;
2592 block.timestamp = self.timestamp;
2593 block.previous_block_hash = self.previous_block_hash;
2594 block.creator = self.creator;
2595 block.burnfee = self.burnfee;
2596 block.difficulty = self.difficulty;
2597 block.graveyard = self.graveyard;
2598 block.treasury = self.treasury;
2599 block.signature = self.signature;
2600 block.avg_fee_per_byte = self.avg_fee_per_byte;
2601 block.avg_nolan_rebroadcast_per_block = self.avg_nolan_rebroadcast_per_block;
2602 block.previous_block_unpaid = self.previous_block_unpaid;
2603 block.avg_total_fees = self.avg_total_fees;
2604 block.avg_total_fees_new = self.avg_total_fees_new;
2605 block.avg_total_fees_atr = self.avg_total_fees_atr;
2606 block.avg_payout_routing = self.avg_payout_routing;
2607 block.avg_payout_mining = self.avg_payout_mining;
2608 block.avg_payout_treasury = self.avg_payout_treasury;
2609 block.avg_payout_graveyard = self.avg_payout_graveyard;
2610 block.avg_payout_atr = self.avg_payout_atr;
2611 block.total_payout_routing = self.total_payout_routing;
2612 block.total_payout_mining = self.total_payout_mining;
2613 block.total_payout_treasury = self.total_payout_treasury;
2614 block.total_payout_graveyard = self.total_payout_graveyard;
2615 block.total_payout_atr = self.total_payout_atr;
2616 block.total_fees = self.total_fees;
2617 block.total_fees_new = self.total_fees_new;
2618 block.total_fees_atr = self.total_fees_atr;
2619 block.fee_per_byte = self.fee_per_byte;
2620 block.hash = self.hash;
2621 block.total_fees_cumulative = self.total_fees_cumulative;
2622
2623 block.merkle_root = self.generate_merkle_root(true, true);
2624
2625 block
2626 }
2627
2628 pub async fn validate(
2629 &self,
2630 blockchain: &Blockchain,
2631 utxoset: &UtxoSet,
2632 configs: &(dyn Configuration + Send + Sync),
2633 storage: &Storage,
2634 validate_against_utxo: bool,
2635 ) -> bool {
2636 assert!(self.id > 0);
2640 if configs.is_spv_mode() {
2641 self.generate_consensus_values(blockchain, storage, configs)
2642 .await;
2643 return true;
2644 }
2645
2646 if let BlockType::Ghost = self.block_type {
2653 return true;
2654 }
2655
2656 if self.transactions.is_empty() && self.id != 1 && !blockchain.blocks.is_empty() {
2660 error!("ERROR 424342: block does not validate as it has no transactions",);
2661 return false;
2662 }
2663
2664 if !verify_signature(&self.pre_hash, &self.signature, &self.creator) {
2668 error!("ERROR 582039: block is not signed by creator or signature does not validate",);
2669 return false;
2670 }
2671
2672 info!("validate block : {:?}-{:?}", self.id, self.hash.to_hex());
2673
2674 let cv = self
2678 .generate_consensus_values(blockchain, storage, configs)
2679 .await;
2680 trace!("consensus values generated : {}", cv);
2681
2682 if validate_against_utxo {
2683 if cv.total_fees != self.total_fees {
2687 error!(
2688 "total_fees actual: {:?} expected : {:?}",
2689 self.total_fees, cv.total_fees
2690 );
2691 return false;
2692 }
2693
2694 if cv.total_fees_new != self.total_fees_new {
2698 error!(
2699 "total_fees_new actual: {:?} expected : {:?}",
2700 self.total_fees_new, cv.total_fees_new
2701 );
2702 return false;
2703 }
2704
2705 if cv.total_fees_atr != self.total_fees_atr {
2709 error!(
2710 "total_fees_atr actual: {:?} expected : {:?}",
2711 self.total_fees_atr, cv.total_fees_atr
2712 );
2713 return false;
2714 }
2715
2716 if cv.total_fees_cumulative != self.total_fees_cumulative {
2720 error!(
2721 "total_fees_cumulative actual: {:?} expected : {:?}",
2722 self.total_fees_cumulative, cv.total_fees_cumulative
2723 );
2724 return false;
2725 }
2726
2727 if cv.avg_total_fees != self.avg_total_fees {
2731 error!(
2732 "avg_total_fees actual: {:?} expected : {:?}",
2733 self.avg_total_fees, cv.avg_total_fees
2734 );
2735 return false;
2736 }
2737
2738 if cv.avg_total_fees_new != self.avg_total_fees_new {
2742 error!(
2743 "avg_total_fees_new actual: {:?} expected : {:?}",
2744 self.avg_total_fees_new, cv.avg_total_fees_new
2745 );
2746 return false;
2747 }
2748
2749 if cv.avg_total_fees_atr != self.avg_total_fees_atr {
2753 error!(
2754 "avg_total_fees_atr error: {:?} expected : {:?}",
2755 self.avg_total_fees_atr, cv.avg_total_fees_atr
2756 );
2757 return false;
2758 }
2759
2760 if cv.total_payout_routing != self.total_payout_routing {
2764 error!(
2765 "total_payout_routing error: {:?} expected : {:?}",
2766 self.total_payout_routing, cv.total_payout_routing
2767 );
2768 return false;
2769 }
2770
2771 if cv.total_payout_mining != self.total_payout_mining {
2775 error!(
2776 "total_payout_mining actual: {:?} expected : {:?}",
2777 self.total_payout_mining, cv.total_payout_mining
2778 );
2779 return false;
2780 }
2781
2782 if cv.total_payout_treasury != self.total_payout_treasury {
2786 error!(
2787 "total_payout_treasury actual: {:?} expected : {:?}",
2788 self.total_payout_treasury, cv.total_payout_treasury
2789 );
2790 return false;
2791 }
2792
2793 if cv.total_payout_graveyard != self.total_payout_graveyard {
2797 error!(
2798 "total_payout_graveyard actual: {:?} expected : {:?}",
2799 self.total_payout_graveyard, cv.total_payout_graveyard
2800 );
2801 return false;
2802 }
2803
2804 if cv.total_payout_atr != self.total_payout_atr {
2808 error!(
2809 "total_payout_atr actual: {:?} expected : {:?}",
2810 self.total_payout_atr, cv.total_payout_atr
2811 );
2812 return false;
2813 }
2814
2815 if cv.avg_payout_routing != self.avg_payout_routing {
2819 error!(
2820 "avg_payout_routing actual: {:?} expected : {:?}",
2821 self.avg_payout_routing, cv.avg_payout_routing
2822 );
2823 return false;
2824 }
2825
2826 if cv.avg_payout_mining != self.avg_payout_mining {
2830 error!(
2831 "avg_payout_mining actual: {:?} expected : {:?}",
2832 self.avg_payout_mining, cv.avg_payout_mining
2833 );
2834 return false;
2835 }
2836
2837 if cv.avg_payout_treasury != self.avg_payout_treasury {
2841 error!(
2842 "avg_payout_treasury actual: {:?} expected : {:?}",
2843 self.avg_payout_treasury, cv.avg_payout_treasury
2844 );
2845 return false;
2846 }
2847
2848 if cv.avg_payout_graveyard != self.avg_payout_graveyard {
2852 error!(
2853 "avg_payout_graveyard actual: {:?} expected : {:?}",
2854 self.avg_payout_graveyard, cv.avg_payout_graveyard
2855 );
2856 return false;
2857 }
2858
2859 if cv.avg_payout_atr != self.avg_payout_atr {
2863 error!(
2864 "avg_payout_atr actual: {:?} expected : {:?}",
2865 self.avg_payout_atr, cv.avg_payout_atr
2866 );
2867 return false;
2868 }
2869
2870 if cv.avg_fee_per_byte != self.avg_fee_per_byte {
2874 error!(
2875 "ERROR 202392: avg_fee_per_byte is invalid. expected: {:?} vs actual : {:?}",
2876 cv.avg_fee_per_byte, self.avg_fee_per_byte
2877 );
2878 return false;
2879 }
2880
2881 if cv.fee_per_byte != self.fee_per_byte {
2885 error!(
2886 "ERROR 202392: fee_per_byte is invalid. expected: {:?} vs actual : {:?}",
2887 cv.fee_per_byte, self.fee_per_byte
2888 );
2889 return false;
2890 }
2891
2892 if cv.avg_nolan_rebroadcast_per_block != self.avg_nolan_rebroadcast_per_block {
2896 error!(
2897 "ERROR 202392: avg_nolan_rebroadcast_per_block is invalid. expected: {:?} vs actual : {:?}",
2898 cv.avg_nolan_rebroadcast_per_block, self.avg_nolan_rebroadcast_per_block
2899 );
2900 return false;
2901 }
2902 }
2903
2904 if cv.burnfee != self.burnfee {
2908 error!(
2909 "block is misreporting its burnfee. current : {:?} expected : {:?}",
2910 self.burnfee, cv.burnfee
2911 );
2912 return false;
2913 }
2914
2915 if cv.difficulty != self.difficulty {
2919 error!(
2920 "ERROR 202392: difficulty is invalid. expected: {:?} vs actual : {:?}",
2921 cv.difficulty, self.difficulty
2922 );
2923 return false;
2924 }
2925
2926 if cv.it_num > 0 && self.id > 1 {
2930 error!("ERROR: blockchain contains issuance after block 1 in chain",);
2931 return false;
2932 }
2933
2934 if blockchain.social_stake_requirement != 0 && cv.st_num != 1 && self.id > 1 {
2938 error!(
2939 "block : {:?} does not have a staking transaction",
2940 self.hash.to_hex()
2941 );
2942 return false;
2943 }
2944
2945 if let Some(previous_block) = blockchain.blocks.get(&self.previous_block_hash) {
2949 if let BlockType::Ghost = previous_block.block_type {
2953 return true;
2954 }
2955
2956 let mut expected_treasury = previous_block.treasury;
2960 expected_treasury += cv.total_payout_treasury;
2961 expected_treasury -= cv.total_payout_atr;
2962 if validate_against_utxo && self.treasury != expected_treasury {
2963 error!(
2964 "ERROR 820391: treasury does not validate: {} expected versus {} found",
2965 expected_treasury, self.treasury,
2966 );
2967 return false;
2968 }
2969
2970 let mut expected_graveyard = previous_block.graveyard;
2974 expected_graveyard += cv.total_payout_graveyard;
2975 if validate_against_utxo && self.graveyard != expected_graveyard {
2976 error!(
2977 "ERROR 123243: graveyard does not validate: {} expected versus {} found",
2978 expected_graveyard, self.graveyard,
2979 );
2980 return false;
2981 }
2982
2983 let amount_of_routing_work_needed: Currency =
2987 BurnFee::return_routing_work_needed_to_produce_block_in_nolan(
2988 previous_block.burnfee,
2989 self.timestamp,
2990 previous_block.timestamp,
2991 configs.get_consensus_config().unwrap().heartbeat_interval,
2992 );
2993 if self.total_work < amount_of_routing_work_needed {
2994 error!("Error 510293: block lacking adequate routing work from creator. actual : {:?} expected : {:?}",self.total_work, amount_of_routing_work_needed);
2995 return false;
2996 }
2997
2998 if let Some(gt_index) = cv.gt_index {
3013 let golden_ticket: GoldenTicket =
3014 GoldenTicket::deserialize_from_net(&self.transactions[gt_index].data);
3015
3016 let gt = GoldenTicket::create(
3023 previous_block.hash,
3024 golden_ticket.random,
3025 golden_ticket.public_key,
3026 );
3027
3028 if self.previous_block_unpaid != 0 {
3033 error!("ERROR 720351: golden ticket but previous block incorrect");
3034 return false;
3035 }
3036
3037 trace!("validating gt...");
3042 if !gt.validate(previous_block.difficulty) {
3043 error!(
3044 "ERROR 801923: Golden Ticket solution does not validate against previous_block_hash : {:?}, difficulty : {:?}, random : {:?}, public_key : {:?} target : {:?}",
3045 previous_block.hash.to_hex(),
3046 previous_block.difficulty,
3047 gt.random.to_hex(),
3048 gt.public_key.to_base58(),
3049 gt.target.to_hex()
3050 );
3051 let solution = hash(>.serialize_for_net());
3052 let solution_num = primitive_types::U256::from_big_endian(&solution);
3053
3054 error!(
3055 "solution : {:?} leading zeros : {:?}",
3056 solution.to_hex(),
3057 solution_num.leading_zeros()
3058 );
3059 return false;
3060 }
3061 trace!("gt validated !");
3062 } else {
3063 if self.previous_block_unpaid != previous_block.total_fees {
3070 error!("ERROR 572983: previous_block_unpaid value incorrect");
3071 return false;
3072 }
3073 }
3074 }
3076
3077 if validate_against_utxo && cv.total_rebroadcast_slips != self.total_rebroadcast_slips {
3091 error!(
3092 "ERROR 624442: rebroadcast slips total incorrect. expected : {:?} actual : {:?}",
3093 cv.total_rebroadcast_slips, self.total_rebroadcast_slips
3094 );
3095 return false;
3096 }
3097 if validate_against_utxo && cv.rebroadcast_hash != self.rebroadcast_hash {
3106 error!("ERROR 123422: hash of rebroadcast transactions incorrect. expected : {:?} actual : {:?}",cv.rebroadcast_hash.to_hex(), self.rebroadcast_hash.to_hex());
3107 return false;
3108 }
3109
3110 if self.merkle_root == [0; 32]
3114 && self.merkle_root
3115 != self.generate_merkle_root(configs.is_browser(), configs.is_spv_mode())
3116 {
3117 error!("merkle root is unset or is invalid false 1");
3118 return false;
3119 }
3120
3121 if cv.ft_num > 0 {
3130 if let (Some(ft_index), Some(fee_transaction_expected)) =
3131 (cv.ft_index, cv.fee_transaction)
3132 {
3133 if cv.gt_index.is_none() {
3134 error!("ERROR 48203: block has fee transaction but no golden ticket");
3135 return false;
3136 }
3137
3138 let fee_transaction_in_block = self.transactions.get(ft_index).unwrap();
3142 let hash1 = hash(&fee_transaction_expected.serialize_for_signature());
3143 let hash2 = hash(&fee_transaction_in_block.serialize_for_signature());
3144
3145 if validate_against_utxo && hash1 != hash2 {
3146 error!(
3147 "ERROR 892032: block {} fee transaction doesn't match cv-expected fee transaction",
3148 self.id
3149 );
3150 error!(
3151 "expected = {:?}",
3152 &fee_transaction_expected.serialize_for_signature()
3153 );
3154 error!(
3155 "actual = {:?}",
3156 &fee_transaction_in_block.serialize_for_signature()
3157 );
3158 if let Some(gt_index) = cv.gt_index {
3159 let golden_ticket: GoldenTicket =
3160 GoldenTicket::deserialize_from_net(&self.transactions[gt_index].data);
3161 error!("gt.publickey = {:?}", golden_ticket.public_key.to_hex());
3162 }
3163
3164 return false;
3165 }
3166 }
3167 }
3168
3169 trace!(
3190 "validating transactions ... count : {:?}",
3191 self.transactions.len()
3192 );
3193 let mut new_slips_map = std::collections::HashMap::new();
3194 let transactions_valid = self.transactions.iter().all(|tx: &Transaction| -> bool {
3195 let valid_tx = tx.validate(utxoset, blockchain, validate_against_utxo);
3196 if valid_tx && tx.transaction_type != TransactionType::Fee {
3198 for input in tx.from.iter() {
3199 if input.amount == 0 || input.slip_type == SlipType::Bound {
3200 continue;
3201 }
3202 let utxo_key = input.get_utxoset_key();
3203
3204 if new_slips_map.contains_key(&utxo_key) {
3205 error!(
3206 "double-spend detected in block {} : {} in block.validate()",
3207 self.id,
3208 Slip::parse_slip_from_utxokey(&utxo_key).unwrap()
3209 );
3210 return false;
3211 }
3212
3213 new_slips_map.insert(utxo_key, 1);
3214 }
3215 }
3216 true
3217 });
3218
3219 if !transactions_valid {
3220 error!("ERROR 579128: Invalid transactions found, block validation failed");
3221 }
3222 trace!("transactions validation complete");
3223
3224 transactions_valid
3225 }
3226
3227 pub fn generate_transaction_hashmap(&mut self) {
3228 if !self.transaction_map.is_empty() {
3229 return;
3230 }
3231 for tx in self.transactions.iter() {
3232 for slip in tx.from.iter() {
3233 self.transaction_map.insert(slip.public_key, true);
3234 }
3235 for slip in tx.to.iter() {
3236 self.transaction_map.insert(slip.public_key, true);
3237 }
3238 }
3239 }
3240 pub fn has_keylist_txs(&self, keylist: &Vec<SaitoPublicKey>) -> bool {
3241 for key in keylist {
3242 if self.transaction_map.contains_key(key) {
3243 return true;
3244 }
3245 }
3246 false
3247 }
3248
3249 pub fn get_file_name(&self) -> String {
3250 let timestamp = self.timestamp;
3251 let block_hash = self.hash;
3252
3253 timestamp.to_string() + "-" + block_hash.to_hex().as_str() + BLOCK_FILE_EXTENSION
3254 }
3255 pub fn print_all(&self) {
3256 info!(
3257 "Block {{ id: {}, timestamp: {}, previous_block_hash: {:?}, creator: {:?}, merkle_root: {:?}, signature: {:?}, graveyard: {}, treasury: {}, total_fees: {}, total_fees_new: {}, total_fees_atr: {}, avg_total_fees: {}, avg_total_fees_new: {}, avg_total_fees_atr: {}, total_payout_routing: {}, total_payout_mining: {}, total_payout_treasury: {}, total_payout_graveyard: {}, total_payout_atr: {}, avg_payout_routing: {}, avg_payout_mining: {}, avg_payout_treasury: {}, avg_payout_graveyard: {}, avg_payout_atr: {}, avg_fee_per_byte: {}, fee_per_byte: {}, avg_nolan_rebroadcast_per_block: {}, burnfee: {}, difficulty: {}, previous_block_unpaid: {}, hash: {:?}, total_work: {}, in_longest_chain: {}, has_golden_ticket: {}, has_issuance_transaction: {}, issuance_transaction_index: {}, has_fee_transaction: {}, has_staking_transaction: {}, golden_ticket_index: {}, fee_transaction_index: {}, total_rebroadcast_slips: {}, total_rebroadcast_nolan: {}, rebroadcast_hash: {}, block_type: {:?}, cv: {}, routed_from_peer: {:?} ",
3258 self.id,
3259 self.timestamp,
3260 self.previous_block_hash.to_hex(),
3261 self.creator.to_base58(),
3262 self.merkle_root.to_hex(),
3263 self.signature.to_hex(),
3264 self.graveyard,
3265 self.treasury,
3266 self.total_fees,
3267 self.total_fees_new,
3268 self.total_fees_atr,
3269 self.avg_total_fees,
3270 self.avg_total_fees_new,
3271 self.avg_total_fees_atr,
3272 self.total_payout_routing,
3273 self.total_payout_mining,
3274 self.total_payout_treasury,
3275 self.total_payout_graveyard,
3276 self.total_payout_atr,
3277 self.avg_payout_routing,
3278 self.avg_payout_mining,
3279 self.avg_payout_treasury,
3280 self.avg_payout_graveyard,
3281 self.avg_payout_atr,
3282 self.avg_fee_per_byte,
3283 self.fee_per_byte,
3284 self.avg_nolan_rebroadcast_per_block,
3285 self.burnfee,
3286 self.difficulty,
3287 self.previous_block_unpaid,
3288 self.hash.to_hex(),
3289 self.total_work,
3290 self.in_longest_chain,
3291 self.has_golden_ticket,
3292 self.has_issuance_transaction,
3293 self.issuance_transaction_index,
3294 self.has_fee_transaction,
3295 self.has_staking_transaction,
3296 self.golden_ticket_index,
3297 self.fee_transaction_index,
3298 self.total_rebroadcast_slips,
3299 self.total_rebroadcast_nolan,
3300 self.rebroadcast_hash.to_hex(),
3301 self.block_type,
3302 self.cv,
3303 self.routed_from_peer,
3304 );
3305 info!(" transactions : ");
3306 for (index, tx) in self.transactions.iter().enumerate() {
3307 info!("tx {} : {}", index, tx);
3308 }
3309 }
3310}
3311
3312#[cfg(test)]
3313mod tests {
3314 use ahash::AHashMap;
3315 use futures::future::join_all;
3316 use log::info;
3317
3318 use crate::core::consensus::block::{Block, BlockType};
3319
3320 use crate::core::consensus::merkle::MerkleTree;
3321 use crate::core::consensus::slip::{Slip, SlipType};
3322 use crate::core::consensus::transaction::{Transaction, TransactionType};
3323 use crate::core::consensus::wallet::Wallet;
3324 use crate::core::defs::{
3325 Currency, PrintForLog, SaitoHash, SaitoPrivateKey, SaitoPublicKey, NOLAN_PER_SAITO,
3326 };
3327 use crate::core::io::storage::Storage;
3328 use crate::core::util::crypto::{generate_keys, verify_signature};
3329 use crate::core::util::test::node_tester::test::NodeTester;
3330 use crate::core::util::test::test_manager::test::TestManager;
3331
3332 #[test]
3333 fn block_new_test() {
3334 let block = Block::new();
3335 assert_eq!(block.id, 0);
3336 assert_eq!(block.timestamp, 0);
3337 assert_eq!(block.previous_block_hash, [0; 32]);
3338 assert_eq!(block.creator, [0; 33]);
3339 assert_eq!(block.merkle_root, [0; 32]);
3340 assert_eq!(block.signature, [0; 64]);
3341 assert_eq!(block.graveyard, 0);
3342 assert_eq!(block.burnfee, 0);
3343 assert_eq!(block.difficulty, 0);
3344 assert_eq!(block.transactions, vec![]);
3345 assert_eq!(block.pre_hash, [0; 32]);
3346 assert_eq!(block.hash, [0; 32]);
3347 assert_eq!(block.total_fees, 0);
3348 assert_eq!(block.total_work, 0);
3349 assert_eq!(block.in_longest_chain, false);
3350 assert_eq!(block.has_golden_ticket, false);
3351 assert_eq!(block.has_issuance_transaction, false);
3352 assert_eq!(block.issuance_transaction_index, 0);
3353 assert_eq!(block.has_fee_transaction, false);
3354 assert_eq!(block.fee_transaction_index, 0);
3355 assert_eq!(block.golden_ticket_index, 0);
3356 assert_eq!(block.total_rebroadcast_slips, 0);
3357 assert_eq!(block.total_rebroadcast_nolan, 0);
3358 assert_eq!(block.rebroadcast_hash, [0; 32]);
3359 assert_eq!(block.block_type, BlockType::Full);
3360 assert_eq!(block.slips_spent_this_block, AHashMap::new());
3361 assert_eq!(block.created_hashmap_of_slips_spent_this_block, false);
3362 assert_eq!(block.routed_from_peer, None);
3363 }
3364
3365 #[test]
3366 fn block_generate_test() {
3367 let mut block = Block::new();
3368 block.generate().unwrap();
3369
3370 assert_ne!(block.pre_hash, [0; 32]);
3372 assert_ne!(block.hash, [0; 32]);
3373 assert_ne!(block.pre_hash, [0; 32]);
3374 assert_ne!(block.hash, [0; 32]);
3375 assert_eq!(block.pre_hash, block.pre_hash);
3376 assert_eq!(block.hash, block.hash);
3377 }
3378
3379 #[test]
3380 fn block_signature_test() {
3381 let mut block = Block::new();
3382
3383 block.id = 10;
3384 block.timestamp = 1637034582;
3385 block.previous_block_hash = <SaitoHash>::from_hex(
3386 "bcf6cceb74717f98c3f7239459bb36fdcd8f350eedbfccfbebf7c0b0161fcd8b",
3387 )
3388 .unwrap();
3389 block.merkle_root = <SaitoHash>::from_hex(
3390 "ccf6cceb74717f98c3f7239459bb36fdcd8f350eedbfccfbebf7c0b0161fcd8b",
3391 )
3392 .unwrap();
3393 block.creator = <SaitoPublicKey>::from_hex(
3394 "dcf6cceb74717f98c3f7239459bb36fdcd8f350eedbfccfbebf7c0b0161fcd8bcc",
3395 )
3396 .unwrap();
3397 block.burnfee = 50000000;
3398 block.difficulty = 0;
3399 block.graveyard = 0;
3400 block.treasury = 0;
3401 block.signature = <[u8; 64]>::from_hex("c9a6c2d0bf884be6933878577171a3c8094c2bf6e0bc1b4ec3535a4a55224d186d4d891e254736cae6c0d2002c8dfc0ddfc7fcdbe4bc583f96fa5b273b9d63f4").unwrap();
3402
3403 let serialized_body = block.serialize_for_signature();
3404 assert_eq!(serialized_body.len(), 209);
3405
3406 block.creator = <SaitoPublicKey>::from_hex(
3407 "dcf6cceb74717f98c3f7239459bb36fdcd8f350eedbfccfbebf7c0b0161fcd8bcc",
3408 )
3409 .unwrap();
3410
3411 block.sign(
3412 &<SaitoHash>::from_hex(
3413 "854702489d49c7fb2334005b903580c7a48fe81121ff16ee6d1a528ad32f235d",
3414 )
3415 .unwrap(),
3416 );
3417
3418 assert_eq!(block.signature.len(), 64);
3419 }
3420
3421 #[test]
3422 fn block_serialization_and_deserialization_test() {
3423 let mock_input = Slip::default();
3425 let mock_output = Slip::default();
3426
3427 let mut mock_tx = Transaction::default();
3428 mock_tx.timestamp = 0;
3429 mock_tx.add_from_slip(mock_input.clone());
3430 mock_tx.add_to_slip(mock_output.clone());
3431 mock_tx.data = vec![104, 101, 108, 111];
3432 mock_tx.transaction_type = TransactionType::Normal;
3433 mock_tx.signature = [1; 64];
3434
3435 let mut mock_tx2 = Transaction::default();
3436 mock_tx2.timestamp = 0;
3437 mock_tx2.add_from_slip(mock_input);
3438 mock_tx2.add_to_slip(mock_output);
3439 mock_tx2.data = vec![];
3440 mock_tx2.transaction_type = TransactionType::Normal;
3441 mock_tx2.signature = [2; 64];
3442
3443 let timestamp = 0;
3444
3445 let mut block = Block::new();
3446 block.id = 1;
3447 block.timestamp = timestamp;
3448 block.previous_block_hash = [1; 32];
3449 block.creator = [2; 33];
3450 block.merkle_root = [0; 32];
3451 block.signature = [4; 64];
3452 block.graveyard = 1_000_000;
3453 block.burnfee = 2;
3454 block.difficulty = 3;
3455 block.transactions = vec![mock_tx, mock_tx2];
3456 block.generate().unwrap();
3457
3458 let serialized_block = block.serialize_for_net(BlockType::Full);
3459 let deserialized_block = Block::deserialize_from_net(&serialized_block).unwrap();
3460
3461 let serialized_block_header = block.serialize_for_net(BlockType::Header);
3462 let deserialized_block_header =
3463 Block::deserialize_from_net(&serialized_block_header).unwrap();
3464
3465 assert_eq!(
3466 block.serialize_for_net(BlockType::Full),
3467 deserialized_block.serialize_for_net(BlockType::Full)
3468 );
3469
3470 assert_eq!(deserialized_block.id, 1);
3471 assert_eq!(deserialized_block.timestamp, timestamp);
3472 assert_eq!(deserialized_block.previous_block_hash, [1; 32]);
3473 assert_eq!(deserialized_block.creator, [2; 33]);
3474 assert_ne!(deserialized_block.merkle_root, [0; 32]);
3475 assert_eq!(deserialized_block.signature, [4; 64]);
3476 assert_eq!(deserialized_block.graveyard, 1_000_000);
3477 assert_eq!(deserialized_block.burnfee, 2);
3478 assert_eq!(deserialized_block.difficulty, 3);
3479
3480 assert_eq!(
3481 deserialized_block_header.serialize_for_net(BlockType::Full),
3482 deserialized_block.serialize_for_net(BlockType::Header)
3483 );
3484
3485 assert_eq!(deserialized_block_header.id, 1);
3486 assert_eq!(deserialized_block_header.timestamp, timestamp);
3487 assert_eq!(deserialized_block_header.previous_block_hash, [1; 32]);
3488 assert_eq!(deserialized_block_header.creator, [2; 33]);
3489 assert_ne!(deserialized_block_header.merkle_root, [0; 32]);
3490 assert_eq!(deserialized_block_header.signature, [4; 64]);
3491 assert_eq!(deserialized_block_header.graveyard, 1_000_000);
3492 assert_eq!(deserialized_block_header.burnfee, 2);
3493 assert_eq!(deserialized_block_header.difficulty, 3);
3494
3495 let mut lite_block = block.generate_lite_block(vec![]);
3496 lite_block.generate().unwrap();
3497 assert_eq!(block.id, lite_block.id);
3498 assert_eq!(block.timestamp, lite_block.timestamp);
3499 assert_eq!(
3500 block.previous_block_hash.to_hex(),
3501 lite_block.previous_block_hash.to_hex()
3502 );
3503 assert_eq!(block.creator, lite_block.creator);
3504 assert_eq!(block.graveyard, lite_block.graveyard);
3505 assert_eq!(block.treasury, lite_block.treasury);
3506 assert_eq!(block.burnfee, lite_block.burnfee);
3507 assert_eq!(block.difficulty, lite_block.difficulty);
3508 assert_eq!(block.avg_total_fees, lite_block.avg_total_fees);
3509 assert_eq!(block.avg_fee_per_byte, lite_block.avg_fee_per_byte);
3510 assert_eq!(
3511 block.avg_nolan_rebroadcast_per_block,
3512 lite_block.avg_nolan_rebroadcast_per_block
3513 );
3514 assert_eq!(
3515 block.previous_block_unpaid,
3516 lite_block.previous_block_unpaid
3517 );
3518 assert_eq!(block.merkle_root.to_hex(), lite_block.merkle_root.to_hex());
3519
3520 assert_eq!(block.pre_hash.to_hex(), lite_block.pre_hash.to_hex());
3521 assert_eq!(block.hash.to_hex(), lite_block.hash.to_hex());
3522 }
3523
3524 #[test]
3525 fn block_sign_and_verify_test() {
3526 let keys = generate_keys();
3527
3528 let wallet = Wallet::new(keys.1, keys.0);
3529 let mut block = Block::new();
3530 block.creator = wallet.public_key;
3531 block.generate().unwrap();
3532 block.sign(&wallet.private_key);
3533 block.generate_hash();
3534
3535 assert_eq!(block.creator, wallet.public_key);
3536 assert!(verify_signature(
3537 &block.pre_hash,
3538 &block.signature,
3539 &block.creator,
3540 ));
3541 assert_ne!(block.hash, [0; 32]);
3542 assert_ne!(block.signature, [0; 64]);
3543 }
3544
3545 #[test]
3546 fn block_merkle_root_test() {
3547 let mut block = Block::new();
3548 let keys = generate_keys();
3549 let wallet = Wallet::new(keys.1, keys.0);
3550
3551 let transactions: Vec<Transaction> = (0..5)
3552 .map(|_| {
3553 let mut transaction = Transaction::default();
3554 transaction.sign(&wallet.private_key);
3555 transaction
3556 })
3557 .collect();
3558
3559 block.transactions = transactions;
3560 block.merkle_root = block.generate_merkle_root(false, false);
3561
3562 assert_eq!(block.merkle_root.len(), 32);
3563 assert_ne!(block.merkle_root, [0; 32]);
3564 }
3565
3566 #[tokio::test]
3567 #[serial_test::serial]
3568 async fn block_downgrade_upgrade_test() {
3570 let mut t = TestManager::default();
3571 let wallet_lock = t.wallet_lock.clone();
3572 let mut block = Block::new();
3573 let transactions = join_all((0..5).map(|_| async {
3574 let mut transaction = Transaction::default();
3575 let wallet = wallet_lock.read().await;
3576
3577 transaction.sign(&wallet.private_key);
3578 transaction
3579 }))
3580 .await
3581 .to_vec();
3582
3583 block.transactions = transactions;
3584 block.generate().unwrap();
3585
3586 t.storage.write_block_to_disk(&mut block).await;
3588
3589 assert_eq!(block.transactions.len(), 5);
3590 assert_eq!(block.block_type, BlockType::Full);
3591
3592 let serialized_full_block = block.serialize_for_net(BlockType::Full);
3593 block
3594 .update_block_to_block_type(BlockType::Pruned, &t.storage, false)
3595 .await;
3596
3597 assert_eq!(block.transactions.len(), 0);
3598 assert_eq!(block.block_type, BlockType::Pruned);
3599
3600 block
3601 .update_block_to_block_type(BlockType::Full, &t.storage, false)
3602 .await;
3603
3604 assert_eq!(block.transactions.len(), 5);
3605 assert_eq!(block.block_type, BlockType::Full);
3606 assert_eq!(
3607 serialized_full_block,
3608 block.serialize_for_net(BlockType::Full)
3609 );
3610 }
3611
3612 #[tokio::test]
3613 #[serial_test::serial]
3614 async fn generate_lite_block_test() {
3615 let mut t = TestManager::default();
3616
3617 t.initialize(100, 200_000_000_000_000).await;
3621 let block1 = t.get_latest_block().await;
3622 let public_key: SaitoPublicKey;
3623 {
3624 let wallet = t.wallet_lock.read().await;
3625 public_key = wallet.public_key;
3626 }
3627 let lite_block = block1.generate_lite_block(vec![public_key]);
3628 assert_eq!(lite_block.hash, block1.hash);
3629 assert_eq!(lite_block.signature, block1.signature);
3630
3631 let public_key =
3634 Storage::decode_str("s8oFPjBX97NC2vbm9E5Kd2oHWUShuSTUuZwSB1U4wsPR").unwrap();
3635 let mut to_public_key: SaitoPublicKey = [0u8; 33];
3636 to_public_key.copy_from_slice(&public_key);
3637 t.transfer_value_to_public_key(to_public_key, 500, block1.timestamp + 120000)
3638 .await
3639 .unwrap();
3640 let block2 = t.get_latest_block().await;
3641 let mut lite_block2 = block2.generate_lite_block(vec![to_public_key]);
3642 assert_eq!(lite_block2.signature, block2.clone().signature);
3643 assert_eq!(lite_block2.hash, block2.hash);
3644 assert_eq!(lite_block2.merkle_root, block2.merkle_root);
3645 assert_eq!(lite_block2.difficulty, block2.difficulty);
3646 assert_eq!(lite_block2.id, block2.id);
3647 assert_eq!(lite_block2.block_type, BlockType::Full);
3648
3649 lite_block2.generate().unwrap();
3650 assert_eq!(lite_block2.signature, block2.clone().signature);
3651 assert_eq!(lite_block2.hash, block2.hash);
3652
3653 let buffer = lite_block2.serialize_for_net(BlockType::Pruned);
3654 let mut block2 = Block::deserialize_from_net(&buffer).unwrap();
3655 block2.generate().unwrap();
3656 assert_eq!(lite_block2.signature, block2.clone().signature);
3657 assert_eq!(lite_block2.hash, block2.hash);
3658
3659 let block2_hash = block2.hash;
3662 let mut block3 = t
3663 .create_block(
3664 block2_hash, block2.timestamp + 120000, 0, 0, 0, true, )
3671 .await;
3672 block3.generate().unwrap(); dbg!(block3.id);
3674 }
3675
3676 #[tokio::test]
3677 #[serial_test::serial]
3678 async fn verify_spv_transaction_in_lite_block_test() {
3679 let mut t = TestManager::default();
3680
3681 t.initialize(100, 100000).await;
3683
3684 let mut block = t.get_latest_block().await;
3686
3687 let private_key: SaitoPrivateKey;
3689 let public_key: SaitoPublicKey;
3690 {
3691 let wallet = t.wallet_lock.read().await;
3692
3693 public_key = wallet.public_key;
3694 private_key = wallet.private_key;
3695 }
3696
3697 let _public_key = "27UK2MuBTdeARhYp97XBnCovGkEquJjkrQntCgYoqj6GC";
3699 let mut to_public_key: SaitoPublicKey = [0u8; 33];
3700
3701 for _ in 0..50 {
3703 let public_key_ = Storage::decode_str(_public_key).unwrap();
3704 to_public_key.copy_from_slice(&public_key_);
3705 let mut tx = Transaction::default();
3706 tx.transaction_type = TransactionType::Normal;
3707 let mut output = Slip::default();
3708 output.public_key = to_public_key;
3709 output.amount = 0;
3710 output.slip_type = SlipType::Normal;
3711 tx.add_to_slip(output);
3712 tx.generate(&public_key, 0, 0);
3713 tx.sign(&private_key);
3714 block.add_transaction(tx);
3716 }
3717
3718 {
3719 let configs = t.config_lock.read().await;
3720 block.merkle_root =
3721 block.generate_merkle_root(configs.is_browser(), configs.is_spv_mode());
3722 }
3723
3724 block.generate().unwrap();
3726 block.sign(&private_key);
3727
3728 let lite_block = block.generate_lite_block(vec![public_key]);
3730
3731 let _spv_tx = lite_block
3733 .transactions
3734 .iter()
3735 .find(|&tx| tx.transaction_type == TransactionType::SPV)
3736 .expect("No SPV transaction found")
3737 .clone();
3738
3739 let _merkle_tree = MerkleTree::generate(&lite_block.transactions)
3741 .expect("Failed to generate Merkle tree for block");
3742
3743 dbg!(
3744 lite_block.generate_merkle_root(false, false),
3745 block.generate_merkle_root(false, false)
3746 );
3747 }
3748
3749 #[tokio::test]
3750 #[ignore]
3751 #[serial_test::serial]
3752 async fn avg_fee_per_byte_test() {
3753 let mut t = TestManager::default();
3755
3756 t.initialize(250, 200_000_000_000_000).await;
3758
3759 let latest_block = t.get_latest_block().await;
3760
3761 let mut block = t
3762 .create_block(
3763 latest_block.hash,
3764 latest_block.timestamp + 40000,
3765 100,
3766 1000,
3767 1_000_000,
3768 true,
3769 )
3770 .await;
3771
3772 block.generate().unwrap();
3773
3774 let mut tx_size = 0;
3775 let mut total_fees = 0;
3776
3777 for tx in &block.transactions {
3778 if !tx.is_fee_transaction() {
3779 tx_size += tx.serialize_for_net().len();
3780 total_fees += tx.total_fees;
3781 }
3782 }
3783
3784 info!(
3785 "avg fee per byte 1: {:?} total fees = {:?} tx size = {:?} tx count = {:?}",
3786 block.avg_fee_per_byte,
3787 total_fees,
3788 tx_size,
3789 block.transactions.len()
3790 );
3791 assert_eq!(block.avg_fee_per_byte, total_fees / tx_size as Currency);
3792
3793 let mut block = t
3794 .create_block(
3795 latest_block.hash,
3796 latest_block.timestamp + 140000,
3797 100,
3798 1000,
3799 1_000_000,
3800 false,
3801 )
3802 .await;
3803
3804 block.generate().unwrap();
3805
3806 let mut tx_size = 0;
3807 let mut total_fees = 0;
3808
3809 for tx in &block.transactions {
3810 if !tx.is_fee_transaction() {
3811 tx_size += tx.serialize_for_net().len();
3812 total_fees += tx.total_fees;
3813 }
3814 }
3815 info!(
3816 "avg fee per byte 2: {:?} total fees = {:?} tx size = {:?} tx count = {:?}",
3817 block.avg_fee_per_byte,
3818 total_fees,
3819 tx_size,
3820 block.transactions.len()
3821 );
3822 assert_eq!(block.avg_fee_per_byte, total_fees / tx_size as Currency);
3823 }
3824
3825 #[ignore]
3826 #[tokio::test]
3827 #[serial_test::serial]
3828 async fn atr_test() {
3829 let mut t = TestManager::default();
3833
3834 t.initialize_with_timestamp(100, 10000, 0).await;
3835 let genesis_period = t
3836 .config_lock
3837 .read()
3838 .await
3839 .get_consensus_config()
3840 .unwrap()
3841 .genesis_period;
3842 assert_eq!(genesis_period, 100, "Genesis period is not 10");
3844
3845 for _i in 0..genesis_period {
3847 let mut block = t
3848 .create_block(
3849 t.latest_block_hash,
3850 t.get_latest_block().await.timestamp + 10_000,
3851 10,
3852 100,
3853 10,
3854 true,
3855 )
3856 .await;
3857 block.generate().unwrap();
3858 t.add_block(block).await;
3859 }
3860
3861 t.check_blockchain().await;
3863 t.check_utxoset().await;
3864 t.check_token_supply().await;
3865
3866 let latest_block = t.get_latest_block().await;
3867 let cv = latest_block.cv;
3868
3869 println!("cv : {:?} \n", cv);
3870
3871 assert_eq!(cv.rebroadcasts.len(), 0);
3872 assert_eq!(cv.avg_nolan_rebroadcast_per_block, 0);
3873
3874 let mut block = t
3876 .create_block(
3877 t.latest_block_hash,
3878 t.get_latest_block().await.timestamp + 10_000,
3879 10,
3880 100,
3881 10,
3882 true,
3883 )
3884 .await;
3885 block.generate().unwrap();
3886 t.add_block(block).await;
3887
3888 t.check_blockchain().await;
3890 t.check_utxoset().await;
3891 t.check_token_supply().await;
3892
3893 let latest_block = t.get_latest_block().await;
3894 let cv = latest_block.cv;
3895
3896 println!("cv2 : {:?}", cv);
3897
3898 assert_eq!(cv.rebroadcasts.len(), 1);
3903 assert_eq!(cv.avg_nolan_rebroadcast_per_block, 10);
3904 }
3905
3906 #[tokio::test]
3907 #[serial_test::serial]
3908 async fn atr_test_2() {
3909 pretty_env_logger::init();
3910 NodeTester::delete_data().await.unwrap();
3911 let mut tester = NodeTester::default();
3912
3913 let public_key = tester.get_public_key().await;
3914 tester
3915 .set_staking_requirement(2_000_000 * NOLAN_PER_SAITO, 60)
3916 .await;
3917 let issuance = vec![
3918 (public_key.to_base58(), 100 * 2_000_000 * NOLAN_PER_SAITO),
3919 (public_key.to_base58(), 100_000 * NOLAN_PER_SAITO),
3920 (
3921 "27UK2MuBTdeARhYp97XBnCovGkEquJjkrQntCgYoqj6GC".to_string(),
3922 50_000 * NOLAN_PER_SAITO,
3923 ),
3924 ];
3925 tester.set_issuance(issuance).await.unwrap();
3926
3927 tester.init().await.unwrap();
3928 let genesis_period = (tester
3930 .routing_thread
3931 .config_lock
3932 .read()
3933 .await
3934 .get_consensus_config()
3935 .unwrap()
3936 .genesis_period)
3937 + 1;
3938 tester.wait_till_block_id(1).await.unwrap();
3939
3940 for i in 1..genesis_period {
3941 let tx = tester.create_transaction(10, 0, public_key).await.unwrap();
3942 tester.add_transaction(tx).await;
3943 tester.wait_till_block_id(i + 1).await.unwrap();
3944 }
3945
3946 let wallet = tester.consensus_thread.wallet_lock.read().await;
3947 let have_atr_slips = wallet
3948 .slips
3949 .iter()
3950 .any(|(_, slip)| slip.slip_type == SlipType::ATR);
3951 assert!(!have_atr_slips);
3952 drop(wallet);
3953
3954 tester.wait_till_block_id(genesis_period).await.unwrap();
3955 {
3956 let wallet = tester.consensus_thread.wallet_lock.read().await;
3957 let atr_slip_count = wallet
3958 .slips
3959 .iter()
3960 .filter(|(_, slip)| matches!(slip.slip_type, SlipType::ATR))
3961 .count();
3962 assert_eq!(atr_slip_count, 0);
3963 }
3964
3965 {
3966 let tx = tester.create_transaction(10, 0, public_key).await.unwrap();
3967 tester.add_transaction(tx).await;
3968
3969 tester.wait_till_block_id(genesis_period + 1).await.unwrap();
3970
3971 let wallet = tester.consensus_thread.wallet_lock.read().await;
3972 let atr_slip_count = wallet
3973 .slips
3974 .iter()
3975 .filter(|(_, slip)| matches!(slip.slip_type, SlipType::ATR))
3976 .count();
3977 assert_eq!(atr_slip_count, 0);
3979 }
3980 {
3981 let blockchain = tester.consensus_thread.blockchain_lock.read().await;
3982 let block = blockchain.get_latest_block().unwrap();
3983 assert_eq!(blockchain.get_latest_block_id(), genesis_period + 1);
3984 assert_eq!(block.id, genesis_period + 1);
3985 let mut have_atr_tx = false;
3986 for tx in block.transactions.iter() {
3987 if tx.transaction_type == TransactionType::ATR {
3988 have_atr_tx = true;
3989 }
3990 }
3991 assert!(have_atr_tx);
3992 }
3993
3994 {
3995 let tx = tester.create_transaction(10, 0, public_key).await.unwrap();
3996 tester.add_transaction(tx).await;
3997
3998 tester.wait_till_block_id(genesis_period + 2).await.unwrap();
3999
4000 let wallet = tester.consensus_thread.wallet_lock.read().await;
4001 let atr_slip_count = wallet
4002 .slips
4003 .iter()
4004 .filter(|(_, slip)| matches!(slip.slip_type, SlipType::ATR))
4005 .count();
4006 assert_eq!(atr_slip_count, 1);
4007 }
4008 {
4009 let blockchain = tester.consensus_thread.blockchain_lock.read().await;
4010 let block = blockchain.get_latest_block().unwrap();
4011 assert_eq!(blockchain.get_latest_block_id(), genesis_period + 2);
4012 assert_eq!(block.id, genesis_period + 2);
4013 let mut have_atr_tx = false;
4014 for tx in block.transactions.iter() {
4015 if tx.transaction_type == TransactionType::ATR {
4016 have_atr_tx = true;
4017 }
4018 }
4019 assert!(have_atr_tx);
4020 }
4021 }
4022}