Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: new hardfork with ckb vm #1502

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions common/config-parser/src/types/spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,8 @@ pub enum HardforkName {
/// If this hardfork is activated, chain validators can modify the EVM
/// contract size limit.
Andromeda = 0b1,
/// Enable CKB hardfork 2023 with new VM
Antlia = 0b10,
}

impl HardforkName {
Expand Down
12 changes: 8 additions & 4 deletions core/executor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -408,10 +408,7 @@ impl AxonExecutor {
fn config(&self) -> Config {
let mut evm_config = Config::london();
let create_contract_limit = {
let latest_hardfork_info = &**HARDFORK_INFO.load();
let enable_contract_limit_flag =
H256::from_low_u64_be((HardforkName::Andromeda as u64).to_be());
if latest_hardfork_info & &enable_contract_limit_flag == enable_contract_limit_flag {
if enable_hardfork(HardforkName::Andromeda) {
let handle = MetadataHandle::new(CURRENT_METADATA_ROOT.with(|r| *r.borrow()));
let consensus_config = handle.get_consensus_config().unwrap();
Some(consensus_config.max_contract_limit as usize)
Expand Down Expand Up @@ -515,6 +512,13 @@ pub fn is_transaction_call(action: &TransactionAction, addr: &H160) -> bool {
action == &TransactionAction::Call(*addr)
}

pub fn enable_hardfork(name: HardforkName) -> bool {
let latest_hardfork_info = &**HARDFORK_INFO.load();
let enable_flag = H256::from_low_u64_be((name as u64).to_be());

latest_hardfork_info & &enable_flag == enable_flag
}

#[cfg(test)]
mod test {
use super::*;
Expand Down
11 changes: 9 additions & 2 deletions core/executor/src/precompiles/call_ckb_vm.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
use common_config_parser::types::spec::HardforkName;
use ethers::contract::{EthAbiCodec, EthAbiType};
use ethers::{abi::AbiDecode, core::types::Bytes as EthBytes};
use evm::executor::stack::{PrecompileFailure, PrecompileOutput};
use evm::{Context, ExitError, ExitSucceed};

use protocol::traits::Interoperation;
use protocol::types::{Bytes, H160};
use protocol::types::{Bytes, CKBVMVersion, H160};

use core_interoperation::{cycle_to_gas, gas_to_cycle, InteroperationImpl};

use crate::precompiles::{axon_precompile_address, PrecompileContract};
use crate::system_contract::{image_cell::image_cell_abi::OutPoint, DataProvider};
use crate::{err, CURRENT_HEADER_CELL_ROOT};
use crate::{enable_hardfork, err, CURRENT_HEADER_CELL_ROOT};

#[derive(Default, Clone)]
pub struct CallCkbVM;
Expand All @@ -27,12 +28,18 @@ impl PrecompileContract for CallCkbVM {
) -> Result<(PrecompileOutput, u64), PrecompileFailure> {
if let Some(gas) = gas_limit {
let (cell_dep, args) = parse_input(input)?;
let version = if enable_hardfork(HardforkName::Antlia) {
CKBVMVersion::V2023
} else {
CKBVMVersion::V2021
};
let res = <InteroperationImpl as Interoperation>::call_ckb_vm(
Default::default(),
&DataProvider::new(CURRENT_HEADER_CELL_ROOT.with(|r| *r.borrow())),
cell_dep.into(),
&args,
gas_to_cycle(gas),
version,
)
.map_err(|e| err!(_, e.to_string()))?;

Expand Down
11 changes: 9 additions & 2 deletions core/executor/src/precompiles/verify_by_ckb_vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ use evm::executor::stack::{PrecompileFailure, PrecompileOutput};
use evm::{Context, ExitError, ExitSucceed};

use protocol::traits::Interoperation;
use protocol::types::{SignatureR, SignatureS, H160, H256};
use protocol::types::{CKBVMVersion, SignatureR, SignatureS, H160, H256};

use common_config_parser::types::spec::HardforkName;
use core_interoperation::{cycle_to_gas, gas_to_cycle, InteroperationImpl};

use crate::precompiles::{axon_precompile_address, call_ckb_vm::CellDep, PrecompileContract};
use crate::system_contract::{image_cell::image_cell_abi::OutPoint, DataProvider};
use crate::{err, CURRENT_HEADER_CELL_ROOT};
use crate::{enable_hardfork, err, CURRENT_HEADER_CELL_ROOT};

#[derive(Default, Clone)]
pub struct CkbVM;
Expand All @@ -28,6 +29,11 @@ impl PrecompileContract for CkbVM {
let payload = parse_input(input)?;

if let Some(gas) = gas_limit {
let version = if enable_hardfork(HardforkName::Antlia) {
CKBVMVersion::V2023
} else {
CKBVMVersion::V2021
};
let res = InteroperationImpl::verify_by_ckb_vm(
Default::default(),
DataProvider::new(CURRENT_HEADER_CELL_ROOT.with(|r| *r.borrow())),
Expand All @@ -43,6 +49,7 @@ impl PrecompileContract for CkbVM {
),
None,
gas_to_cycle(gas),
version,
)
.map_err(|e| err!(_, e.to_string()))?;

Expand Down
50 changes: 34 additions & 16 deletions core/interoperation/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,19 @@ use ckb_script::{TransactionScriptsVerifier, TxVerifyEnv};
use ckb_traits::CellDataProvider;
use ckb_types::core::{Cycle, HeaderBuilder, TransactionView};
use ckb_types::{packed, prelude::Pack};
use ckb_vm::machine::{asm::AsmCoreMachine, DefaultMachineBuilder, SupportMachine, VERSION1};
use ckb_vm::{Error as VMError, ISA_B, ISA_IMC, ISA_MOP};
use ckb_vm::machine::{
asm::AsmCoreMachine, DefaultMachineBuilder, SupportMachine, VERSION1, VERSION2,
};
use ckb_vm::{Error as VMError, ISA_A, ISA_B, ISA_IMC, ISA_MOP};

use protocol::traits::{CkbDataProvider, Context, Interoperation};
use protocol::types::{Bytes, CellDep, CellWithData, OutPoint, VMResp};
use protocol::types::{Bytes, CKBVMVersion, CellDep, CellWithData, OutPoint, VMResp};
use protocol::{Display, ProtocolError, ProtocolErrorKind, ProtocolResult};

use crate::utils::resolve_transaction;

const ISA: u8 = ISA_IMC | ISA_B | ISA_MOP;
const ISA_2021: u8 = ISA_IMC | ISA_B | ISA_MOP;
const ISA_2023: u8 = ISA_IMC | ISA_B | ISA_MOP | ISA_A;
const GAS_TO_CYCLE_COEF: u64 = 6_000;

// The following information is from CKB block [10976708](https://explorer.nervos.org/block/10976708)
Expand Down Expand Up @@ -59,14 +62,18 @@ impl Interoperation for InteroperationImpl {
data_cell_dep: CellDep,
args: &[Bytes],
max_cycles: u64,
version: CKBVMVersion,
) -> ProtocolResult<VMResp> {
let data_cell_dep: packed::CellDep = (&data_cell_dep).into();
let program = data_loader
.get_cell_data(&data_cell_dep.out_point())
.ok_or_else(|| InteroperationError::GetProgram((&data_cell_dep.out_point()).into()))?;
let mut vm = ckb_vm::machine::asm::AsmMachine::new(
DefaultMachineBuilder::new(AsmCoreMachine::new(ISA, VERSION1, max_cycles)).build(),
);
let core = match version {
CKBVMVersion::V2021 => AsmCoreMachine::new(ISA_2021, VERSION1, max_cycles),
CKBVMVersion::V2023 => AsmCoreMachine::new(ISA_2023, VERSION2, max_cycles),
};
let mut vm =
ckb_vm::machine::asm::AsmMachine::new(DefaultMachineBuilder::new(core).build());
let _ = vm
.load_program(&program, args)
.map_err(InteroperationError::CkbVM)?;
Expand All @@ -85,6 +92,7 @@ impl Interoperation for InteroperationImpl {
mocked_tx: &TransactionView,
dummy_input: Option<CellWithData>,
max_cycles: u64,
version: CKBVMVersion,
) -> ProtocolResult<Cycle> {
let rtx = Arc::new(resolve_transaction(&data_loader, mocked_tx, dummy_input)?);
log::debug!("[mempool]: Verify by ckb vm tx {:?}", rtx);
Expand All @@ -93,15 +101,25 @@ impl Interoperation for InteroperationImpl {
// syscalls3 are enabled. Due to only the hardfork field in consensus and the
// epoch field in tx_env is used, the provided arguments only need to fill these
// fields correctly.
let (ckb_spec, ckb2023_disabled_env) = (
Arc::new(Consensus::default()),
Arc::new(TxVerifyEnv::new_commit(
&HeaderBuilder::default()
.number(CKB2023_DISABLED_NUMBER.pack())
.epoch(CKB2023_DISABLED_EPOCH.pack())
.build(),
)),
);
let (ckb_spec, ckb2023_disabled_env) = {
let env = match version {
CKBVMVersion::V2021 => TxVerifyEnv::new_commit(
&HeaderBuilder::default()
.number(CKB2023_DISABLED_NUMBER.pack())
.epoch(CKB2023_DISABLED_EPOCH.pack())
.build(),
),
// TODO: Determine 2023 activation time
CKBVMVersion::V2023 => TxVerifyEnv::new_commit(
&HeaderBuilder::default()
.number(CKB2023_DISABLED_NUMBER.pack())
.epoch(CKB2023_DISABLED_EPOCH.pack())
.build(),
),
};

(Arc::new(Consensus::default()), Arc::new(env))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consensus includes hardfork_switch so it should be different depending on hardfork?

Copy link
Contributor Author

@driftluo driftluo Oct 26, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't this depend on both consensus.hardfork_switch() and tx_env?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consensus.hardfork_switch() confirms the activated epoch, this is a fixed value
tx_env confirms the epoch the transaction is in. It belongs to the new environment if it is greater than the epoch in hardfork_switch.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK this works because Consensus::default() uses mirana hardfork switches. But it's kind of undocumented. I'm not sure whether it'll change in later versions of ckb.

};

TransactionScriptsVerifier::new(rtx, data_loader, ckb_spec, ckb2023_disabled_env)
.verify(max_cycles)
Expand Down
15 changes: 12 additions & 3 deletions core/mempool/src/adapter/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,20 @@ use protocol::traits::{
TrustFeedback,
};
use protocol::types::{
recover_intact_pub_key, Backend, BatchSignedTxs, CellDepWithPubKey, Hash, MerkleRoot,
SignatureR, SignatureS, SignedTransaction, H160, U256,
recover_intact_pub_key, Backend, BatchSignedTxs, CKBVMVersion, CellDepWithPubKey, Hash,
MerkleRoot, SignatureR, SignatureS, SignedTransaction, H160, U256,
};
use protocol::{
async_trait, codec::ProtocolCodec, tokio, trie, Display, ProtocolError, ProtocolErrorKind,
ProtocolResult,
};

use common_apm_derive::trace_span;
use common_config_parser::types::spec::HardforkName;
use common_crypto::{Crypto, Secp256k1Recoverable};
use core_executor::{
is_call_system_script, AxonExecutorReadOnlyAdapter, DataProvider, MetadataHandle,
enable_hardfork, is_call_system_script, AxonExecutorReadOnlyAdapter, DataProvider,
MetadataHandle,
};
use core_interoperation::InteroperationImpl;

Expand Down Expand Up @@ -288,6 +290,11 @@ where
}

let root = self.executor_backend(ctx).await?.get_image_cell_root();
let version = if enable_hardfork(HardforkName::Antlia) {
CKBVMVersion::V2023
} else {
CKBVMVersion::V2021
};

// Verify interoperation signature
match signature.r[0] {
Expand All @@ -302,6 +309,7 @@ where
r.cell_dep,
&[r.pub_key, signature.s],
u64::MAX,
version,
)
.map_err(|e| AdapterError::VerifySignature(e.to_string()))?;
}
Expand All @@ -327,6 +335,7 @@ where
),
r.dummy_input(),
MAX_VERIFY_CKB_VM_CYCLES,
version,
)
.map_err(|e| AdapterError::VerifySignature(e.to_string()))?;
}
Expand Down
4 changes: 3 additions & 1 deletion protocol/src/traits/interoperation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use ckb_traits::{CellDataProvider, ExtensionProvider, HeaderProvider};
use ckb_types::core::{cell::CellProvider, Cycle, TransactionView};
use ckb_types::{packed, prelude::*};

use crate::types::{Bytes, CellDep, CellWithData, SignatureR, SignatureS, VMResp};
use crate::types::{Bytes, CKBVMVersion, CellDep, CellWithData, SignatureR, SignatureS, VMResp};
use crate::{lazy::DUMMY_INPUT_OUT_POINT, traits::Context, ProtocolResult};

pub const BYTE_SHANNONS: u64 = 100_000_000;
Expand Down Expand Up @@ -36,6 +36,7 @@ pub trait Interoperation: Sync + Send {
data_cell_dep: CellDep,
args: &[Bytes],
max_cycles: u64,
vesion: CKBVMVersion,
) -> ProtocolResult<VMResp>;

fn verify_by_ckb_vm<DL: CkbDataProvider + Sync + Send + 'static>(
Expand All @@ -44,6 +45,7 @@ pub trait Interoperation: Sync + Send {
mocked_tx: &TransactionView,
dummy_input: Option<CellWithData>,
max_cycles: u64,
vesion: CKBVMVersion,
) -> ProtocolResult<Cycle>;

/// The function construct the `TransactionView` payload required by
Expand Down
5 changes: 5 additions & 0 deletions protocol/src/types/interoperation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,11 @@ impl SignatureR {
}
}

pub enum CKBVMVersion {
V2021,
V2023,
}

#[derive(RlpEncodable, RlpDecodable, Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
pub struct CKBTxMockByRef {
pub cell_deps: Vec<CellDep>,
Expand Down
Loading