Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ ckb-util = "=0.202.0"
ckb-error = "=0.202.0"
ckb-script = "=0.202.0"
ckb-chain-spec = "=0.202.0"
ckb-sdk = { git="https://github.com/eval-exec/ckb-sdk-rust.git", branch="exec-cookies", features = ["native-tls-vendored"] }
ckb-sdk = { version = "4.2.0", features = ["native-tls-vendored"] }
ckb-mock-tx-types = "=0.202.0"
ckb-signer = { path = "ckb-signer", version = "0.4.1" }
plugin-protocol = { path = "plugin-protocol", package = "ckb-cli-plugin-protocol", version = "=1.3.1" }
Expand Down
23 changes: 21 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,15 @@ ci: fmt clippy test security-audit check-crates check-licenses
git diff --exit-code Cargo.lock

integration:
bash devtools/ci/integration.sh v0.200.0
bash devtools/ci/integration.sh v0.200.0 $(ARGS)

integration-spec:
@if [ -z "$(SPEC)" ]; then \
echo "Usage: make integration-spec SPEC=pattern"; \
echo "Example: make integration-spec SPEC=deploy_type_id"; \
exit 1; \
fi
bash devtools/ci/integration.sh v0.200.0 --spec=$(SPEC)

prod: ## Build binary with release profile.
cargo build --locked --release
Expand All @@ -31,4 +39,15 @@ check-crates: ## Use cargo-deny to check specific crates, detect and handle mult
check-licenses: ## Use cargo-deny to check licenses for all dependencies.
cargo deny check --hide-inclusion-graph --show-stats licenses

.PHONY: test clippy fmt integration ci prod security-audit check-crates check-licenses
integration-help: ## Show usage examples for integration tests
@echo "Integration test usage examples:"
@echo " make integration # Run all integration tests"
@echo " make integration ARGS='--spec=deploy' # Run tests containing 'deploy'"
@echo " make integration-spec SPEC=deploy_type_id # Run tests containing 'deploy_type_id'"
@echo " make integration-spec SPEC=deploy # Run tests containing 'deploy'"
@echo ""
@echo "Environment variable usage:"
@echo " SPEC_FILTER=deploy make integration # Run tests containing 'deploy'"
@echo ""

.PHONY: test clippy fmt integration integration-spec integration-help ci prod security-audit check-crates check-licenses
2 changes: 1 addition & 1 deletion ckb-signer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,4 @@ anyhow = "1.0.63"
ckb-types = "=0.202.0"
ckb-hash = "=0.202.0"
ckb-crypto = { version = "=0.202.0", features = ["secp"] }
ckb-sdk = { git="https://github.com/eval-exec/ckb-sdk-rust.git", branch="exec-cookies", features = ["native-tls-vendored"] }
ckb-sdk = { version = "4.2.0", features = ["native-tls-vendored"] }
3 changes: 2 additions & 1 deletion devtools/ci/integration.sh
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,5 @@ export RUST_LOG=ckb_cli=info,cli_test=info
cd test && cargo run -- \
--ckb-bin "${CKB_BIN}" \
--cli-bin "${CKB_CLI_DIR}/target/release/ckb-cli" \
--keystore-plugin "${CKB_CLI_DIR}/target/debug/examples/keystore_no_password"
--keystore-plugin "${CKB_CLI_DIR}/target/debug/examples/keystore_no_password" \
"${@:2}"
1 change: 1 addition & 0 deletions src/deployment.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ location = { tx_hash = "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
# Dep group cells
[[dep_groups]]
name = "my_dep_group"
enable_type_id = false
cells = [
"my_cell",
"genesis_cell"
Expand Down
2 changes: 2 additions & 0 deletions src/subcommands/deploy/deployment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ pub struct Cell {
pub struct DepGroup {
pub name: String,
pub cells: Vec<String>,
pub enable_type_id: bool,
}

// Recipe
Expand All @@ -56,6 +57,7 @@ pub struct DepGroupRecipe {
#[serde(default)]
pub data_hash: H256,
pub occupied_capacity: u64,
pub type_id: Option<H256>,
}

#[derive(Clone, Debug, Serialize, Deserialize, Default)]
Expand Down
91 changes: 58 additions & 33 deletions src/subcommands/deploy/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -252,11 +252,29 @@ impl CliSubCommand for DeploySubCommand<'_> {
}

// * Build new dep_group recipes
// Only get first input if any dep_group needs TypeID
let needs_type_id = dep_group_changes.iter().any(|change| match change {
StateChange::NewAdded { config, .. } | StateChange::Changed { config, .. } => {
config.enable_type_id
}
_ => false,
});

let first_dep_group_input_opt = if needs_type_id {
dep_group_tx_opt
.as_ref()
.and_then(|dep_group_tx| dep_group_tx.raw().inputs().get(0))
} else {
None
};

let new_dep_group_recipes = build_new_dep_group_recipes(
&lock_script,
dep_group_tx_opt.as_ref(),
&dep_group_changes,
);
first_dep_group_input_opt.as_ref(),
)
.map_err(|err| err.to_string())?;

// * Explain transactions
let repr_cell_changes: Vec<_> = cell_changes
Expand Down Expand Up @@ -887,40 +905,43 @@ fn load_dep_groups(
let data = out_points_vec.as_bytes();
let data_hash = H256::from(blake2b_256(data.as_ref()));
let config = (*dep_group).clone();
let change = if let Some((old_recipe, removed)) =
dep_group_recipes_map.get_mut(&dep_group.name)
{
let old_recipe = old_recipe.clone();
*removed = false;
let (old_data_hash, _, old_output) =
load_cell_info(rpc_client, &old_recipe.tx_hash, old_recipe.index)?;
let old_lock_script = packed::Script::from(old_output.lock);
if data_hash == old_data_hash && lock_script.as_slice() == old_lock_script.as_slice() {
StateChange::Unchanged {
data,
data_hash,
config,
old_recipe,
old_type_id_args: None,
let change =
if let Some((old_recipe, removed)) = dep_group_recipes_map.get_mut(&dep_group.name) {
let old_recipe = old_recipe.clone();
*removed = false;
let (old_data_hash, _, old_output) =
load_cell_info(rpc_client, &old_recipe.tx_hash, old_recipe.index)?;
let old_lock_script = packed::Script::from(old_output.lock);
let old_type_id_args = old_output.type_.map(|script| script.args.into_bytes());
let data_unchanged = data_hash == old_data_hash;
let lock_script_unchanged = lock_script.as_slice() == old_lock_script.as_slice();
let type_id_unchanged = old_recipe.type_id.is_some() == config.enable_type_id;
if data_unchanged && lock_script_unchanged && type_id_unchanged {
StateChange::Unchanged {
data,
data_hash,
config,
old_recipe,
old_type_id_args,
}
} else {
StateChange::Changed {
data,
data_hash,
config,
old_recipe,
output_index,
old_type_id_args,
}
}
} else {
StateChange::Changed {
StateChange::NewAdded {
data,
data_hash,
config,
old_recipe,
output_index,
old_type_id_args: None,
}
}
} else {
StateChange::NewAdded {
data,
data_hash,
config,
output_index,
}
};
};
if change.has_new_output() {
output_index += 1;
}
Expand Down Expand Up @@ -970,18 +991,22 @@ fn build_new_dep_group_recipes(
lock_script: &packed::Script,
dep_group_tx_opt: Option<&packed::Transaction>,
dep_group_changes: &[DepGroupChange],
) -> Vec<DepGroupRecipe> {
first_dep_group_input_opt: Option<&packed::CellInput>,
) -> Result<Vec<DepGroupRecipe>> {
let new_tx_hash: H256 = dep_group_tx_opt
.map(|dep_group_tx| dep_group_tx.calc_tx_hash().unpack())
.unwrap_or_default();
dep_group_changes

let recipes: Result<Vec<_>, _> = dep_group_changes
.iter()
.filter(|info| info.has_new_recipe())
.map(|info| {
info.build_new_recipe(lock_script, new_tx_hash.clone())
.expect("to new dep_group recipe")
info.build_new_recipe(lock_script, new_tx_hash.clone(), first_dep_group_input_opt)
.ok_or_else(|| anyhow!("Failed to build dep_group recipe for '{}'", info.name()))
})
.collect()
.collect();

recipes
}

fn explain_txs(info: &IntermediumInfo) -> Result<()> {
Expand Down
104 changes: 92 additions & 12 deletions src/subcommands/deploy/state_change.rs
Original file line number Diff line number Diff line change
Expand Up @@ -318,15 +318,21 @@ impl ChangeInfo for DepGroupChange {
}

fn occupied_capacity(&self, lock_script: &packed::Script) -> u64 {
let data = match self {
let (data, config) = match self {
StateChange::Removed { .. } => return 0,
StateChange::Changed { data, .. } => data,
StateChange::Unchanged { data, .. } => data,
StateChange::Reference { .. } => return 0,
StateChange::NewAdded { data, .. } => data,
StateChange::Changed { data, config, .. } => (data, config),
StateChange::Unchanged { data, config, .. } => (data, config),
StateChange::NewAdded { data, config, .. } => (data, config),
};
let data_size = data.len() as u64;
lock_script.occupied_capacity().expect("capacity").as_u64() + (data_size + 8) * ONE_CKB
let type_script_size: u64 = if config.enable_type_id {
32 + 1 + 32
} else {
0
};
lock_script.occupied_capacity().expect("capacity").as_u64()
+ (type_script_size + data_size + 8) * ONE_CKB
}

fn build_input(&self) -> Option<(packed::CellInput, u64)> {
Expand All @@ -343,19 +349,51 @@ impl ChangeInfo for DepGroupChange {
fn build_cell_output(
&self,
lock_script: &packed::Script,
_first_cell_input: &packed::CellInput,
first_cell_input: &packed::CellInput,
) -> Option<(packed::CellOutput, Bytes)> {
let data = match self {
let (data, config, output_index, old_type_id_args) = match self {
StateChange::Removed { .. } => return None,
StateChange::Unchanged { .. } => return None,
StateChange::Reference { .. } => return None,
StateChange::Changed { data, .. } => data,
StateChange::NewAdded { data, .. } => data,
StateChange::Changed {
data,
config,
old_type_id_args,
output_index,
..
} => (data, config, *output_index, old_type_id_args.clone()),
StateChange::NewAdded {
data,
config,
output_index,
..
} => (data, config, *output_index, None),
};
let type_id_args = if config.enable_type_id {
old_type_id_args.or_else(|| {
Some(Bytes::from(
calculate_type_id(first_cell_input, output_index).to_vec(),
))
})
} else {
None
};
let occupied_capacity = self.occupied_capacity(lock_script);
let type_script_opt = type_id_args.map(|type_id_args| {
packed::Script::new_builder()
.code_hash(TYPE_ID_CODE_HASH.pack())
.hash_type(ScriptHashType::Type.into())
.args(Bytes::from(type_id_args.to_vec()).pack())
.build()
});
let output = packed::CellOutput::new_builder()
.capacity(Capacity::shannons(occupied_capacity).pack())
.lock(lock_script.clone())
.type_(
packed::ScriptOpt::new_builder()
.set(type_script_opt)
.build(),
)
.build();
Some((output, data.clone()))
}
Expand All @@ -366,33 +404,74 @@ impl DepGroupChange {
&self,
lock_script: &packed::Script,
new_tx_hash: H256,
first_cell_input: Option<&packed::CellInput>,
) -> Option<DepGroupRecipe> {
let (tx_hash, index, data_hash) = match self {
let (tx_hash, index, data_hash, config, old_type_id_args) = match self {
StateChange::Removed { .. } => {
return None;
}
StateChange::Changed {
data_hash,
config,
old_type_id_args,
output_index,
..
} => (new_tx_hash, *output_index as u32, data_hash.clone()),
} => (
new_tx_hash,
*output_index as u32,
data_hash.clone(),
config,
old_type_id_args.clone(),
),
StateChange::Unchanged {
data_hash,
config,
old_recipe,
old_type_id_args,
..
} => (
old_recipe.tx_hash.clone(),
old_recipe.index,
data_hash.clone(),
config,
old_type_id_args.clone(),
),
StateChange::Reference { .. } => {
return None;
}
StateChange::NewAdded {
data_hash,
config,
output_index,
..
} => (new_tx_hash, *output_index as u32, data_hash.clone()),
} => (
new_tx_hash,
*output_index as u32,
data_hash.clone(),
config,
None,
),
};
let type_id = if config.enable_type_id {
let args = if let Some(existing_args) = old_type_id_args {
existing_args
} else {
let input = first_cell_input.unwrap_or_else(|| {
panic!(
"TypeID requested for dep_group '{}' but no first input available",
config.name
)
});
Bytes::from(calculate_type_id(input, index as u64).to_vec())
};
let type_script = packed::Script::new_builder()
.code_hash(TYPE_ID_CODE_HASH.pack())
.hash_type(ScriptHashType::Type.into())
.args(Bytes::from(args.to_vec()).pack())
.build();
Some(type_script.calc_script_hash().unpack())
} else {
None
};
Some(DepGroupRecipe {
name: self.name().clone(),
Expand All @@ -401,6 +480,7 @@ impl DepGroupChange {
index,
data_hash,
occupied_capacity: self.occupied_capacity(lock_script),
type_id,
})
}
}
Loading