diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 52cfd07..9b3c962 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -151,6 +151,35 @@ jobs: path: ./**/*.so key: ${{ runner.os }}-builds-${{ github.sha }} + build_ptoken: + name: Build p-token + runs-on: ubuntu-latest + steps: + - name: Git Checkout + uses: actions/checkout@v4 + + - name: Setup Environment + uses: ./.github/actions/setup + with: + cargo-cache-key: cargo-build-program + solana: true + + - name: Build + run: pnpm p-token:build + + - name: Upload p-token Builds + uses: actions/upload-artifact@v4 + with: + name: p-token-builds + path: ./target/deploy/*.so + if-no-files-found: error + + - name: Save p-token Build For Client Jobs + uses: actions/cache/save@v4 + with: + path: ./**/*.so + key: ${{ runner.os }}-ptoken-build-${{ github.sha }} + test_client_js: name: Test Client JS runs-on: ubuntu-latest @@ -212,3 +241,34 @@ jobs: - name: Test run: pnpm programs:test + + conformance_ptoken: + name: Conformance Test for p-token + runs-on: ubuntu-latest + needs: build_ptoken + steps: + - name: Git Checkout + uses: actions/checkout@v4 + + - name: Setup Environment + uses: ./.github/actions/setup + with: + cargo-cache-key: cargo-fixtures-ptoken + solana: true + + - name: Restore Program Builds + uses: actions/cache/restore@v4 + with: + path: ./**/*.so + key: ${{ runner.os }}-ptoken-build-${{ github.sha }} + + - name: Install mollusk-svm-cli + uses: taiki-e/cache-cargo-install-action@v2 + with: + tool: mollusk-svm-cli + + - name: Generate SPL Token Fixtures + run: pnpm fixtures:generate + + - name: Run Fixtures + run: pnpm fixtures:run pinocchio_token_program diff --git a/package.json b/package.json index dfcd107..e336c22 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,10 @@ "rust:publish": "zx ./scripts/rust/publish.mjs", "rust:semver": "cargo semver-checks", "p-token:build": "zx ./scripts/rust/build-sbf.mjs p-token", - "p-token:test": "zx ./scripts/rust/test.mjs p-token" + "p-token:test": "zx ./scripts/rust/test.mjs p-token", + "fixtures:clean": "zx ./scripts/rust/fixtures.mjs clean", + "fixtures:generate": "zx ./scripts/rust/fixtures.mjs generate", + "fixtures:run": "zx ./scripts/rust/fixtures.mjs run" }, "devDependencies": { "@codama/renderers-js": "^1.2.7", diff --git a/program/tests/processor.rs b/program/tests/processor.rs index 025577a..7466e55 100644 --- a/program/tests/processor.rs +++ b/program/tests/processor.rs @@ -5366,32 +5366,6 @@ fn test_overflow() { .unwrap(); let account = Account::unpack_unchecked(&account_account.data).unwrap(); assert_eq!(account.amount, u64::MAX); - - // manipulate account balance to attempt overflow transfer - let mut account = Account::unpack_unchecked(&account2_account.data).unwrap(); - account.amount = 1; - Account::pack(account, &mut account2_account.data).unwrap(); - - assert_eq!( - Err(TokenError::Overflow.into()), - do_process_instruction( - transfer( - &program_id, - &account2_key, - &account_key, - &owner2_key, - &[], - 1, - ) - .unwrap(), - vec![ - &mut account2_account, - &mut account_account, - &mut owner2_account, - ], - &[Check::err(TokenError::Overflow.into())], - ) - ); } #[test] diff --git a/scripts/rust/fixtures.mjs b/scripts/rust/fixtures.mjs new file mode 100644 index 0000000..7ea6158 --- /dev/null +++ b/scripts/rust/fixtures.mjs @@ -0,0 +1,61 @@ +#!/usr/bin/env zx +import 'zx/globals'; +import { existsSync } from 'fs'; +import { cliArguments, workingDirectory } from '../utils.mjs'; + +// Directory where the fixtures are generated. +const FIXTURES_DIR = path.join(workingDirectory, 'target', 'fixtures'); +// Directory of the SPL Token program. +const SPL_TOKEN_DIR = path.join(workingDirectory, 'program'); +// Directory of the SBF program. +const SBF_OUTPUT_DIR = path.join(workingDirectory, 'target', 'deploy'); + +const [command, ...args] = cliArguments(); + +switch (command) { + case 'clean': + await clean(); + break; + case 'generate': + await generate(); + break; + case 'run': + await run(args); + break; + default: + throw new Error(`Unknown command: ${command}`); +} + +async function clean() { + await $`rm -rf ${FIXTURES_DIR}`; +} + +async function generate() { + if (existsSync(FIXTURES_DIR)) { + echo(chalk.yellow('[ WARNING ]'), `Fixtures directory already exists.`); + } else { + await $`mkdir ${FIXTURES_DIR}`; + + // Fixtures are generated from the SPL Token program. + cd(SPL_TOKEN_DIR); + + await $`RUST_LOG=error EJECT_FUZZ_FIXTURES=${FIXTURES_DIR} cargo test-sbf --features mollusk-svm/fuzz`; + } +} + +async function run(args) { + if (!existsSync(FIXTURES_DIR)) { + throw new Error(`Fixtures directory does not exist: ${FIXTURES_DIR}`); + } + + const [programName] = args; + if (!programName) { + throw new Error('The name of the program file must be provided.'); + } + + await $`mollusk execute-fixture \ + ${path.join(SBF_OUTPUT_DIR, programName + '.so')} \ + ${FIXTURES_DIR} \ + TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA \ + --ignore-compute-units`; +}