1#![allow(clippy::inconsistent_digit_grouping)]
5
6use crate::{
7 OUTPUT_INDEX_DAO, OUTPUT_INDEX_SECP256K1_BLAKE160_MULTISIG_ALL,
8 OUTPUT_INDEX_SECP256K1_BLAKE160_SIGHASH_ALL, calculate_block_reward,
9 versionbits::{
10 self, Deployment, DeploymentPos, ThresholdState, Versionbits, VersionbitsCache,
11 VersionbitsConditionChecker, VersionbitsIndexer,
12 },
13};
14use ckb_constant::{
15 consensus::TAU,
16 hardfork::{mainnet, testnet},
17 softfork,
18};
19use ckb_dao_utils::genesis_dao_data_with_satoshi_gift;
20use ckb_pow::{Pow, PowEngine};
21use ckb_rational::RationalU256;
22use ckb_resource::Resource;
23use ckb_traits::{BlockEpoch, EpochProvider};
24use ckb_types::{
25 H160, H256, U256,
26 bytes::Bytes,
27 constants::{BLOCK_VERSION, TX_VERSION},
28 core::{
29 BlockBuilder, BlockNumber, BlockView, Capacity, Cycle, EpochExt, EpochNumber,
30 EpochNumberWithFraction, HeaderView, Ratio, TransactionBuilder, TransactionView, Version,
31 hardfork::HardForks,
32 },
33 h160, h256,
34 packed::{Byte32, CellInput, CellOutput, Script},
35 prelude::*,
36 utilities::{DIFF_TWO, compact_to_difficulty, difficulty_to_compact},
37};
38use std::cmp;
39use std::collections::HashMap;
40use std::sync::Arc;
41
42pub(crate) const DEFAULT_SECONDARY_EPOCH_REWARD: Capacity = Capacity::shannons(613_698_63013698);
44pub(crate) const INITIAL_PRIMARY_EPOCH_REWARD: Capacity = Capacity::shannons(1_917_808_21917808);
46const MAX_UNCLE_NUM: usize = 2;
47pub const TX_PROPOSAL_WINDOW: ProposalWindow = ProposalWindow(2, 10);
49pub(crate) const CELLBASE_MATURITY: EpochNumberWithFraction =
53 EpochNumberWithFraction::new_unchecked(4, 0, 1);
54
55const MEDIAN_TIME_BLOCK_COUNT: usize = 37;
56
57pub(crate) const GENESIS_EPOCH_LENGTH: u64 = 1_000;
60
61pub(crate) const DEFAULT_ORPHAN_RATE_TARGET: (u32, u32) = (1, 40);
63
64pub const MAX_BLOCK_INTERVAL: u64 = 48;
66pub const MIN_BLOCK_INTERVAL: u64 = 8;
68
69pub const TWO_IN_TWO_OUT_CYCLES: Cycle = 3_500_000;
71pub const TWO_IN_TWO_OUT_BYTES: u64 = 597;
73const TWO_IN_TWO_OUT_COUNT: u64 = 1_000;
75pub(crate) const DEFAULT_EPOCH_DURATION_TARGET: u64 = 4 * 60 * 60; const MILLISECONDS_IN_A_SECOND: u64 = 1000;
77const MAX_EPOCH_LENGTH: u64 = DEFAULT_EPOCH_DURATION_TARGET / MIN_BLOCK_INTERVAL; const MIN_EPOCH_LENGTH: u64 = DEFAULT_EPOCH_DURATION_TARGET / MAX_BLOCK_INTERVAL; pub(crate) const DEFAULT_PRIMARY_EPOCH_REWARD_HALVING_INTERVAL: EpochNumber =
80 4 * 365 * 24 * 60 * 60 / DEFAULT_EPOCH_DURATION_TARGET; pub const MAX_BLOCK_BYTES: u64 = TWO_IN_TWO_OUT_BYTES * TWO_IN_TWO_OUT_COUNT;
84pub(crate) const MAX_BLOCK_CYCLES: u64 = TWO_IN_TWO_OUT_CYCLES * TWO_IN_TWO_OUT_COUNT;
85
86pub const MAX_BLOCK_PROPOSALS_LIMIT: u64 = 1_500;
90const PROPOSER_REWARD_RATIO: Ratio = Ratio::new(4, 10);
91
92pub(crate) const SATOSHI_PUBKEY_HASH: H160 = h160!("0x62e907b15cbf27d5425399ebf6f0fb50ebb88f18");
94pub(crate) const SATOSHI_CELL_OCCUPIED_RATIO: Ratio = Ratio::new(6, 10);
97
98pub const LC_MAINNET_ACTIVATION_THRESHOLD: Ratio = Ratio::new(8, 10);
100pub const TESTNET_ACTIVATION_THRESHOLD: Ratio = Ratio::new(3, 4);
102
103pub(crate) const STARTING_BLOCK_LIMITING_DAO_WITHDRAWING_LOCK: u64 = 10_000_000;
106
107#[derive(Clone, PartialEq, Debug, Eq, Copy)]
115pub struct ProposalWindow(pub BlockNumber, pub BlockNumber);
116
117pub const TYPE_ID_CODE_HASH: H256 = h256!("0x545950455f4944");
119
120impl ProposalWindow {
140 pub const fn closest(&self) -> BlockNumber {
142 self.0
143 }
144
145 pub const fn farthest(&self) -> BlockNumber {
147 self.1
148 }
149
150 pub const fn length(&self) -> BlockNumber {
152 self.1 - self.0 + 1
153 }
154}
155
156pub struct ConsensusBuilder {
158 inner: Consensus,
159}
160
161impl Default for ConsensusBuilder {
163 fn default() -> Self {
164 let input = CellInput::new_cellbase_input(0);
165 let output = {
167 let empty_output = CellOutput::new_builder().build();
168 let occupied = empty_output
169 .occupied_capacity(Capacity::zero())
170 .expect("default occupied");
171 empty_output.as_builder().capacity(occupied).build()
172 };
173 let witness = Script::default().into_witness();
174 let cellbase = TransactionBuilder::default()
175 .input(input)
176 .output(output)
177 .output_data(Bytes::new())
178 .witness(witness)
179 .build();
180
181 let epoch_ext = build_genesis_epoch_ext(
182 INITIAL_PRIMARY_EPOCH_REWARD,
183 DIFF_TWO,
184 GENESIS_EPOCH_LENGTH,
185 DEFAULT_EPOCH_DURATION_TARGET,
186 DEFAULT_ORPHAN_RATE_TARGET,
187 );
188 let primary_issuance =
189 calculate_block_reward(INITIAL_PRIMARY_EPOCH_REWARD, GENESIS_EPOCH_LENGTH);
190 let secondary_issuance =
191 calculate_block_reward(DEFAULT_SECONDARY_EPOCH_REWARD, GENESIS_EPOCH_LENGTH);
192
193 let dao = genesis_dao_data_with_satoshi_gift(
194 vec![&cellbase],
195 &SATOSHI_PUBKEY_HASH,
196 SATOSHI_CELL_OCCUPIED_RATIO,
197 primary_issuance,
198 secondary_issuance,
199 )
200 .expect("genesis dao data calculation error!");
201
202 let genesis_block = BlockBuilder::default()
203 .compact_target(DIFF_TWO)
204 .epoch(EpochNumberWithFraction::new_unchecked(0, 0, 0))
205 .dao(dao)
206 .transaction(cellbase)
207 .build();
208
209 ConsensusBuilder::new(genesis_block, epoch_ext)
210 .initial_primary_epoch_reward(INITIAL_PRIMARY_EPOCH_REWARD)
211 }
212}
213
214pub fn build_genesis_epoch_ext(
216 epoch_reward: Capacity,
217 compact_target: u32,
218 genesis_epoch_length: BlockNumber,
219 epoch_duration_target: u64,
220 genesis_orphan_rate: (u32, u32),
221) -> EpochExt {
222 let block_reward = Capacity::shannons(epoch_reward.as_u64() / genesis_epoch_length);
223 let remainder_reward = Capacity::shannons(epoch_reward.as_u64() % genesis_epoch_length);
224
225 let genesis_orphan_count =
226 genesis_epoch_length * genesis_orphan_rate.0 as u64 / genesis_orphan_rate.1 as u64;
227 let genesis_hash_rate = compact_to_difficulty(compact_target)
228 * (genesis_epoch_length + genesis_orphan_count)
229 / epoch_duration_target;
230
231 EpochExt::new_builder()
232 .number(0)
233 .base_block_reward(block_reward)
234 .remainder_reward(remainder_reward)
235 .previous_epoch_hash_rate(genesis_hash_rate)
236 .last_block_hash_in_previous_epoch(Byte32::zero())
237 .start_number(0)
238 .length(genesis_epoch_length)
239 .compact_target(compact_target)
240 .build()
241}
242
243pub fn build_genesis_dao_data(
245 txs: Vec<&TransactionView>,
246 satoshi_pubkey_hash: &H160,
247 satoshi_cell_occupied_ratio: Ratio,
248 genesis_primary_issuance: Capacity,
249 genesis_secondary_issuance: Capacity,
250) -> Byte32 {
251 genesis_dao_data_with_satoshi_gift(
252 txs,
253 satoshi_pubkey_hash,
254 satoshi_cell_occupied_ratio,
255 genesis_primary_issuance,
256 genesis_secondary_issuance,
257 )
258 .expect("genesis dao data calculation error!")
259}
260
261impl ConsensusBuilder {
262 pub fn new(genesis_block: BlockView, genesis_epoch_ext: EpochExt) -> Self {
264 let orphan_rate_target = RationalU256::new_raw(
265 U256::from(DEFAULT_ORPHAN_RATE_TARGET.0),
266 U256::from(DEFAULT_ORPHAN_RATE_TARGET.1),
267 );
268 ConsensusBuilder {
269 inner: Consensus {
270 genesis_hash: genesis_block.header().hash(),
271 genesis_block,
272 id: "main".to_owned(),
273 max_uncles_num: MAX_UNCLE_NUM,
274 initial_primary_epoch_reward: INITIAL_PRIMARY_EPOCH_REWARD,
275 orphan_rate_target,
276 epoch_duration_target: DEFAULT_EPOCH_DURATION_TARGET,
277 secondary_epoch_reward: DEFAULT_SECONDARY_EPOCH_REWARD,
278 tx_proposal_window: TX_PROPOSAL_WINDOW,
279 pow: Pow::Dummy,
280 cellbase_maturity: CELLBASE_MATURITY,
281 median_time_block_count: MEDIAN_TIME_BLOCK_COUNT,
282 max_block_cycles: MAX_BLOCK_CYCLES,
283 max_block_bytes: MAX_BLOCK_BYTES,
284 dao_type_hash: Byte32::default(),
285 secp256k1_blake160_sighash_all_type_hash: None,
286 secp256k1_blake160_multisig_all_type_hash: None,
287 genesis_epoch_ext,
288 block_version: BLOCK_VERSION,
289 tx_version: TX_VERSION,
290 type_id_code_hash: TYPE_ID_CODE_HASH,
291 proposer_reward_ratio: PROPOSER_REWARD_RATIO,
292 max_block_proposals_limit: MAX_BLOCK_PROPOSALS_LIMIT,
293 satoshi_pubkey_hash: SATOSHI_PUBKEY_HASH,
294 satoshi_cell_occupied_ratio: SATOSHI_CELL_OCCUPIED_RATIO,
295 primary_epoch_reward_halving_interval:
296 DEFAULT_PRIMARY_EPOCH_REWARD_HALVING_INTERVAL,
297 permanent_difficulty_in_dummy: false,
298 hardfork_switch: HardForks::new_mirana(),
299 deployments: HashMap::new(),
300 versionbits_caches: VersionbitsCache::default(),
301 starting_block_limiting_dao_withdrawing_lock:
302 STARTING_BLOCK_LIMITING_DAO_WITHDRAWING_LOCK,
303 },
304 }
305 }
306
307 fn get_type_hash(&self, output_index: u64) -> Option<Byte32> {
308 self.inner
309 .genesis_block
310 .transaction(0)
311 .expect("Genesis must have cellbase")
312 .output(output_index as usize)
313 .and_then(|output| output.type_().to_opt())
314 .map(|type_script| type_script.calc_script_hash())
315 }
316
317 pub fn build(mut self) -> Consensus {
319 debug_assert!(
320 self.inner.genesis_block.difficulty() > U256::zero(),
321 "genesis difficulty should greater than zero"
322 );
323 debug_assert!(
324 !self.inner.genesis_block.data().transactions().is_empty()
325 && !self
326 .inner
327 .genesis_block
328 .data()
329 .transactions()
330 .get(0)
331 .unwrap()
332 .witnesses()
333 .is_empty(),
334 "genesis block must contain the witness for cellbase"
335 );
336
337 debug_assert!(
338 self.inner.initial_primary_epoch_reward != Capacity::zero(),
339 "initial_primary_epoch_reward must be non-zero"
340 );
341
342 debug_assert!(
343 self.inner.epoch_duration_target() != 0,
344 "epoch_duration_target must be non-zero"
345 );
346
347 debug_assert!(
348 !self.inner.genesis_block.transactions().is_empty()
349 && !self.inner.genesis_block.transactions()[0]
350 .witnesses()
351 .is_empty(),
352 "genesis block must contain the witness for cellbase"
353 );
354
355 self.inner.dao_type_hash = self.get_type_hash(OUTPUT_INDEX_DAO).unwrap_or_default();
356 self.inner.secp256k1_blake160_sighash_all_type_hash =
357 self.get_type_hash(OUTPUT_INDEX_SECP256K1_BLAKE160_SIGHASH_ALL);
358 self.inner.secp256k1_blake160_multisig_all_type_hash =
359 self.get_type_hash(OUTPUT_INDEX_SECP256K1_BLAKE160_MULTISIG_ALL);
360 self.inner
361 .genesis_epoch_ext
362 .set_compact_target(self.inner.genesis_block.compact_target());
363 self.inner.genesis_hash = self.inner.genesis_block.hash();
364 self.inner
365 }
366
367 pub fn id(mut self, id: String) -> Self {
369 self.inner.id = id;
370 self
371 }
372
373 pub fn genesis_block(mut self, genesis_block: BlockView) -> Self {
375 self.inner.genesis_block = genesis_block;
376 self
377 }
378
379 #[must_use]
381 pub fn initial_primary_epoch_reward(mut self, initial_primary_epoch_reward: Capacity) -> Self {
382 self.inner.initial_primary_epoch_reward = initial_primary_epoch_reward;
383 self
384 }
385
386 pub fn orphan_rate_target(mut self, orphan_rate_target: (u32, u32)) -> Self {
388 self.inner.orphan_rate_target = RationalU256::new_raw(
389 U256::from(orphan_rate_target.0),
390 U256::from(orphan_rate_target.1),
391 );
392 self
393 }
394
395 #[must_use]
397 pub fn secondary_epoch_reward(mut self, secondary_epoch_reward: Capacity) -> Self {
398 self.inner.secondary_epoch_reward = secondary_epoch_reward;
399 self
400 }
401
402 #[must_use]
404 pub fn max_block_cycles(mut self, max_block_cycles: Cycle) -> Self {
405 self.inner.max_block_cycles = max_block_cycles;
406 self
407 }
408
409 #[must_use]
411 pub fn max_block_bytes(mut self, max_block_bytes: u64) -> Self {
412 self.inner.max_block_bytes = max_block_bytes;
413 self
414 }
415
416 #[must_use]
418 pub fn cellbase_maturity(mut self, cellbase_maturity: EpochNumberWithFraction) -> Self {
419 self.inner.cellbase_maturity = cellbase_maturity;
420 self
421 }
422
423 pub fn median_time_block_count(mut self, median_time_block_count: usize) -> Self {
425 self.inner.median_time_block_count = median_time_block_count;
426 self
427 }
428
429 pub fn tx_proposal_window(mut self, proposal_window: ProposalWindow) -> Self {
431 self.inner.tx_proposal_window = proposal_window;
432 self
433 }
434
435 pub fn pow(mut self, pow: Pow) -> Self {
437 self.inner.pow = pow;
438 self
439 }
440
441 pub fn satoshi_pubkey_hash(mut self, pubkey_hash: H160) -> Self {
443 self.inner.satoshi_pubkey_hash = pubkey_hash;
444 self
445 }
446
447 pub fn satoshi_cell_occupied_ratio(mut self, ratio: Ratio) -> Self {
449 self.inner.satoshi_cell_occupied_ratio = ratio;
450 self
451 }
452
453 #[must_use]
455 pub fn primary_epoch_reward_halving_interval(mut self, halving_interval: u64) -> Self {
456 self.inner.primary_epoch_reward_halving_interval = halving_interval;
457 self
458 }
459
460 #[must_use]
462 pub fn epoch_duration_target(mut self, target: u64) -> Self {
463 self.inner.epoch_duration_target = target;
464 self
465 }
466
467 #[must_use]
473 pub fn permanent_difficulty_in_dummy(mut self, permanent: bool) -> Self {
474 self.inner.permanent_difficulty_in_dummy = permanent;
475 self
476 }
477
478 #[must_use]
480 pub fn max_block_proposals_limit(mut self, max_block_proposals_limit: u64) -> Self {
481 self.inner.max_block_proposals_limit = max_block_proposals_limit;
482 self
483 }
484
485 pub fn hardfork_switch(mut self, hardfork_switch: HardForks) -> Self {
487 self.inner.hardfork_switch = hardfork_switch;
488 self
489 }
490
491 pub fn softfork_deployments(mut self, deployments: HashMap<DeploymentPos, Deployment>) -> Self {
493 self.inner.versionbits_caches = VersionbitsCache::new(deployments.keys());
494 self.inner.deployments = deployments;
495 self
496 }
497
498 pub fn starting_block_limiting_dao_withdrawing_lock(
501 mut self,
502 starting_block_limiting_dao_withdrawing_lock: u64,
503 ) -> Self {
504 self.inner.starting_block_limiting_dao_withdrawing_lock =
505 starting_block_limiting_dao_withdrawing_lock;
506 self
507 }
508}
509
510#[derive(Clone, Debug)]
512pub struct Consensus {
513 pub id: String,
515 pub genesis_block: BlockView,
517 pub genesis_hash: Byte32,
519 pub dao_type_hash: Byte32,
523 pub secp256k1_blake160_sighash_all_type_hash: Option<Byte32>,
527 pub secp256k1_blake160_multisig_all_type_hash: Option<Byte32>,
531 pub initial_primary_epoch_reward: Capacity,
535 pub secondary_epoch_reward: Capacity,
539 pub max_uncles_num: usize,
541 pub orphan_rate_target: RationalU256,
543 pub epoch_duration_target: u64,
545 pub tx_proposal_window: ProposalWindow,
547 pub proposer_reward_ratio: Ratio,
549 pub pow: Pow,
551 pub cellbase_maturity: EpochNumberWithFraction,
556 pub median_time_block_count: usize,
558 pub max_block_cycles: Cycle,
560 pub max_block_bytes: u64,
562 pub block_version: Version,
564 pub tx_version: Version,
566 pub type_id_code_hash: H256,
568 pub max_block_proposals_limit: u64,
570 pub genesis_epoch_ext: EpochExt,
572 pub satoshi_pubkey_hash: H160,
574 pub satoshi_cell_occupied_ratio: Ratio,
577 pub primary_epoch_reward_halving_interval: EpochNumber,
580 pub permanent_difficulty_in_dummy: bool,
582 pub hardfork_switch: HardForks,
584 pub deployments: HashMap<DeploymentPos, Deployment>,
586 pub versionbits_caches: VersionbitsCache,
588 pub starting_block_limiting_dao_withdrawing_lock: u64,
590}
591
592impl Default for Consensus {
594 fn default() -> Self {
595 ConsensusBuilder::default().build()
596 }
597}
598
599#[allow(clippy::op_ref)]
600impl Consensus {
601 pub fn genesis_block(&self) -> &BlockView {
603 &self.genesis_block
604 }
605
606 pub fn proposer_reward_ratio(&self) -> Ratio {
608 self.proposer_reward_ratio
609 }
610
611 pub fn finalization_delay_length(&self) -> BlockNumber {
613 self.tx_proposal_window.farthest() + 1
614 }
615
616 pub fn finalize_target(&self, block_number: BlockNumber) -> Option<BlockNumber> {
618 if block_number != 0 {
619 Some(block_number.saturating_sub(self.finalization_delay_length()))
620 } else {
621 None
623 }
624 }
625
626 pub fn genesis_hash(&self) -> Byte32 {
628 self.genesis_hash.clone()
629 }
630
631 pub fn dao_type_hash(&self) -> Byte32 {
635 self.dao_type_hash.clone()
636 }
637
638 pub fn secp256k1_blake160_sighash_all_type_hash(&self) -> Option<Byte32> {
642 self.secp256k1_blake160_sighash_all_type_hash.clone()
643 }
644
645 pub fn secp256k1_blake160_multisig_all_type_hash(&self) -> Option<Byte32> {
649 self.secp256k1_blake160_multisig_all_type_hash.clone()
650 }
651
652 pub fn max_uncles_num(&self) -> usize {
654 self.max_uncles_num
655 }
656
657 pub fn min_difficulty(&self) -> U256 {
659 self.genesis_block.difficulty()
660 }
661
662 pub fn initial_primary_epoch_reward(&self) -> Capacity {
664 self.initial_primary_epoch_reward
665 }
666
667 pub fn primary_epoch_reward(&self, epoch_number: u64) -> Capacity {
671 let halvings = epoch_number / self.primary_epoch_reward_halving_interval();
672 Capacity::shannons(self.initial_primary_epoch_reward.as_u64() >> halvings)
673 }
674
675 pub fn primary_epoch_reward_halving_interval(&self) -> EpochNumber {
678 self.primary_epoch_reward_halving_interval
679 }
680
681 pub fn epoch_duration_target(&self) -> u64 {
683 self.epoch_duration_target
684 }
685
686 pub fn genesis_epoch_ext(&self) -> &EpochExt {
688 &self.genesis_epoch_ext
689 }
690
691 pub fn max_epoch_length(&self) -> BlockNumber {
693 MAX_EPOCH_LENGTH
694 }
695
696 pub fn min_epoch_length(&self) -> BlockNumber {
698 MIN_EPOCH_LENGTH
699 }
700
701 pub fn secondary_epoch_reward(&self) -> Capacity {
705 self.secondary_epoch_reward
706 }
707
708 pub fn orphan_rate_target(&self) -> &RationalU256 {
710 &self.orphan_rate_target
711 }
712
713 pub fn pow_engine(&self) -> Arc<dyn PowEngine> {
715 self.pow.engine()
716 }
717
718 pub fn permanent_difficulty(&self) -> bool {
720 self.pow.is_dummy() && self.permanent_difficulty_in_dummy
721 }
722
723 pub fn cellbase_maturity(&self) -> EpochNumberWithFraction {
725 self.cellbase_maturity
726 }
727
728 pub fn median_time_block_count(&self) -> usize {
730 self.median_time_block_count
731 }
732
733 pub fn max_block_cycles(&self) -> Cycle {
735 self.max_block_cycles
736 }
737
738 pub fn max_block_bytes(&self) -> u64 {
740 self.max_block_bytes
741 }
742
743 pub fn max_block_proposals_limit(&self) -> u64 {
745 self.max_block_proposals_limit
746 }
747
748 pub fn block_version(&self) -> Version {
750 self.block_version
751 }
752
753 pub fn tx_version(&self) -> Version {
755 self.tx_version
756 }
757
758 pub fn type_id_code_hash(&self) -> &H256 {
760 &self.type_id_code_hash
761 }
762
763 pub fn tx_proposal_window(&self) -> ProposalWindow {
765 self.tx_proposal_window
766 }
767
768 pub fn starting_block_limiting_dao_withdrawing_lock(&self) -> u64 {
771 self.starting_block_limiting_dao_withdrawing_lock
772 }
773
774 fn bounding_hash_rate(
776 &self,
777 last_epoch_hash_rate: U256,
778 last_epoch_previous_hash_rate: U256,
779 ) -> U256 {
780 if last_epoch_previous_hash_rate == U256::zero() {
781 return last_epoch_hash_rate;
782 }
783
784 let lower_bound = &last_epoch_previous_hash_rate / TAU;
785 if last_epoch_hash_rate < lower_bound {
786 return lower_bound;
787 }
788
789 let upper_bound = &last_epoch_previous_hash_rate * TAU;
790 if last_epoch_hash_rate > upper_bound {
791 return upper_bound;
792 }
793 last_epoch_hash_rate
794 }
795
796 fn bounding_epoch_length(
798 &self,
799 length: BlockNumber,
800 last_epoch_length: BlockNumber,
801 ) -> (BlockNumber, bool) {
802 let max_length = cmp::min(self.max_epoch_length(), last_epoch_length * TAU);
803 let min_length = cmp::max(self.min_epoch_length(), last_epoch_length / TAU);
804 if length > max_length {
805 (max_length, true)
806 } else if length < min_length {
807 (min_length, true)
808 } else {
809 (length, false)
810 }
811 }
812
813 pub fn next_epoch_ext<P: EpochProvider>(
816 &self,
817 header: &HeaderView,
818 provider: &P,
819 ) -> Option<NextBlockEpoch> {
820 provider
821 .get_block_epoch(header)
822 .map(|block_epoch| match block_epoch {
823 BlockEpoch::NonTailBlock { epoch } => NextBlockEpoch::NonHeadBlock(epoch),
824 BlockEpoch::TailBlock {
825 epoch,
826 epoch_uncles_count,
827 epoch_duration_in_milliseconds,
828 } => {
829 if self.permanent_difficulty() {
830 let next_epoch_length =
831 self.epoch_duration_target().div_ceil(MIN_BLOCK_INTERVAL);
832 let primary_epoch_reward =
833 self.primary_epoch_reward_of_next_epoch(&epoch).as_u64();
834 let block_reward =
835 Capacity::shannons(primary_epoch_reward / next_epoch_length);
836 let remainder_reward =
837 Capacity::shannons(primary_epoch_reward % next_epoch_length);
838
839 let dummy_epoch_ext = epoch
840 .clone()
841 .into_builder()
842 .base_block_reward(block_reward)
843 .remainder_reward(remainder_reward)
844 .number(epoch.number() + 1)
845 .last_block_hash_in_previous_epoch(header.hash())
846 .start_number(header.number() + 1)
847 .length(next_epoch_length)
848 .build();
849 NextBlockEpoch::HeadBlock(dummy_epoch_ext)
850 } else {
851 let last_difficulty = &header.difficulty();
853 let last_epoch_duration = U256::from(cmp::max(
854 epoch_duration_in_milliseconds / MILLISECONDS_IN_A_SECOND,
855 1,
856 ));
857
858 let last_epoch_hash_rate = last_difficulty
859 * (epoch.length() + epoch_uncles_count)
860 / &last_epoch_duration;
861
862 let adjusted_last_epoch_hash_rate = cmp::max(
863 self.bounding_hash_rate(
864 last_epoch_hash_rate,
865 epoch.previous_epoch_hash_rate().to_owned(),
866 ),
867 U256::one(),
868 );
869
870 let orphan_rate_target = self.orphan_rate_target();
872 let epoch_duration_target = self.epoch_duration_target();
873 let epoch_duration_target_u256 = U256::from(self.epoch_duration_target());
874 let last_epoch_length_u256 = U256::from(epoch.length());
875 let last_orphan_rate = RationalU256::new(
876 U256::from(epoch_uncles_count),
877 last_epoch_length_u256.clone(),
878 );
879
880 let (next_epoch_length, bound) = if epoch_uncles_count == 0 {
881 (
882 cmp::min(self.max_epoch_length(), epoch.length() * TAU),
883 true,
884 )
885 } else {
886 let numerator = orphan_rate_target
888 * (&last_orphan_rate + U256::one())
889 * &epoch_duration_target_u256
890 * &last_epoch_length_u256;
891 let denominator = &last_orphan_rate
893 * (orphan_rate_target + U256::one())
894 * &last_epoch_duration;
895 let raw_next_epoch_length =
896 u256_low_u64((numerator / denominator).into_u256());
897
898 self.bounding_epoch_length(raw_next_epoch_length, epoch.length())
899 };
900
901 let next_epoch_length_u256 = U256::from(next_epoch_length);
903 let diff_numerator = RationalU256::new(
904 &adjusted_last_epoch_hash_rate * epoch_duration_target,
905 U256::one(),
906 );
907 let diff_denominator = if bound {
908 if last_orphan_rate.is_zero() {
909 RationalU256::new(next_epoch_length_u256, U256::one())
910 } else {
911 let orphan_rate_estimation_recip = ((&last_orphan_rate
912 + U256::one())
913 * &epoch_duration_target_u256
914 * &last_epoch_length_u256
915 / (&last_orphan_rate
916 * &last_epoch_duration
917 * &next_epoch_length_u256))
918 .saturating_sub_u256(U256::one());
919
920 if orphan_rate_estimation_recip.is_zero() {
921 (orphan_rate_target + U256::one()) * next_epoch_length_u256
923 } else {
924 let orphan_rate_estimation =
925 RationalU256::one() / orphan_rate_estimation_recip;
926 (orphan_rate_estimation + U256::one()) * next_epoch_length_u256
927 }
928 }
929 } else {
930 (orphan_rate_target + U256::one()) * next_epoch_length_u256
931 };
932
933 let next_epoch_diff = if diff_numerator > diff_denominator {
934 (diff_numerator / diff_denominator).into_u256()
935 } else {
936 U256::one()
938 };
939
940 let primary_epoch_reward =
941 self.primary_epoch_reward_of_next_epoch(&epoch).as_u64();
942 let block_reward =
943 Capacity::shannons(primary_epoch_reward / next_epoch_length);
944 let remainder_reward =
945 Capacity::shannons(primary_epoch_reward % next_epoch_length);
946
947 let epoch_ext = EpochExt::new_builder()
948 .number(epoch.number() + 1)
949 .base_block_reward(block_reward)
950 .remainder_reward(remainder_reward)
951 .previous_epoch_hash_rate(adjusted_last_epoch_hash_rate)
952 .last_block_hash_in_previous_epoch(header.hash())
953 .start_number(header.number() + 1)
954 .length(next_epoch_length)
955 .compact_target(difficulty_to_compact(next_epoch_diff))
956 .build();
957
958 NextBlockEpoch::HeadBlock(epoch_ext)
959 }
960 }
961 })
962 }
963
964 pub fn identify_name(&self) -> String {
966 let genesis_hash = format!("{:x}", Into::<H256>::into(&self.genesis_hash));
967 format!("/{}/{}", self.id, &genesis_hash[..8])
968 }
969
970 pub fn get_secp_type_script_hash(&self) -> Byte32 {
972 let secp_cell_data =
973 Resource::bundled("specs/cells/secp256k1_blake160_sighash_all".to_string())
974 .get()
975 .expect("Load secp script data failed");
976 let genesis_cellbase = &self.genesis_block().transactions()[0];
977 genesis_cellbase
978 .outputs()
979 .into_iter()
980 .zip(genesis_cellbase.outputs_data())
981 .find(|(_, data)| data.raw_data() == secp_cell_data.as_ref())
982 .and_then(|(output, _)| {
983 output
984 .type_()
985 .to_opt()
986 .map(|script| script.calc_script_hash())
987 })
988 .expect("Can not find secp script")
989 }
990
991 fn primary_epoch_reward_of_next_epoch(&self, epoch: &EpochExt) -> Capacity {
992 if (epoch.number() + 1) % self.primary_epoch_reward_halving_interval() != 0 {
993 epoch.primary_reward()
994 } else {
995 self.primary_epoch_reward(epoch.number() + 1)
996 }
997 }
998
999 pub fn hardfork_switch(&self) -> &HardForks {
1001 &self.hardfork_switch
1002 }
1003
1004 pub fn rfc0044_active(&self, target: EpochNumber) -> bool {
1006 let rfc0044_active_epoch = match self.id.as_str() {
1007 mainnet::CHAIN_SPEC_NAME => softfork::mainnet::RFC0044_ACTIVE_EPOCH,
1008 testnet::CHAIN_SPEC_NAME => softfork::testnet::RFC0044_ACTIVE_EPOCH,
1009 _ => 0,
1010 };
1011 target >= rfc0044_active_epoch
1012 }
1013
1014 pub fn compute_versionbits<I: VersionbitsIndexer>(
1016 &self,
1017 parent: &HeaderView,
1018 indexer: &I,
1019 ) -> Option<Version> {
1020 let mut version = versionbits::VERSIONBITS_TOP_BITS;
1021 for pos in self.deployments.keys() {
1022 let versionbits = Versionbits::new(*pos, self);
1023 let cache = self.versionbits_caches.cache(pos)?;
1024 let state = versionbits.get_state(parent, cache, indexer)?;
1025 if state == versionbits::ThresholdState::LockedIn
1026 || state == versionbits::ThresholdState::Started
1027 {
1028 version |= versionbits.mask();
1029 }
1030 }
1031 Some(version)
1032 }
1033
1034 pub fn versionbits_state<I: VersionbitsIndexer>(
1036 &self,
1037 pos: DeploymentPos,
1038 parent: &HeaderView,
1039 indexer: &I,
1040 ) -> Option<ThresholdState> {
1041 let cache = self.versionbits_caches.cache(&pos)?;
1042 let versionbits = Versionbits::new(pos, self);
1043 versionbits.get_state(parent, cache, indexer)
1044 }
1045
1046 pub fn versionbits_state_since_epoch<I: VersionbitsIndexer>(
1048 &self,
1049 pos: DeploymentPos,
1050 parent: &HeaderView,
1051 indexer: &I,
1052 ) -> Option<EpochNumber> {
1053 let cache = self.versionbits_caches.cache(&pos)?;
1054 let versionbits = Versionbits::new(pos, self);
1055 versionbits.get_state_since_epoch(parent, cache, indexer)
1056 }
1057
1058 pub fn is_public_chain(&self) -> bool {
1060 matches!(
1061 self.id.as_str(),
1062 mainnet::CHAIN_SPEC_NAME | testnet::CHAIN_SPEC_NAME
1063 )
1064 }
1065}
1066
1067pub trait ConsensusProvider {
1069 fn get_consensus(&self) -> &Consensus;
1071}
1072
1073pub enum NextBlockEpoch {
1075 HeadBlock(EpochExt),
1077 NonHeadBlock(EpochExt),
1079}
1080
1081impl NextBlockEpoch {
1082 pub fn epoch(self) -> EpochExt {
1084 match self {
1085 Self::HeadBlock(epoch_ext) => epoch_ext,
1086 Self::NonHeadBlock(epoch_ext) => epoch_ext,
1087 }
1088 }
1089
1090 pub fn is_head(&self) -> bool {
1092 matches!(*self, Self::HeadBlock(_))
1093 }
1094}
1095
1096impl From<Consensus> for ckb_jsonrpc_types::Consensus {
1097 fn from(consensus: Consensus) -> Self {
1098 let mut softforks = HashMap::new();
1099 for (pos, deployment) in consensus.deployments {
1100 softforks.insert(
1101 pos.into(),
1102 ckb_jsonrpc_types::SoftFork::new_rfc0043(deployment.into()),
1103 );
1104 }
1105 match consensus.id.as_str() {
1106 mainnet::CHAIN_SPEC_NAME => {
1107 softforks.insert(
1108 DeploymentPos::LightClient.into(),
1109 ckb_jsonrpc_types::SoftFork::new_buried(
1110 true,
1111 softfork::mainnet::RFC0044_ACTIVE_EPOCH.into(),
1112 ),
1113 );
1114 }
1115 testnet::CHAIN_SPEC_NAME => {
1116 softforks.insert(
1117 DeploymentPos::LightClient.into(),
1118 ckb_jsonrpc_types::SoftFork::new_buried(
1119 true,
1120 softfork::testnet::RFC0044_ACTIVE_EPOCH.into(),
1121 ),
1122 );
1123 }
1124 _ => {}
1125 };
1126 Self {
1127 id: consensus.id,
1128 genesis_hash: consensus.genesis_hash.into(),
1129 dao_type_hash: consensus.dao_type_hash.into(),
1130 secp256k1_blake160_sighash_all_type_hash: consensus
1131 .secp256k1_blake160_sighash_all_type_hash
1132 .map(|h| h.into()),
1133 secp256k1_blake160_multisig_all_type_hash: consensus
1134 .secp256k1_blake160_multisig_all_type_hash
1135 .map(|h| h.into()),
1136 initial_primary_epoch_reward: consensus.initial_primary_epoch_reward.into(),
1137 secondary_epoch_reward: consensus.secondary_epoch_reward.into(),
1138 max_uncles_num: (consensus.max_uncles_num as u64).into(),
1139 orphan_rate_target: consensus.orphan_rate_target,
1140 epoch_duration_target: consensus.epoch_duration_target.into(),
1141 tx_proposal_window: ckb_jsonrpc_types::ProposalWindow {
1142 closest: consensus.tx_proposal_window.0.into(),
1143 farthest: consensus.tx_proposal_window.1.into(),
1144 },
1145 proposer_reward_ratio: RationalU256::new_raw(
1146 consensus.proposer_reward_ratio.numer().into(),
1147 consensus.proposer_reward_ratio.denom().into(),
1148 ),
1149 cellbase_maturity: consensus.cellbase_maturity.into(),
1150 median_time_block_count: (consensus.median_time_block_count as u64).into(),
1151 max_block_cycles: consensus.max_block_cycles.into(),
1152 max_block_bytes: consensus.max_block_bytes.into(),
1153 block_version: consensus.block_version.into(),
1154 tx_version: consensus.tx_version.into(),
1155 type_id_code_hash: consensus.type_id_code_hash,
1156 max_block_proposals_limit: consensus.max_block_proposals_limit.into(),
1157 primary_epoch_reward_halving_interval: consensus
1158 .primary_epoch_reward_halving_interval
1159 .into(),
1160 permanent_difficulty_in_dummy: consensus.permanent_difficulty_in_dummy,
1161 hardfork_features: ckb_jsonrpc_types::HardForks::new(&consensus.hardfork_switch),
1162 softforks,
1163 }
1164 }
1165}
1166
1167fn u256_low_u64(u: U256) -> u64 {
1169 u.0[0]
1170}