From bcf0ecc75cce8709736f8d3a1f2f68ca4290db82 Mon Sep 17 00:00:00 2001 From: who-biz <37732338+who-biz@users.noreply.github.com> Date: Fri, 1 Sep 2023 00:15:12 +0000 Subject: [PATCH] Add 'disable_checkpoints' config setting, refactor checkpoint code - This commit adds a config file option in server settings 'disable_checkpoints' - If a user sets 'skip_pow_validation' they will skip pow validation on all blocks up to last checkpoint - If a user sets 'disable_checkpoints' in addition to 'skip_pow_validation', they will fast sync all the way to chaintip - This also required a relocation BlockchainCheckpoints code, and resolves an omission i made in original addition of this functionality (not sure it would have made a difference, but its resolved here also) --- chain/src/pipe.rs | 22 +------ chain/src/types.rs | 104 ------------------------------ config/src/comments.rs | 11 +++- servers/src/common/adapters.rs | 41 +++++++++++- servers/src/common/types.rs | 113 ++++++++++++++++++++++++++++++++- 5 files changed, 163 insertions(+), 128 deletions(-) diff --git a/chain/src/pipe.rs b/chain/src/pipe.rs index aa2e4f73..4c03f620 100644 --- a/chain/src/pipe.rs +++ b/chain/src/pipe.rs @@ -27,7 +27,7 @@ use crate::error::{Error, ErrorKind}; use crate::store; use crate::store::BottleIter; use crate::txhashset; -use crate::types::{BlockchainCheckpoints, CommitPos, Options, Tip}; +use crate::types::{CommitPos, Options, Tip}; use chrono::prelude::Utc; use chrono::Duration; use epic_store; @@ -353,25 +353,7 @@ fn validate_header(header: &BlockHeader, ctx: &mut BlockContext<'_>) -> Result<( check_bad_header(header)?; - let checkpoints = BlockchainCheckpoints::new().checkpoints; - - for c in &checkpoints { - if header.height == c.height { - if header.hash() == c.block_hash { - info!( - "Checkpoint successfully passed at height({})! Hashes: header({:?}), checkpoint({:?})", - c.height, - header.hash(), - c.block_hash - ); - } else { - return Err(ErrorKind::CheckpointFailure.into()); - } - } - } - - if !ctx.opts.contains(Options::SKIP_POW) || (header.height > checkpoints.last().unwrap().height) - { + if !ctx.opts.contains(Options::SKIP_POW) { if !header.pow.is_primary() && !header.pow.is_secondary() { return Err(ErrorKind::LowEdgebits.into()); } diff --git a/chain/src/types.rs b/chain/src/types.rs index 33f30257..1a507e86 100644 --- a/chain/src/types.rs +++ b/chain/src/types.rs @@ -411,107 +411,3 @@ pub enum BlockStatus { /// Previous block was not our previous chain head. Reorg(u64), } - -// Elements in checkpoint data vector -#[derive(Debug)] -pub struct Checkpoint { - pub height: u64, - pub block_hash: Hash, -} - -#[derive(Debug)] -pub struct BlockchainCheckpoints { - pub checkpoints: Vec, -} - -impl BlockchainCheckpoints { - pub fn new() -> BlockchainCheckpoints { - let checkpoints = vec![ - Checkpoint { - height: 100000, - block_hash: Hash::from_hex( - "e835eb9ebc9f2e13b11061691cb268f44b20001f081003169b634497eb730848", - ) - .unwrap(), - }, - Checkpoint { - height: 200000, - block_hash: Hash::from_hex( - "b2365a8c9719a709f11d450bbddfd012011e21c862239bdc8590aba00815e84c", - ) - .unwrap(), - }, - Checkpoint { - height: 400000, - block_hash: Hash::from_hex( - "6578f1cdf5504d29fc757424e75ac60494e0f6d24b7553d124c8bea6ef99b5d8", - ) - .unwrap(), - }, - Checkpoint { - height: 600000, - block_hash: Hash::from_hex( - "de483eafb2141d66bf541a94d8e41858f01ffc517b9fa61d8781483c34c2a6f7", - ) - .unwrap(), - }, - Checkpoint { - height: 800000, - block_hash: Hash::from_hex( - "1465e7c094376e781b1e80ebd6b7a0c6350ec4d6554f9acdd843802162831003", - ) - .unwrap(), - }, - Checkpoint { - height: 1000000, - block_hash: Hash::from_hex( - "00e4a404130ac192face23fd25f2c46a99a38a31d8cf2d3cc79ea7a518830686", - ) - .unwrap(), - }, - Checkpoint { - height: 1200000, - block_hash: Hash::from_hex( - "8d69282df5579d32346ad0f6d3f4e03a43b1e00e741b1f3ba71c2934d81e5e1a", - ) - .unwrap(), - }, - Checkpoint { - height: 1400000, - block_hash: Hash::from_hex( - "e7e34e50e8a5c9bcf3fe7b7ad99e62a848cda37171ce8d37f21bc334035df4d2", - ) - .unwrap(), - }, - Checkpoint { - height: 1600000, - block_hash: Hash::from_hex( - "ba44beaf37776c3e7da3f4a1b906ae238e1178794cbaa90685e3945d2662d7a2", - ) - .unwrap(), - }, - Checkpoint { - height: 1800000, - block_hash: Hash::from_hex( - "4f23aaf2e83e4041cac670226d3024f4468e3b9bb6ffa2548ebc59489bd09b63", - ) - .unwrap(), - }, - Checkpoint { - height: 2000000, - block_hash: Hash::from_hex( - "eaf5d7a4b6f07ccb8bdbe5db2f39e10eea3ee1c28f8333907d91c9ccc21ce99d", - ) - .unwrap(), - }, - Checkpoint { - height: 2050000, - block_hash: Hash::from_hex( - "1a51bb18562e120f33783e53a70c449fd14197ac77082dc23d664c7f47a744c9", - ) - .unwrap(), - }, - ]; - return BlockchainCheckpoints { checkpoints }; - } -} diff --git a/config/src/comments.rs b/config/src/comments.rs index f25292f1..32633475 100644 --- a/config/src/comments.rs +++ b/config/src/comments.rs @@ -107,7 +107,16 @@ fn comments() -> HashMap { "skip_pow_validation".to_string(), " #Whether or not to skip pow validation when syncing headers -#Only applies to blocks within checkpointed history range (default is false) +#Only applies to blocks in checkpointed range, unless disable_checkpoints is set to true +" + .to_string(), + ); + + retval.insert( + "disable_checkpoints".to_string(), + " +#Disables checkpoint-based pow_validation, no proof of work will be validated whatsoever +#while syncing. Has no effect unless 'skip_pow_validation' is set to true " .to_string(), ); diff --git a/servers/src/common/adapters.rs b/servers/src/common/adapters.rs index d825b3e0..9ab1019b 100644 --- a/servers/src/common/adapters.rs +++ b/servers/src/common/adapters.rs @@ -25,7 +25,9 @@ use std::time::Instant; use crate::chain::{self, BlockStatus, ChainAdapter, Options, SyncState, SyncStatus}; use crate::common::hooks::{ChainEvents, NetEvents}; -use crate::common::types::{ChainValidationMode, DandelionEpoch, ServerConfig}; +use crate::common::types::{ + BlockchainCheckpoints, ChainValidationMode, DandelionEpoch, ServerConfig, +}; use crate::core::core::hash::{Hash, Hashed}; use crate::core::core::transaction::Transaction; use crate::core::core::{BlockHeader, BlockSums, CompactBlock}; @@ -306,12 +308,47 @@ impl p2p::ChainAdapter for NetToChainAdapter { ); let mut ctx_option = Options::SYNC; + let mut within_checkpointed_range = true; + let mut disable_checkpoints = false; + + let checkpoints = BlockchainCheckpoints::new().checkpoints; + + for header in bhs { + for c in &checkpoints { + if header.height == c.height { + if header.hash() == c.block_hash { + info!("Checkpoint successfully passed at height({})! Hashes: header({:?}), checkpoint({:?})", + c.height, + header.hash(), + c.block_hash + ); + } else { + return Err(chain::ErrorKind::CheckpointFailure.into()); + } + } + } + if header.height > checkpoints.last().unwrap().height { + within_checkpointed_range = false; + } + } + + if self.config.disable_checkpoints.is_some() { + if self.config.disable_checkpoints.unwrap() { + disable_checkpoints = true; + } + } if self.config.skip_pow_validation.is_some() { if self.config.skip_pow_validation.unwrap() { - ctx_option = Options::SKIP_POW; + if within_checkpointed_range || disable_checkpoints { + // only skip pow validation if setting is toggled AND we are within checkpointed range + // OR if we have 'skip_pow_validation' AND 'disable_checkpoints' toggled + // fully validate pow for all other cases + ctx_option = Options::SKIP_POW; + } } } + match self.chain().sync_block_headers(bhs, ctx_option) { Ok(_) => { info!( diff --git a/servers/src/common/types.rs b/servers/src/common/types.rs index 8d251223..f4b91b4b 100644 --- a/servers/src/common/types.rs +++ b/servers/src/common/types.rs @@ -21,6 +21,7 @@ use rand::prelude::*; use crate::api; use crate::chain; +use crate::core::core::hash::Hash; use crate::core::global; use crate::core::global::ChainTypes; use crate::core::{consensus, core, libtx, pow}; @@ -172,9 +173,14 @@ pub struct ServerConfig { /// Whether this node is a full archival node or a fast-sync, pruned node pub archive_mode: Option, - // How to validate new block headers + /// Disable pow validation in checkpointed range, fully validate all blocks + /// Outside of checkpointed range pub skip_pow_validation: Option, + /// Disable pow validation all the way to chaintip, only has effect when + /// skip_pow_validation is also set to 'true' + pub disable_checkpoints: Option, + /// Whether to skip the sync timeout on startup /// (To assist testing on solo chains) pub skip_sync_wait: Option, @@ -240,6 +246,7 @@ impl Default for ServerConfig { chain_type: ChainTypes::default(), archive_mode: Some(false), skip_pow_validation: Some(false), + disable_checkpoints: Some(false), chain_validation_mode: ChainValidationMode::default(), pool_config: pool::PoolConfig::default(), skip_sync_wait: Some(false), @@ -446,3 +453,107 @@ impl DandelionEpoch { self.relay_peer.clone() } } + +// Elements in checkpoint data vector +#[derive(Debug)] +pub struct Checkpoint { + pub height: u64, + pub block_hash: Hash, +} + +#[derive(Debug)] +pub struct BlockchainCheckpoints { + pub checkpoints: Vec, +} + +impl BlockchainCheckpoints { + pub fn new() -> BlockchainCheckpoints { + let checkpoints = vec![ + Checkpoint { + height: 100000, + block_hash: Hash::from_hex( + "e835eb9ebc9f2e13b11061691cb268f44b20001f081003169b634497eb730848", + ) + .unwrap(), + }, + Checkpoint { + height: 200000, + block_hash: Hash::from_hex( + "b2365a8c9719a709f11d450bbddfd012011e21c862239bdc8590aba00815e84c", + ) + .unwrap(), + }, + Checkpoint { + height: 400000, + block_hash: Hash::from_hex( + "6578f1cdf5504d29fc757424e75ac60494e0f6d24b7553d124c8bea6ef99b5d8", + ) + .unwrap(), + }, + Checkpoint { + height: 600000, + block_hash: Hash::from_hex( + "de483eafb2141d66bf541a94d8e41858f01ffc517b9fa61d8781483c34c2a6f7", + ) + .unwrap(), + }, + Checkpoint { + height: 800000, + block_hash: Hash::from_hex( + "1465e7c094376e781b1e80ebd6b7a0c6350ec4d6554f9acdd843802162831003", + ) + .unwrap(), + }, + Checkpoint { + height: 1000000, + block_hash: Hash::from_hex( + "00e4a404130ac192face23fd25f2c46a99a38a31d8cf2d3cc79ea7a518830686", + ) + .unwrap(), + }, + Checkpoint { + height: 1200000, + block_hash: Hash::from_hex( + "8d69282df5579d32346ad0f6d3f4e03a43b1e00e741b1f3ba71c2934d81e5e1a", + ) + .unwrap(), + }, + Checkpoint { + height: 1400000, + block_hash: Hash::from_hex( + "e7e34e50e8a5c9bcf3fe7b7ad99e62a848cda37171ce8d37f21bc334035df4d2", + ) + .unwrap(), + }, + Checkpoint { + height: 1600000, + block_hash: Hash::from_hex( + "ba44beaf37776c3e7da3f4a1b906ae238e1178794cbaa90685e3945d2662d7a2", + ) + .unwrap(), + }, + Checkpoint { + height: 1800000, + block_hash: Hash::from_hex( + "4f23aaf2e83e4041cac670226d3024f4468e3b9bb6ffa2548ebc59489bd09b63", + ) + .unwrap(), + }, + Checkpoint { + height: 2000000, + block_hash: Hash::from_hex( + "eaf5d7a4b6f07ccb8bdbe5db2f39e10eea3ee1c28f8333907d91c9ccc21ce99d", + ) + .unwrap(), + }, + Checkpoint { + height: 2050000, + block_hash: Hash::from_hex( + "1a51bb18562e120f33783e53a70c449fd14197ac77082dc23d664c7f47a744c9", + ) + .unwrap(), + }, + ]; + return BlockchainCheckpoints { checkpoints }; + } +}