Skip to content

Commit

Permalink
Merge pull request #8 from EthanYuan/v0.116.1-branch-chain-leap-tx
Browse files Browse the repository at this point in the history
rpc accepts the leap tx to mint capacity
  • Loading branch information
EthanYuan authored Jul 30, 2024
2 parents 84ef305 + 19693d4 commit 222af37
Show file tree
Hide file tree
Showing 6 changed files with 87 additions and 12 deletions.
27 changes: 26 additions & 1 deletion spec/src/consensus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use crate::{
VersionbitsConditionChecker, VersionbitsIndexer,
},
OUTPUT_INDEX_DAO, OUTPUT_INDEX_SECP256K1_BLAKE160_MULTISIG_ALL,
OUTPUT_INDEX_SECP256K1_BLAKE160_SIGHASH_ALL,
OUTPUT_INDEX_SECP256K1_BLAKE160_SIGHASH_ALL, OUTPUT_INDEX_TOKEN_MANAGER,
};
use ckb_constant::{
consensus::TAU,
Expand Down Expand Up @@ -280,6 +280,7 @@ impl ConsensusBuilder {
max_block_cycles: MAX_BLOCK_CYCLES,
max_block_bytes: MAX_BLOCK_BYTES,
dao_type_hash: Byte32::default(),
token_manager_type_hash: Byte32::default(),
secp256k1_blake160_sighash_all_type_hash: None,
secp256k1_blake160_multisig_all_type_hash: None,
genesis_epoch_ext,
Expand Down Expand Up @@ -312,6 +313,18 @@ impl ConsensusBuilder {
.map(|type_script| type_script.calc_script_hash())
}

fn get_lock_hash(&self, output_index: u64) -> Option<Byte32> {
self.inner
.genesis_block
.transaction(0)
.expect("Genesis must have cellbase")
.output(output_index as usize)
.map(|output| {
ckb_logger::info!("output: {:?}", output);
output.lock().calc_script_hash()
})
}

/// Build a new Consensus by taking ownership of the `Builder`, and returns a [`Consensus`].
pub fn build(mut self) -> Consensus {
debug_assert!(
Expand Down Expand Up @@ -346,6 +359,11 @@ impl ConsensusBuilder {
);

self.inner.dao_type_hash = self.get_type_hash(OUTPUT_INDEX_DAO).unwrap_or_default();
// Dummy implementation, currently using the hash of the lock script,
// will be changed to use the type script shortly
self.inner.token_manager_type_hash = self
.get_lock_hash(OUTPUT_INDEX_TOKEN_MANAGER)
.unwrap_or_default();
self.inner.secp256k1_blake160_sighash_all_type_hash =
self.get_type_hash(OUTPUT_INDEX_SECP256K1_BLAKE160_SIGHASH_ALL);
self.inner.secp256k1_blake160_multisig_all_type_hash =
Expand Down Expand Up @@ -513,6 +531,8 @@ pub struct Consensus {
///
/// [nervos-dao](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0024-ckb-genesis-script-list/0024-ckb-genesis-script-list.md#nervos-dao)
pub dao_type_hash: Byte32,
/// The token manager type hash
pub token_manager_type_hash: Byte32,
/// The secp256k1_blake160_sighash_all_type_hash
///
/// [SECP256K1/blake160](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0024-ckb-genesis-script-list/0024-ckb-genesis-script-list.md#secp256k1blake160)
Expand Down Expand Up @@ -628,6 +648,11 @@ impl Consensus {
self.dao_type_hash.clone()
}

/// The token manager type hash
pub fn token_manager_type_hash(&self) -> Byte32 {
self.token_manager_type_hash.clone()
}

/// The secp256k1_blake160_sighash_all_type_hash
///
/// [SECP256K1/blake160](https://github.com/nervosnetwork/rfcs/blob/master/rfcs/0024-ckb-genesis-script-list/0024-ckb-genesis-script-list.md#secp256k1blake160)
Expand Down
2 changes: 2 additions & 0 deletions spec/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ pub const OUTPUT_INDEX_DAO: u64 = 2;
pub const OUTPUT_INDEX_SECP256K1_DATA: u64 = 3;
/// The output index of SECP256K1/multisig script in the genesis no.0 transaction
pub const OUTPUT_INDEX_SECP256K1_BLAKE160_MULTISIG_ALL: u64 = 4;
/// The output index of Token Manager script in the genesis no.0 transaction
pub const OUTPUT_INDEX_TOKEN_MANAGER: u64 = 8;

/// The CKB block chain specification
#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
Expand Down
4 changes: 4 additions & 0 deletions tx-pool/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ pub(crate) fn check_tx_fee(
rtx: &ResolvedTransaction,
tx_size: usize,
) -> Result<Capacity, Reject> {
if rtx.is_leap_tx(&snapshot.consensus().token_manager_type_hash) {
return Ok(Capacity::zero());
}

let fee = DaoCalculator::new(snapshot.consensus(), &snapshot.borrow_as_data_loader())
.transaction_fee(rtx)
.map_err(|err| {
Expand Down
19 changes: 19 additions & 0 deletions util/types/src/core/cell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,25 @@ impl ResolvedTransaction {
self.resolved_inputs.is_empty()
}

/// Returns true if the transaction is leap transaction.
pub fn is_leap_tx(&self, token_manager_type_hash: &Byte32) -> bool {
self.resolved_inputs.iter().any(|cell_meta| {
Self::cell_uses_token_manager_lock_script(
&cell_meta.cell_output,
token_manager_type_hash,
)
})
}

fn cell_uses_token_manager_lock_script(
cell_output: &CellOutput,
token_manager_type_hash: &Byte32,
) -> bool {
// Dummy implementation, currently using the hash of the lock script,
// will be changed to use the type script shortly
&cell_output.lock().calc_script_hash() == token_manager_type_hash
}

/// TODO(doc): @quake
pub fn inputs_capacity(&self) -> CapacityResult<Capacity> {
self.resolved_inputs
Expand Down
7 changes: 4 additions & 3 deletions verification/src/tests/transaction_verifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ pub fn test_capacity_outofbound() {
resolved_dep_groups: vec![],
});
let dao_type_hash = build_genesis_type_id_script(OUTPUT_INDEX_DAO).calc_script_hash();
let verifier = CapacityVerifier::new(rtx, dao_type_hash);
let verifier = CapacityVerifier::new(rtx, dao_type_hash, Byte32::default());

assert_error_eq!(
verifier.verify().unwrap_err(),
Expand Down Expand Up @@ -136,7 +136,8 @@ pub fn test_skip_dao_capacity_check() {
resolved_inputs: vec![],
resolved_dep_groups: vec![],
});
let verifier = CapacityVerifier::new(rtx, dao_type_script.calc_script_hash());
let verifier =
CapacityVerifier::new(rtx, dao_type_script.calc_script_hash(), Byte32::default());

assert!(verifier.verify().is_ok());
}
Expand Down Expand Up @@ -329,7 +330,7 @@ pub fn test_capacity_invalid() {
resolved_dep_groups: vec![],
});
let dao_type_hash = build_genesis_type_id_script(OUTPUT_INDEX_DAO).calc_script_hash();
let verifier = CapacityVerifier::new(rtx, dao_type_hash);
let verifier = CapacityVerifier::new(rtx, dao_type_hash, Byte32::default());

assert_error_eq!(
verifier.verify().unwrap_err(),
Expand Down
40 changes: 32 additions & 8 deletions verification/src/transaction_verifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,11 @@ where
Arc::clone(&consensus),
Arc::clone(&tx_env),
),
capacity: CapacityVerifier::new(Arc::clone(&rtx), consensus.dao_type_hash()),
capacity: CapacityVerifier::new(
Arc::clone(&rtx),
consensus.dao_type_hash(),
consensus.token_manager_type_hash(),
),
fee_calculator: FeeCalculator::new(rtx, consensus, data_loader),
}
}
Expand Down Expand Up @@ -255,8 +259,12 @@ impl<DL: CellDataProvider + HeaderProvider + ExtensionProvider + EpochProvider>
}

fn transaction_fee(&self) -> Result<Capacity, DaoError> {
// skip tx fee calculation for cellbase
if self.transaction.is_cellbase() {
// skip tx fee calculation for cellbase and leap tx
if self.transaction.is_cellbase()
|| self
.transaction
.is_leap_tx(&self.consensus.token_manager_type_hash)
{
Ok(Capacity::zero())
} else {
DaoCalculator::new(self.consensus.as_ref(), &self.data_loader)
Expand Down Expand Up @@ -454,25 +462,37 @@ impl<'a> DuplicateDepsVerifier<'a> {
pub struct CapacityVerifier {
resolved_transaction: Arc<ResolvedTransaction>,
dao_type_hash: Byte32,
token_manager_type_hash: Byte32,
}

impl CapacityVerifier {
/// Create a new `CapacityVerifier`
pub fn new(resolved_transaction: Arc<ResolvedTransaction>, dao_type_hash: Byte32) -> Self {
pub fn new(
resolved_transaction: Arc<ResolvedTransaction>,
dao_type_hash: Byte32,
token_manager_type_hash: Byte32,
) -> Self {
CapacityVerifier {
resolved_transaction,
dao_type_hash,
token_manager_type_hash,
}
}

/// Verify sum of inputs capacity should be greater than or equal to sum of outputs capacity
/// Verify outputs capacity should be greater than or equal to its occupied capacity
pub fn verify(&self) -> Result<(), Error> {
// skip OutputsSumOverflow verification for resolved cellbase and DAO
// withdraw transactions.
// skip OutputsSumOverflow verification for resolved cellbase, leap tx
// and DAO withdraw transactions.
// cellbase's outputs are verified by RewardVerifier
// leap transaction is verified via the type script of Token Manager cell
// DAO withdraw transaction is verified via the type script of DAO cells
if !(self.resolved_transaction.is_cellbase() || self.valid_dao_withdraw_transaction()) {
if !(self.resolved_transaction.is_cellbase()
|| self.valid_dao_withdraw_transaction()
|| self
.resolved_transaction
.is_leap_tx(&self.token_manager_type_hash))
{
let inputs_sum = self.resolved_transaction.inputs_capacity()?;
let outputs_sum = self.resolved_transaction.outputs_capacity()?;

Expand Down Expand Up @@ -874,7 +894,11 @@ where
data_loader.clone(),
tx_env,
),
capacity: CapacityVerifier::new(Arc::clone(&rtx), consensus.dao_type_hash()),
capacity: CapacityVerifier::new(
Arc::clone(&rtx),
consensus.dao_type_hash(),
consensus.token_manager_type_hash(),
),
fee_calculator: FeeCalculator::new(rtx, consensus, data_loader),
}
}
Expand Down

0 comments on commit 222af37

Please sign in to comment.