From befcbb92fd06c9c8c8f979f45e6fee515018e92c Mon Sep 17 00:00:00 2001 From: Eason <kaoimin@qq.com> Date: Thu, 9 Nov 2023 10:09:20 +0800 Subject: [PATCH] refactor: remove the verify by ckb vm verification --- core/executor/src/precompiles/mod.rs | 1 - .../src/precompiles/verify_by_ckb_vm.rs | 140 -------- core/interoperation/src/lib.rs | 51 +-- core/interoperation/src/utils.rs | 82 ----- core/mempool/src/adapter/mod.rs | 55 +-- core/mempool/src/lib.rs | 10 +- protocol/src/codec/transaction.rs | 43 +-- protocol/src/traits/interoperation.rs | 102 +----- protocol/src/types/interoperation.rs | 316 +----------------- 9 files changed, 22 insertions(+), 778 deletions(-) delete mode 100644 core/executor/src/precompiles/verify_by_ckb_vm.rs delete mode 100644 core/interoperation/src/utils.rs diff --git a/core/executor/src/precompiles/mod.rs b/core/executor/src/precompiles/mod.rs index beedf1fa2..7c2590eea 100644 --- a/core/executor/src/precompiles/mod.rs +++ b/core/executor/src/precompiles/mod.rs @@ -15,7 +15,6 @@ mod sha256; #[cfg(test)] mod tests; -mod verify_by_ckb_vm; use std::collections::BTreeMap; diff --git a/core/executor/src/precompiles/verify_by_ckb_vm.rs b/core/executor/src/precompiles/verify_by_ckb_vm.rs deleted file mode 100644 index d2ccc31ca..000000000 --- a/core/executor/src/precompiles/verify_by_ckb_vm.rs +++ /dev/null @@ -1,140 +0,0 @@ -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::{SignatureR, SignatureS, H160, H256}; - -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}; - -#[derive(Default, Clone)] -pub struct CkbVM; - -impl PrecompileContract for CkbVM { - const ADDRESS: H160 = axon_precompile_address(0x05); - const MIN_GAS: u64 = 500; - - fn exec_fn( - input: &[u8], - gas_limit: Option<u64>, - _context: &Context, - _is_static: bool, - ) -> Result<(PrecompileOutput, u64), PrecompileFailure> { - let payload = parse_input(input)?; - - if let Some(gas) = gas_limit { - let res = InteroperationImpl::verify_by_ckb_vm( - Default::default(), - DataProvider::new(CURRENT_HEADER_CELL_ROOT.with(|r| *r.borrow())), - &InteroperationImpl::dummy_transaction( - SignatureR::new_by_ref( - payload.cell_deps(), - payload.header_deps(), - payload.inputs(), - Default::default(), - ), - SignatureS::new(payload.witnesses()), - None, - ), - None, - gas_to_cycle(gas), - ) - .map_err(|e| err!(_, e.to_string()))?; - - return Ok(( - PrecompileOutput { - exit_status: ExitSucceed::Returned, - output: res.to_le_bytes().to_vec(), - }, - cycle_to_gas(res).max(Self::MIN_GAS), - )); - } - - err!() - } - - fn gas_cost(_input: &[u8]) -> u64 { - unreachable!() - } -} - -fn parse_input(input: &[u8]) -> Result<VerifyByCkbPayload, PrecompileFailure> { - <VerifyByCkbPayload as AbiDecode>::decode(input).map_err(|_| err!(_, "decode input")) -} - -#[derive(EthAbiType, EthAbiCodec, Clone, Default, Debug, PartialEq, Eq)] -pub struct VerifyByCkbPayload { - pub cell_deps: Vec<CellDep>, - pub header_deps: Vec<[u8; 32]>, - pub inputs: Vec<OutPoint>, - pub witnesses: Vec<WitnessArgs>, -} - -impl VerifyByCkbPayload { - pub fn cell_deps(&self) -> Vec<protocol::types::CellDep> { - self.cell_deps - .iter() - .map(|c| protocol::types::CellDep { - tx_hash: c.out_point.tx_hash.into(), - index: c.out_point.index, - dep_type: c.dep_type, - }) - .collect() - } - - pub fn header_deps(&self) -> Vec<H256> { - self.header_deps.iter().map(Into::into).collect() - } - - pub fn inputs(&self) -> Vec<protocol::types::OutPoint> { - self.inputs - .iter() - .map(|i| protocol::types::OutPoint { - tx_hash: i.tx_hash.into(), - index: i.index, - }) - .collect() - } - - pub fn witnesses(&self) -> Vec<protocol::types::Witness> { - self.witnesses.clone().into_iter().map(Into::into).collect() - } -} - -#[derive(EthAbiType, EthAbiCodec, Clone, Default, Debug, PartialEq, Eq)] -pub struct WitnessArgs { - pub lock: EthBytes, - pub input_type: EthBytes, - pub output_type: EthBytes, -} - -impl From<WitnessArgs> for protocol::types::Witness { - fn from(w: WitnessArgs) -> Self { - let lock = if w.lock.is_empty() { - None - } else { - Some(w.lock.0) - }; - let input_type = if w.input_type.is_empty() { - None - } else { - Some(w.input_type.0) - }; - let output_type = if w.output_type.is_empty() { - None - } else { - Some(w.output_type.0) - }; - - protocol::types::Witness { - lock, - input_type, - output_type, - } - } -} diff --git a/core/interoperation/src/lib.rs b/core/interoperation/src/lib.rs index fe3256327..826726821 100644 --- a/core/interoperation/src/lib.rs +++ b/core/interoperation/src/lib.rs @@ -1,29 +1,17 @@ -pub mod utils; +use std::error::Error; -use std::{error::Error, sync::Arc}; - -use ckb_chain_spec::consensus::Consensus; -use ckb_script::{TransactionScriptsVerifier, TxVerifyEnv}; use ckb_traits::CellDataProvider; -use ckb_types::core::{Cycle, HeaderBuilder, TransactionView}; -use ckb_types::{packed, prelude::Pack}; +use ckb_types::packed; use ckb_vm::machine::{asm::AsmCoreMachine, DefaultMachineBuilder, SupportMachine, VERSION1}; use ckb_vm::{Error as VMError, ISA_B, ISA_IMC, ISA_MOP}; -use protocol::traits::{CkbDataProvider, Context, Interoperation}; -use protocol::types::{Bytes, CellDep, CellWithData, OutPoint, VMResp}; +use protocol::traits::{Context, Interoperation}; +use protocol::types::{Bytes, CellDep, OutPoint, VMResp}; use protocol::{Display, ProtocolError, ProtocolErrorKind, ProtocolResult}; -use crate::utils::resolve_transaction; - const ISA: u8 = ISA_IMC | ISA_B | ISA_MOP; const GAS_TO_CYCLE_COEF: u64 = 6_000; -// The following information is from CKB block [10976708](https://explorer.nervos.org/block/10976708) -// which is CKB2023 disabled. -const CKB2023_DISABLED_NUMBER: u64 = 10_976_708; -const CKB2023_DISABLED_EPOCH: u64 = 0x53c007f0020c8; - pub const fn gas_to_cycle(gas: u64) -> u64 { gas * GAS_TO_CYCLE_COEF } @@ -76,37 +64,6 @@ impl Interoperation for InteroperationImpl { cycles: vm.machine.cycles(), }) } - - /// Todo: After CKB2023 is enabled, a hardfork is needed to support the new - /// VM version and syscalls. - fn verify_by_ckb_vm<DL: CkbDataProvider + Sync + Send + 'static>( - _ctx: Context, - data_loader: DL, - mocked_tx: &TransactionView, - dummy_input: Option<CellWithData>, - max_cycles: u64, - ) -> ProtocolResult<Cycle> { - let rtx = Arc::new(resolve_transaction(&data_loader, mocked_tx, dummy_input)?); - log::debug!("[mempool]: Verify by ckb vm tx {:?}", rtx); - - // The consensus and tx_env arguments are used for judge if the VM version2 and - // 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(), - )), - ); - - TransactionScriptsVerifier::new(rtx, data_loader, ckb_spec, ckb2023_disabled_env) - .verify(max_cycles) - .map_err(|e| InteroperationError::Ckb(e).into()) - } } #[derive(Debug, Display)] diff --git a/core/interoperation/src/utils.rs b/core/interoperation/src/utils.rs deleted file mode 100644 index 557f3c3a3..000000000 --- a/core/interoperation/src/utils.rs +++ /dev/null @@ -1,82 +0,0 @@ -use ckb_types::core::cell::{CellMeta, CellProvider, CellStatus, ResolvedTransaction}; -use ckb_types::core::{DepType, TransactionView}; -use ckb_types::{packed, prelude::*}; - -use protocol::{lazy::DUMMY_INPUT_OUT_POINT, types::CellWithData, ProtocolResult}; - -use crate::InteroperationError; - -pub fn resolve_transaction<CL: CellProvider>( - cell_loader: &CL, - tx: &TransactionView, - dummy_input: Option<CellWithData>, -) -> ProtocolResult<ResolvedTransaction> { - let resolve_cell = |out_point: &packed::OutPoint| -> ProtocolResult<CellMeta> { - match cell_loader.cell(out_point, true) { - CellStatus::Live(meta) => Ok(meta), - _ => Err(InteroperationError::GetUnknownCell(out_point.into()).into()), - } - }; - - let (mut resolved_inputs, mut resolved_cell_deps, mut resolved_dep_groups) = ( - Vec::with_capacity(tx.inputs().len()), - Vec::with_capacity(tx.cell_deps().len()), - Vec::with_capacity(tx.cell_deps().len()), - ); - - for outpoint in tx.input_pts_iter() { - if is_dummy_out_point(&outpoint) { - if let Some(ref cell) = dummy_input { - resolved_inputs.push(cell.into()); - } else { - return Err(InteroperationError::InvalidDummyInput.into()); - } - } else { - resolved_inputs.push(resolve_cell(&outpoint)?); - } - } - - for cell_dep in tx.cell_deps_iter() { - if cell_dep.dep_type() == DepType::DepGroup.into() { - let dep_group = resolve_cell(&cell_dep.out_point())?; - let data = dep_group.mem_cell_data.as_ref().unwrap(); - let sub_out_points = - parse_dep_group_data(data).map_err(InteroperationError::InvalidDepGroup)?; - - for sub_out_point in sub_out_points.into_iter() { - resolved_cell_deps.push(resolve_cell(&sub_out_point)?); - } - resolved_dep_groups.push(dep_group); - } else { - resolved_cell_deps.push(resolve_cell(&cell_dep.out_point())?); - } - } - - Ok(ResolvedTransaction { - transaction: tx.clone(), - resolved_cell_deps, - resolved_inputs, - resolved_dep_groups, - }) -} - -pub fn parse_dep_group_data(slice: &[u8]) -> Result<packed::OutPointVec, String> { - if slice.is_empty() { - Err("data is empty".to_owned()) - } else { - match packed::OutPointVec::from_slice(slice) { - Ok(v) => { - if v.is_empty() { - Err("dep group is empty".to_owned()) - } else { - Ok(v) - } - } - Err(err) => Err(err.to_string()), - } - } -} - -pub fn is_dummy_out_point(out_point: &packed::OutPoint) -> bool { - *out_point == *DUMMY_INPUT_OUT_POINT -} diff --git a/core/mempool/src/adapter/mod.rs b/core/mempool/src/adapter/mod.rs index f701e7466..26c871815 100644 --- a/core/mempool/src/adapter/mod.rs +++ b/core/mempool/src/adapter/mod.rs @@ -17,7 +17,7 @@ use protocol::traits::{ }; use protocol::types::{ recover_intact_pub_key, Backend, BatchSignedTxs, CellDepWithPubKey, Hash, MerkleRoot, - SignatureR, SignatureS, SignedTransaction, H160, U256, + SignedTransaction, H160, U256, }; use protocol::{ async_trait, codec::ProtocolCodec, tokio, trie, Display, ProtocolError, ProtocolErrorKind, @@ -35,8 +35,6 @@ use crate::adapter::message::{MsgPullTxs, END_GOSSIP_NEW_TXS, RPC_PULL_TXS}; use crate::context::TxContext; use crate::MemPoolError; -const MAX_VERIFY_CKB_VM_CYCLES: u64 = 50_000_000; - struct IntervalTxsBroadcaster; impl IntervalTxsBroadcaster { @@ -289,48 +287,17 @@ where let root = self.executor_backend(ctx).await?.get_image_cell_root(); - // Verify interoperation signature - match signature.r[0] { - 0u8 => { - // Call CKB-VM mode - let r = rlp::decode::<CellDepWithPubKey>(&signature.r[1..]) - .map_err(AdapterError::Rlp)?; - - InteroperationImpl::call_ckb_vm( - Default::default(), - &DataProvider::new(root), - r.cell_dep, - &[r.pub_key, signature.s], - u64::MAX, - ) - .map_err(|e| AdapterError::VerifySignature(e.to_string()))?; - } - _ => { - // Verify by mock transaction mode - let r = SignatureR::decode(&signature.r)?; - let s = SignatureS::decode(&signature.s)?; - - if r.inputs_len() != s.witnesses.len() { - return Err(AdapterError::VerifySignature( - "signature item mismatch".to_string(), - ) - .into()); - } + // Verify interoperation signature call CKB-VM mode + let r = rlp::decode::<CellDepWithPubKey>(&signature.r[1..]).map_err(AdapterError::Rlp)?; + InteroperationImpl::call_ckb_vm( + Default::default(), + &DataProvider::new(root), + r.cell_dep, + &[r.pub_key, signature.s], + u64::MAX, + ) + .map_err(|e| AdapterError::VerifySignature(e.to_string()))?; - InteroperationImpl::verify_by_ckb_vm( - Default::default(), - DataProvider::new(root), - &InteroperationImpl::dummy_transaction( - r.clone(), - s, - Some(stx.transaction.signature_hash(true).0), - ), - r.dummy_input(), - MAX_VERIFY_CKB_VM_CYCLES, - ) - .map_err(|e| AdapterError::VerifySignature(e.to_string()))?; - } - } Ok(()) } diff --git a/core/mempool/src/lib.rs b/core/mempool/src/lib.rs index b87386d8d..819056e9a 100644 --- a/core/mempool/src/lib.rs +++ b/core/mempool/src/lib.rs @@ -20,9 +20,7 @@ use futures::future::try_join_all; use common_apm::Instant; use protocol::traits::{Context, MemPool, MemPoolAdapter}; -use protocol::types::{ - AddressSource, BlockNumber, Hash, PackedTxHashes, SignedTransaction, H160, H256, U256, -}; +use protocol::types::{BlockNumber, Hash, PackedTxHashes, SignedTransaction, H160, H256, U256}; use protocol::{async_trait, tokio, Display, ProtocolError, ProtocolErrorKind, ProtocolResult}; use core_executor::is_call_system_script; @@ -451,12 +449,6 @@ pub enum MemPoolError { #[display(fmt = "Encode transaction to JSON failed")] EncodeJson, - #[display(fmt = "Invalid address source {:?}", _0)] - InvalidAddressSource(AddressSource), - - #[display(fmt = "Invalid dummy input")] - InvalidDummyInput, - #[display(fmt = "Invalid sender, expect: {:?}, get: {:?}", expect, actual)] InvalidSender { expect: H160, actual: H160 }, } diff --git a/protocol/src/codec/transaction.rs b/protocol/src/codec/transaction.rs index 5b5537d1b..9659b5a5d 100644 --- a/protocol/src/codec/transaction.rs +++ b/protocol/src/codec/transaction.rs @@ -370,10 +370,7 @@ mod tests { use common_crypto::secp256k1_recover; use crate::codec::hex_decode; - use crate::types::{ - AddressSource, Bytes, CKBTxMockByRefAndOneInput, CellDep, CellWithData, Public, Script, - SignatureR, SignatureS, Witness, H160, H256, U256, - }; + use crate::types::{Public, SignatureS, Witness, H160, U256}; #[test] fn test_legacy_decode() { @@ -616,44 +613,6 @@ mod tests { assert!(!utx.signature.as_ref().unwrap().is_eth_sig()); } - #[test] - fn test_signature_r_codec() { - let cell_dep = CellDep { - tx_hash: H256::from_slice(&[ - 243, 81, 120, 199, 161, 165, 164, 229, 177, 100, 21, 122, 165, 73, 164, 147, 206, - 188, 154, 48, 121, 182, 169, 237, 231, 174, 82, 7, 173, 179, 244, 212, - ]), - index: 0, - dep_type: 1, - }; - let cell_with_data = CellWithData { - type_script: None, - lock_script: Script { - code_hash: H256::from_slice(&[ - 210, 55, 97, 179, 100, 33, 7, 53, 193, 156, 96, 86, 29, 33, 63, 179, 190, 174, - 47, 214, 23, 39, 67, 113, 158, 255, 105, 32, 224, 32, 186, 172, - ]), - args: vec![ - 0, 1, 96, 145, 217, 61, 186, 177, 47, 22, 100, 15, 179, 160, 168, 241, 231, - 126, 3, 251, 197, 28, - ] - .into(), - hash_type: 1, - }, - data: Bytes::new(), - }; - let address_source = AddressSource { index: 0, type_: 0 }; - - let sig_r = SignatureR::ByRefAndOneInput(CKBTxMockByRefAndOneInput { - cell_deps: vec![cell_dep], - header_deps: vec![], - input_cell_with_data: cell_with_data, - out_point_addr_source: address_source, - }); - - assert_eq!(SignatureR::decode(&sig_r.encode()).unwrap(), sig_r); - } - #[test] fn test_signature_s_codec() { let witness = Witness { diff --git a/protocol/src/traits/interoperation.rs b/protocol/src/traits/interoperation.rs index 72b38d151..15409999f 100644 --- a/protocol/src/traits/interoperation.rs +++ b/protocol/src/traits/interoperation.rs @@ -1,9 +1,8 @@ use ckb_traits::{CellDataProvider, ExtensionProvider, HeaderProvider}; -use ckb_types::core::{cell::CellProvider, Cycle, TransactionView}; -use ckb_types::{packed, prelude::*}; +use ckb_types::core::cell::CellProvider; -use crate::types::{Bytes, CellDep, CellWithData, SignatureR, SignatureS, VMResp}; -use crate::{lazy::DUMMY_INPUT_OUT_POINT, traits::Context, ProtocolResult}; +use crate::types::{Bytes, CellDep, VMResp}; +use crate::{traits::Context, ProtocolResult}; pub const BYTE_SHANNONS: u64 = 100_000_000; pub const SIGNATURE_HASH_CELL_OCCUPIED_CAPACITY: u64 = signature_hash_cell_bytes() * BYTE_SHANNONS; @@ -37,99 +36,4 @@ pub trait Interoperation: Sync + Send { args: &[Bytes], max_cycles: u64, ) -> ProtocolResult<VMResp>; - - fn verify_by_ckb_vm<DL: CkbDataProvider + Sync + Send + 'static>( - ctx: Context, - data_loader: DL, - mocked_tx: &TransactionView, - dummy_input: Option<CellWithData>, - max_cycles: u64, - ) -> ProtocolResult<Cycle>; - - /// The function construct the `TransactionView` payload required by - /// `verify_by_ckb_vm()`. - fn dummy_transaction( - r: SignatureR, - s: SignatureS, - signature_hash: Option<[u8; 32]>, - ) -> TransactionView { - let cell_deps = r.cell_deps(); - let header_deps = r.header_deps(); - let signature_hash = signature_hash.map(|hash| hash.to_vec()).unwrap_or_default(); - - let tx_builder = TransactionView::new_advanced_builder() - .cell_deps(cell_deps.iter().map(Into::into)) - .header_deps(header_deps.iter().map(|dep| dep.0.pack())) - .witnesses(s.witnesses.iter().map(|i| { - packed::WitnessArgsBuilder::default() - .input_type( - packed::BytesOptBuilder::default() - .set(i.input_type.clone().map(|inner| inner.pack())) - .build(), - ) - .output_type( - packed::BytesOptBuilder::default() - .set(i.output_type.clone().map(|inner| inner.pack())) - .build(), - ) - .lock( - packed::BytesOptBuilder::default() - .set(i.lock.clone().map(|inner| inner.pack())) - .build(), - ) - .build() - .as_bytes() - .pack() - })); - - if r.is_only_by_ref() { - return tx_builder - .inputs(r.out_points().iter().map(|i| { - packed::CellInput::new( - packed::OutPointBuilder::default() - .tx_hash(i.tx_hash.0.pack()) - .index(i.index.pack()) - .build(), - 0u64, - ) - })) - .output( - packed::CellOutputBuilder::default() - .capacity(SIGNATURE_HASH_CELL_OCCUPIED_CAPACITY.pack()) - .build(), - ) - .output_data(signature_hash.pack()) - .build(); - } - - let output_capacity = (r.dummy_input().unwrap().capacity() - BYTE_SHANNONS) - .max(SIGNATURE_HASH_CELL_OCCUPIED_CAPACITY); - - tx_builder - .input(packed::CellInput::new(DUMMY_INPUT_OUT_POINT.clone(), 0u64)) - .output( - packed::CellOutputBuilder::default() - .capacity(output_capacity.pack()) - .build(), - ) - .output_data(signature_hash.pack()) - .build() - } -} - -#[cfg(test)] -mod tests { - use super::*; - use ckb_types::core::Capacity; - - #[test] - fn test_const_signature_hash_cell_bytes() { - let data_capacity = Capacity::bytes(32).unwrap(); - let actual = packed::CellOutputBuilder::default() - .build() - .occupied_capacity(data_capacity) - .unwrap() - .as_u64(); - assert_eq!(SIGNATURE_HASH_CELL_OCCUPIED_CAPACITY, actual); - } } diff --git a/protocol/src/types/interoperation.rs b/protocol/src/types/interoperation.rs index 4c5f5c84c..8524f5fda 100644 --- a/protocol/src/types/interoperation.rs +++ b/protocol/src/types/interoperation.rs @@ -1,13 +1,9 @@ -use ckb_types::{core::cell::CellMeta, packed, prelude::*}; +use ckb_types::{packed, prelude::*}; use derive_more::Display; use rlp_derive::{RlpDecodable, RlpEncodable}; use serde::{Deserialize, Serialize}; -use crate::traits::{BYTE_SHANNONS, SIGNATURE_HASH_CELL_OCCUPIED_CAPACITY}; -use crate::types::{Bytes, TypesError, H256}; -use crate::{ckb_blake2b_256, codec::ProtocolCodec, lazy::DUMMY_INPUT_OUT_POINT, ProtocolResult}; - -const CAPACITY_BYTES_LEN: usize = 8; +use crate::types::{Bytes, H256}; #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] pub struct VMResp { @@ -15,143 +11,6 @@ pub struct VMResp { pub cycles: u64, } -/// The address mapping for calculate an Axon address by the input cell, which -/// is `keccak(input[index].content).into()`. The `type_` field means the type -/// of content to calculate hash with the following rules: -/// `0u8`: use lock script hash. -/// `1u8`: use type script hash. -/// So that the default value of `AddressSource` means using -/// `blake2b_256(input[0].lock().as_bytes())` as `keccak()` input. -#[derive( - RlpEncodable, RlpDecodable, Serialize, Deserialize, Default, Clone, Copy, Debug, PartialEq, Eq, -)] -pub struct AddressSource { - pub type_: u8, - pub index: u32, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum SignatureR { - ByRef(CKBTxMockByRef), - ByRefAndOneInput(CKBTxMockByRefAndOneInput), -} - -impl SignatureR { - pub fn new_by_ref( - cell_deps: Vec<CellDep>, - header_deps: Vec<H256>, - out_points: Vec<OutPoint>, - out_point_addr_source: AddressSource, - ) -> Self { - SignatureR::ByRef(CKBTxMockByRef { - cell_deps, - header_deps, - out_points, - out_point_addr_source, - }) - } - - pub fn decode(data: &[u8]) -> ProtocolResult<Self> { - if data.is_empty() { - return Err(TypesError::SignatureRIsEmpty.into()); - } - - let ret = match data[0] { - 1u8 => SignatureR::ByRef(CKBTxMockByRef::decode(&data[1..])?), - 2u8 => SignatureR::ByRefAndOneInput(CKBTxMockByRefAndOneInput::decode(&data[1..])?), - _ => return Err(TypesError::InvalidSignatureRType.into()), - }; - - if ret.address_source().type_ > 1 { - return Err(TypesError::InvalidAddressSourceType.into()); - } - - Ok(ret) - } - - pub fn inputs_len(&self) -> usize { - match self { - SignatureR::ByRef(i) => i.out_points.len(), - SignatureR::ByRefAndOneInput(_) => 1usize, - } - } - - pub fn address_source(&self) -> AddressSource { - match self { - SignatureR::ByRef(i) => i.out_point_addr_source, - SignatureR::ByRefAndOneInput(i) => i.out_point_addr_source, - } - } - - pub fn cell_deps(&self) -> &[CellDep] { - match self { - SignatureR::ByRef(i) => &i.cell_deps, - SignatureR::ByRefAndOneInput(i) => &i.cell_deps, - } - } - - pub fn header_deps(&self) -> &[H256] { - match self { - SignatureR::ByRef(i) => &i.header_deps, - SignatureR::ByRefAndOneInput(i) => &i.header_deps, - } - } - - pub(crate) fn out_points(&self) -> &[OutPoint] { - match self { - SignatureR::ByRef(i) => &i.out_points, - _ => unreachable!(), - } - } - - pub fn dummy_input(&self) -> Option<CellWithData> { - match self { - SignatureR::ByRefAndOneInput(i) => Some(i.input_cell_with_data.clone()), - SignatureR::ByRef(_) => None, - } - } - - pub fn is_only_by_ref(&self) -> bool { - match self { - SignatureR::ByRef(_) => true, - SignatureR::ByRefAndOneInput(_) => false, - } - } - - #[cfg(test)] - pub(crate) fn encode(&self) -> Bytes { - match self { - SignatureR::ByRef(r) => { - let mut ret = vec![1]; - ret.extend_from_slice(&rlp::encode(r)); - ret - } - SignatureR::ByRefAndOneInput(r) => { - let mut ret = vec![2]; - ret.extend_from_slice(&rlp::encode(r)); - ret - } - } - .into() - } -} - -#[derive(RlpEncodable, RlpDecodable, Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] -pub struct CKBTxMockByRef { - pub cell_deps: Vec<CellDep>, - pub header_deps: Vec<H256>, - pub out_points: Vec<OutPoint>, - pub out_point_addr_source: AddressSource, -} - -#[derive(RlpEncodable, RlpDecodable, Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] -pub struct CKBTxMockByRefAndOneInput { - pub cell_deps: Vec<CellDep>, - pub header_deps: Vec<H256>, - pub input_cell_with_data: CellWithData, - pub out_point_addr_source: AddressSource, -} - #[derive(RlpEncodable, RlpDecodable, Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] pub struct CellWithData { pub type_script: Option<Script>, @@ -159,54 +18,6 @@ pub struct CellWithData { pub data: Bytes, } -impl From<&CellWithData> for CellMeta { - fn from(cell: &CellWithData) -> Self { - let necessary_capacity = - (SIGNATURE_HASH_CELL_OCCUPIED_CAPACITY + BYTE_SHANNONS).max(cell.capacity()); - - CellMeta { - cell_output: packed::CellOutputBuilder::default() - .lock(cell.lock_script()) - .type_(cell.type_script()) - .capacity(necessary_capacity.pack()) - .build(), - out_point: DUMMY_INPUT_OUT_POINT.clone(), - transaction_info: None, - data_bytes: cell.data.len() as u64, - mem_cell_data_hash: Some(ckb_blake2b_256(&cell.data).pack()), - mem_cell_data: Some(cell.data.clone()), - } - } -} - -impl CellWithData { - pub fn capacity(&self) -> u64 { - let capacity = self.type_script.as_ref().map(|s| s.len()).unwrap_or(0) - + self.lock_script.len() - + self.data.len() - + CAPACITY_BYTES_LEN; - (capacity as u64) * BYTE_SHANNONS - } - - pub fn lock_script(&self) -> packed::Script { - (&self.lock_script).into() - } - - pub fn type_script(&self) -> packed::ScriptOpt { - self.type_script.as_ref().map(packed::Script::from).pack() - } - - pub fn lock_script_hash(&self) -> [u8; 32] { - ckb_hash::blake2b_256(self.lock_script().as_slice()) - } - - pub fn type_script_hash(&self) -> Option<[u8; 32]> { - self.type_script() - .to_opt() - .map(|s| ckb_hash::blake2b_256(s.as_slice())) - } -} - #[derive(RlpEncodable, RlpDecodable, Serialize, Deserialize, Clone, Debug, PartialEq, Eq)] pub struct Script { pub code_hash: H256, @@ -293,126 +104,3 @@ impl From<&CellDep> for packed::CellDep { .build() } } - -#[cfg(test)] -mod tests { - use super::*; - use rand::random; - - fn random_out_point() -> OutPoint { - OutPoint { - tx_hash: H256::random(), - index: 0, - } - } - - fn random_cell_dep() -> CellDep { - let out_point = random_out_point(); - CellDep { - tx_hash: out_point.tx_hash, - index: out_point.index, - dep_type: 0, - } - } - - fn random_script() -> Script { - Script { - code_hash: H256::random(), - args: H256::random().0.to_vec().into(), - hash_type: 0, - } - } - - fn random_witness() -> Witness { - Witness { - input_type: random::<bool>().then(|| H256::random().0.to_vec().into()), - output_type: random::<bool>().then(|| H256::random().0.to_vec().into()), - lock: random::<bool>().then(|| H256::random().0.to_vec().into()), - } - } - - #[test] - fn test_signature_r_decode() { - let mock_by_ref = CKBTxMockByRef { - cell_deps: vec![random_cell_dep()], - header_deps: vec![H256::random()], - out_points: vec![random_out_point()], - out_point_addr_source: AddressSource { type_: 0, index: 0 }, - }; - - let mock_by_one_input_with_type_script = CKBTxMockByRefAndOneInput { - cell_deps: vec![random_cell_dep()], - header_deps: vec![H256::random()], - input_cell_with_data: CellWithData { - type_script: Some(random_script()), - lock_script: (random_script()), - data: H256::random().0.to_vec().into(), - }, - out_point_addr_source: AddressSource { type_: 1, index: 0 }, - }; - - let mock_by_one_input_without_type_script = CKBTxMockByRefAndOneInput { - cell_deps: vec![random_cell_dep()], - header_deps: vec![H256::random()], - input_cell_with_data: CellWithData { - type_script: None, - lock_script: (random_script()), - data: H256::random().0.to_vec().into(), - }, - out_point_addr_source: AddressSource { type_: 0, index: 0 }, - }; - - let mut raw = vec![1]; - raw.extend_from_slice(&rlp::encode(&mock_by_ref)); - assert_eq!( - SignatureR::ByRef(mock_by_ref.clone()), - SignatureR::decode(&raw).unwrap() - ); - - let mut raw = vec![2]; - raw.extend_from_slice(&rlp::encode(&mock_by_ref)); - assert!(SignatureR::decode(&raw).is_err()); - - let mut raw = vec![2]; - raw.extend_from_slice(&rlp::encode(&mock_by_one_input_with_type_script)); - assert_eq!( - SignatureR::ByRefAndOneInput(mock_by_one_input_with_type_script), - SignatureR::decode(&raw).unwrap() - ); - - let mut raw = vec![2]; - raw.extend_from_slice(&rlp::encode(&mock_by_one_input_without_type_script)); - assert_eq!( - SignatureR::ByRefAndOneInput(mock_by_one_input_without_type_script.clone()), - SignatureR::decode(&raw).unwrap() - ); - - let mut raw = vec![1]; - raw.extend_from_slice(&rlp::encode(&mock_by_one_input_without_type_script)); - assert!(SignatureR::decode(&raw).is_err()); - } - - #[test] - fn test_address_source_decode() { - let mock_by_ref = CKBTxMockByRef { - cell_deps: vec![random_cell_dep()], - header_deps: vec![H256::random()], - out_points: vec![random_out_point()], - out_point_addr_source: AddressSource { type_: 2, index: 0 }, - }; - - let mut raw = vec![1]; - raw.extend_from_slice(&rlp::encode(&mock_by_ref)); - assert!(SignatureR::decode(&raw).is_err()); - } - - #[test] - fn test_signature_s_decode() { - let signature_s = SignatureS { - witnesses: (0..25).map(|_| random_witness()).collect(), - }; - - let raw = rlp::encode(&signature_s); - assert_eq!(rlp::decode::<SignatureS>(&raw).unwrap(), signature_s); - } -}