1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
pub use self::{attr::*, blockchain::*, utils::*};
pub(crate) mod attr;
pub(crate) mod blockchain;
pub(crate) mod utils {
use crate::{
blockchains::{BlockData, Blockchain, ChainWrapperExt},
blocks::{Block, BlockHeader, BlockHeaderSpec, CoreBlockSpec},
};
use scsys::prelude::{
rand::{self, Rng},
Hashable, H256,
};
pub trait OuroborosPraos {
fn insert_selfish_pos(&self, blockchain: &mut Blockchain, block: &Block) -> bool {
insert_selfish_pos(blockchain, block)
}
fn insert_unselfish_pos(&self, blockchain: &mut Blockchain, block: &Block) -> bool {
insert_unselfish_pos(blockchain, block)
}
fn insert(&self, blockchain: &mut Blockchain, block: &Block, selfish: bool) -> bool {
if !selfish {
self.insert_unselfish_pos(blockchain, block)
} else {
self.insert_selfish_pos(blockchain, block)
}
}
}
pub fn insert_selfish_pos(bc: &mut Blockchain, block: &Block) -> bool {
if bc.chain.contains_key(&block.hash()) {
false
} else {
let header: BlockHeader = block.header().clone();
let parenthash: H256 = header.parent();
let parentdata: BlockData = match bc.chain.get(&parenthash) {
Some(data) => data.clone(),
None => return false,
};
let parentheight = parentdata.height;
let newheight = parentheight + 1;
let newdata = BlockData::new(block.clone(), newheight);
let newhash = block.hash();
bc.chain.insert(newhash, newdata);
bc.position.pos += 1;
if newheight > bc.position.depth && block.selfish_block {
bc.lead += 1;
bc.position.depth = newheight;
bc.tip = newhash;
return true;
} else if !block.selfish_block && newheight > bc.length {
if bc.lead > 0 {
bc.lead -= 1;
bc.length += 1;
return false;
} else {
bc.position.depth = newheight;
bc.tip = newhash;
bc.length = newheight;
return true;
}
}
false
}
}
pub fn insert_unselfish_pos(bc: &mut Blockchain, block: &Block) -> bool {
if bc.chain.contains_key(&block.hash()) {
false
} else {
let pdata: BlockData = match bc.find_one_payload(&block.header.parent()) {
Some(v) => v,
None => return false,
};
let height = pdata.height + 1;
let data = BlockData::new(block.clone(), height);
let newhash = block.hash();
bc.chain.insert(newhash, data);
bc.position.pos += 1;
let mut rng = rand::thread_rng();
let p: f64 = rng.gen::<f64>(); if height > bc.position.depth
|| (height == bc.position.depth && block.selfish_block && p < 1.0)
{
bc.position.depth = height;
bc.tip = newhash;
return true;
}
false
}
}
pub fn insert_pos(bc: &mut Blockchain, block: &Block, selfish: bool) -> bool {
if !selfish {
insert_unselfish_pos(bc, block)
} else {
insert_selfish_pos(bc, block)
}
}
pub fn insert_pow(bc: &mut Blockchain, block: &Block) -> bool {
if bc.is_block(&block.hash()) {
return false;
}
let prev: BlockData = match bc.find_one_payload(&block.header().parent()) {
None => return false,
Some(v) => v,
};
let data = BlockData::new(block.clone(), prev.height + 1);
let hash = block.hash();
bc.chain.insert(hash, data);
bc.position.pow += 1;
true
}
}