Skip to content

Commit

Permalink
add firedancer conformance to ci
Browse files Browse the repository at this point in the history
  • Loading branch information
buffalojoec committed Dec 11, 2024
1 parent ac994f0 commit f14b052
Show file tree
Hide file tree
Showing 5 changed files with 157 additions and 0 deletions.
25 changes: 25 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,31 @@ jobs:
echo "CU usage has changed. Please run `cargo bench` and commit the new results.";
exit 1;
fi
fd_conformance:
name: Builtin-BPF Conformance Test
runs-on: ubuntu-latest
needs: build_programs
steps:
- name: Git Checkout
uses: actions/checkout@v4

- name: Setup Environment
uses: ./.github/actions/setup
with:
cargo-cache-key: cargo-program-conformance
cargo-cache-fallback-key: cargo-programs
solana: true

- name: Restore Program Builds
uses: actions/cache/restore@v4
with:
path: ./**/*.so
key: ${{ runner.os }}-builds-${{ github.sha }}

- name: Builtin-BPF Conformance Test
shell: bash
run: pnpm zx ./scripts/ci/fd-conformance.mjs

generate_clients:
name: Check Client Generation
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@
node_modules
test-ledger
dist
solana-conformance
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
[workspace]
resolver = "2"
members = ["clients/rust", "program"]
# Required for CI
exclude = ["solana-conformance/impl/solfuzz-agave"]

[workspace.metadata.cli]
solana = "2.0.1"
Expand Down
108 changes: 108 additions & 0 deletions scripts/ci/fd-conformance.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
#!/usr/bin/env zx

// Firedancer conformance testing of the Core BPF Config program against its
// original builtin implementation.
//
// Note: This script can only be run on Ubuntu.

import 'zx/globals';
import { getProgramId, getProgramSharedObjectPath, workingDirectory } from '../utils.mjs';

// Clone the conformance harness.
const harnessPath = path.join(workingDirectory, 'solana-conformance');
await $`git clone https://github.com/firedancer-io/solana-conformance.git`;

// Clone the test vectors.
const testVectorsPath = path.join(harnessPath, 'impl', 'test-vectors');
await $`git clone https://github.com/firedancer-io/test-vectors.git ${testVectorsPath}`;

// Add the Mollusk-generated fixtures to the test inputs.
const firedancerFixturesPath = path.join(testVectorsPath, 'instr', 'fixtures', 'config');
const molluskFixturesPath = path.join(workingDirectory, 'program', 'fuzz', 'blob');
await $`cp -a ${molluskFixturesPath}/. ${firedancerFixturesPath}/`;

// Remove the fixtures we want to skip.
const skipFixtures = [
// In these fixtures, the builtin has > DEFAULT_COMPUTE_UNITS available, but
// it goes over by CPI'ing to the System program to allocate & assign a new
// lookup table.
// It's extremely difficult and tedious to apply conformance special-casing to
// conditional CPI-based CU consumption.
// However, when the same CU constraints are applied directly on the BPF
// program, it too will exhaust the meter and throw.
'36e43433c2609890226ea8c5586b007071b96fa4_3246919.fix',
'9ea61485a2f27361460ddfee9df3ba5dfde25dc5_3246919.fix',
'a1a7bb8702d184ec9703498e2478c0a527e515f6_3246919.fix',
// In this fixture, the ALT program itself is not provided as `executable`.
// Until executable checks are relaxed, this is never going to work for BPF.
// Builtins succeed because they need only the `native_loader::check_id()`
// check.
// The BPF loader's program invocation is where BPF programs' `executable`
// flags are checked.
// https://github.com/anza-xyz/agave/blob/970606e842d1027b5a34211219aacf3d39bb468d/programs/bpf_loader/src/lib.rs#L432-L436
'b7e56ebaf6df34ab71ca9c1a42c0551cfb79dab7_2789718.fix',
];
for (const fixture of skipFixtures) {
await $`rm -f ${path.join(firedancerFixturesPath, fixture)}`;
}

// Clone the SolFuzz-Agave harness.
const solFuzzAgavePath = path.join(harnessPath, 'impl', 'solfuzz-agave');
await $`git clone -b agave-v2.1.3 http://github.com/firedancer-io/solfuzz-agave.git ${solFuzzAgavePath}`;

// Fetch protobuf files.
await $`make -j -C ${solFuzzAgavePath} fetch_proto`

// Move into the conformance harness.
cd(harnessPath);

// Build the environment.
await $`bash install_ubuntu_lite.sh`;

const solFuzzAgaveManifestPath = path.join(solFuzzAgavePath, 'Cargo.toml');
const solFuzzAgaveTargetPath = path.join(
solFuzzAgavePath,
'target',
'x86_64-unknown-linux-gnu',
'release',
'libsolfuzz_agave.so',
);

const testTargetsDir = path.join(harnessPath, 'impl', 'lib');
await $`mkdir -p ${testTargetsDir}`;

// Build the Agave target with the builtin version.
const testTargetPathBuiltin = path.join(testTargetsDir, 'builtin.so');
await $`cargo build --manifest-path ${solFuzzAgaveManifestPath} \
--lib --release --target x86_64-unknown-linux-gnu`;
await $`mv ${solFuzzAgaveTargetPath} ${testTargetPathBuiltin}`;

// Build the Agave target with the BPF version.
const testTargetPathCoreBpf = path.join(testTargetsDir, 'core_bpf.so');
await $`CORE_BPF_PROGRAM_ID=${getProgramId('program')} \
CORE_BPF_TARGET=${getProgramSharedObjectPath('program')} \
FORCE_RECOMPILE=true \
cargo build --manifest-path ${solFuzzAgaveManifestPath} \
--lib --release --target x86_64-unknown-linux-gnu \
--features core-bpf-conformance`;
await $`mv ${solFuzzAgaveTargetPath} ${testTargetPathCoreBpf}`;

// Remove any test results if they exist.
await $`rm -rf test_results`;

// Run the tests.
const fixturesPath = path.join(testVectorsPath, 'instr', 'fixtures', 'address-lookup-table');
await $`source test_suite_env/bin/activate && \
solana-test-suite run-tests \
-i ${fixturesPath} -s ${testTargetPathBuiltin} -t ${testTargetPathCoreBpf} \
--core-bpf-mode --save-failures`;

// Assert conformance.
// There should be no fixtures in the `failed_protobufs` directory.
if (fs.existsSync('test_results/failed_protobufs')) {
if (fs.readdirSync('test_results/failed_protobufs').length > 0) {
throw new Error(`Error: mismatches detected.`);
}
}

console.log('All tests passed.');
21 changes: 21 additions & 0 deletions scripts/utils.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,27 @@ export function getAllProgramFolders() {
);
}

export function getProgramId(folder) {
return getCargoMetadata(folder)?.solana?.['program-id'];
}

export function getProgramName(folder) {
return getCargo(folder).package?.name;
}

export function getProgramSharedObjectName(folder) {
return `${getProgramName(folder).replace(/-/g, '_')}.so`;
}

export function getProgramSharedObjectPath(folder) {
return path.join(
workingDirectory,
'target',
'deploy',
getProgramSharedObjectName(folder),
);
}

export function getCargo(folder) {
return parseToml(
fs.readFileSync(
Expand Down

0 comments on commit f14b052

Please sign in to comment.