Skip to content

Commit e1649ff

Browse files
authored
[DRAFT]: add firedancer conformance to ci (#19)
* add firedancer conformance to ci * add fixture skips * adjust status check
1 parent 65ecb85 commit e1649ff

File tree

5 files changed

+134
-0
lines changed

5 files changed

+134
-0
lines changed

.github/workflows/main.yml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,31 @@ jobs:
140140
echo "CU usage has changed. Please run `cargo bench` and commit the new results.";
141141
exit 1;
142142
fi
143+
144+
fd_conformance:
145+
name: Builtin-BPF Conformance Test
146+
runs-on: ubuntu-latest
147+
needs: build_programs
148+
steps:
149+
- name: Git Checkout
150+
uses: actions/checkout@v4
151+
152+
- name: Setup Environment
153+
uses: ./.github/actions/setup
154+
with:
155+
cargo-cache-key: cargo-program-conformance
156+
cargo-cache-fallback-key: cargo-programs
157+
solana: true
158+
159+
- name: Restore Program Builds
160+
uses: actions/cache/restore@v4
161+
with:
162+
path: ./**/*.so
163+
key: ${{ runner.os }}-builds-${{ github.sha }}
164+
165+
- name: Builtin-BPF Conformance Test
166+
shell: bash
167+
run: pnpm zx ./scripts/ci/fd-conformance.mjs
143168

144169
## SKIP: IDL is hand-cranked here for now.
145170
##

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@
77
node_modules
88
test-ledger
99
dist
10+
solana-conformance

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
[workspace]
22
resolver = "2"
33
members = ["clients/rust", "program"]
4+
# Required for CI
5+
exclude = ["solana-conformance/impl/solfuzz-agave"]
46

57
[workspace.metadata.cli]
68
solana = "2.0.2"

scripts/ci/fd-conformance.mjs

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
#!/usr/bin/env zx
2+
3+
// Firedancer conformance testing of the Core BPF Config program against its
4+
// original builtin implementation.
5+
//
6+
// Note: This script can only be run on Ubuntu.
7+
8+
import 'zx/globals';
9+
import { getProgramId, getProgramSharedObjectPath, workingDirectory } from '../utils.mjs';
10+
11+
// Clone the conformance harness.
12+
const harnessPath = path.join(workingDirectory, 'solana-conformance');
13+
await $`git clone https://github.com/firedancer-io/solana-conformance.git`;
14+
15+
// Clone the test vectors.
16+
const testVectorsPath = path.join(harnessPath, 'impl', 'test-vectors');
17+
await $`git clone https://github.com/firedancer-io/test-vectors.git ${testVectorsPath}`;
18+
19+
// Remove the fixtures we want to skip.
20+
const fixturesPath = path.join(testVectorsPath, 'instr', 'fixtures', 'config');
21+
const skipFixtures = [
22+
// These fixtures provide executable config accounts, which we know is a
23+
// case that can't manifest under the Solana protocol.
24+
'04a0b782cb1f4b1be044313331edda9dfb4696d6.fix',
25+
'c7ec10c03d5faadcebd32dc5b9a4086abef892ca_3157979.fix',
26+
'68e8dbf0f31de69a2bd1d2c0fe9af3ba676301d6_3157979.fix',
27+
'f84b5ad44f7a253ebc8056d06396694370a7fa4c_3157979.fix',
28+
'8bbe900444c675cfc3fbf0f80ae2eb061e536a09.fix',
29+
];
30+
for (const fixture of skipFixtures) {
31+
await $`rm -f ${path.join(fixturesPath, fixture)}`;
32+
}
33+
34+
// Clone the SolFuzz-Agave harness.
35+
const solFuzzAgavePath = path.join(harnessPath, 'impl', 'solfuzz-agave');
36+
await $`git clone -b agave-v2.1.0 http://github.com/firedancer-io/solfuzz-agave.git ${solFuzzAgavePath}`;
37+
38+
// Fetch protobuf files.
39+
await $`make -j -C ${solFuzzAgavePath} fetch_proto`
40+
41+
// Move into the conformance harness.
42+
cd(harnessPath);
43+
44+
// Build the environment.
45+
await $`bash install_ubuntu_lite.sh`;
46+
47+
const solFuzzAgaveManifestPath = path.join(solFuzzAgavePath, 'Cargo.toml');
48+
const solFuzzAgaveTargetPath = path.join(
49+
solFuzzAgavePath,
50+
'target',
51+
'x86_64-unknown-linux-gnu',
52+
'release',
53+
'libsolfuzz_agave.so',
54+
);
55+
56+
const testTargetsDir = path.join(harnessPath, 'impl', 'lib');
57+
await $`mkdir -p ${testTargetsDir}`;
58+
59+
// Build the Agave target with the builtin version.
60+
const testTargetPathBuiltin = path.join(testTargetsDir, 'builtin.so');
61+
await $`cargo build --manifest-path ${solFuzzAgaveManifestPath} \
62+
--lib --release --target x86_64-unknown-linux-gnu`;
63+
await $`mv ${solFuzzAgaveTargetPath} ${testTargetPathBuiltin}`;
64+
65+
// Build the Agave target with the BPF version.
66+
const testTargetPathCoreBpf = path.join(testTargetsDir, 'core_bpf.so');
67+
await $`CORE_BPF_PROGRAM_ID=${getProgramId('program')} \
68+
CORE_BPF_TARGET=${getProgramSharedObjectPath('program')} \
69+
FORCE_RECOMPILE=true \
70+
cargo build --manifest-path ${solFuzzAgaveManifestPath} \
71+
--lib --release --target x86_64-unknown-linux-gnu --features core-bpf`;
72+
await $`mv ${solFuzzAgaveTargetPath} ${testTargetPathCoreBpf}`;
73+
74+
// Run the tests.
75+
await $`source test_suite_env/bin/activate && \
76+
solana-test-suite run-tests \
77+
-i ${fixturesPath} -s ${testTargetPathBuiltin} -t ${testTargetPathCoreBpf}`;
78+
79+
// Assert conformance.
80+
// There should be no fixtures in the `failed_protobufs` directory.
81+
if (fs.readdirSync('test_results/failed_protobufs').length > 0) {
82+
throw new Error(`Error: mismatches detected.`);
83+
} else {
84+
console.log('All tests passed.');
85+
}

scripts/utils.mjs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,27 @@ export function getAllProgramFolders() {
7070
);
7171
}
7272

73+
export function getProgramId(folder) {
74+
return getCargoMetadata(folder)?.solana?.['program-id'];
75+
}
76+
77+
export function getProgramName(folder) {
78+
return getCargo(folder).package?.name;
79+
}
80+
81+
export function getProgramSharedObjectName(folder) {
82+
return `${getProgramName(folder).replace(/-/g, '_')}.so`;
83+
}
84+
85+
export function getProgramSharedObjectPath(folder) {
86+
return path.join(
87+
workingDirectory,
88+
'target',
89+
'deploy',
90+
getProgramSharedObjectName(folder),
91+
);
92+
}
93+
7394
export function getCargo(folder) {
7495
return parseToml(
7596
fs.readFileSync(

0 commit comments

Comments
 (0)