Skip to content

Commit 04d0654

Browse files
committed
Upgrade multisig
Signed-off-by: Eval EXEC <[email protected]>
1 parent 0022ed7 commit 04d0654

15 files changed

+359
-133
lines changed

examples/send_ckb_multisig_example.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use ckb_sdk::{
2+
constants::MultisigScript,
23
transaction::{
34
builder::{CkbTransactionBuilder, SimpleTransactionBuilder},
45
handler::HandlerContexts,
@@ -17,22 +18,25 @@ fn main() -> Result<(), Box<dyn StdErr>> {
1718
let configuration = TransactionBuilderConfiguration::new_with_network(network_info.clone())?;
1819

1920
let multisig_config = MultisigConfig::new_with(
21+
MultisigScript::V1,
2022
vec![
2123
h160!("0x7336b0ba900684cb3cb00f0d46d4f64c0994a562"),
2224
h160!("0x5724c1e3925a5206944d753a6f3edaedf977d77f"),
2325
],
2426
0,
2527
2,
2628
)?;
27-
let sender = multisig_config.to_address(network_info.network_type, None);
29+
let sender = multisig_config.to_address(network_info.network_type, MultisigScript::V1, None);
30+
println!("sender: {}", sender);
2831
let receiver = Address::from_str("ckt1qzda0cr08m85hc8jlnfp3zer7xulejywt49kt2rr0vthywaa50xwsq2qf8keemy2p5uu0g0gn8cd4ju23s5269qk8rg4r")?;
2932

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

3437
let mut tx_with_groups =
3538
builder.build(&HandlerContexts::new_multisig(multisig_config.clone()))?;
39+
println!("tx_with_groups:{:?}", &tx_with_groups);
3640

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

examples/transfer_from_multisig.rs

Lines changed: 10 additions & 5 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::{MultisigScript, SIGHASH_TYPE_HASH},
1010
rpc::CkbRpcClient,
1111
traits::{
1212
DefaultCellCollector, DefaultCellDepResolver, DefaultHeaderDepResolver,
@@ -144,7 +144,12 @@ fn main() -> Result<(), Box<dyn StdErr>> {
144144
}
145145
sighash_addresses.push(H160::from_slice(lock_args.as_ref()).unwrap());
146146
}
147-
MultisigConfig::new_with(sighash_addresses, args.require_first_n, args.threshold)?
147+
MultisigConfig::new_with(
148+
ckb_sdk::constants::MultisigScript::V1,
149+
sighash_addresses,
150+
args.require_first_n,
151+
args.threshold,
152+
)?
148153
};
149154
let tx = build_transfer_tx(&args, &multisig_config)?;
150155
let tx_info = TxInfo {
@@ -222,8 +227,8 @@ fn build_transfer_tx(
222227
) -> Result<TransactionView, Box<dyn StdErr>> {
223228
// Build CapacityBalancer
224229
let sender = Script::new_builder()
225-
.code_hash(MULTISIG_TYPE_HASH.pack())
226-
.hash_type(ScriptHashType::Type.into())
230+
.code_hash(MultisigScript::V1.script_id().code_hash.pack())
231+
.hash_type(MultisigScript::V1.script_id().hash_type.into())
227232
.args(Bytes::from(multisig_config.hash160().as_bytes().to_vec()).pack())
228233
.build();
229234
let sender_addr = Address::new(args.receiver.network(), sender.clone().into(), true);
@@ -289,7 +294,7 @@ fn build_multisig_unlockers(
289294
let signer = SecpCkbRawKeySigner::new_with_secret_keys(keys);
290295
let multisig_signer = SecpMultisigScriptSigner::new(Box::new(signer), config);
291296
let multisig_unlocker = SecpMultisigUnlocker::new(multisig_signer);
292-
let multisig_script_id = ScriptId::new_type(MULTISIG_TYPE_HASH.clone());
297+
let multisig_script_id = MultisigScript::V1.script_id();
293298
let mut unlockers = HashMap::default();
294299
unlockers.insert(
295300
multisig_script_id,

examples/transfer_from_omnilock_multisig.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use ckb_jsonrpc_types as json_types;
22
use ckb_sdk::{
3-
constants::SIGHASH_TYPE_HASH,
3+
constants::{MultisigScript, SIGHASH_TYPE_HASH},
44
rpc::CkbRpcClient,
55
traits::{
66
DefaultCellCollector, DefaultCellDepResolver, DefaultHeaderDepResolver,
@@ -11,8 +11,10 @@ use ckb_sdk::{
1111
unlock_tx, CapacityBalancer, TxBuilder,
1212
},
1313
types::NetworkType,
14-
unlock::{MultisigConfig, OmniLockUnlocker, ScriptUnlocker},
15-
unlock::{OmniLockConfig, OmniLockScriptSigner, OmniUnlockMode},
14+
unlock::{
15+
MultisigConfig, OmniLockConfig, OmniLockScriptSigner, OmniLockUnlocker, OmniUnlockMode,
16+
ScriptUnlocker,
17+
},
1618
Address, HumanCapacity, ScriptGroup, ScriptId,
1719
};
1820
use ckb_types::{
@@ -272,6 +274,7 @@ fn build_multisig_config(
272274
sighash_addresses.push(H160::from_slice(lock_args.as_ref()).unwrap());
273275
}
274276
Ok(MultisigConfig::new_with(
277+
MultisigScript::V1,
275278
sighash_addresses,
276279
require_first_n,
277280
threshold,

src/constants.rs

Lines changed: 81 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
1+
use std::convert::TryFrom;
2+
13
use ckb_types::{core::EpochNumberWithFraction, h256, H256};
24

5+
use crate::{NetworkType, ScriptId};
6+
37
pub const PREFIX_MAINNET: &str = "ckb";
48
pub const PREFIX_TESTNET: &str = "ckt";
59

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

3640
pub const SIGHASH_TYPE_HASH: H256 =
3741
h256!("0x9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8");
38-
pub const MULTISIG_TYPE_HASH: H256 =
39-
h256!("0x5c5069eb0857efc65e1bca0c07df34c31663b3622fd3876c876320fc9634e2a8");
42+
43+
pub const GENESIS_BLOCK_HASH_MAINNET: H256 =
44+
h256!("0x92b197aa1fba0f63633922c61c92375c9c074a93e85963554f5499fe1450d0e5");
45+
46+
pub const GENESIS_BLOCK_HASH_TESTNET: H256 =
47+
h256!("0x10639e0895502b5688a6be8cf69460d76541bfa4821629d86d62ba0aae3f9606");
48+
49+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
50+
pub enum MultisigScript {
51+
/// Multisig Script deployed on Genesis Block
52+
/// https://explorer.nervos.org/script/0x5c5069eb0857efc65e1bca0c07df34c31663b3622fd3876c876320fc9634e2a8/type
53+
Legacy,
54+
55+
/// Latest multisig script
56+
/// https://explorer.nervos.org/script/0x36c971b8d41fbd94aabca77dc75e826729ac98447b46f91e00796155dddb0d29/data1
57+
V1,
58+
}
59+
60+
impl MultisigScript {
61+
pub const fn script_id(&self) -> ScriptId {
62+
match self {
63+
MultisigScript::Legacy => ScriptId::new_type(h256!(
64+
"0x5c5069eb0857efc65e1bca0c07df34c31663b3622fd3876c876320fc9634e2a8"
65+
)),
66+
MultisigScript::V1 => ScriptId::new_data1(h256!(
67+
"0x36c971b8d41fbd94aabca77dc75e826729ac98447b46f91e00796155dddb0d29"
68+
)),
69+
}
70+
}
71+
72+
pub const fn dep_group(&self, network: NetworkType) -> (H256, u32) {
73+
match self {
74+
MultisigScript::Legacy => match network {
75+
NetworkType::Mainnet => (
76+
h256!("0x71a7ba8fc96349fea0ed3a5c47992e3b4084b031a42264a018e0072e8172e46c"),
77+
1,
78+
),
79+
NetworkType::Testnet => (
80+
h256!("0xf8de3bb47d055cdf460d93a2a6e1b05f7432f9777c8c474abf4eec1d4aee5d37"),
81+
1,
82+
),
83+
NetworkType::Staging => todo!(),
84+
NetworkType::Preview => todo!(),
85+
NetworkType::Dev => todo!(),
86+
},
87+
MultisigScript::V1 => match network {
88+
// https://github.com/nervosnetwork/ckb-system-scripts/pull/99#issuecomment-2814285588
89+
NetworkType::Mainnet => (
90+
h256!("0x6888aa39ab30c570c2c30d9d5684d3769bf77265a7973211a3c087fe8efbf738"),
91+
0,
92+
),
93+
// https://github.com/nervosnetwork/ckb-system-scripts/pull/99#issuecomment-2757175017
94+
NetworkType::Testnet => (
95+
h256!("0x2eefdeb21f3a3edf697c28a52601b4419806ed60bb427420455cc29a090b26d5"),
96+
0,
97+
),
98+
NetworkType::Staging => todo!(),
99+
NetworkType::Preview => todo!(),
100+
NetworkType::Dev => todo!(),
101+
},
102+
}
103+
}
104+
}
105+
impl TryFrom<H256> for MultisigScript {
106+
type Error = ();
107+
108+
fn try_from(code_hash: H256) -> Result<Self, Self::Error> {
109+
if code_hash.eq(&MultisigScript::Legacy.script_id().code_hash) {
110+
Ok(MultisigScript::Legacy)
111+
} else if code_hash.eq(&MultisigScript::V1.script_id().code_hash) {
112+
Ok(MultisigScript::V1)
113+
} else {
114+
Err(())
115+
}
116+
}
117+
}
118+
40119
pub const DAO_TYPE_HASH: H256 =
41120
h256!("0x82d76d1b75fe2fd9a27dfbaa65a039221a380d76c926f378d3f81cf3e7e13f2e");
42121

src/test_util.rs

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use thiserror::Error;
1111

1212
use crate::{
1313
constants::{
14-
MULTISIG_GROUP_OUTPUT_LOC, MULTISIG_TYPE_HASH, ONE_CKB, SIGHASH_GROUP_OUTPUT_LOC,
14+
MultisigScript, MULTISIG_GROUP_OUTPUT_LOC, ONE_CKB, SIGHASH_GROUP_OUTPUT_LOC,
1515
SIGHASH_TYPE_HASH,
1616
},
1717
traits::{
@@ -91,26 +91,35 @@ impl Context {
9191
SIGHASH_GROUP_OUTPUT_LOC,
9292
),
9393
(
94-
cell_dep_resolver.multisig_dep().unwrap().clone().0,
94+
cell_dep_resolver
95+
.multisig_dep(MultisigScript::Legacy)
96+
.unwrap()
97+
.clone()
98+
.0,
9599
MULTISIG_GROUP_OUTPUT_LOC,
96100
),
97101
] {
98102
let tx = block.transaction(tx_idx).expect("get tx");
99103
let (output, data) = tx.output_with_data(output_idx).expect("get output+data");
100104
ctx.add_cell_dep(cell_dep, output, data, Some(block_hash.clone()));
101105
}
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);
106+
ctx.add_cell_dep_map(
107+
ScriptId::new_type(SIGHASH_TYPE_HASH),
108+
cell_dep_resolver.sighash_dep().unwrap().0.clone(),
109+
);
110+
111+
ctx.add_cell_dep_map(
112+
MultisigScript::Legacy.script_id(),
113+
cell_dep_resolver
114+
.multisig_dep(MultisigScript::Legacy)
115+
.unwrap()
116+
.0
117+
.clone(),
118+
);
119+
if let Some(cell_deps) = cell_dep_resolver.multisig_dep(MultisigScript::V1) {
120+
ctx.add_cell_dep_map(MultisigScript::V1.script_id(), cell_deps.0.clone());
113121
}
122+
114123
for tx in block.transactions().iter() {
115124
for (idx, (output, data)) in tx
116125
.outputs()

src/tests/mod.rs

Lines changed: 50 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,8 @@
11
use std::collections::HashMap;
2-
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-
};
2+
use std::convert::TryFrom;
143

154
use crate::constants::{
16-
CHEQUE_CELL_SINCE, DAO_TYPE_HASH, MULTISIG_TYPE_HASH, ONE_CKB, SIGHASH_TYPE_HASH,
5+
MultisigScript, CHEQUE_CELL_SINCE, DAO_TYPE_HASH, ONE_CKB, SIGHASH_TYPE_HASH,
176
};
187
use crate::traits::SecpCkbRawKeySigner;
198
use crate::tx_builder::{
@@ -33,6 +22,17 @@ use crate::unlock::{
3322
};
3423
use crate::util::{calculate_dao_maximum_withdraw4, minimal_unlock_point};
3524
use crate::{ScriptId, Since, SinceType};
25+
use ckb_dao_utils::pack_dao_data;
26+
use ckb_hash::blake2b_256;
27+
use ckb_jsonrpc_types as json_types;
28+
use ckb_types::{
29+
bytes::Bytes,
30+
core::{BlockView, Capacity, EpochNumberWithFraction, HeaderBuilder, ScriptHashType},
31+
h160, h256,
32+
packed::{CellInput, CellOutput, Script, ScriptOpt, WitnessArgs},
33+
prelude::*,
34+
H160, H256,
35+
};
3636

3737
use crate::test_util::{random_out_point, Context};
3838

@@ -72,9 +72,18 @@ fn build_sighash_script(args: H160) -> Script {
7272
}
7373

7474
fn build_multisig_script(cfg: &MultisigConfig) -> Script {
75+
let multisig_script = MultisigScript::try_from(cfg.lock_code_hash())
76+
.unwrap_or_else(|err| {
77+
panic!(
78+
"Failed to get multisig script from {}: {:?}",
79+
cfg.lock_code_hash(),
80+
err
81+
)
82+
})
83+
.script_id();
7584
Script::new_builder()
76-
.code_hash(MULTISIG_TYPE_HASH.pack())
77-
.hash_type(ScriptHashType::Type.into())
85+
.code_hash(multisig_script.code_hash.pack())
86+
.hash_type(multisig_script.hash_type.into())
7887
.args(Bytes::from(cfg.hash160().0.to_vec()).pack())
7988
.build()
8089
}
@@ -104,8 +113,17 @@ fn build_multisig_unlockers(
104113
config: MultisigConfig,
105114
) -> HashMap<ScriptId, Box<dyn ScriptUnlocker>> {
106115
let signer = SecpCkbRawKeySigner::new_with_secret_keys(vec![key]);
107-
let multisig_unlocker = SecpMultisigUnlocker::from((Box::new(signer) as Box<_>, config));
108-
let multisig_script_id = ScriptId::new_type(MULTISIG_TYPE_HASH.clone());
116+
let multisig_unlocker =
117+
SecpMultisigUnlocker::from((Box::new(signer) as Box<_>, config.clone()));
118+
let multisig_script_id = MultisigScript::try_from(config.lock_code_hash())
119+
.unwrap_or_else(|err| {
120+
panic!(
121+
"Failed to get multisig script from {}:{:?}",
122+
config.lock_code_hash(),
123+
err
124+
)
125+
})
126+
.script_id();
109127
let mut unlockers = HashMap::default();
110128
unlockers.insert(
111129
multisig_script_id,
@@ -214,13 +232,21 @@ fn test_transfer_from_multisig() {
214232
ACCOUNT1_ARG.clone(),
215233
ACCOUNT2_ARG.clone(),
216234
];
217-
let cfg = MultisigConfig::new_with(lock_args, 0, 2).unwrap();
235+
let cfg = MultisigConfig::new_with(MultisigScript::V1, lock_args, 0, 2).unwrap();
218236

219237
let sender = build_multisig_script(&cfg);
220238
let receiver = build_sighash_script(ACCOUNT2_ARG);
221239

240+
// The multisig contract is not in the genesis block, so we need to add it to the context.
241+
// 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
242+
let multisig_contract =
243+
std::fs::read_to_string("./src/tests/secp256k1_blake160_multisig_all.hex.txt").unwrap();
244+
let multisig_contract = multisig_contract.trim();
245+
let contract = hex::decode(multisig_contract).unwrap();
246+
247+
let contract: (&[u8], bool) = (contract.as_slice(), true);
222248
let ctx = init_context(
223-
Vec::new(),
249+
vec![contract],
224250
vec![
225251
(sender.clone(), Some(100 * ONE_CKB)),
226252
(sender.clone(), Some(200 * ONE_CKB)),
@@ -258,6 +284,7 @@ fn test_transfer_from_multisig() {
258284
assert_eq!(tx.cell_deps().len(), 1);
259285
assert_eq!(tx.inputs().len(), 2);
260286
for out_point in tx.input_pts_iter() {
287+
dbg!(&out_point);
261288
assert_eq!(ctx.get_input(&out_point).unwrap().0.lock(), sender);
262289
}
263290
assert_eq!(tx.outputs().len(), 2);
@@ -271,6 +298,10 @@ fn test_transfer_from_multisig() {
271298
assert_eq!(witnesses.len(), 2);
272299
assert_eq!(witnesses[0].len(), placeholder_witness.as_slice().len());
273300
assert_eq!(witnesses[1].len(), 0);
301+
tx.inputs().into_iter().for_each(|input| {
302+
dbg!(&input);
303+
});
304+
dbg!(&tx);
274305
ctx.verify(tx, FEE_RATE).unwrap();
275306
}
276307

0 commit comments

Comments
 (0)