Skip to content

Commit

Permalink
implement calldata parsing and testing for BytesParsing
Browse files Browse the repository at this point in the history
  • Loading branch information
nonergodic committed Sep 13, 2024
1 parent 3f1cbfa commit e24e304
Show file tree
Hide file tree
Showing 5 changed files with 1,065 additions and 271 deletions.
48 changes: 33 additions & 15 deletions gen/libraryTestWrapper.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
//Simple parser for .sol files that finds libraries defined in the file and creates a wrapper
// that converts all their internal functions to external functions so they can be tested
// in forge unit tests.
// that converts all their internal functions to external functions so they can be externally
// called in forge unit tests.
//
//Forge supports vm.expectRevert even for internal functions, so this wrapper is primarily
// helpful for libraries like BytesParsing (the original motivation for this script) where
// you have a large family of similar functions to test and you don't want to write a separate
// test for each one. So, it really mostly is a workaround for Solidity's lack of support for
// generics.

//Regarding the implementation of this script:
//Instead of properly parsing the full AST, we make our task of finding and transforming the
// relevant bits easier by making some basic assumptions about code formatting that any sane
// code should almost certainly adhere to regardless.

// code should almost certainly adhere to regardless, like closing braces of library definitions
// being on their own line with no leading whitespace, etc.
//
//Solidity language grammar:
// https://docs.soliditylang.org/en/latest/grammar.html

Expand Down Expand Up @@ -43,8 +52,22 @@ if (process.argv.length != 3) {
process.exit(1);
}

const filename = process.argv[2];
let fileCode = readFileSync("../src/" + filename + filename.endsWith(".sol") ? "" : ".sol", "utf8");
//convenience for use with Makefile:
//If no .sol file ending is specified, this script will use Wormhole Solidity SDK defaults for
// the file paths, the SPDX license header, the pragma version, and the import statement.
const fullPath = (() => {
const filename = process.argv[2];
if (filename.endsWith(".sol"))
return filename;

console.log(
`// SPDX-License-Identifier: Apache 2\npragma solidity ^0.8.24;\n\n` +
`import "wormhole-sdk/${filename}.sol";\n`
);

return "../src/" + filename + ".sol";
})();
let fileCode = readFileSync(fullPath, "utf8");

//we first remove all comments so we can be sure that everything we're parsing is actual code
fileCode = removeComments(fileCode);
Expand Down Expand Up @@ -76,13 +99,13 @@ for (const libs of libMatches) {
const [_, funcName, funcParasRaw, modsRaw, close] = funcs;
if (close == ';')
continue; //function pointer, not a function definition

if (!modsRaw.includes("internal"))
continue; //not an internal function

const retParasRegex = /returns\s*\(([\s\S]*?)\)/;
const retParasRaw = modsRaw.match(retParasRegex);

const collapseSpaceRegex = /\s\s+/g;
const paramsToArray = (paramList: string) =>
paramList.replace(collapseSpaceRegex, ' ').trim().split(',').map(param => {
Expand All @@ -100,12 +123,7 @@ for (const libs of libMatches) {
}
}

console.log(`// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.24;
//This file was auto-generated by libraryTestWrapper.ts
import "wormhole-sdk/${filename}.sol";`);
console.log(`// This file was auto-generated by wormhole-solidity-sdk gen/libraryTestWrapper.ts`);

const pConcat = (paras: string[]) =>
(paras.length > 2 ? "\n " : "") +
Expand All @@ -121,7 +139,7 @@ const pNames = (paras: string[]) =>

for (const [libName, funcs] of Object.entries(libraries)) {
console.log(`\ncontract ${libName}TestWrapper {`);
const funcCode = [];
const funcCode = [];
for (const func of funcs)
funcCode.push([
` function ${func.name}(${pConcat(func.paras)}) external ${func.stateMut}` +
Expand Down
11 changes: 11 additions & 0 deletions src/constants/Common.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.4;

uint256 constant FREE_MEMORY_PTR = 0x40;
uint256 constant WORD_SIZE = 32;
//we can't define _WORD_SIZE_MINUS_ONE via _WORD_SIZE - 1 because of solc restrictions
// what constants can be used in inline assembly
uint256 constant WORD_SIZE_MINUS_ONE = 31; //=0x1f=0b00011111

//see section "prefer `< MAX + 1` over `<= MAX` for const comparison" in docs/Optimization.md
uint256 constant WORD_SIZE_PLUS_ONE = 33;
Loading

0 comments on commit e24e304

Please sign in to comment.