diff --git a/node/src/node.rs b/node/src/node.rs index fd3e7fcf77..409292cd91 100644 --- a/node/src/node.rs +++ b/node/src/node.rs @@ -308,6 +308,7 @@ impl NodeService { let start_time = SystemTime::now(); storage_instance.check_upgrade()?; storage_instance.barnard_hard_fork(config.clone())?; + storage_instance.dragon_hard_fork(config.clone())?; let upgrade_time = SystemTime::now().duration_since(start_time)?; let storage = Arc::new(Storage::new(storage_instance)?); registry.put_shared(storage.clone()).await?; diff --git a/storage/src/chain_info/mod.rs b/storage/src/chain_info/mod.rs index 3f193be3f0..b29012a898 100644 --- a/storage/src/chain_info/mod.rs +++ b/storage/src/chain_info/mod.rs @@ -5,7 +5,7 @@ use crate::storage::{ColumnFamily, InnerStorage, KVStore}; use crate::{StorageVersion, CHAIN_INFO_PREFIX_NAME}; use anyhow::Result; use starcoin_crypto::HashValue; -use starcoin_types::startup_info::{BarnardHardFork, SnapshotRange, StartupInfo}; +use starcoin_types::startup_info::{BarnardHardFork, DragonHardFork, SnapshotRange, StartupInfo}; use std::convert::{TryFrom, TryInto}; #[derive(Clone)] @@ -28,6 +28,7 @@ impl ChainInfoStorage { const STORAGE_VERSION_KEY: &'static str = "storage_version"; const SNAPSHOT_RANGE_KEY: &'static str = "snapshot_height"; const BARNARD_HARD_FORK: &'static str = "barnard_hard_fork"; + const DRAGON_HARD_FORK: &'static str = "dragon_hard_fork"; pub fn get_startup_info(&self) -> Result> { self.get(Self::STARTUP_INFO_KEY.as_bytes()) @@ -111,4 +112,19 @@ impl ChainInfoStorage { barnard_hard_fork.try_into()?, ) } + + pub fn get_dragon_hard_fork(&self) -> Result> { + self.get(Self::DRAGON_HARD_FORK.as_bytes()) + .and_then(|bytes| match bytes { + Some(bytes) => Ok(Some(bytes.try_into()?)), + None => Ok(None), + }) + } + + pub fn save_dragon_hard_fork(&self, dragon_hard_fork: DragonHardFork) -> Result<()> { + self.put_sync( + Self::DRAGON_HARD_FORK.as_bytes().to_vec(), + dragon_hard_fork.try_into()?, + ) + } } diff --git a/storage/src/storage.rs b/storage/src/storage.rs index cddd7269b1..bd012da98b 100644 --- a/storage/src/storage.rs +++ b/storage/src/storage.rs @@ -118,6 +118,14 @@ impl StorageInstance { } Ok(()) } + + pub fn dragon_hard_fork(&mut self, config: Arc) -> Result<()> { + if config.net().id().chain_id().is_main() { + info!("dragon_hard_fork in"); + return DBUpgrade::dragon_hard_fork(self); + } + Ok(()) + } } impl InnerStore for StorageInstance { diff --git a/storage/src/upgrade.rs b/storage/src/upgrade.rs index b8fcd18b43..d4a57a38e1 100644 --- a/storage/src/upgrade.rs +++ b/storage/src/upgrade.rs @@ -16,7 +16,7 @@ use once_cell::sync::Lazy; use starcoin_crypto::HashValue; use starcoin_logger::prelude::{debug, info, warn}; use starcoin_types::block::BlockNumber; -use starcoin_types::startup_info::{BarnardHardFork, StartupInfo}; +use starcoin_types::startup_info::{BarnardHardFork, DragonHardFork, StartupInfo}; use starcoin_types::transaction::Transaction; use std::cmp::Ordering; @@ -30,6 +30,14 @@ pub static BARNARD_HARD_FORK_HASH: Lazy = Lazy::new(|| { .expect("") }); +pub static DRAGON_HARD_FORK_HEIGHT: BlockNumber = 16801958; +pub static DRAGON_HARD_FORK_HASH: Lazy = Lazy::new(|| { + HashValue::from_hex_literal( + "0xbef8d0af3b358af9fe25f7383fd2580679c54fe2ce7ff7a7434785ba6d11b943", + ) + .expect("") +}); + impl DBUpgrade { pub fn check_upgrade(instance: &mut StorageInstance) -> Result<()> { let version_in_db = { @@ -233,4 +241,54 @@ impl DBUpgrade { } Ok(()) } + + pub fn dragon_hard_fork(instance: &mut StorageInstance) -> Result<()> { + let block_storage = BlockStorage::new(instance.clone()); + let chain_info_storage = ChainInfoStorage::new(instance.clone()); + let hard_fork = chain_info_storage.get_dragon_hard_fork()?; + + let fork_info = DragonHardFork::new(DRAGON_HARD_FORK_HEIGHT, *DRAGON_HARD_FORK_HASH); + if hard_fork == Some(fork_info.clone()) { + info!("dragon hard forked"); + return Ok(()); + } + + let block = block_storage.get_block_by_hash(*DRAGON_HARD_FORK_HASH)?; + if let Some(block) = block { + if block.header().number() == DRAGON_HARD_FORK_HEIGHT { + info!("dragon hard fork rollback height"); + let mut to_deleted = vec![]; + let mut iter = block_storage.header_store.iter()?; + iter.seek_to_first(); + for item in iter { + let (id, block_header) = item?; + if block_header.number() > DRAGON_HARD_FORK_HEIGHT { + to_deleted.push(id); + } + } + let block_info_storage = BlockInfoStorage::new(instance.clone()); + let mut processed_count = 0; + for id in to_deleted { + block_info_storage.remove(id)?; + block_storage.delete_block(id)?; + processed_count += 1; + if processed_count % 10000 == 0 { + info!( + "dragon hard fork rollback height processed items: {}", + processed_count + ); + } + } + if processed_count % 10000 != 0 { + info!( + "dragon hard fork rollback height processed items: {}", + processed_count + ); + } + chain_info_storage.save_dragon_hard_fork(fork_info)?; + chain_info_storage.save_startup_info(StartupInfo::new(*DRAGON_HARD_FORK_HASH))?; + } + } + Ok(()) + } } diff --git a/types/src/startup_info.rs b/types/src/startup_info.rs index d536020128..453e6c789b 100644 --- a/types/src/startup_info.rs +++ b/types/src/startup_info.rs @@ -281,3 +281,40 @@ impl TryInto> for BarnardHardFork { self.encode() } } + +#[derive(Eq, PartialEq, Hash, Deserialize, Serialize, Clone, Debug)] +pub struct DragonHardFork { + // block whose number is greater than `number` will be purged + number: BlockNumber, + hash: HashValue, +} + +impl DragonHardFork { + pub fn new(number: BlockNumber, hash: HashValue) -> Self { + Self { number, hash } + } + + pub fn get_number(&self) -> BlockNumber { + self.number + } + + pub fn get_hash(&self) -> HashValue { + self.hash + } +} + +impl TryFrom> for DragonHardFork { + type Error = anyhow::Error; + + fn try_from(value: Vec) -> Result { + DragonHardFork::decode(value.as_slice()) + } +} + +impl TryInto> for DragonHardFork { + type Error = anyhow::Error; + + fn try_into(self) -> Result> { + self.encode() + } +}