Skip to content

Commit e6e85a8

Browse files
committed
Upgrade multisig
Signed-off-by: Eval EXEC <execvy@gmail.com>
1 parent c8877c2 commit e6e85a8

File tree

13 files changed

+174
-108
lines changed

13 files changed

+174
-108
lines changed

examples/send_ckb_multisig_example.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,16 @@ fn main() -> Result<(), Box<dyn StdErr>> {
2525
2,
2626
)?;
2727
let sender = multisig_config.to_address(network_info.network_type, None);
28+
println!("sender: {}", sender);
2829
let receiver = Address::from_str("ckt1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsq2qf8keemy2p5uu0g0gn8cd4ju23s5269qk8rg4r")?;
2930

3031
let iterator = InputIterator::new_with_address(&[sender], &network_info);
3132
let mut builder = SimpleTransactionBuilder::new(configuration, iterator);
32-
builder.add_output(&receiver, Capacity::shannons(510_0000_0000u64));
33+
builder.add_output(&receiver, Capacity::shannons(6100000000u64));
3334

3435
let mut tx_with_groups =
3536
builder.build(&HandlerContexts::new_multisig(multisig_config.clone()))?;
37+
println!("tx_with_groups:{:?}", &tx_with_groups);
3638

3739
let json_tx = ckb_jsonrpc_types::TransactionView::from(tx_with_groups.get_tx_view().clone());
3840
println!("tx: {}", serde_json::to_string_pretty(&json_tx).unwrap());

examples/transfer_from_multisig.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use std::path::PathBuf;
66
use ckb_hash::blake2b_256;
77
use ckb_jsonrpc_types as json_types;
88
use ckb_sdk::{
9-
constants::{MULTISIG_TYPE_HASH, SIGHASH_TYPE_HASH},
9+
constants::{MULTISIG_SCRIPT, SIGHASH_TYPE_HASH},
1010
rpc::CkbRpcClient,
1111
traits::{
1212
DefaultCellCollector, DefaultCellDepResolver, DefaultHeaderDepResolver,
@@ -222,8 +222,8 @@ fn build_transfer_tx(
222222
) -> Result<TransactionView, Box<dyn StdErr>> {
223223
// Build CapacityBalancer
224224
let sender = Script::new_builder()
225-
.code_hash(MULTISIG_TYPE_HASH.pack())
226-
.hash_type(ScriptHashType::Type.into())
225+
.code_hash(MULTISIG_SCRIPT.code_hash.pack())
226+
.hash_type(MULTISIG_SCRIPT.hash_type.into())
227227
.args(Bytes::from(multisig_config.hash160().as_bytes().to_vec()).pack())
228228
.build();
229229
let sender_addr = Address::new(args.receiver.network(), sender.clone().into(), true);
@@ -289,7 +289,7 @@ fn build_multisig_unlockers(
289289
let signer = SecpCkbRawKeySigner::new_with_secret_keys(keys);
290290
let multisig_signer = SecpMultisigScriptSigner::new(Box::new(signer), config);
291291
let multisig_unlocker = SecpMultisigUnlocker::new(multisig_signer);
292-
let multisig_script_id = ScriptId::new_type(MULTISIG_TYPE_HASH.clone());
292+
let multisig_script_id = MULTISIG_SCRIPT;
293293
let mut unlockers = HashMap::default();
294294
unlockers.insert(
295295
multisig_script_id,

src/constants.rs

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use ckb_types::{core::EpochNumberWithFraction, h256, H256};
22

3+
use crate::ScriptId;
4+
35
pub const PREFIX_MAINNET: &str = "ckb";
46
pub const PREFIX_TESTNET: &str = "ckt";
57

@@ -35,8 +37,35 @@ pub const TYPE_ID_CODE_HASH: H256 = h256!("0x545950455f4944");
3537

3638
pub const SIGHASH_TYPE_HASH: H256 =
3739
h256!("0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8");
38-
pub const MULTISIG_TYPE_HASH: H256 =
39-
h256!("0x5c5069eb0857efc65e1bca0c07df34c31663b3622fd3876c876320fc9634e2a8");
40+
41+
pub const GENESIS_BLOCK_HASH_MAINNET: H256 =
42+
h256!("0x92b197aa1fba0f63633922c61c92375c9c074a93e85963554f5499fe1450d0e5");
43+
44+
pub const GENESIS_BLOCK_HASH_TESTNET: H256 =
45+
h256!("0x10639e0895502b5688a6be8cf69460d76541bfa4821629d86d62ba0aae3f9606");
46+
47+
/// Depreacted MultiSig: HashType: type
48+
pub const MULTISIG_SCRIPT_DEPRECATED: ScriptId = ScriptId::new_type(h256!(
49+
"0x5c5069eb0857efc65e1bca0c07df34c31663b3622fd3876c876320fc9634e2a8"
50+
));
51+
52+
/// MultiSig: HashType: data1,
53+
pub const MULTISIG_SCRIPT: ScriptId = ScriptId::new_data1(h256!(
54+
"0x36c971b8d41fbd94aabca77dc75e826729ac98447b46f91e00796155dddb0d29"
55+
));
56+
57+
/// https://github.com/nervosnetwork/ckb-system-scripts/pull/99#issuecomment-2814285588
58+
pub const MULTISIG_DEP_GROUP_MAINNET: (H256, u32) = (
59+
h256!("0x6888aa39ab30c570c2c30d9d5684d3769bf77265a7973211a3c087fe8efbf738"),
60+
0,
61+
);
62+
63+
/// https://github.com/nervosnetwork/ckb-system-scripts/pull/99#issuecomment-2757175017
64+
pub const MULTISIG_DEP_GROUP_TESTNET: (H256, u32) = (
65+
h256!("0x2eefdeb21f3a3edf697c28a52601b4419806ed60bb427420455cc29a090b26d5"),
66+
0,
67+
);
68+
4069
pub const DAO_TYPE_HASH: H256 =
4170
h256!("0x82d76d1b75fe2fd9a27dfbaa65a039221a380d76c926f378d3f81cf3e7e13f2e");
4271

src/test_util.rs

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,9 @@ use ckb_types::core::{HeaderBuilder, TransactionBuilder};
99
use rand::{thread_rng, Rng};
1010
use thiserror::Error;
1111

12+
use crate::constants::MULTISIG_SCRIPT;
1213
use crate::{
13-
constants::{
14-
MULTISIG_GROUP_OUTPUT_LOC, MULTISIG_TYPE_HASH, ONE_CKB, SIGHASH_GROUP_OUTPUT_LOC,
15-
SIGHASH_TYPE_HASH,
16-
},
14+
constants::{MULTISIG_GROUP_OUTPUT_LOC, ONE_CKB, SIGHASH_GROUP_OUTPUT_LOC, SIGHASH_TYPE_HASH},
1715
traits::{
1816
CellCollector, CellCollectorError, CellDepResolver, CellQueryOptions,
1917
DefaultCellDepResolver, HeaderDepResolver, LiveCell, TransactionDependencyError,
@@ -99,18 +97,15 @@ impl Context {
9997
let (output, data) = tx.output_with_data(output_idx).expect("get output+data");
10098
ctx.add_cell_dep(cell_dep, output, data, Some(block_hash.clone()));
10199
}
102-
for (code_hash, cell_dep) in [
103-
(
104-
SIGHASH_TYPE_HASH,
105-
cell_dep_resolver.sighash_dep().unwrap().0.clone(),
106-
),
107-
(
108-
MULTISIG_TYPE_HASH,
109-
cell_dep_resolver.multisig_dep().unwrap().0.clone(),
110-
),
111-
] {
112-
ctx.add_cell_dep_map(ScriptId::new_type(code_hash), cell_dep);
113-
}
100+
ctx.add_cell_dep_map(
101+
ScriptId::new_type(SIGHASH_TYPE_HASH),
102+
cell_dep_resolver.sighash_dep().unwrap().0.clone(),
103+
);
104+
105+
ctx.add_cell_dep_map(
106+
MULTISIG_SCRIPT,
107+
cell_dep_resolver.sighash_dep().unwrap().0.clone(),
108+
);
114109
for tx in block.transactions().iter() {
115110
for (idx, (output, data)) in tx
116111
.outputs()

src/tests/mod.rs

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,7 @@
11
use std::collections::HashMap;
22

3-
use ckb_dao_utils::pack_dao_data;
4-
use ckb_hash::blake2b_256;
5-
use ckb_jsonrpc_types as json_types;
6-
use ckb_types::{
7-
bytes::Bytes,
8-
core::{BlockView, Capacity, EpochNumberWithFraction, HeaderBuilder, ScriptHashType},
9-
h160, h256,
10-
packed::{CellInput, CellOutput, Script, ScriptOpt, WitnessArgs},
11-
prelude::*,
12-
H160, H256,
13-
};
14-
153
use crate::constants::{
16-
CHEQUE_CELL_SINCE, DAO_TYPE_HASH, MULTISIG_TYPE_HASH, ONE_CKB, SIGHASH_TYPE_HASH,
4+
CHEQUE_CELL_SINCE, DAO_TYPE_HASH, MULTISIG_SCRIPT, ONE_CKB, SIGHASH_TYPE_HASH,
175
};
186
use crate::traits::SecpCkbRawKeySigner;
197
use crate::tx_builder::{
@@ -33,6 +21,17 @@ use crate::unlock::{
3321
};
3422
use crate::util::{calculate_dao_maximum_withdraw4, minimal_unlock_point};
3523
use crate::{ScriptId, Since, SinceType};
24+
use ckb_dao_utils::pack_dao_data;
25+
use ckb_hash::blake2b_256;
26+
use ckb_jsonrpc_types as json_types;
27+
use ckb_types::{
28+
bytes::Bytes,
29+
core::{BlockView, Capacity, EpochNumberWithFraction, HeaderBuilder, ScriptHashType},
30+
h160, h256,
31+
packed::{CellInput, CellOutput, Script, ScriptOpt, WitnessArgs},
32+
prelude::*,
33+
H160, H256,
34+
};
3635

3736
use crate::test_util::{random_out_point, Context};
3837

@@ -73,8 +72,8 @@ fn build_sighash_script(args: H160) -> Script {
7372

7473
fn build_multisig_script(cfg: &MultisigConfig) -> Script {
7574
Script::new_builder()
76-
.code_hash(MULTISIG_TYPE_HASH.pack())
77-
.hash_type(ScriptHashType::Type.into())
75+
.code_hash(MULTISIG_SCRIPT.code_hash.pack())
76+
.hash_type(MULTISIG_SCRIPT.hash_type.into())
7877
.args(Bytes::from(cfg.hash160().0.to_vec()).pack())
7978
.build()
8079
}
@@ -105,7 +104,7 @@ fn build_multisig_unlockers(
105104
) -> HashMap<ScriptId, Box<dyn ScriptUnlocker>> {
106105
let signer = SecpCkbRawKeySigner::new_with_secret_keys(vec![key]);
107106
let multisig_unlocker = SecpMultisigUnlocker::from((Box::new(signer) as Box<_>, config));
108-
let multisig_script_id = ScriptId::new_type(MULTISIG_TYPE_HASH.clone());
107+
let multisig_script_id = MULTISIG_SCRIPT;
109108
let mut unlockers = HashMap::default();
110109
unlockers.insert(
111110
multisig_script_id,
@@ -219,8 +218,16 @@ fn test_transfer_from_multisig() {
219218
let sender = build_multisig_script(&cfg);
220219
let receiver = build_sighash_script(ACCOUNT2_ARG);
221220

221+
// The multisig contract is not in the genesis block, so we need to add it to the context.
222+
// xxd -p -c 0 /home/exec/.cargo/git/checkouts/ckb-system-scripts-b6291a7e08e07936/d262955/specs/cells/secp256k1_blake160_multisig_all > src/tests/secp256k1_blake160_multisig_all.hex.txt
223+
let multisig_contract =
224+
std::fs::read_to_string("./src/tests/secp256k1_blake160_multisig_all.hex.txt").unwrap();
225+
let multisig_contract = multisig_contract.trim();
226+
let contract = hex::decode(multisig_contract).unwrap();
227+
228+
let contract: (&[u8], bool) = (contract.as_slice(), true);
222229
let ctx = init_context(
223-
Vec::new(),
230+
vec![contract],
224231
vec![
225232
(sender.clone(), Some(100 * ONE_CKB)),
226233
(sender.clone(), Some(200 * ONE_CKB)),
@@ -258,6 +265,7 @@ fn test_transfer_from_multisig() {
258265
assert_eq!(tx.cell_deps().len(), 1);
259266
assert_eq!(tx.inputs().len(), 2);
260267
for out_point in tx.input_pts_iter() {
268+
dbg!(&out_point);
261269
assert_eq!(ctx.get_input(&out_point).unwrap().0.lock(), sender);
262270
}
263271
assert_eq!(tx.outputs().len(), 2);
@@ -271,6 +279,10 @@ fn test_transfer_from_multisig() {
271279
assert_eq!(witnesses.len(), 2);
272280
assert_eq!(witnesses[0].len(), placeholder_witness.as_slice().len());
273281
assert_eq!(witnesses[1].len(), 0);
282+
tx.inputs().into_iter().for_each(|input| {
283+
dbg!(&input);
284+
});
285+
dbg!(&tx);
274286
ctx.verify(tx, FEE_RATE).unwrap();
275287
}
276288

src/tests/secp256k1_blake160_multisig_all.hex.txt

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.

src/traits/default_impls.rs

Lines changed: 63 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -23,24 +23,32 @@ use super::{
2323
OffchainTransactionDependencyProvider,
2424
};
2525
use crate::rpc::ckb_indexer::{Order, SearchKey, Tip};
26-
use crate::rpc::{CkbRpcAsyncClient, IndexerRpcAsyncClient};
27-
use crate::traits::{
28-
CellCollector, CellCollectorError, CellDepResolver, CellQueryOptions, HeaderDepResolver,
29-
LiveCell, QueryOrder, Signer, SignerError, TransactionDependencyError,
30-
TransactionDependencyProvider,
31-
};
32-
use crate::types::ScriptId;
3326
use crate::util::{get_max_mature_number_async, serialize_signature, zeroize_privkey};
3427
use crate::SECP256K1;
28+
use crate::{
29+
constants::GENESIS_BLOCK_HASH_MAINNET,
30+
rpc::{CkbRpcAsyncClient, IndexerRpcAsyncClient},
31+
};
32+
use crate::{constants::MULTISIG_SCRIPT, types::ScriptId};
3533
use crate::{
3634
constants::{
37-
DAO_OUTPUT_LOC, DAO_TYPE_HASH, MULTISIG_GROUP_OUTPUT_LOC, MULTISIG_OUTPUT_LOC,
38-
MULTISIG_TYPE_HASH, SIGHASH_GROUP_OUTPUT_LOC, SIGHASH_OUTPUT_LOC, SIGHASH_TYPE_HASH,
35+
DAO_OUTPUT_LOC, DAO_TYPE_HASH, SIGHASH_GROUP_OUTPUT_LOC, SIGHASH_OUTPUT_LOC,
36+
SIGHASH_TYPE_HASH,
3937
},
4038
util::keccak160,
4139
};
40+
use crate::{
41+
constants::{
42+
GENESIS_BLOCK_HASH_TESTNET, MULTISIG_DEP_GROUP_MAINNET, MULTISIG_DEP_GROUP_TESTNET,
43+
},
44+
traits::{
45+
CellCollector, CellCollectorError, CellDepResolver, CellQueryOptions, HeaderDepResolver,
46+
LiveCell, QueryOrder, Signer, SignerError, TransactionDependencyError,
47+
TransactionDependencyProvider,
48+
},
49+
};
4250
use ckb_resource::{
43-
CODE_HASH_DAO, CODE_HASH_SECP256K1_BLAKE160_MULTISIG_ALL,
51+
CODE_HASH_DAO, // CODE_HASH_SECP256K1_BLAKE160_MULTISIG_ALL,
4452
CODE_HASH_SECP256K1_BLAKE160_SIGHASH_ALL,
4553
};
4654

@@ -69,7 +77,7 @@ impl DefaultCellDepResolver {
6977
return Err(ParseGenesisInfoError::InvalidBlockNumber(header.number()));
7078
}
7179
let mut sighash_type_hash = None;
72-
let mut multisig_type_hash = None;
80+
// let mut multisig_type_hash = None;
7381
let mut dao_type_hash = None;
7482
let out_points = genesis_block
7583
.transactions()
@@ -95,20 +103,20 @@ impl DefaultCellDepResolver {
95103
);
96104
}
97105
}
98-
if tx_index == MULTISIG_OUTPUT_LOC.0 && index == MULTISIG_OUTPUT_LOC.1 {
99-
multisig_type_hash = output
100-
.type_()
101-
.to_opt()
102-
.map(|script| script.calc_script_hash());
103-
let data_hash = CellOutput::calc_data_hash(&data.raw_data());
104-
if data_hash != CODE_HASH_SECP256K1_BLAKE160_MULTISIG_ALL.pack() {
105-
log::error!(
106-
"System multisig script code hash error! found: {}, expected: {}",
107-
data_hash,
108-
CODE_HASH_SECP256K1_BLAKE160_MULTISIG_ALL,
109-
);
110-
}
111-
}
106+
// if tx_index == MULTISIG_OUTPUT_LOC.0 && index == MULTISIG_OUTPUT_LOC.1 {
107+
// multisig_type_hash = output
108+
// .type_()
109+
// .to_opt()
110+
// .map(|script| script.calc_script_hash());
111+
// let data_hash = CellOutput::calc_data_hash(&data.raw_data());
112+
// if data_hash != CODE_HASH_SECP256K1_BLAKE160_MULTISIG_ALL.pack() {
113+
// log::error!(
114+
// "System multisig script code hash error! found: {}, expected: {}",
115+
// data_hash,
116+
// CODE_HASH_SECP256K1_BLAKE160_MULTISIG_ALL,
117+
// );
118+
// }
119+
// }
112120
if tx_index == DAO_OUTPUT_LOC.0 && index == DAO_OUTPUT_LOC.1 {
113121
dao_type_hash = output
114122
.type_()
@@ -132,9 +140,6 @@ impl DefaultCellDepResolver {
132140
let sighash_type_hash = sighash_type_hash
133141
.ok_or_else(|| "No type hash(sighash) found in txs[0][1]".to_owned())
134142
.map_err(ParseGenesisInfoError::TypeHashNotFound)?;
135-
let multisig_type_hash = multisig_type_hash
136-
.ok_or_else(|| "No type hash(multisig) found in txs[0][4]".to_owned())
137-
.map_err(ParseGenesisInfoError::TypeHashNotFound)?;
138143
let dao_type_hash = dao_type_hash
139144
.ok_or_else(|| "No type hash(dao) found in txs[0][2]".to_owned())
140145
.map_err(ParseGenesisInfoError::TypeHashNotFound)?;
@@ -143,10 +148,34 @@ impl DefaultCellDepResolver {
143148
.out_point(out_points[SIGHASH_GROUP_OUTPUT_LOC.0][SIGHASH_GROUP_OUTPUT_LOC.1].clone())
144149
.dep_type(DepType::DepGroup.into())
145150
.build();
146-
let multisig_dep = CellDep::new_builder()
147-
.out_point(out_points[MULTISIG_GROUP_OUTPUT_LOC.0][MULTISIG_GROUP_OUTPUT_LOC.1].clone())
148-
.dep_type(DepType::DepGroup.into())
149-
.build();
151+
152+
let multisig_dep = if genesis_block.hash().eq(&GENESIS_BLOCK_HASH_MAINNET.pack()) {
153+
// mainnet
154+
CellDep::new_builder()
155+
.out_point(
156+
ckb_types::packed::OutPoint::new_builder()
157+
.tx_hash(MULTISIG_DEP_GROUP_MAINNET.0.pack())
158+
.index(MULTISIG_DEP_GROUP_MAINNET.1.pack())
159+
.build(),
160+
)
161+
.dep_type(DepType::DepGroup.into())
162+
.build()
163+
} else if genesis_block.hash().eq(&GENESIS_BLOCK_HASH_TESTNET.pack()) {
164+
// testnet
165+
CellDep::new_builder()
166+
.out_point(
167+
ckb_types::packed::OutPoint::new_builder()
168+
.tx_hash(MULTISIG_DEP_GROUP_TESTNET.0.pack())
169+
.index(MULTISIG_DEP_GROUP_TESTNET.1.pack())
170+
.build(),
171+
)
172+
.dep_type(DepType::DepGroup.into())
173+
.build()
174+
} else {
175+
//dev net
176+
unimplemented!()
177+
};
178+
150179
let dao_dep = CellDep::new_builder()
151180
.out_point(out_points[DAO_OUTPUT_LOC.0][DAO_OUTPUT_LOC.1].clone())
152181
.build();
@@ -157,7 +186,7 @@ impl DefaultCellDepResolver {
157186
(sighash_dep, "Secp256k1 blake160 sighash all".to_string()),
158187
);
159188
items.insert(
160-
ScriptId::new_type(multisig_type_hash.unpack()),
189+
MULTISIG_SCRIPT,
161190
(multisig_dep, "Secp256k1 blake160 multisig all".to_string()),
162191
);
163192
items.insert(
@@ -188,7 +217,7 @@ impl DefaultCellDepResolver {
188217
self.get(&ScriptId::new_type(SIGHASH_TYPE_HASH))
189218
}
190219
pub fn multisig_dep(&self) -> Option<&(CellDep, String)> {
191-
self.get(&ScriptId::new_type(MULTISIG_TYPE_HASH))
220+
self.get(&MULTISIG_SCRIPT)
192221
}
193222
pub fn dao_dep(&self) -> Option<&(CellDep, String)> {
194223
self.get(&ScriptId::new_type(DAO_TYPE_HASH))

0 commit comments

Comments
 (0)