Skip to content

Commit

Permalink
Barnard hard fork test (#3834)
Browse files Browse the repository at this point in the history
* 1.add BARNARD_HARD_FORK logic 2.add version_string ban logic

* add release version compare ban logic

* fix test

* fix fmt
  • Loading branch information
nkysg authored Feb 16, 2023
1 parent 0bb317e commit de534ff
Show file tree
Hide file tree
Showing 12 changed files with 222 additions and 3 deletions.
6 changes: 6 additions & 0 deletions chain/api/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ pub enum ConnectBlockError {
ParentNotExist(Box<BlockHeader>),
#[error("Verify block {0} failed: {1:?}")]
VerifyBlockFailed(VerifyBlockField, Error),
#[error("Barnard hard fork block: {:?} ", .0.header())]
BarnardHardFork(Box<Block>),
}

impl ConnectBlockError {
Expand All @@ -70,12 +72,15 @@ impl ConnectBlockError {
ReputationChange::new_fatal("ParentNotExist");
pub const REP_VERIFY_BLOCK_FAILED: ReputationChange =
ReputationChange::new_fatal("VerifyBlockFailed");
pub const REP_BARNARD_HARD_FORK: ReputationChange =
ReputationChange::new_fatal("BarnardHardFork");

pub fn reason(&self) -> &str {
match self {
ConnectBlockError::FutureBlock(_) => "FutureBlock",
ConnectBlockError::ParentNotExist(_) => "ParentNotExist",
ConnectBlockError::VerifyBlockFailed(_, _) => "VerifyBlockFailed",
ConnectBlockError::BarnardHardFork(_) => "BarnardHardFork",
}
}

Expand All @@ -86,6 +91,7 @@ impl ConnectBlockError {
ConnectBlockError::VerifyBlockFailed(_, _) => {
ConnectBlockError::REP_VERIFY_BLOCK_FAILED
}
ConnectBlockError::BarnardHardFork(_) => ConnectBlockError::REP_BARNARD_HARD_FORK,
}
}
}
77 changes: 77 additions & 0 deletions network/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,14 @@ use starcoin_types::startup_info::{ChainInfo, ChainStatus};
use starcoin_types::sync_status::SyncStatus;
use starcoin_types::system_events::SyncStatusChangeEvent;
use std::borrow::Cow;
use std::cmp::Ordering;
use std::collections::HashMap;
use std::ops::RangeInclusive;
use std::sync::Arc;

const BARNARD_HARD_FORK_PEER_VERSION_STRING_PREFIX: &str = "barnard_rollback_block_fix";
const BARNARD_HARD_FORK_VERSION: [i32; 3] = [1, 12, 9];

pub struct NetworkActorService {
worker: Option<NetworkWorker>,
inner: Inner,
Expand Down Expand Up @@ -114,6 +118,49 @@ impl EventHandler<Self, SyncStatusChangeEvent> for NetworkActorService {
self.inner.update_chain_status(msg.0);
}
}
// ver_str like starcoin/1.12.6 (build:v1.12.6) (kele01)
fn greater_barnard_fork_version(ver_str: &str) -> bool {
let start = ver_str.find("build:v");
if start.is_none() {
return false;
}
let end = ver_str.find(") ");
if end.is_none() {
return false;
}
let i = start.unwrap().saturating_add(7);
let j = end.unwrap();
if i >= j {
return false;
}
let str = &ver_str[i..j];

let mut ver = String::from("");
for c in str.chars() {
if !c.is_numeric() && c != '.' {
break;
} else {
ver.push(c);
}
}
let str_list: Vec<&str> = ver.split('.').collect();
if str_list.len() != 3 {
return false;
}
let nums: Result<Vec<i32>, _> = str_list.iter().map(|x| x.parse()).collect();
if nums.is_err() {
return false;
}
let nums = nums.unwrap();
for (a, b) in nums.iter().zip(BARNARD_HARD_FORK_VERSION.iter()) {
match a.cmp(b) {
Ordering::Greater => return true,
Ordering::Less => return false,
Ordering::Equal => continue,
}
}
false
}

impl EventHandler<Self, Event> for NetworkActorService {
fn handle_event(&mut self, event: Event, ctx: &mut ServiceContext<NetworkActorService>) {
Expand All @@ -135,6 +182,21 @@ impl EventHandler<Self, Event> for NetworkActorService {
"Connected peer {:?}, protocol: {}, notif_protocols: {:?}, rpc_protocols: {:?}",
remote, protocol, notif_protocols, rpc_protocols
);
if info.chain_id().is_barnard() {
info!("Connected peer ver_string {:?}", version_string);
if let Some(ref ver_str) = version_string {
if !ver_str.contains(BARNARD_HARD_FORK_PEER_VERSION_STRING_PREFIX)
&& !greater_barnard_fork_version(ver_str)
{
info!(
"ban {} peer {:?} ver_str {}",
BARNARD_HARD_FORK_PEER_VERSION_STRING_PREFIX, remote, ver_str
);
self.inner.network_service.ban_peer(remote, true);
return;
}
}
}
let peer_event = PeerEvent::Open(remote.into(), info.clone());
self.inner.on_peer_connected(
remote.into(),
Expand Down Expand Up @@ -802,6 +864,7 @@ where

#[cfg(test)]
mod test {
use crate::service::greater_barnard_fork_version;
use crate::service::select_random_peers;
use network_api::PeerId;

Expand Down Expand Up @@ -835,4 +898,18 @@ mod test {
);
assert_eq!(select_random_peers(3..=3, create_peers(3).iter()).len(), 3);
}

#[test]
fn greater_version_test() {
let v1 = String::from("starcoin/1.12.6 (build:v1.12.6) (kele01)");
assert!(!greater_barnard_fork_version(&v1));
let v2 = String::from("starcoin 1.13.0-alpha (build:halley-v1.13.1-alpha-dirty)");
assert!(!greater_barnard_fork_version(&v2));
let v3 = String::from("starcoin/1.13.0-alpha (build:v1.13.0-alpha) (kele01)");
assert!(greater_barnard_fork_version(&v3));
let v4 = String::from("starcoin/1.12.9 (build:v1.12.9) (kele01)");
assert!(!greater_barnard_fork_version(&v4));
let v5 = String::from("starcoin/1.13.1 (build:v1.13.1) (kele01)");
assert!(greater_barnard_fork_version(&v5));
}
}
1 change: 1 addition & 0 deletions node/src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,7 @@ impl NodeService {

let start_time = SystemTime::now();
storage_instance.check_upgrade()?;
storage_instance.barnard_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?;
Expand Down
2 changes: 1 addition & 1 deletion storage/src/block/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ define_storage!(
#[derive(Clone)]
pub struct BlockStorage {
block_store: BlockInnerStorage,
header_store: BlockHeaderStorage,
pub(crate) header_store: BlockHeaderStorage,
body_store: BlockBodyStorage,
block_txns_store: BlockTransactionsStorage,
block_txn_infos_store: BlockTransactionInfosStorage,
Expand Down
18 changes: 17 additions & 1 deletion storage/src/chain_info/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{SnapshotRange, StartupInfo};
use starcoin_types::startup_info::{BarnardHardFork, SnapshotRange, StartupInfo};
use std::convert::{TryFrom, TryInto};

#[derive(Clone)]
Expand All @@ -27,6 +27,7 @@ impl ChainInfoStorage {
const GENESIS_KEY: &'static str = "genesis";
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";

pub fn get_startup_info(&self) -> Result<Option<StartupInfo>> {
self.get(Self::STARTUP_INFO_KEY.as_bytes())
Expand Down Expand Up @@ -95,4 +96,19 @@ impl ChainInfoStorage {
snapshot_range.try_into()?,
)
}

pub fn get_barnard_hard_fork(&self) -> Result<Option<BarnardHardFork>> {
self.get(Self::BARNARD_HARD_FORK.as_bytes())
.and_then(|bytes| match bytes {
Some(bytes) => Ok(Some(bytes.try_into()?)),
None => Ok(None),
})
}

pub fn save_barnard_hard_fork(&self, barnard_hard_fork: BarnardHardFork) -> Result<()> {
self.put_sync(
Self::BARNARD_HARD_FORK.as_bytes().to_vec(),
barnard_hard_fork.try_into()?,
)
}
}
2 changes: 2 additions & 0 deletions storage/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ use starcoin_types::{
use std::collections::BTreeMap;
use std::fmt::{Debug, Display, Formatter};
use std::sync::Arc;
pub use upgrade::BARNARD_HARD_FORK_HASH;
pub use upgrade::BARNARD_HARD_FORK_HEIGHT;

pub mod accumulator;
pub mod batch;
Expand Down
10 changes: 10 additions & 0 deletions storage/src/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ use crate::db_storage::{DBStorage, SchemaIterator};
use crate::upgrade::DBUpgrade;
use anyhow::{bail, format_err, Result};
use byteorder::{BigEndian, ReadBytesExt};
use starcoin_config::NodeConfig;
use starcoin_crypto::HashValue;
use starcoin_logger::prelude::info;
use starcoin_vm_types::state_store::table::TableHandle;
use std::convert::TryInto;
use std::fmt::Debug;
Expand Down Expand Up @@ -108,6 +110,14 @@ impl StorageInstance {
pub fn check_upgrade(&mut self) -> Result<()> {
DBUpgrade::check_upgrade(self)
}

pub fn barnard_hard_fork(&mut self, config: Arc<NodeConfig>) -> Result<()> {
if config.net().id().chain_id().is_barnard() {
info!("barnard_hard_fork in");
return DBUpgrade::barnard_hard_fork(self);
}
Ok(())
}
}

impl InnerStore for StorageInstance {
Expand Down
52 changes: 52 additions & 0 deletions storage/src/upgrade.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,24 @@ use crate::{
BLOCK_BODY_PREFIX_NAME, TRANSACTION_INFO_PREFIX_NAME,
};
use anyhow::{bail, ensure, format_err, Result};
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::transaction::Transaction;
use std::cmp::Ordering;

pub struct DBUpgrade;

pub static BARNARD_HARD_FORK_HEIGHT: BlockNumber = 9716880;
pub static BARNARD_HARD_FORK_HASH: Lazy<HashValue> = Lazy::new(|| {
HashValue::from_hex_literal(
"0x98f32397569e26540985f0d487c5e7cc229a8c9be9afe10f973b3d95204d06d7",
)
.expect("")
});

impl DBUpgrade {
pub fn check_upgrade(instance: &mut StorageInstance) -> Result<()> {
let version_in_db = {
Expand Down Expand Up @@ -181,4 +193,44 @@ impl DBUpgrade {
}
Ok(())
}

pub fn barnard_hard_fork(instance: &mut StorageInstance) -> Result<()> {
let block_storage = BlockStorage::new(instance.clone());
let chain_info_storage = ChainInfoStorage::new(instance.clone());
let barnard_hard_fork = chain_info_storage.get_barnard_hard_fork()?;

let barnard_info = BarnardHardFork::new(BARNARD_HARD_FORK_HEIGHT, *BARNARD_HARD_FORK_HASH);
if barnard_hard_fork == Some(barnard_info.clone()) {
info!("barnard had forked");
return Ok(());
}

let block = block_storage.get_block_by_hash(*BARNARD_HARD_FORK_HASH)?;
if let Some(block) = block {
if block.header().number() == BARNARD_HARD_FORK_HEIGHT {
info!("barnard hard fork rollback height");
let mut processed_count = 0;
let block_info_storage = BlockInfoStorage::new(instance.clone());
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() >= BARNARD_HARD_FORK_HEIGHT {
block_info_storage.remove(id)?;
processed_count += 1;
if processed_count % 10000 == 0 {
info!(
"barnard hard fork rollback height processed items: {}",
processed_count
);
}
}
}
let main_hash = block.header().parent_hash();
chain_info_storage.save_barnard_hard_fork(barnard_info)?;
chain_info_storage.save_startup_info(StartupInfo::new(main_hash))?;
}
}
Ok(())
}
}
10 changes: 10 additions & 0 deletions sync/src/block_connector/write_block_chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,12 @@ where

fn connect_inner(&mut self, block: Block) -> Result<ConnectOk> {
let block_id = block.id();
if block_id == *starcoin_storage::BARNARD_HARD_FORK_HASH
&& block.header().number() == starcoin_storage::BARNARD_HARD_FORK_HEIGHT
{
debug!("barnard hard fork {}", block_id);
return Err(ConnectBlockError::BarnardHardFork(Box::new(block)).into());
}
if self.main.current_header().id() == block_id {
debug!("Repeat connect, current header is {} already.", block_id);
return Ok(ConnectOk::Duplicate);
Expand Down Expand Up @@ -430,6 +436,10 @@ where
block: block.clone(),
block_info,
})?;
info!(
"Block {} main has been processed, trigger head selection",
block_id
);
self.do_new_head(executed_block, 1, vec![block], 0, vec![])?;
Ok(ConnectOk::Connect)
}
Expand Down
8 changes: 8 additions & 0 deletions sync/src/tasks/block_sync_task.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use starcoin_chain::{verifier::BasicVerifier, BlockChain};
use starcoin_chain_api::{ChainReader, ChainWriter, ConnectBlockError, ExecutedBlock};
use starcoin_config::G_CRATE_VERSION;
use starcoin_logger::prelude::*;
use starcoin_storage::BARNARD_HARD_FORK_HASH;
use starcoin_sync_api::SyncTarget;
use starcoin_types::block::{Block, BlockIdAndNumber, BlockInfo, BlockNumber};
use std::collections::HashMap;
Expand Down Expand Up @@ -236,6 +237,13 @@ where
return Err(format_err!("collect previous failed block:{}", block.id()));
}
}
if block.id() == *BARNARD_HARD_FORK_HASH {
if let Some(peer) = peer_id {
warn!("[barnard hard fork] ban peer {}", peer);
self.peer_provider.ban_peer(peer, true);
}
return Err(format_err!("reject barnard hard fork block:{}", block.id()));
}
let apply_result = if self.skip_pow_verify {
self.chain
.apply_with_verifier::<BasicVerifier>(block.clone())
Expand Down
37 changes: 37 additions & 0 deletions types/src/startup_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -234,3 +234,40 @@ impl TryInto<Vec<u8>> for SnapshotRange {
self.encode()
}
}

#[derive(Eq, PartialEq, Hash, Deserialize, Serialize, Clone, Debug)]
pub struct BarnardHardFork {
// [number, ...) block will remove
number: BlockNumber,
hash: HashValue,
}

impl BarnardHardFork {
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<Vec<u8>> for BarnardHardFork {
type Error = anyhow::Error;

fn try_from(value: Vec<u8>) -> Result<Self> {
BarnardHardFork::decode(value.as_slice())
}
}

impl TryInto<Vec<u8>> for BarnardHardFork {
type Error = anyhow::Error;

fn try_into(self) -> Result<Vec<u8>> {
self.encode()
}
}
Loading

0 comments on commit de534ff

Please sign in to comment.