Эх сурвалжийг харах

research/pow: Block timestamp verification

parazyd 2 жил өмнө
parent
commit
96d35d5022

+ 1 - 1
script/research/pow/Cargo.toml

@@ -9,7 +9,7 @@ edition = "2021"
 randomx = {git = "https://github.com/darkrenaissance/RandomX"}
 darkfi-serial = {path = "../../../src/serial"}
 darkfi-sdk = {path = "../../../src/sdk", features = ["async"]}
-darkfi = {path = "../../../", features = ["util"]}
+darkfi = {path = "../../../", features = ["util", "async-serial"]}
 
 rand = "0.8.5"
 blake2b_simd = "1.0.1"

+ 57 - 0
script/research/pow/src/main.rs

@@ -55,6 +55,10 @@ const DIFFICULTY_CUT: usize = 60;
 const DIFFICULTY_LAG: usize = 15;
 /// Target block time in seconds
 const DIFFICULTY_TARGET: usize = 60;
+/// The most recent blocks used to verify new blocks' timestamp
+const BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW: usize = 60;
+/// Time limit in the future of what blocks can be
+const BLOCK_FUTURE_TIME_LIMIT: u64 = 60 * 60 * 2;
 
 #[derive(Clone, SerialEncodable, SerialDecodable)]
 struct Transaction(Vec<u8>);
@@ -148,6 +152,57 @@ fn next_difficulty(
     (total_work * target_seconds + time_span - BigUint::one()) / time_span
 }
 
+fn get_mid(a: u64, b: u64) -> u64 {
+    (a / 2) + (b / 2) + ((a - 2 * (a / 2)) + (b - 2 * (b / 2))) / 2
+}
+
+fn median(v: &mut Vec<u64>) -> u64 {
+    assert!(!v.is_empty());
+
+    if v.len() == 1 {
+        return v[0]
+    }
+
+    let n = v.len() / 2;
+    v.sort();
+
+    if v.len() % 2 == 0 {
+        v[n]
+    } else {
+        get_mid(v[n - 1], v[n])
+    }
+}
+
+fn check_block_timestamp_median(timestamps: &mut Vec<u64>, block: &Block) -> bool {
+    let median_ts = median(timestamps);
+
+    if block.header.timestamp.0 < median_ts {
+        return false
+    }
+
+    true
+}
+
+fn check_block_timestamp(block: &Block, blockchain: &[Block]) -> bool {
+    if block.header.timestamp.0 > Timestamp::current_time().0 + BLOCK_FUTURE_TIME_LIMIT {
+        return false
+    }
+
+    // If not enough blocks, no proper median yet, return true
+    if blockchain.len() < BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW {
+        return true
+    }
+
+    let mut timestamps: Vec<u64> = blockchain
+        .iter()
+        .rev()
+        .take(BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW)
+        .map(|x| x.header.timestamp.0)
+        .collect();
+
+    check_block_timestamp_median(&mut timestamps, block)
+}
+
 fn main() -> Result<()> {
     // Construct the genesis block
     let genesis_hash =
@@ -277,6 +332,8 @@ fn main() -> Result<()> {
         miner_block.header.nonce = found_nonce.load(Ordering::SeqCst);
 
         // Verify
+        assert!(check_block_timestamp(&miner_block, &blockchain));
+
         let verifier_setup = Instant::now();
         let flags = RandomXFlags::default();
         let cache = RandomXCache::new(flags, pow_input.as_bytes()).unwrap();