|
| 1 | +use crate::miner::Miner; |
| 2 | +use crate::setup::Setup; |
| 3 | +use crate::spec::udt::ACP_BIN; |
| 4 | +use crate::spec::Spec; |
| 5 | +use ckb_types::H256; |
| 6 | +use serde_json::{Map, Value}; |
| 7 | +use std::fs; |
| 8 | +use tempfile::tempdir; |
| 9 | + |
| 10 | +pub struct DeployInfoOrdering; |
| 11 | + |
| 12 | +impl Spec for DeployInfoOrdering { |
| 13 | + fn run(&self, setup: &mut Setup) { |
| 14 | + let temp_dir = tempdir().expect("create tempdir failed"); |
| 15 | + |
| 16 | + let deployment_config = format!( |
| 17 | + r#" |
| 18 | +[[cells]] |
| 19 | +name = "test_cell" |
| 20 | +enable_type_id = false |
| 21 | +location = {{ file = "{}/test_cell.bin" }} |
| 22 | +
|
| 23 | +[[dep_groups]] |
| 24 | +name = "test_dep_group" |
| 25 | +enable_type_id = false |
| 26 | +cells = ["test_cell"] |
| 27 | +
|
| 28 | +[lock] |
| 29 | +code_hash = "0x{}" |
| 30 | +args = "0x{}" |
| 31 | +hash_type = "type" |
| 32 | +
|
| 33 | +[multisig_config] |
| 34 | +sighash_addresses = [] |
| 35 | +require_first_n = 0 |
| 36 | +threshold = 1 |
| 37 | +"#, |
| 38 | + temp_dir.path().display(), |
| 39 | + "9bd7e06f3ecf4be0f2fcd2188b23f1b9fcc88e5d4b65a8637b17723bbda3cce8", |
| 40 | + "c8328aabcd9b9e8e64fbc566c4385c3bdeb219d7" |
| 41 | + ); |
| 42 | + |
| 43 | + fs::write(temp_dir.path().join("test_cell.bin"), ACP_BIN).unwrap(); |
| 44 | + let config_path = temp_dir.path().join("deployment.toml"); |
| 45 | + fs::write(&config_path, deployment_config).unwrap(); |
| 46 | + |
| 47 | + let info_file = temp_dir.path().join("deployment_info.json"); |
| 48 | + let migration_dir = temp_dir.path().join("migrations"); |
| 49 | + fs::create_dir_all(&migration_dir).unwrap(); |
| 50 | + |
| 51 | + setup.cli(&format!( |
| 52 | + "deploy gen-txs --deployment-config {} --info-file {} --migration-dir {} --from-address {} --fee-rate 1000", |
| 53 | + config_path.display(), |
| 54 | + info_file.display(), |
| 55 | + migration_dir.display(), |
| 56 | + Miner::address() |
| 57 | + )); |
| 58 | + |
| 59 | + let info_content = fs::read_to_string(&info_file).unwrap(); |
| 60 | + let mut info_json: Value = serde_json::from_str(&info_content).unwrap(); |
| 61 | + let used_input_txs = info_json["used_input_txs"] |
| 62 | + .as_object() |
| 63 | + .expect("used_input_txs should be a map"); |
| 64 | + assert!( |
| 65 | + !used_input_txs.is_empty(), |
| 66 | + "used_input_txs should not be empty" |
| 67 | + ); |
| 68 | + |
| 69 | + let sample_tx = used_input_txs.values().next().cloned().unwrap(); |
| 70 | + let mut reordered_map = Map::new(); |
| 71 | + let extra_keys = vec![ |
| 72 | + H256::from_low_u64_be(3), |
| 73 | + H256::from_low_u64_be(1), |
| 74 | + H256::from_low_u64_be(4), |
| 75 | + H256::from_low_u64_be(2), |
| 76 | + ]; |
| 77 | + for key in &extra_keys { |
| 78 | + reordered_map.insert(format!("{:#x}", key), sample_tx.clone()); |
| 79 | + } |
| 80 | + for (key, value) in used_input_txs.iter() { |
| 81 | + reordered_map.insert(key.clone(), value.clone()); |
| 82 | + } |
| 83 | + info_json["used_input_txs"] = Value::Object(reordered_map); |
| 84 | + fs::write(&info_file, serde_json::to_string_pretty(&info_json).unwrap()).unwrap(); |
| 85 | + |
| 86 | + let privkey_path = setup.miner().privkey_path().to_string(); |
| 87 | + setup.cli(&format!( |
| 88 | + "deploy sign-txs --info-file {} --privkey-path {} --add-signatures", |
| 89 | + info_file.display(), |
| 90 | + privkey_path |
| 91 | + )); |
| 92 | + |
| 93 | + let updated_content = fs::read_to_string(&info_file).unwrap(); |
| 94 | + let updated_json: Value = serde_json::from_str(&updated_content).unwrap(); |
| 95 | + let updated_map = updated_json["used_input_txs"] |
| 96 | + .as_object() |
| 97 | + .expect("used_input_txs should be a map"); |
| 98 | + let ordered_keys: Vec<String> = updated_map.keys().cloned().collect(); |
| 99 | + |
| 100 | + let mut sorted_keys: Vec<H256> = ordered_keys |
| 101 | + .iter() |
| 102 | + .map(|key| serde_json::from_str::<H256>(&format!("\"{}\"", key)).unwrap()) |
| 103 | + .collect(); |
| 104 | + sorted_keys.sort(); |
| 105 | + let sorted_key_strings: Vec<String> = |
| 106 | + sorted_keys.iter().map(|key| format!("{:#x}", key)).collect(); |
| 107 | + |
| 108 | + assert_eq!( |
| 109 | + ordered_keys, sorted_key_strings, |
| 110 | + "used_input_txs keys should be sorted for stable JSON output" |
| 111 | + ); |
| 112 | + } |
| 113 | + |
| 114 | + fn spec_name(&self) -> &'static str { |
| 115 | + "DeployInfoOrdering" |
| 116 | + } |
| 117 | +} |
0 commit comments