Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/counter tests #223

Merged
merged 4 commits into from
Jan 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/main.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ jobs:
run: |
npm i
npm run build
- name: run counters tests
run: |
npm run test:counters
- name: Generate tests
run: |
npm run test:gen
Expand Down
45 changes: 45 additions & 0 deletions counters/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
## Counters testing tool

The purpose of this tool is to detect counters altertions in zkrom code.
A unit test is created for each function and opcode of the zkEVM. The structure of the test is the following:
`````
INCLUDE "../initIncludes.zkasm" // Include the files imported at the beginning of the test

start:
1000000 => GAS

operation:
2 :MSTORE(SP++)
2 :MSTORE(SP++)
:JMP(opADD)
// Assert counters. Check for each function, the exact number of each counter is matched
checkCounters:
%OPADD_STEP - STEP:JMPN(failedCounters)
%OPADD_CNT_BINARY - CNT_BINARY :JMPNZ(failedCounters)
%OPADD_CNT_ARITH - CNT_ARITH :JMPNZ(failedCounters)
%OPADD_CNT_KECCAK_F - CNT_KECCAK_F :JMPNZ(failedCounters)
%OPADD_CNT_MEM_ALIGN - CNT_MEM_ALIGN :JMPNZ(failedCounters)
%OPADD_CNT_PADDING_PG - CNT_PADDING_PG :JMPNZ(failedCounters)
%OPADD_CNT_POSEIDON_G - CNT_POSEIDON_G :JMPNZ(failedCounters)
// Finalize execution
0 => A,B,C,D,E,CTX, SP, PC, GAS, MAXMEM, SR, HASHPOS, RR ; Set all registers to 0
finalizeExecution:
:JMP(finalWait)
readCode:
txType:
:JMP(checkCounters)
failedCounters: // Force failed assert
2 => A
1 :ASSERT
INCLUDE "../endIncludes.zkasm" // Include the files imported at the end of the test
`````

Run all tests:
`````
node counters/counters-executor.js
`````
Limitations:
- Not all the tests are implemented yet, just the most complex ones
- For some test (the simplest ones), the counters it should spend are stored in `countersConstants.zkasm` file. For tests with a lot of utils calls or a lot of complexity, the values of the counters are hardcoded in the test.
- The tests always try to cover as much coverage as posible and always with the worst case counters scenario but this approach gets a bit tricky for complex opcodes as they have different contexts and behaviours.
- The objective is to keep adding tests with already not implemented functions but also adding tests for already implemented opcodes but with different scenarios (Example: calldatacopy from a call or from a create2)
68 changes: 68 additions & 0 deletions counters/counters-executor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
const path = require('path');
const fs = require('fs');
const smMain = require('@0xpolygonhermez/zkevm-proverjs/src/sm/sm_main/sm_main');
const fileCachePil = path.join(__dirname, '../node_modules/@0xpolygonhermez/zkevm-proverjs/cache-main-pil.json');
const empty_input = require('@0xpolygonhermez/zkevm-proverjs/test/inputs/empty_input.json')
const buildPoseidon = require('@0xpolygonhermez/zkevm-commonjs').getPoseidon;
const pathMainPil = path.join(__dirname, '../node_modules/@0xpolygonhermez/zkevm-proverjs/pil/main.pil');
const { newCommitPolsArray } = require('pilcom');
const { compile } = require('pilcom');
const zkasm = require("@0xpolygonhermez/zkasmcom");
const testFilesDir = path.join(__dirname, './tests');
const { argv } = require('yargs');

async function main() {

// Compile pil
const cmPols = await compilePil();

// Get all zkasm files
const files = getTestFiles();

// Run all zkasm files
for (let file of files) {
await runTest(file, cmPols)
}
}

async function runTest(testName, cmPols) {
const zkasmFile = `${testFilesDir}/${testName}`;
// Compile rom
const rom = await zkasm.compile(zkasmFile);
const config = {
debug: true,
stepsN: 8388608,
}
console.log(`Running ${testName}`)
// Execute test
const res = await smMain.execute(cmPols.Main, empty_input, rom, config);
console.log(res.counters)
}

// Get all zkasm counter test files
function getTestFiles() {
if(argv.test){
return [`${argv.test}.zkasm`]
}
const files = fs.readdirSync(testFilesDir).filter(name => name.endsWith('.zkasm'))
return files
}

async function compilePil() {
if (!fs.existsSync(fileCachePil)) {
const poseidon = await buildPoseidon();
const { F } = poseidon;
const pilConfig = {
defines: { N: 4096 },
namespaces: ['Main', 'Global'],
disableUnusedError: true
};
const p = await compile(F, pathMainPil, null, pilConfig);
fs.writeFileSync(fileCachePil, `${JSON.stringify(p, null, 1)}\n`, 'utf8');
}

const pil = JSON.parse(fs.readFileSync(fileCachePil));
return newCommitPolsArray(pil);
}

main()
Loading