Skip to content

Commit

Permalink
Merge pull request #5089 from stacks-network/feat/clarity-wasm-develo…
Browse files Browse the repository at this point in the history
…p-merge

Merging latest develop
  • Loading branch information
obycode authored Aug 20, 2024
2 parents c241855 + f97df0d commit 4eaeabe
Show file tree
Hide file tree
Showing 84 changed files with 4,877 additions and 1,759 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/bitcoin-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ jobs:
- tests::neon_integrations::confirm_unparsed_ongoing_ops
- tests::neon_integrations::min_txs
- tests::neon_integrations::vote_for_aggregate_key_burn_op_test
- tests::neon_integrations::mock_miner_replay
- tests::epoch_25::microblocks_disabled
- tests::should_succeed_handling_malformed_and_valid_txs
- tests::nakamoto_integrations::simple_neon_integration
Expand All @@ -95,6 +96,8 @@ jobs:
- tests::signer::v0::mock_sign_epoch_25
- tests::signer::v0::signer_set_rollover
- tests::signer::v0::miner_forking
- tests::signer::v0::reloads_signer_set_in
- tests::signer::v0::signers_broadcast_signed_blocks
- tests::nakamoto_integrations::stack_stx_burn_op_integration_test
- tests::nakamoto_integrations::check_block_heights
- tests::nakamoto_integrations::clarity_burn_state
Expand Down
1 change: 0 additions & 1 deletion .github/workflows/stacks-core-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,6 @@ jobs:
if: always()
needs:
- full-genesis
- unit-tests
- open-api-validation
- core-contracts-clarinet-test
steps:
Expand Down
5 changes: 2 additions & 3 deletions clarity/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,5 @@ developer-mode = ["stacks-common/developer-mode"]
slog_json = ["stacks-common/slog_json"]
testing = ["canonical", "rstest", "rstest_reuse"]
devtools = []

[target.'cfg(all(target_arch = "x86_64", not(target_env = "msvc")))'.dependencies]
sha2-asm = "0.5.3"
rollback_value_check = []
disable-costs = []
2 changes: 1 addition & 1 deletion clarity/src/vm/ast/definition_sorter/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ impl DefinitionSorter {
return Ok(());
}
DefineFunctions::Map => {
// Args: [name, key, value]: with key value being potentialy tuples
// Args: [name, key, value]: with key value being potentially tuples
if function_args.len() == 3 {
self.probe_for_dependencies(
function_args[1],
Expand Down
16 changes: 8 additions & 8 deletions clarity/src/vm/database/key_value_wrapper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,23 +31,23 @@ use crate::vm::types::{
};
use crate::vm::{StacksEpoch, Value};

#[cfg(rollback_value_check)]
#[cfg(feature = "rollback_value_check")]
type RollbackValueCheck = String;
#[cfg(not(rollback_value_check))]
#[cfg(not(feature = "rollback_value_check"))]
type RollbackValueCheck = ();

#[cfg(not(rollback_value_check))]
#[cfg(not(feature = "rollback_value_check"))]
fn rollback_value_check(_value: &str, _check: &RollbackValueCheck) {}

#[cfg(not(rollback_value_check))]
#[cfg(not(feature = "rollback_value_check"))]
fn rollback_edits_push<T>(edits: &mut Vec<(T, RollbackValueCheck)>, key: T, _value: &str) {
edits.push((key, ()));
}
// this function is used to check the lookup map when committing at the "bottom" of the
// wrapper -- i.e., when committing to the underlying store. for the _unchecked_ implementation
// this is used to get the edit _value_ out of the lookupmap, for used in the subsequent `put_all`
// command.
#[cfg(not(rollback_value_check))]
#[cfg(not(feature = "rollback_value_check"))]
fn rollback_check_pre_bottom_commit<T>(
edits: Vec<(T, RollbackValueCheck)>,
lookup_map: &mut HashMap<T, Vec<String>>,
Expand All @@ -71,11 +71,11 @@ where
output
}

#[cfg(rollback_value_check)]
#[cfg(feature = "rollback_value_check")]
fn rollback_value_check(value: &String, check: &RollbackValueCheck) {
assert_eq!(value, check)
}
#[cfg(rollback_value_check)]
#[cfg(feature = "rollback_value_check")]
fn rollback_edits_push<T>(edits: &mut Vec<(T, RollbackValueCheck)>, key: T, value: &String)
where
T: Eq + Hash + Clone,
Expand All @@ -84,7 +84,7 @@ where
}
// this function is used to check the lookup map when committing at the "bottom" of the
// wrapper -- i.e., when committing to the underlying store.
#[cfg(rollback_value_check)]
#[cfg(feature = "rollback_value_check")]
fn rollback_check_pre_bottom_commit<T>(
edits: Vec<(T, RollbackValueCheck)>,
lookup_map: &mut HashMap<T, Vec<String>>,
Expand Down
4 changes: 3 additions & 1 deletion clarity/src/vm/types/signatures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1701,7 +1701,9 @@ impl TypeSignature {
clarity_version: ClarityVersion,
) -> Result<BTreeMap<ClarityName, FunctionSignature>> {
let mut trait_signature: BTreeMap<ClarityName, FunctionSignature> = BTreeMap::new();
let functions_types = type_args[0]
let functions_types = type_args
.get(0)
.ok_or_else(|| CheckErrors::InvalidTypeDescription)?
.match_list()
.ok_or(CheckErrors::DefineTraitBadSignature)?;

Expand Down
2 changes: 1 addition & 1 deletion contrib/boot-contracts-unit-tests/tests/misc.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -575,7 +575,7 @@ describe("test `get-total-ustx-stacked`", () => {
expect(response.result).toBeUint(amount * 3n);
});

it("expires stacking after the stacking duration has finsihed", () => {
it("expires stacking after the stacking duration has finished", () => {
const amount = getStackingMinimum() * 2n;

stackers.forEach((stacker, i) => {
Expand Down
87 changes: 87 additions & 0 deletions contrib/tools/local-mutation-testing.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#!/bin/bash

set -euo pipefail

# Install cargo-mutants
cargo install --version 24.7.1 cargo-mutants --locked

# Create diff file between current branch and develop branch
git diff origin/develop...HEAD > git.diff

# Remove git diff files about removed/renamed files
awk '
/^diff --git/ {
diff_line = $0
getline
if ($0 !~ /^(deleted file mode|similarity index)/) {
print diff_line
print
}
}
!/^(diff --git|deleted file mode|similarity index|rename from|rename to)/ {print}
' git.diff > processed.diff

# Extract mutants based on the processed diff
cargo mutants --in-diff processed.diff --list > all_mutants.txt

# Create a directory for organizing mutants
mkdir -p mutants_by_package

# Organize mutants into files based on their main folder
while IFS= read -r line; do
package=$(echo "$line" | cut -d'/' -f1)

case $package in
"stackslib")
echo "$line" >> "mutants_by_package/stackslib.txt"
;;
"testnet")
echo "$line" >> "mutants_by_package/stacks-node.txt"
;;
"stacks-signer")
echo "$line" >> "mutants_by_package/stacks-signer.txt"
;;
*)
echo "$line" >> "mutants_by_package/small-packages.txt"
;;
esac
done < all_mutants.txt

# Function to run mutants for a package
run_mutants() {
local package=$1
local threshold=$2
local output_dir=$3
local mutant_file="mutants_by_package/${package}.txt"

if [ ! -f "$mutant_file" ]; then
echo "No mutants found for $package"
return 0
fi

local regex_pattern=$(sed 's/[][()\.^$*+?{}|]/\\&/g' "$mutant_file" | paste -sd'|' -)
local mutant_count=$(cargo mutants -F "$regex_pattern" -E ": replace .{1,2} with .{1,2} in " --list | wc -l)

if [ "$mutant_count" -gt "$threshold" ]; then
echo "Running mutants for $package ($mutant_count mutants)"
RUST_BACKTRACE=1 BITCOIND_TEST=1 \
cargo mutants --timeout-multiplier 1.5 --no-shuffle -vV \
-F "$regex_pattern" \
-E ": replace .{1,2} with .{1,2} in " \
--output "$output_dir" \
--test-tool=nextest \
--package "$package" \
-- --all-targets --test-threads 1 || true

echo $? > "${output_dir}/exit_code.txt"
else
echo "Skipping $package, only $mutant_count mutants (threshold: $threshold)"
fi

return 0
}

# Run mutants for each wanted package
run_mutants "stacks-signer" 500 "./stacks-signer_mutants" || true
run_mutants "stacks-node" 540 "./stacks-node_mutants" || true
run_mutants "stackslib" 72 "./stackslib_mutants" || true
146 changes: 146 additions & 0 deletions docs/mutation-testing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
# Mutation Testing

This document describes how to run mutation testing locally to mimic the outcome of a PR, without the CI limitation it provides by timing out after 6 hours.
[Here is the script](../contrib/tools/local-mutation-testing.sh) to run the tests locally by running the mutants created by the changes between `HEAD` and develop.
It does automatically all the steps explained below.

From the root level of the stacks-core repository run
```sh
./contrib/tools/local-mutation-testing.sh
```

## Prerequirements

Install the cargo mutants library
```sh
cargo install --version 24.7.1 cargo-mutants --locked
```


## Steps
1. Be on source branch you would use for the PR.
2. Create diff file comparing this branch with the `develop` branch
```sh
git diff origin/develop..HEAD > git.diff
```
3. Clean up the diff file and create auxiliary files
```sh
awk '
/^diff --git/ {
diff_line = $0
getline
if ($0 !~ /^(deleted file mode|similarity index)/) {
print diff_line
print
}
}
!/^(diff --git|deleted file mode|similarity index|rename from|rename to)/ {print}
' git.diff > processed.diff
# Extract mutants based on the processed diff
cargo mutants --in-diff processed.diff --list > all_mutants.txt
# Create a directory for organizing mutants
mkdir -p mutants_by_package
# Organize mutants into files based on their main folder
while IFS= read -r line; do
package=$(echo "$line" | cut -d'/' -f1)
case $package in
"stackslib")
echo "$line" >> "mutants_by_package/stackslib.txt"
;;
"testnet")
echo "$line" >> "mutants_by_package/stacks-node.txt"
;;
"stacks-signer")
echo "$line" >> "mutants_by_package/stacks-signer.txt"
;;
*)
echo "$line" >> "mutants_by_package/small-packages.txt"
;;
esac
done < all_mutants.txt
```
4. Based on the package required to run the mutants for
a. Stackslib package
```sh
regex_pattern=$(sed 's/[][()\.^$*+?{}|]/\\&/g' "mutants_by_package/stackslib.txt" | paste -sd'|' -)
RUST_BACKTRACE=1 BITCOIND_TEST=1 \
cargo mutants --timeout-multiplier 1.5 --no-shuffle -vV \
-F "$regex_pattern" \
-E ": replace .{1,2} with .{1,2} in " \
--output "./stackslib_mutants" \
--test-tool=nextest \
-- --all-targets --test-threads 1
```
b. Stacks-node (testnet) package
```sh
regex_pattern=$(sed 's/[][()\.^$*+?{}|]/\\&/g' "mutants_by_package/testnet.txt" | paste -sd'|' -)
RUST_BACKTRACE=1 BITCOIND_TEST=1 \
cargo mutants --timeout-multiplier 1.5 --no-shuffle -vV \
-F "$regex_pattern" \
-E ": replace .{1,2} with .{1,2} in " \
--output "./testnet_mutants" \
--test-tool=nextest \
-- --all-targets --test-threads 1
```
c. Stacks-signer
```sh
regex_pattern=$(sed 's/[][()\.^$*+?{}|]/\\&/g' "mutants_by_package/stacks-signer.txt" | paste -sd'|' -)
RUST_BACKTRACE=1 BITCOIND_TEST=1 \
cargo mutants --timeout-multiplier 1.5 --no-shuffle -vV \
-F "$regex_pattern" \
-E ": replace .{1,2} with .{1,2} in " \
--output "./stacks-signer_mutants" \
--test-tool=nextest \
-- --all-targets --test-threads 1
```
d. All other packages combined
```sh
regex_pattern=$(sed 's/[][()\.^$*+?{}|]/\\&/g' "mutants_by_package/small-packages.txt" | paste -sd'|' -)
cargo mutants --timeout-multiplier 1.5 --no-shuffle -vV \
-F "$regex_pattern" \
-E ": replace .{1,2} with .{1,2} in " \
--output "./small-packages_mutants" \
--test-tool=nextest \
-- --all-targets --test-threads 1
```

## How to run one specific mutant to test it

Example of output which had a missing mutant
```sh
MISSED stacks-signer/src/runloop.rs:424:9: replace <impl SignerRunLoop for RunLoop<Signer, T>>::run_one_pass -> Option<Vec<SignerResult>> with None in 3.0s build + 9.3s test
```
Example of fix for it
```sh
RUST_BACKTRACE=1 BITCOIND_TEST=1 \
cargo mutants -vV \
-F "replace process_stackerdb_event" \
-E ": replace <impl SignerRunLoop for RunLoop<Signer, T>>::run_one_pass -> Option<Vec<SignerResult>> with None in " \
--test-tool=nextest \
-- \
--run-ignored all \
--fail-fast \
--test-threads 1
```
General command to run
```sh
RUST_BACKTRACE=1 BITCOIND_TEST=1 \
cargo mutants -vV \
-F "replace process_stackerdb_event" \
-E ": replace [modify this] with [modify this] in " \
--test-tool=nextest \
-- \
--run-ignored all \
--fail-fast \
--test-threads 1
```
2 changes: 1 addition & 1 deletion docs/rpc-endpoints.md
Original file line number Diff line number Diff line change
Expand Up @@ -427,7 +427,7 @@ Determine whether a given trait is implemented within the specified contract (ei

See OpenAPI [spec](./rpc/openapi.yaml) for details.

### POST /v2/block_proposal
### POST /v3/block_proposal

Used by miner to validate a proposed Stacks block using JSON encoding.

Expand Down
Loading

0 comments on commit 4eaeabe

Please sign in to comment.