Skip to content

Commit 7d86f9d

Browse files
committed
difficulty 추가
1 parent 8c3e989 commit 7d86f9d

3 files changed

Lines changed: 100 additions & 16 deletions

File tree

jaeseung-blockchain/src/block/block.rs

Lines changed: 91 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ use sha256::digest;
44

55
use rs_merkle::{algorithms::Sha256, Hasher, MerkleTree};
66

7+
use crate::constants::{
8+
BLOCK_GENERATION_INTERVAL_MINUTE, BLOCK_GENERATION_MILLIS, DIFFICULTY_ADJUSTMENT_INTERVAL_COUNT,
9+
};
10+
711
#[derive(Debug, PartialEq, Clone)] // TODO : Copy 와 Clone 의 차이점?
812
pub struct Block {
913
header: BlockHeader,
@@ -17,19 +21,82 @@ impl Block {
1721
let data = vec![Self::GENESIS_DATA.to_string()];
1822

1923
Ok(Block {
20-
header: BlockHeader::make(0, &["0"; 64].join(""), 0, &data)?,
24+
header: BlockHeader::make(
25+
0,
26+
Self::unsafe_get_timestamp(),
27+
&["0"; 64].join(""),
28+
0,
29+
0,
30+
&data,
31+
)?,
2132
data: data,
2233
})
2334
}
2435

25-
pub fn new(previous_block: &Block, nonce: i32, data: &Vec<String>) -> Result<Block, String> {
36+
pub fn new(
37+
previous_block: &Block,
38+
nonce: i32,
39+
data: &Vec<String>,
40+
adjustment_block: &Block,
41+
) -> Result<Block, String> {
2642
let p_header = &previous_block.header;
2743

44+
let new_height = p_header.height + 1;
45+
let new_timestamp = Self::unsafe_get_timestamp();
46+
47+
let difficulty =
48+
Self::get_difficulty(new_height, new_timestamp, previous_block, adjustment_block);
49+
2850
Ok(Block {
29-
header: BlockHeader::make(p_header.height + 1, &p_header.hash, nonce, data)?,
30-
data: data.clone(),
51+
header: BlockHeader::make(
52+
p_header.height + 1,
53+
new_timestamp,
54+
&p_header.hash,
55+
nonce,
56+
difficulty,
57+
data,
58+
)?,
59+
data: data.clone(), // TODO : clone 이 맞을까?
3160
})
3261
}
62+
63+
fn get_difficulty(
64+
new_height: i32,
65+
new_timestamp: u64,
66+
previous_block: &Block,
67+
adjustment_block: &Block,
68+
) -> i32 {
69+
match new_height {
70+
0..=9 => 0,
71+
10..=19 => 1,
72+
h if h % 10 != i32::from(DIFFICULTY_ADJUSTMENT_INTERVAL_COUNT) => {
73+
previous_block.header.difficulty
74+
}
75+
_ => {
76+
let time_taken = new_timestamp - adjustment_block.header.timestamp;
77+
let time_expected = u64::from(
78+
DIFFICULTY_ADJUSTMENT_INTERVAL_COUNT
79+
* BLOCK_GENERATION_INTERVAL_MINUTE
80+
* BLOCK_GENERATION_MILLIS,
81+
);
82+
83+
if time_taken < time_expected / 2 {
84+
adjustment_block.header.difficulty + 1
85+
} else if time_taken > time_expected * 2 {
86+
adjustment_block.header.difficulty - 1
87+
} else {
88+
adjustment_block.header.difficulty
89+
}
90+
}
91+
}
92+
}
93+
94+
fn unsafe_get_timestamp() -> u64 {
95+
SystemTime::now()
96+
.duration_since(UNIX_EPOCH)
97+
.unwrap()
98+
.as_secs()
99+
}
33100
}
34101

35102
#[derive(Debug, PartialEq, Clone)]
@@ -46,27 +113,30 @@ struct BlockHeader {
46113

47114
impl BlockHeader {
48115
const VERSION: &str = "1.0.0";
49-
const DIFFICULTY: i32 = 0;
50116

51117
fn make(
52118
height: i32,
119+
timestamp: u64,
53120
previous_hash: &String,
54121
nonce: i32,
122+
difficulty: i32,
55123
data: &Vec<String>,
56124
) -> Result<BlockHeader, String> {
57-
let version = Self::VERSION.to_string();
58-
let timestamp = SystemTime::now()
59-
.duration_since(UNIX_EPOCH)
60-
.unwrap()
61-
.as_secs();
62-
let difficulty = Self::DIFFICULTY;
63125
let merkle_root = Self::make_merkle_root(data).ok_or("Merkle Tree Parsing Failed")?;
64126

65127
Ok(BlockHeader {
66-
version,
128+
version: Self::VERSION.to_string(),
67129
height,
68130
timestamp,
69-
hash: Self::make_hash(timestamp, &merkle_root, previous_hash, nonce),
131+
hash: Self::make_block_hash(
132+
// TODO : 여기서 바로 마이닝을 하자.
133+
height,
134+
timestamp,
135+
&merkle_root,
136+
previous_hash,
137+
nonce,
138+
difficulty,
139+
),
70140
previous_hash: Some(previous_hash.clone()),
71141
merkle_root,
72142
nonce,
@@ -83,18 +153,23 @@ impl BlockHeader {
83153
merkle_tree.root_hex()
84154
}
85155

86-
fn make_hash(
156+
fn make_block_hash(
157+
height: i32,
87158
timestamp: u64,
88159
merkle_root: &String,
89160
previous_hash: &String,
90161
nonce: i32,
162+
difficulty: i32,
91163
) -> String {
92164
let target = format!(
93-
"{}{}{}{}",
165+
"{}{}{}{}{}{}{}",
166+
Self::VERSION.to_string(),
167+
height.to_string(),
94168
timestamp.to_string(),
95169
merkle_root,
96170
previous_hash,
97-
nonce.to_string()
171+
nonce.to_string(),
172+
difficulty.to_string()
98173
);
99174
digest(target)
100175
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// 블록 1 묶음의 블록 개수
2+
pub const DIFFICULTY_ADJUSTMENT_INTERVAL_COUNT: u16 = 10;
3+
4+
// 블록 1 묶음이 생성 되기까지의 예상 시간(분)
5+
pub const BLOCK_GENERATION_INTERVAL_MINUTE: u16 = 10;
6+
7+
// 블록 1 개가 생성 되기까지의 예상 시간(밀리초)
8+
pub const BLOCK_GENERATION_MILLIS: u16 = 60000;

jaeseung-blockchain/src/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
mod block;
22
mod chain;
3+
mod constants;
34

45
use block::Block;
56

0 commit comments

Comments
 (0)