1mod error;
4
5use byteorder::{ByteOrder, LittleEndian};
6use ckb_types::{
7 H160,
8 core::{Capacity, Ratio, TransactionView, capacity_bytes},
9 packed::{Byte32, OutPoint},
10 prelude::*,
11};
12use std::collections::HashSet;
13
14pub use crate::error::DaoError;
15
16const DEFAULT_GENESIS_ACCUMULATE_RATE: u64 = 10_000_000_000_000_000;
18
19#[doc(hidden)]
23pub fn genesis_dao_data(txs: Vec<&TransactionView>) -> Result<Byte32, DaoError> {
24 genesis_dao_data_with_satoshi_gift(
25 txs,
26 &H160([0u8; 20]),
27 Ratio::new(1, 1),
28 capacity_bytes!(1_000_000),
29 capacity_bytes!(1000),
30 )
31}
32
33#[doc(hidden)]
35pub fn genesis_dao_data_with_satoshi_gift(
36 txs: Vec<&TransactionView>,
37 satoshi_pubkey_hash: &H160,
38 satoshi_cell_occupied_ratio: Ratio,
39 initial_primary_issuance: Capacity,
40 initial_secondary_issuance: Capacity,
41) -> Result<Byte32, DaoError> {
42 let dead_cells = txs
43 .iter()
44 .flat_map(|tx| tx.inputs().into_iter().map(|input| input.previous_output()))
45 .collect::<HashSet<_>>();
46 let statistics_outputs = |tx_index, tx: &TransactionView| -> Result<_, DaoError> {
47 let c = tx
48 .data()
49 .raw()
50 .outputs()
51 .into_iter()
52 .enumerate()
53 .filter(|(index, _)| !dead_cells.contains(&OutPoint::new(tx.hash(), *index as u32)))
54 .try_fold(Capacity::zero(), |capacity, (_, output)| {
55 let cap: Capacity = output.capacity().into();
56 capacity.safe_add(cap)
57 })?;
58 let u = tx
59 .outputs_with_data_iter()
60 .enumerate()
61 .filter(|(index, _)| !dead_cells.contains(&OutPoint::new(tx.hash(), *index as u32)))
62 .try_fold(Capacity::zero(), |capacity, (_, (output, data))| {
63 let occupied_capacity = if tx_index == 0
65 && output.lock().args().raw_data() == satoshi_pubkey_hash.0[..]
66 {
67 Into::<Capacity>::into(output.capacity())
68 .safe_mul_ratio(satoshi_cell_occupied_ratio)
69 } else {
70 Capacity::bytes(data.len()).and_then(|c| output.occupied_capacity(c))
71 };
72 occupied_capacity.and_then(|c| capacity.safe_add(c))
73 })?;
74 Ok((c, u))
75 };
76
77 let initial_issuance = initial_primary_issuance.safe_add(initial_secondary_issuance)?;
78 let result: Result<_, DaoError> = txs.into_iter().enumerate().try_fold(
79 (initial_issuance, Capacity::zero()),
80 |(c, u), (tx_index, tx)| {
81 let (tx_c, tx_u) = statistics_outputs(tx_index, tx)?;
82 let c = c.safe_add(tx_c)?;
83 let u = u.safe_add(tx_u)?;
84 Ok((c, u))
85 },
86 );
87 let (c, u) = result?;
88 if c == Capacity::zero() {
91 return Err(DaoError::ZeroC);
92 }
93 Ok(pack_dao_data(
94 DEFAULT_GENESIS_ACCUMULATE_RATE,
95 c,
96 initial_secondary_issuance,
97 u,
98 ))
99}
100
101pub fn extract_dao_data(dao: Byte32) -> (u64, Capacity, Capacity, Capacity) {
105 let data = dao.raw_data();
106 let c = Capacity::shannons(LittleEndian::read_u64(&data[0..8]));
107 let ar = LittleEndian::read_u64(&data[8..16]);
108 let s = Capacity::shannons(LittleEndian::read_u64(&data[16..24]));
109 let u = Capacity::shannons(LittleEndian::read_u64(&data[24..32]));
110 (ar, c, s, u)
111}
112
113pub fn pack_dao_data(ar: u64, c: Capacity, s: Capacity, u: Capacity) -> Byte32 {
117 let mut buf = [0u8; 32];
118 LittleEndian::write_u64(&mut buf[0..8], c.as_u64());
119 LittleEndian::write_u64(&mut buf[8..16], ar);
120 LittleEndian::write_u64(&mut buf[16..24], s.as_u64());
121 LittleEndian::write_u64(&mut buf[24..32], u.as_u64());
122 Byte32::from_slice(&buf).expect("impossible: fail to read array")
123}
124
125#[cfg(test)]
126mod tests {
127 pub use super::{extract_dao_data, pack_dao_data};
128 pub use ckb_types::core::Capacity;
129 pub use ckb_types::h256;
130 pub use ckb_types::packed::Byte32;
131
132 #[test]
133 #[allow(clippy::unreadable_literal)]
134 fn test_dao_data() {
135 let cases = vec![
136 (
137 h256!("0x8874337e541ea12e0000c16ff286230029bfa3320800000000710b00c0fefe06"),
139 10000000000000000,
140 Capacity::shannons(3360000145238488200),
141 Capacity::shannons(35209330473),
142 Capacity::shannons(504120308900000000),
143 ),
144 (
145 h256!("0x10e9164f761ea12ea5f6ff75f28623007b7f682a0f00000000710b00c0fefe06"),
147 10000000104789669,
148 Capacity::shannons(3360000290476976400),
149 Capacity::shannons(65136000891),
150 Capacity::shannons(504120308900000000),
151 ),
152 (
153 h256!("0x95b47fdcff26a42ed0fb76e081872300bb585ebd10a000000043c2f76b5eff06"),
155 10000616071298000,
156 Capacity::shannons(3360854102283105429),
157 Capacity::shannons(175993756997819),
158 Capacity::shannons(504225501100000000),
159 ),
160 ];
161 for (dao_h256, ar, c, s, u) in cases {
162 let dao_byte32: Byte32 = dao_h256.into();
163 assert_eq!((ar, c, s, u), extract_dao_data(dao_byte32.clone()));
164 assert_eq!(dao_byte32, pack_dao_data(ar, c, s, u,));
165 }
166 }
167}