Skip to content

Commit

Permalink
feat: first hardfork with contract limit
Browse files Browse the repository at this point in the history
  • Loading branch information
driftluo committed Oct 10, 2023
1 parent 5b2310c commit 5e8a0e6
Show file tree
Hide file tree
Showing 11 changed files with 304 additions and 83 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ library MetadataType {
uint64 max_tx_size;
uint64 gas_limit;
uint64 interval;
uint64 max_contract_limit;
}

struct CkbRelatedInfo {
Expand All @@ -56,7 +57,11 @@ library MetadataType {
interface MetadataManager {
function appendMetadata(MetadataType.Metadata memory metadata) external;

function updateConsensusConfig(MetadataType.ConsensusConfig memory config) external;
function updateConsensusConfig(
MetadataType.ConsensusConfig memory config
) external;

function setCkbRelatedInfo(MetadataType.CkbRelatedInfo memory info) external;
function setCkbRelatedInfo(
MetadataType.CkbRelatedInfo memory info
) external;
}
25 changes: 19 additions & 6 deletions common/config-parser/src/types/spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,12 +208,18 @@ impl Genesis {
// genesis
extra_data: {
vec![ExtraData {
inner: Into::<HardforkInfoInner>::into(HardforkInput {
hardforks: self.hardforks.clone(),
block_number: 0,
})
.encode()
.unwrap(),
inner: {
let mut info = Into::<HardforkInfoInner>::into(HardforkInput {
hardforks: self.hardforks.clone(),
block_number: 0,
});

if info.flags.is_zero() {
info.flags = H256::from_low_u64_be(HardforkName::all().to_be());
}

info.encode().unwrap()
},
}]
},
base_fee_per_gas: self.base_fee_per_gas,
Expand Down Expand Up @@ -253,4 +259,11 @@ impl From<HardforkInput> for HardforkInfoInner {
#[derive(Clone, Debug, Serialize, Deserialize, Copy, ValueEnum, EnumIter, PartialEq, Eq, Hash)]
pub enum HardforkName {
None = 0b0,
Andromeda = 0b1,
}

impl HardforkName {
pub fn all() -> u64 {
HardforkName::None as u64 | HardforkName::Andromeda as u64
}
}
10 changes: 10 additions & 0 deletions core/executor/src/system_contract/metadata/abi/metadata_abi.json
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,11 @@
"internalType": "uint64",
"name": "interval",
"type": "uint64"
},
{
"internalType": "uint64",
"name": "max_contract_limit",
"type": "uint64"
}
],
"internalType": "struct MetadataType.ConsensusConfig",
Expand Down Expand Up @@ -220,6 +225,11 @@
"internalType": "uint64",
"name": "interval",
"type": "uint64"
},
{
"internalType": "uint64",
"name": "max_contract_limit",
"type": "uint64"
}
],
"internalType": "struct MetadataType.ConsensusConfig",
Expand Down
39 changes: 20 additions & 19 deletions core/executor/src/system_contract/metadata/abi/metadata_abi.rs

Large diffs are not rendered by default.

34 changes: 18 additions & 16 deletions core/executor/src/system_contract/metadata/abi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,29 +35,31 @@ impl From<Metadata> for metadata_abi::Metadata {
impl From<ConsensusConfig> for metadata_abi::ConsensusConfig {
fn from(value: ConsensusConfig) -> Self {
metadata_abi::ConsensusConfig {
propose_ratio: value.propose_ratio,
prevote_ratio: value.prevote_ratio,
precommit_ratio: value.precommit_ratio,
brake_ratio: value.brake_ratio,
tx_num_limit: value.tx_num_limit,
max_tx_size: value.max_tx_size,
gas_limit: value.gas_limit,
interval: value.interval,
propose_ratio: value.propose_ratio,
prevote_ratio: value.prevote_ratio,
precommit_ratio: value.precommit_ratio,
brake_ratio: value.brake_ratio,
tx_num_limit: value.tx_num_limit,
max_tx_size: value.max_tx_size,
gas_limit: value.gas_limit,
interval: value.interval,
max_contract_limit: value.max_contract_limit,
}
}
}

impl From<metadata_abi::ConsensusConfig> for ConsensusConfig {
fn from(value: metadata_abi::ConsensusConfig) -> Self {
ConsensusConfig {
propose_ratio: value.propose_ratio,
prevote_ratio: value.prevote_ratio,
precommit_ratio: value.precommit_ratio,
brake_ratio: value.brake_ratio,
tx_num_limit: value.tx_num_limit,
max_tx_size: value.max_tx_size,
gas_limit: value.gas_limit,
interval: value.interval,
propose_ratio: value.propose_ratio,
prevote_ratio: value.prevote_ratio,
precommit_ratio: value.precommit_ratio,
brake_ratio: value.brake_ratio,
tx_num_limit: value.tx_num_limit,
max_tx_size: value.max_tx_size,
gas_limit: value.gas_limit,
interval: value.interval,
max_contract_limit: value.max_contract_limit,
}
}
}
Expand Down
7 changes: 4 additions & 3 deletions core/executor/src/system_contract/metadata/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ mod store;

pub use abi::metadata_abi;
pub use handle::MetadataHandle;
pub use store::MetadataStore;
pub use store::{encode_consensus_config, MetadataStore};

use std::{num::NonZeroUsize, sync::Arc};

Expand All @@ -32,7 +32,8 @@ const METADATA_CACHE_SIZE: NonZeroUsize = unsafe { NonZeroUsize::new_unchecked(1
lazy_static::lazy_static! {
pub static ref EPOCH_SEGMENT_KEY: H256 = Hasher::digest("epoch_segment");
static ref CKB_RELATED_INFO_KEY: H256 = Hasher::digest("ckb_related_info");
static ref HARDFORK_KEY: H256 = Hasher::digest("hardfork");
pub static ref CONSENSUS_CONFIG: H256 = Hasher::digest("consensus_config");
pub static ref HARDFORK_KEY: H256 = Hasher::digest("hardfork");
static ref HARDFORK_INFO: ArcSwap<H256> = ArcSwap::new(Arc::new(H256::zero()));
static ref METADATA_CACHE: RwLock<LruCache<Epoch, Metadata>> = RwLock::new(LruCache::new(METADATA_CACHE_SIZE));
}
Expand Down Expand Up @@ -97,7 +98,7 @@ impl<Adapter: ExecutorAdapter + ApplyBackend> SystemContract<Adapter>
}
metadata_abi::MetadataContractCalls::UpdateConsensusConfig(c) => {
exec_try!(
store.update_consensus_config(c.config),
store.update_consensus_config(c.config.into()),
gas_limit,
"[metadata] update consensus config"
);
Expand Down
102 changes: 87 additions & 15 deletions core/executor/src/system_contract/metadata/store.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
use std::collections::BTreeMap;
use std::sync::Arc;

use common_config_parser::types::spec::HardforkName;
use protocol::trie::Trie as _;
use protocol::types::{CkbRelatedInfo, HardforkInfo, HardforkInfoInner, Metadata, H160, H256};
use protocol::types::{
CkbRelatedInfo, ConsensusConfig, ConsensusConfigV0, HardforkInfo, HardforkInfoInner, Metadata,
MetadataInner, H160, H256,
};
use protocol::{codec::ProtocolCodec, ProtocolResult};

use crate::system_contract::metadata::{
segment::EpochSegment, CKB_RELATED_INFO_KEY, EPOCH_SEGMENT_KEY, HARDFORK_KEY,
segment::EpochSegment, CKB_RELATED_INFO_KEY, CONSENSUS_CONFIG, EPOCH_SEGMENT_KEY,
HARDFORK_INFO, HARDFORK_KEY,
};
use crate::system_contract::{error::SystemScriptError, METADATA_DB};
use crate::{adapter::RocksTrieDB, MPTTrie, CURRENT_METADATA_ROOT};

use super::metadata_abi::ConsensusConfig;

/// The metadata store does not follow the storage layout of EVM smart contract.
/// It use MPT called Metadata MPT with the following layout:
/// | key | value |
Expand Down Expand Up @@ -108,13 +111,18 @@ impl MetadataStore {

epoch_segment.append_endpoint(metadata.version.end)?;

let (inner, config) = metadata.into_part();
let current_hardfork = **HARDFORK_INFO.load();

self.trie.insert(
EPOCH_SEGMENT_KEY.as_bytes().to_vec(),
epoch_segment.as_bytes(),
)?;
self.trie
.insert(inner.epoch.to_be_bytes().to_vec(), inner.encode()?.to_vec())?;
self.trie.insert(
metadata.epoch.to_be_bytes().to_vec(),
metadata.encode()?.to_vec(),
CONSENSUS_CONFIG.as_bytes().to_vec(),
encode_consensus_config(current_hardfork, config.encode()?.to_vec()),
)?;
let new_root = self.trie.commit()?;
CURRENT_METADATA_ROOT.with(|r| *r.borrow_mut() = new_root);
Expand All @@ -127,7 +135,8 @@ impl MetadataStore {
block_number: u64,
proposer: &H160,
) -> ProtocolResult<()> {
let mut metadata = self.get_metadata_by_block_number(block_number)?;
let epoch = self.get_epoch_by_block_number(block_number)?;
let mut metadata = self.get_metadata_inner(epoch)?;
if let Some(counter) = metadata
.propose_counter
.iter_mut()
Expand All @@ -152,11 +161,26 @@ impl MetadataStore {
}

pub fn get_metadata(&self, epoch: u64) -> ProtocolResult<Metadata> {
let inner = self.get_metadata_inner(epoch)?;
let config = self.get_consensus_config()?;
Ok(Metadata::from_parts(inner, config))
}

fn get_metadata_inner(&self, epoch: u64) -> ProtocolResult<MetadataInner> {
let raw = self
.trie
.get(&epoch.to_be_bytes())?
.ok_or_else(|| SystemScriptError::MissingRecord(epoch))?;
Metadata::decode(raw)
MetadataInner::decode(raw)
}

fn get_consensus_config(&self) -> ProtocolResult<ConsensusConfig> {
let raw = self
.trie
.get(CONSENSUS_CONFIG.as_bytes())?
.expect("Inner panic with can't find consensus config");

decode_consensus_config(raw)
}

pub fn get_metadata_by_block_number(&self, block_number: u64) -> ProtocolResult<Metadata> {
Expand All @@ -173,14 +197,10 @@ impl MetadataStore {
}

pub fn update_consensus_config(&mut self, config: ConsensusConfig) -> ProtocolResult<()> {
let epoch_segment = self.get_epoch_segment()?;
let latest_epoch = epoch_segment.get_latest_epoch_number();
let mut metadata = self.get_metadata(latest_epoch)?;

metadata.consensus_config = config.into();
let current_hardfork = **HARDFORK_INFO.load();
self.trie.insert(
metadata.epoch.to_be_bytes().to_vec(),
metadata.encode()?.to_vec(),
CONSENSUS_CONFIG.as_bytes().to_vec(),
encode_consensus_config(current_hardfork, config.encode()?.to_vec()),
)?;
let new_root = self.trie.commit()?;
CURRENT_METADATA_ROOT.with(|r| *r.borrow_mut() = new_root);
Expand Down Expand Up @@ -244,3 +264,55 @@ impl MetadataStore {
}
}
}

#[derive(Debug)]
enum ConsensusConfigFlag {
V0 = 0b0,
V1 = 0b1,
}

impl From<u16> for ConsensusConfigFlag {
fn from(value: u16) -> Self {
match value {
0b0 => ConsensusConfigFlag::V0,
0b1 => ConsensusConfigFlag::V1,
_ => unreachable!(),
}
}
}

impl ConsensusConfigFlag {
fn new(flags: H256) -> Self {
let v1_name_flag = H256::from_low_u64_be((HardforkName::Andromeda as u64).to_be());
let res = flags & v1_name_flag;

if res & v1_name_flag == v1_name_flag {
ConsensusConfigFlag::V1
} else {
ConsensusConfigFlag::V0
}
}
}

fn decode_consensus_config(raw: Vec<u8>) -> ProtocolResult<ConsensusConfig> {
let raw_flag = {
let mut a = [0u8; 2];
a[0] = raw[0];
a[1] = raw[1];
a
};
let flag = ConsensusConfigFlag::from(u16::from_be_bytes(raw_flag));

match flag {
ConsensusConfigFlag::V0 => ConsensusConfigV0::decode(&raw[2..]).map(Into::into),
ConsensusConfigFlag::V1 => ConsensusConfig::decode(&raw[2..]),
}
}

pub fn encode_consensus_config(current_hardfork: H256, config: Vec<u8>) -> Vec<u8> {
let flag = ConsensusConfigFlag::new(current_hardfork);

let mut res = (flag as u16).to_be_bytes().to_vec();
res.extend(config);
res
}
17 changes: 9 additions & 8 deletions core/executor/src/tests/system_script/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,14 +184,15 @@ fn prepare_metadata() -> Metadata {
verifier_list: vec![prepare_validator()],
propose_counter: vec![],
consensus_config: ConsensusConfig {
gas_limit: 1u64,
interval: 0u64,
propose_ratio: 1u64,
prevote_ratio: 1u64,
precommit_ratio: 1u64,
brake_ratio: 1u64,
tx_num_limit: 1u64,
max_tx_size: 1u64,
gas_limit: 1u64,
interval: 0u64,
propose_ratio: 1u64,
prevote_ratio: 1u64,
precommit_ratio: 1u64,
brake_ratio: 1u64,
tx_num_limit: 1u64,
max_tx_size: 1u64,
max_contract_limit: 0x6000u64,
},
}
}
Expand Down
Loading

0 comments on commit 5e8a0e6

Please sign in to comment.