Skip to content
This repository was archived by the owner on Mar 11, 2025. It is now read-only.

Commit b40e0dd

Browse files
authored
token-swap: Add fuzzer for swap / withdraw / deposit (#875)
* token-swap: Add fuzzer for swap / withdraw / deposit * Run cargo fmt * Make end-to-end testing work * Fix test failures * Cleanup for review * Remove Clone trait for Initialize * Fix building fuzz targets * Fix fuzz withdraw logic to avoid ZeroTradingTokens error * Cargo fmt * Clippy / fmt again * Integrate fuzzer in main workspace to share clippy / fmt * Fix clippy * Switch to stable honggfuzz that could work with BPF * Update to most recent honggfuzz * Add build / run requirements * Add fuzz CI and cleanup for honggfuzz * Revert to using fuzz feature to integrate with workspace * Make fuzz script executable * Refactor and cleanup * Add nightly run * Fix workflow typo * Add runtime for pull request fuzz workflow * Fix unrelated new clippy errors
1 parent ac20c5d commit b40e0dd

19 files changed

+1350
-180
lines changed

.github/workflows/fuzz-nightly.yml

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
name: Fuzz Nightly
2+
3+
on:
4+
schedule:
5+
- cron: '0 3 * * *'
6+
7+
jobs:
8+
fuzz-nightly:
9+
runs-on: ubuntu-latest
10+
strategy:
11+
matrix:
12+
fuzz_target: [token-swap-instructions]
13+
fail-fast: false
14+
steps:
15+
- uses: actions/checkout@v2
16+
17+
- name: Set env vars
18+
run: |
19+
source ci/rust-version.sh
20+
echo "RUST_STABLE=$rust_stable" >> $GITHUB_ENV
21+
source ci/solana-version.sh
22+
echo "SOLANA_VERSION=$solana_version" >> $GITHUB_ENV
23+
24+
- uses: actions-rs/toolchain@v1
25+
with:
26+
toolchain: ${{ env.RUST_STABLE }}
27+
override: true
28+
profile: minimal
29+
30+
- uses: actions/cache@v2
31+
with:
32+
path: |
33+
~/.cargo/registry
34+
~/.cargo/git
35+
target
36+
key: cargo-fuzz-${{ hashFiles('**/Cargo.lock') }}
37+
restore-keys: |
38+
cargo-fuzz-
39+
40+
- uses: actions/cache@v2
41+
with:
42+
path: |
43+
~/.cargo/bin/cargo-hfuzz
44+
~/.cargo/bin/cargo-honggfuzz
45+
key: cargo-fuzz-bins-${{ runner.os }}
46+
restore-keys: |
47+
cargo-fuzz-bins-${{ runner.os }}-
48+
49+
- uses: actions/cache@v2
50+
with:
51+
path: |
52+
~/.cache
53+
key: solana-${{ env.SOLANA_VERSION }}
54+
restore-keys: |
55+
solana-
56+
57+
- name: Install dependencies
58+
run: |
59+
./ci/install-build-deps.sh
60+
./ci/install-program-deps.sh
61+
echo "$HOME/.local/share/solana/install/active_release/bin" >> $GITHUB_PATH
62+
63+
- name: Run fuzz target
64+
run: ./ci/fuzz.sh ${{ matrix.fuzz_target }} 18000 # 5 hours, jobs max out at 6

.github/workflows/pull-request.yml

+58
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ jobs:
1515
- js-test-token
1616
- js-test-token-swap
1717
- js-test-token-lending
18+
- fuzz
1819
steps:
1920
- run: echo "Done"
2021

@@ -200,3 +201,60 @@ jobs:
200201
name: programs
201202
path: target/bpfel-unknown-unknown/release
202203
- run: ./ci/js-test-token-lending.sh
204+
205+
fuzz:
206+
runs-on: ubuntu-latest
207+
strategy:
208+
matrix:
209+
fuzz_target: [token-swap-instructions]
210+
steps:
211+
- uses: actions/checkout@v2
212+
213+
- name: Set env vars
214+
run: |
215+
source ci/rust-version.sh
216+
echo "RUST_STABLE=$rust_stable" >> $GITHUB_ENV
217+
source ci/solana-version.sh
218+
echo "SOLANA_VERSION=$solana_version" >> $GITHUB_ENV
219+
220+
- uses: actions-rs/toolchain@v1
221+
with:
222+
toolchain: ${{ env.RUST_STABLE }}
223+
override: true
224+
profile: minimal
225+
226+
- uses: actions/cache@v2
227+
with:
228+
path: |
229+
~/.cargo/registry
230+
~/.cargo/git
231+
target
232+
key: cargo-fuzz-${{ hashFiles('**/Cargo.lock') }}
233+
restore-keys: |
234+
cargo-fuzz-
235+
236+
- uses: actions/cache@v2
237+
with:
238+
path: |
239+
~/.cargo/bin/cargo-hfuzz
240+
~/.cargo/bin/cargo-honggfuzz
241+
key: cargo-fuzz-bins-${{ runner.os }}
242+
restore-keys: |
243+
cargo-fuzz-bins-${{ runner.os }}-
244+
245+
- uses: actions/cache@v2
246+
with:
247+
path: |
248+
~/.cache
249+
key: solana-${{ env.SOLANA_VERSION }}
250+
restore-keys: |
251+
solana-
252+
253+
- name: Install dependencies
254+
run: |
255+
./ci/install-build-deps.sh
256+
./ci/install-program-deps.sh
257+
echo "$HOME/.local/share/solana/install/active_release/bin" >> $GITHUB_PATH
258+
259+
- name: Run fuzz target
260+
run: ./ci/fuzz.sh ${{ matrix.fuzz_target }} 30 # 30 seconds, just to check everything is ok

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,5 @@ bin
55
config.json
66
node_modules
77
./package-lock.json
8+
hfuzz_target
9+
hfuzz_workspace

Cargo.lock

+48-5
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ members = [
1515
"themis/program_ristretto",
1616
"token-lending/program",
1717
"token-swap/program",
18+
"token-swap/program/fuzz",
1819
"token/cli",
1920
"token/perf-monitor",
2021
"token/program",

ci/fuzz.sh

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#!/usr/bin/env bash
2+
3+
set -e
4+
5+
usage() {
6+
exitcode=0
7+
if [[ -n "$1" ]]; then
8+
exitcode=1
9+
echo "Error: $*"
10+
fi
11+
echo "Usage: $0 [fuzz-target] [run-time-in-seconds]"
12+
exit $exitcode
13+
}
14+
15+
fuzz_target=$1
16+
if [[ -z $fuzz_target ]]; then
17+
usage "No fuzz target provided"
18+
fi
19+
20+
run_time=$2
21+
if [[ -z $2 ]]; then
22+
usage "No runtime provided"
23+
fi
24+
25+
set -x
26+
27+
HFUZZ_RUN_ARGS="--run_time $run_time --exit_upon_crash" cargo hfuzz run $fuzz_target
28+
29+
# Until https://github.com/rust-fuzz/honggfuzz-rs/issues/16 is resolved,
30+
# hfuzz does not return an error code on crash, so look for a crash artifact
31+
for crash_file in ./hfuzz_workspace/"$fuzz_target"/*.fuzz; do
32+
# Check if the glob gets expanded to existing files.
33+
if [[ -e "$crash_file" ]]; then
34+
echo ".fuzz file $crash_file found, meaning some error occurred, exiting"
35+
exit 1
36+
fi
37+
# Break early -- we just need one iteration to see if a failure occurred
38+
break
39+
done

ci/install-build-deps.sh

+2
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,6 @@ sudo apt-get install -y openssl --allow-unauthenticated
1010
sudo apt-get install -y libssl-dev --allow-unauthenticated
1111
sudo apt-get install -y libssl1.1 --allow-unauthenticated
1212
sudo apt-get install -y libudev-dev
13+
sudo apt-get install -y binutils-dev
14+
sudo apt-get install -y libunwind-dev
1315
clang-7 --version

ci/install-program-deps.sh

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ set -x
99

1010
cargo --version
1111
cargo install rustfilt || true
12+
cargo install honggfuzz || true
1213

1314
export PATH="$HOME"/.local/share/solana/install/active_release/bin:"$PATH"
1415
solana --version

token-swap/program/Cargo.toml

+2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ edition = "2018"
1010
[features]
1111
no-entrypoint = []
1212
production = []
13+
fuzz = ["arbitrary"]
1314

1415
[dependencies]
1516
arrayref = "0.3.6"
@@ -19,6 +20,7 @@ solana-program = "1.4.9"
1920
spl-token = { version = "3.0", path = "../../token/program", features = [ "no-entrypoint" ] }
2021
thiserror = "1.0"
2122
uint = "0.8"
23+
arbitrary = { version = "0.4", features = ["derive"], optional = true }
2224

2325
[dev-dependencies]
2426
solana-sdk = "1.4.9"

token-swap/program/fuzz/Cargo.toml

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
[package]
2+
name = "spl-token-swap-fuzz"
3+
version = "0.0.1"
4+
description = "Solana Program Library Token Swap Fuzzer"
5+
authors = ["Solana Maintainers <[email protected]>"]
6+
repository = "https://github.com/solana-labs/solana-program-library"
7+
license = "Apache-2.0"
8+
edition = "2018"
9+
publish = false
10+
11+
[dependencies]
12+
honggfuzz = { version = "0.5" }
13+
arbitrary = { version = "0.4", features = ["derive"] }
14+
solana-program = "1.4.8"
15+
spl-token = { version = "3.0", path = "../../../token/program", features = [ "no-entrypoint" ] }
16+
spl-token-swap = { path = "..", features = ["fuzz", "no-entrypoint"] }
17+
18+
[[bin]]
19+
name = "token-swap-instructions"
20+
path = "src/instructions.rs"
21+
test = false
22+
doc = false

0 commit comments

Comments
 (0)