diff --git a/.github/workflows/git-clean.yaml b/.github/workflows/git-clean.yaml new file mode 100644 index 000000000..47161ea03 --- /dev/null +++ b/.github/workflows/git-clean.yaml @@ -0,0 +1,20 @@ +name: Git is clean +on: [push] + +jobs: + git-clean: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + fetch-depth: 0 + + - uses: DeterminateSystems/nix-installer-action@main + - uses: DeterminateSystems/magic-nix-cache-action@main + + - run: nix develop -c i9r-prelude + + - run: nix develop -c forge script ./script/BuildPointers.sol + + - run: git diff --exit-code \ No newline at end of file diff --git a/foundry.toml b/foundry.toml index a4a21857d..8a5d192cf 100644 --- a/foundry.toml +++ b/foundry.toml @@ -23,6 +23,7 @@ cbor_metadata = false fs_permissions = [ { access = "read-write", path = "./meta" }, + { access = "read-write", path = "src/generated" }, { access = "write", path = "./deployments/latest/RainterpreterParserNPE2" }, { access = "write", path = "./deployments/latest/RainterpreterStoreNPE2" }, { access = "write", path = "./deployments/latest/RainterpreterNPE2" }, diff --git a/script/BuildPointers.sol b/script/BuildPointers.sol new file mode 100644 index 000000000..889142482 --- /dev/null +++ b/script/BuildPointers.sol @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: CAL +pragma solidity =0.8.25; + +import {Script} from "forge-std/Script.sol"; +import {RainterpreterNPE2} from "src/concrete/RainterpreterNPE2.sol"; +import {RainterpreterStoreNPE2} from "src/concrete/RainterpreterStoreNPE2.sol"; +import {IInterpreterV2} from "rain.interpreter.interface/interface/IInterpreterV2.sol"; +import {RainterpreterParserNPE2, PARSE_META_BUILD_DEPTH} from "src/concrete/RainterpreterParserNPE2.sol"; +import { + RainterpreterExpressionDeployerNPE2, + RainterpreterExpressionDeployerNPE2ConstructionConfigV2 +} from "src/concrete/RainterpreterExpressionDeployerNPE2.sol"; +import {LibAllStandardOpsNP, AuthoringMetaV2} from "src/lib/op/LibAllStandardOpsNP.sol"; +import {LibParseMeta} from "src/lib/parse/LibParseMeta.sol"; +import {EXPRESSION_DEPLOYER_NP_META_PATH} from "src/lib/constants/ExpressionDeployerNPConstants.sol"; + +contract BuildPointers is Script { + function filePrefix() internal pure returns (string memory) { + return string.concat( + "// THIS FILE IS AUTOGENERATED BY ./script/BuildPointers.sol\n\n", + "// This file is committed to the repository because there is a circular\n" + "// dependency between the contract and its pointers file. The contract\n" + "// needs the pointers file to exist so that it can compile, and the pointers\n" + "// file needs the contract to exist so that it can be compiled.\n\n", + "// SPDX-License-Identifier: CAL\n", + "pragma solidity =0.8.25;\n" + ); + } + + function pathForContract(string memory contractName) internal pure returns (string memory) { + return string.concat("src/generated/", contractName, ".pointers.sol"); + } + + function bytesToHex(bytes memory data) internal pure returns (string memory) { + string memory hexString = vm.toString(data); + assembly ("memory-safe") { + // Remove the leading 0x + let newHexString := add(hexString, 2) + mstore(newHexString, sub(mload(hexString), 2)) + hexString := newHexString + } + return hexString; + } + + function bytecodeHashConstantString(address instance) internal view returns (string memory) { + bytes32 bytecodeHash; + assembly { + bytecodeHash := extcodehash(instance) + } + return string.concat( + "\n", + "/// @dev Hash of the known bytecode.\n", + "bytes32 constant BYTECODE_HASH = bytes32(", + vm.toString(bytecodeHash), + ");\n" + ); + } + + function interpreterFunctionPointersConstantString(IInterpreterV2 interpreter) + internal + view + returns (string memory) + { + return string.concat( + "\n", + "/// @dev The function pointers known to the interpreter for dynamic dispatch.\n", + "/// By setting these as a constant they can be inlined into the interpreter\n", + "/// and loaded at eval time for very low gas (~100) due to the compiler\n", + "/// optimising it to a single `codecopy` to build the in memory bytes array.\n", + "bytes constant OPCODE_FUNCTION_POINTERS =\n", + " hex\"", + bytesToHex(interpreter.functionPointers()), + "\";\n" + ); + } + + function literalParserFunctionPointersConstantString(RainterpreterParserNPE2 instance) + internal + pure + returns (string memory) + { + return string.concat( + "\n", + "/// @dev Every two bytes is a function pointer for a literal parser.\n", + "/// Literal dispatches are determined by the first byte(s) of the literal\n", + "/// rather than a full word lookup, and are done with simple conditional\n", + "/// jumps as the possibilities are limited compared to the number of words we\n" "/// have.\n", + "bytes constant LITERAL_PARSER_FUNCTION_POINTERS = hex\"", + bytesToHex(instance.buildLiteralParserFunctionPointers()), + "\";\n" + ); + } + + function operandHandlerFunctionPointersConstantString(RainterpreterParserNPE2 instance) + internal + pure + returns (string memory) + { + return string.concat( + "\n", + "/// @dev Every two bytes is a function pointer for an operand handler.\n", + "/// These positional indexes all map to the same indexes looked up in the parse\n", + "/// meta.\n", + "bytes constant OPERAND_HANDLER_FUNCTION_POINTERS =\n", + " hex\"", + bytesToHex(instance.buildOperandHandlerFunctionPointers()), + "\";\n" + ); + } + + function parseMetaConstantString(bytes memory authoringMetaBytes) internal pure returns (string memory) { + AuthoringMetaV2[] memory authoringMeta = abi.decode(authoringMetaBytes, (AuthoringMetaV2[])); + bytes memory parseMeta = LibParseMeta.buildParseMetaV2(authoringMeta, PARSE_META_BUILD_DEPTH); + return string.concat( + "\n", + "/// @dev Encodes the parser meta that is used to lookup word definitions.\n", + "/// The structure of the parser meta is:\n", + "/// - 1 byte: The depth of the bloom filters\n", + "/// - 1 byte: The hashing seed\n", + "/// - The bloom filters, each is 32 bytes long, one for each build depth.\n", + "/// - All the items for each word, each is 4 bytes long. Each item's first byte\n", + "/// is its opcode index, the remaining 3 bytes are the word fingerprint.\n", + "/// To do a lookup, the word is hashed with the seed, then the first byte of the\n", + "/// hash is compared against the bloom filter. If there is a hit then we count\n", + "/// the number of 1 bits in the bloom filter up to this item's 1 bit. We then\n", + "/// treat this a the index of the item in the items array. We then compare the\n", + "/// word fingerprint against the fingerprint of the item at this index. If the\n", + "/// fingerprints equal then we have a match, else we increment the seed and try\n", + "/// again with the next bloom filter, offsetting all the indexes by the total\n", + "/// bit count of the previous bloom filter. If we reach the end of the bloom\n", + "/// filters then we have a miss.\n", + "bytes constant PARSE_META =\n", + " hex\"", + bytesToHex(parseMeta), + "\";\n\n", + "/// @dev The build depth of the parser meta.\n", + "uint8 constant PARSE_META_BUILD_DEPTH = ", + vm.toString(PARSE_META_BUILD_DEPTH), + ";\n" + ); + } + + function integrityFunctionPointersConstantString(RainterpreterExpressionDeployerNPE2 deployer) + internal + view + returns (string memory) + { + return string.concat( + "\n", + "/// @dev The function pointers for the integrity check fns.\n", + "bytes constant INTEGRITY_FUNCTION_POINTERS =\n", + " hex\"", + bytesToHex(deployer.integrityFunctionPointers()), + "\";\n" + ); + } + + function describedByMetaHashConstantString(bytes memory describedByMeta) internal pure returns (string memory) { + return string.concat( + "\n", + "/// @dev The hash of the meta that describes the contract.\n", + "bytes32 constant DESCRIBED_BY_META_HASH = bytes32(", + vm.toString(keccak256(describedByMeta)), + ");\n" + ); + } + + function buildFileForContract(address instance, string memory contractName, string memory body) internal { + string memory path = pathForContract(contractName); + + if (vm.exists(path)) { + vm.removeFile(path); + } + vm.writeFile(path, string.concat(filePrefix(), bytecodeHashConstantString(instance), body)); + } + + function buildRainterpreterNPE2Pointers() internal { + RainterpreterNPE2 interpreter = new RainterpreterNPE2(); + + buildFileForContract( + address(interpreter), "RainterpreterNPE2", interpreterFunctionPointersConstantString(interpreter) + ); + } + + function buildRainterpreterStoreNPE2Pointers() internal { + RainterpreterStoreNPE2 store = new RainterpreterStoreNPE2(); + + buildFileForContract(address(store), "RainterpreterStoreNPE2", ""); + } + + function buildRainterpreterParserNPE2Pointers() internal { + RainterpreterParserNPE2 parser = new RainterpreterParserNPE2(); + + buildFileForContract( + address(parser), + "RainterpreterParserNPE2", + string.concat( + parseMetaConstantString(LibAllStandardOpsNP.authoringMetaV2()), + operandHandlerFunctionPointersConstantString(parser), + literalParserFunctionPointersConstantString(parser) + ) + ); + } + + function buildRainterpreterExpressionDeployerNPE2Pointers() internal { + RainterpreterNPE2 interpreter = new RainterpreterNPE2(); + RainterpreterStoreNPE2 store = new RainterpreterStoreNPE2(); + RainterpreterParserNPE2 parser = new RainterpreterParserNPE2(); + + RainterpreterExpressionDeployerNPE2 deployer = new RainterpreterExpressionDeployerNPE2( + RainterpreterExpressionDeployerNPE2ConstructionConfigV2( + address(interpreter), address(store), address(parser) + ) + ); + + buildFileForContract( + address(deployer), + "RainterpreterExpressionDeployerNPE2", + string.concat( + describedByMetaHashConstantString(vm.readFileBinary(EXPRESSION_DEPLOYER_NP_META_PATH)), + integrityFunctionPointersConstantString(deployer) + ) + ); + } + + function run() external { + buildRainterpreterNPE2Pointers(); + buildRainterpreterStoreNPE2Pointers(); + buildRainterpreterParserNPE2Pointers(); + buildRainterpreterExpressionDeployerNPE2Pointers(); + } +} diff --git a/src/concrete/RainterpreterExpressionDeployerNPE2.sol b/src/concrete/RainterpreterExpressionDeployerNPE2.sol index 6b5589c1e..b0230ed0c 100644 --- a/src/concrete/RainterpreterExpressionDeployerNPE2.sol +++ b/src/concrete/RainterpreterExpressionDeployerNPE2.sol @@ -33,13 +33,10 @@ import {LibParse, LibParseMeta} from "../lib/parse/LibParse.sol"; import {RainterpreterNPE2, INTERPRETER_BYTECODE_HASH} from "./RainterpreterNPE2.sol"; import {PARSER_BYTECODE_HASH} from "./RainterpreterParserNPE2.sol"; import {STORE_BYTECODE_HASH} from "./RainterpreterStoreNPE2.sol"; - -/// @dev The function pointers for the integrity check fns. -bytes constant INTEGRITY_FUNCTION_POINTERS = - hex"0e780ef60f5b10d510df10df10e910f2110d11b311b3120f1289129610df10e910df10df10e910d510d510d510d512a012c512df10df12a010df10df129610e910df10df1296129612e912e912e912e910df10e912e910e910e910e910e910df10e910e910e910e910e912e912e912e912e910df10e910e910df10e910e910df10df10e912e912e910e912df"; - -/// @dev Hash of the metadata that describes the deployer (parsing). -bytes32 constant DESCRIBED_BY_META_HASH = bytes32(0x89148873ea148e1c312c3c6cffbc5fb012194570f04ed1177db6002901e7bf38); +import { + INTEGRITY_FUNCTION_POINTERS, + DESCRIBED_BY_META_HASH +} from "../generated/RainterpreterExpressionDeployerNPE2.pointers.sol"; /// All config required to construct a `RainterpreterNPE2`. /// @param interpreter The `IInterpreterV2` to use for evaluation. MUST match diff --git a/src/concrete/RainterpreterNPE2.sol b/src/concrete/RainterpreterNPE2.sol index 8b23dcad3..d8aaf9132 100644 --- a/src/concrete/RainterpreterNPE2.sol +++ b/src/concrete/RainterpreterNPE2.sol @@ -23,16 +23,10 @@ import { IInterpreterStoreV2 } from "rain.interpreter.interface/interface/IInterpreterV2.sol"; import {IInterpreterV3} from "rain.interpreter.interface/interface/unstable/IInterpreterV3.sol"; - -/// @dev Hash of the known interpreter bytecode. -bytes32 constant INTERPRETER_BYTECODE_HASH = bytes32(0x082edcc97843fd74ff6dc51867110b8633b0e419bac46f53765f5a833f36d024); - -/// @dev The function pointers known to the interpreter for dynamic dispatch. -/// By setting these as a constant they can be inlined into the interpreter -/// and loaded at eval time for very low gas (~100) due to the compiler -/// optimising it to a single `codecopy` to build the in memory bytes array. -bytes constant OPCODE_FUNCTION_POINTERS = - hex"0e060e570e991065114c115e1170119311d512271238124912eb132813e6149613e6151a15bc1634166d16a616f5172e1793186718ba18ce1927193b1950196a19751989199e19d619fd1a7d1acb1b191b671b7f1b981be61bf41c021c1d1c321c4a1c631c711c7f1c8d1c9b1ce91d371d851dd31deb1deb1e021e301e301e471e761ecb1ed91ed91f7d2064"; +import { + BYTECODE_HASH as INTERPRETER_BYTECODE_HASH, + OPCODE_FUNCTION_POINTERS +} from "../generated/RainterpreterNPE2.pointers.sol"; /// @title RainterpreterNPE2 /// @notice Implementation of a Rainlang interpreter that is compatible with diff --git a/src/concrete/RainterpreterParserNPE2.sol b/src/concrete/RainterpreterParserNPE2.sol index 688bc361e..0f9127804 100644 --- a/src/concrete/RainterpreterParserNPE2.sol +++ b/src/concrete/RainterpreterParserNPE2.sol @@ -12,43 +12,13 @@ import {LibParseLiteral} from "../lib/parse/literal/LibParseLiteral.sol"; import {LibAllStandardOpsNP} from "../lib/op/LibAllStandardOpsNP.sol"; import {LibBytes, Pointer} from "rain.solmem/lib/LibBytes.sol"; import {LibParseInterstitial} from "../lib/parse/LibParseInterstitial.sol"; - -/// @dev The known hash of the parser bytecode. This is used by the deployer to -/// check that it is deploying a parser that is compatible with the interpreter. -bytes32 constant PARSER_BYTECODE_HASH = bytes32(0x458b319779ec46db91b9a23ad6cef12479a4e05fa05f5c0094fa3211b1c937cd); - -/// @dev Encodes the parser meta that is used to lookup word definitions. -/// The structure of the parser meta is: -/// - 1 byte: The depth of the bloom filters -/// - 1 byte: The hashing seed -/// - The bloom filters, each is 32 bytes long, one for each build depth. -/// - All the items for each word, each is 4 bytes long. Each item's first byte -/// is its opcode index, the remaining 3 bytes are the word fingerprint. -/// To do a lookup, the word is hashed with the seed, then the first byte of the -/// hash is compared against the bloom filter. If there is a hit then we count -/// the number of 1 bits in the bloom filter up to this item's 1 bit. We then -/// treat this a the index of the item in the items array. We then compare the -/// word fingerprint against the fingerprint of the item at this index. If the -/// fingerprints equal then we have a match, else we increment the seed and try -/// again with the next bloom filter, offsetting all the indexes by the total -/// bit count of the previous bloom filter. If we reach the end of the bloom -/// filters then we have a miss. -bytes constant PARSE_META = - hex"027d02482901b41410193601380a408092011324604290a201223062960011040a8900000000000000000800000008000000100000000000000000000000000000000037af1e5831ee31ff1a4c426226d999cd14d454a62287204a17ca041510bfc04d05382451258fb9fe30e745fd28dbc3c529415aff38530a92368e9cbd2f4c3a173b402c5804ea67600a2aa235164d56371805a7653edd323d0cd5a68e1e3f22703f2237031f80073412d4a5b3119bd3ec068483ae402e554c35f6dc5d23f0c0a632fef45a2da6feff1c9677b92edb58d43c742e374178613501d4fa88030cae020885d59f2b766a3e158413022a67b453194070aa2040ab0f245a53d84392737c335bcbd00ff7e3283d5a200713686f5c39bd3f5f024641b909f14a300b1ec71b27a38323349552b91d792a60425d96b7457b8cf22153f8d14433bccc0d403ded0791b7eb002ddffc0e1abd702ce98c713ac04abd1b4507bb"; - -/// @dev The build depth of the parser meta. -uint8 constant PARSE_META_BUILD_DEPTH = 2; - -/// @dev Every two bytes is a function pointer for an operand handler. These -/// positional indexes all map to the same indexes looked up in the parse meta. -bytes constant OPERAND_HANDLER_FUNCTION_POINTERS = - hex"18d818d818d8193d19b619b619b6193d193d18d818d818d819b619b619b619b619b619b619b619b619b619b619b619b619b619b619b619b619b619b619b619b619b619b619b619b619b619b619b619b619b619b619b619b619b619b619b619b619b619b619b619b619b619b619b619b619b619b619fb19b61acd19fb19b61acd19b619b618d81b3619b619b6"; - -/// @dev Every two bytes is a function pointer for a literal parser. Literal -/// dispatches are determined by the first byte(s) of the literal rather than a -/// full word lookup, and are done with simple conditional jumps as the -/// possibilities are limited compared to the number of words we have. -bytes constant LITERAL_PARSER_FUNCTION_POINTERS = hex"0f4e1216161d16f7"; +import { + BYTECODE_HASH as PARSER_BYTECODE_HASH, + LITERAL_PARSER_FUNCTION_POINTERS, + OPERAND_HANDLER_FUNCTION_POINTERS, + PARSE_META, + PARSE_META_BUILD_DEPTH +} from "../generated/RainterpreterParserNPE2.pointers.sol"; /// @title RainterpreterParserNPE2 /// @dev The parser implementation. diff --git a/src/concrete/RainterpreterStoreNPE2.sol b/src/concrete/RainterpreterStoreNPE2.sol index 8675802ef..b8fa31a60 100644 --- a/src/concrete/RainterpreterStoreNPE2.sol +++ b/src/concrete/RainterpreterStoreNPE2.sol @@ -1,17 +1,18 @@ // SPDX-License-Identifier: CAL pragma solidity =0.8.25; -import "openzeppelin-contracts/contracts/utils/introspection/ERC165.sol"; +import {ERC165} from "openzeppelin-contracts/contracts/utils/introspection/ERC165.sol"; -import "rain.interpreter.interface/interface/IInterpreterStoreV2.sol"; -import "rain.interpreter.interface/lib/ns/LibNamespace.sol"; +import {IInterpreterStoreV2} from "rain.interpreter.interface/interface/IInterpreterStoreV2.sol"; +import { + LibNamespace, FullyQualifiedNamespace, StateNamespace +} from "rain.interpreter.interface/lib/ns/LibNamespace.sol"; + +import {BYTECODE_HASH as STORE_BYTECODE_HASH} from "../generated/RainterpreterStoreNPE2.pointers.sol"; /// Thrown when a `set` call is made with an odd number of arguments. error OddSetLength(uint256 length); -/// @dev Hash of the known store bytecode. -bytes32 constant STORE_BYTECODE_HASH = bytes32(0x2a4559222e2f3600b2d393715de8af57620439684463f745059c653bbfe3727f); - /// @title RainterpreterStore /// @notice Simplest possible `IInterpreterStoreV2` that could work. /// Takes key/value pairings from the input array and stores each in an internal diff --git a/src/generated/RainterpreterExpressionDeployerNPE2.pointers.sol b/src/generated/RainterpreterExpressionDeployerNPE2.pointers.sol new file mode 100644 index 000000000..584030f14 --- /dev/null +++ b/src/generated/RainterpreterExpressionDeployerNPE2.pointers.sol @@ -0,0 +1,19 @@ +// THIS FILE IS AUTOGENERATED BY ./script/BuildPointers.sol + +// This file is committed to the repository because there is a circular +// dependency between the contract and its pointers file. The contract +// needs the pointers file to exist so that it can compile, and the pointers +// file needs the contract to exist so that it can be compiled. + +// SPDX-License-Identifier: CAL +pragma solidity =0.8.25; + +/// @dev Hash of the known bytecode. +bytes32 constant BYTECODE_HASH = bytes32(0x1f3ab430cd5a8ad892a5974e85b001b59df9f2a9f9a2ccf562c518b4a6550b5a); + +/// @dev The hash of the meta that describes the contract. +bytes32 constant DESCRIBED_BY_META_HASH = bytes32(0x89148873ea148e1c312c3c6cffbc5fb012194570f04ed1177db6002901e7bf38); + +/// @dev The function pointers for the integrity check fns. +bytes constant INTEGRITY_FUNCTION_POINTERS = + hex"0e780ef60f5b10d510df10df10e910f2110d11b311b3120f1289129610df10e910df10df10e910d510d510d510d512a012c512df10df12a010df10df129610e910df10df1296129612e912e912e912e910df10e912e910e910e910e910e910df10e910e910e910e910e912e912e912e912e910df10e910e910df10e910e910df10df10e912e912e910e912df"; diff --git a/src/generated/RainterpreterNPE2.pointers.sol b/src/generated/RainterpreterNPE2.pointers.sol new file mode 100644 index 000000000..303c49e95 --- /dev/null +++ b/src/generated/RainterpreterNPE2.pointers.sol @@ -0,0 +1,19 @@ +// THIS FILE IS AUTOGENERATED BY ./script/BuildPointers.sol + +// This file is committed to the repository because there is a circular +// dependency between the contract and its pointers file. The contract +// needs the pointers file to exist so that it can compile, and the pointers +// file needs the contract to exist so that it can be compiled. + +// SPDX-License-Identifier: CAL +pragma solidity =0.8.25; + +/// @dev Hash of the known bytecode. +bytes32 constant BYTECODE_HASH = bytes32(0x082edcc97843fd74ff6dc51867110b8633b0e419bac46f53765f5a833f36d024); + +/// @dev The function pointers known to the interpreter for dynamic dispatch. +/// By setting these as a constant they can be inlined into the interpreter +/// and loaded at eval time for very low gas (~100) due to the compiler +/// optimising it to a single `codecopy` to build the in memory bytes array. +bytes constant OPCODE_FUNCTION_POINTERS = + hex"0e060e570e991065114c115e1170119311d512271238124912eb132813e6149613e6151a15bc1634166d16a616f5172e1793186718ba18ce1927193b1950196a19751989199e19d619fd1a7d1acb1b191b671b7f1b981be61bf41c021c1d1c321c4a1c631c711c7f1c8d1c9b1ce91d371d851dd31deb1deb1e021e301e301e471e761ecb1ed91ed91f7d2064"; diff --git a/src/generated/RainterpreterParserNPE2.pointers.sol b/src/generated/RainterpreterParserNPE2.pointers.sol new file mode 100644 index 000000000..3571c39d8 --- /dev/null +++ b/src/generated/RainterpreterParserNPE2.pointers.sol @@ -0,0 +1,47 @@ +// THIS FILE IS AUTOGENERATED BY ./script/BuildPointers.sol + +// This file is committed to the repository because there is a circular +// dependency between the contract and its pointers file. The contract +// needs the pointers file to exist so that it can compile, and the pointers +// file needs the contract to exist so that it can be compiled. + +// SPDX-License-Identifier: CAL +pragma solidity =0.8.25; + +/// @dev Hash of the known bytecode. +bytes32 constant BYTECODE_HASH = bytes32(0x458b319779ec46db91b9a23ad6cef12479a4e05fa05f5c0094fa3211b1c937cd); + +/// @dev Encodes the parser meta that is used to lookup word definitions. +/// The structure of the parser meta is: +/// - 1 byte: The depth of the bloom filters +/// - 1 byte: The hashing seed +/// - The bloom filters, each is 32 bytes long, one for each build depth. +/// - All the items for each word, each is 4 bytes long. Each item's first byte +/// is its opcode index, the remaining 3 bytes are the word fingerprint. +/// To do a lookup, the word is hashed with the seed, then the first byte of the +/// hash is compared against the bloom filter. If there is a hit then we count +/// the number of 1 bits in the bloom filter up to this item's 1 bit. We then +/// treat this a the index of the item in the items array. We then compare the +/// word fingerprint against the fingerprint of the item at this index. If the +/// fingerprints equal then we have a match, else we increment the seed and try +/// again with the next bloom filter, offsetting all the indexes by the total +/// bit count of the previous bloom filter. If we reach the end of the bloom +/// filters then we have a miss. +bytes constant PARSE_META = + hex"027d02482901b41410193601380a408092011324604290a201223062960011040a8900000000000000000800000008000000100000000000000000000000000000000037af1e5831ee31ff1a4c426226d999cd14d454a62287204a17ca041510bfc04d05382451258fb9fe30e745fd28dbc3c529415aff38530a92368e9cbd2f4c3a173b402c5804ea67600a2aa235164d56371805a7653edd323d0cd5a68e1e3f22703f2237031f80073412d4a5b3119bd3ec068483ae402e554c35f6dc5d23f0c0a632fef45a2da6feff1c9677b92edb58d43c742e374178613501d4fa88030cae020885d59f2b766a3e158413022a67b453194070aa2040ab0f245a53d84392737c335bcbd00ff7e3283d5a200713686f5c39bd3f5f024641b909f14a300b1ec71b27a38323349552b91d792a60425d96b7457b8cf22153f8d14433bccc0d403ded0791b7eb002ddffc0e1abd702ce98c713ac04abd1b4507bb"; + +/// @dev The build depth of the parser meta. +uint8 constant PARSE_META_BUILD_DEPTH = 2; + +/// @dev Every two bytes is a function pointer for an operand handler. +/// These positional indexes all map to the same indexes looked up in the parse +/// meta. +bytes constant OPERAND_HANDLER_FUNCTION_POINTERS = + hex"18d818d818d8193d19b619b619b6193d193d18d818d818d819b619b619b619b619b619b619b619b619b619b619b619b619b619b619b619b619b619b619b619b619b619b619b619b619b619b619b619b619b619b619b619b619b619b619b619b619b619b619b619b619b619b619b619b619b619b619fb19b61acd19fb19b61acd19b619b618d81b3619b619b6"; + +/// @dev Every two bytes is a function pointer for a literal parser. +/// Literal dispatches are determined by the first byte(s) of the literal +/// rather than a full word lookup, and are done with simple conditional +/// jumps as the possibilities are limited compared to the number of words we +/// have. +bytes constant LITERAL_PARSER_FUNCTION_POINTERS = hex"0f4e1216161d16f7"; diff --git a/src/generated/RainterpreterStoreNPE2.pointers.sol b/src/generated/RainterpreterStoreNPE2.pointers.sol new file mode 100644 index 000000000..8d6c8c5d9 --- /dev/null +++ b/src/generated/RainterpreterStoreNPE2.pointers.sol @@ -0,0 +1,12 @@ +// THIS FILE IS AUTOGENERATED BY ./script/BuildPointers.sol + +// This file is committed to the repository because there is a circular +// dependency between the contract and its pointers file. The contract +// needs the pointers file to exist so that it can compile, and the pointers +// file needs the contract to exist so that it can be compiled. + +// SPDX-License-Identifier: CAL +pragma solidity =0.8.25; + +/// @dev Hash of the known bytecode. +bytes32 constant BYTECODE_HASH = bytes32(0x2a4559222e2f3600b2d393715de8af57620439684463f745059c653bbfe3727f); diff --git a/test/lib/constants/ExpressionDeployerNPConstants.sol b/src/lib/constants/ExpressionDeployerNPConstants.sol similarity index 100% rename from test/lib/constants/ExpressionDeployerNPConstants.sol rename to src/lib/constants/ExpressionDeployerNPConstants.sol diff --git a/test/src/concrete/RainterpreterExpressionDeployerNPE2.deployCheck.t.sol b/test/src/concrete/RainterpreterExpressionDeployerNPE2.deployCheck.t.sol index a83df7445..2bf74120f 100644 --- a/test/src/concrete/RainterpreterExpressionDeployerNPE2.deployCheck.t.sol +++ b/test/src/concrete/RainterpreterExpressionDeployerNPE2.deployCheck.t.sol @@ -3,7 +3,6 @@ pragma solidity =0.8.25; import {Test} from "forge-std/Test.sol"; import {INVALID_BYTECODE} from "test/lib/etch/LibEtch.sol"; -import {EXPRESSION_DEPLOYER_NP_META_PATH} from "test/lib/constants/ExpressionDeployerNPConstants.sol"; import {IERC1820Registry} from "openzeppelin-contracts/contracts/utils/introspection/IERC1820Registry.sol"; import {IERC1820_REGISTRY} from "rain.erc1820/lib/LibIERC1820.sol"; import {IInterpreterV2} from "rain.interpreter.interface/interface/IInterpreterV2.sol"; diff --git a/test/src/concrete/RainterpreterExpressionDeployerNPE2.describedByMetaV1.t.sol b/test/src/concrete/RainterpreterExpressionDeployerNPE2.describedByMetaV1.t.sol index cf78a6b02..f1cba3489 100644 --- a/test/src/concrete/RainterpreterExpressionDeployerNPE2.describedByMetaV1.t.sol +++ b/test/src/concrete/RainterpreterExpressionDeployerNPE2.describedByMetaV1.t.sol @@ -9,7 +9,7 @@ import { import {RainterpreterNPE2} from "src/concrete/RainterpreterNPE2.sol"; import {RainterpreterStoreNPE2} from "src/concrete/RainterpreterStoreNPE2.sol"; import {RainterpreterParserNPE2} from "src/concrete/RainterpreterParserNPE2.sol"; -import {EXPRESSION_DEPLOYER_NP_META_PATH} from "../../lib/constants/ExpressionDeployerNPConstants.sol"; +import {EXPRESSION_DEPLOYER_NP_META_PATH} from "src/lib/constants/ExpressionDeployerNPConstants.sol"; contract RainterpreterExpressionDeployerNPE2DescribedByMetaV1Test is Test { function testRainterpreterExpressionDeployerNPE2DescribedByMetaV1Happy() external { diff --git a/test/src/concrete/RainterpreterExpressionDeployerNPE2.parse2.t.sol b/test/src/concrete/RainterpreterExpressionDeployerNPE2.parse2.t.sol index 1ed0fe809..44a9102cb 100644 --- a/test/src/concrete/RainterpreterExpressionDeployerNPE2.parse2.t.sol +++ b/test/src/concrete/RainterpreterExpressionDeployerNPE2.parse2.t.sol @@ -2,7 +2,6 @@ pragma solidity =0.8.25; import {Test} from "forge-std/Test.sol"; -import {EXPRESSION_DEPLOYER_NP_META_PATH} from "test/lib/constants/ExpressionDeployerNPConstants.sol"; import { RainterpreterExpressionDeployerNPE2, RainterpreterExpressionDeployerNPE2ConstructionConfigV2 diff --git a/test/src/concrete/RainterpreterParserNPE2.pointers.t.sol b/test/src/concrete/RainterpreterParserNPE2.pointers.t.sol index 5535b3a6a..267aec8a5 100644 --- a/test/src/concrete/RainterpreterParserNPE2.pointers.t.sol +++ b/test/src/concrete/RainterpreterParserNPE2.pointers.t.sol @@ -6,7 +6,8 @@ import { RainterpreterParserNPE2, OPERAND_HANDLER_FUNCTION_POINTERS, LITERAL_PARSER_FUNCTION_POINTERS, - PARSE_META + PARSE_META, + PARSE_META_BUILD_DEPTH } from "src/concrete/RainterpreterParserNPE2.sol"; import {LibAllStandardOpsNP, AuthoringMetaV2} from "src/lib/op/LibAllStandardOpsNP.sol"; import {LibParseMeta} from "src/lib/parse/LibParseMeta.sol"; @@ -29,7 +30,7 @@ contract RainterpreterParserNPE2PointersTest is Test { function testParserParseMeta() external { bytes memory authoringMetaBytes = LibAllStandardOpsNP.authoringMetaV2(); AuthoringMetaV2[] memory authoringMeta = abi.decode(authoringMetaBytes, (AuthoringMetaV2[])); - bytes memory expected = LibParseMeta.buildParseMetaV2(authoringMeta, 2); + bytes memory expected = LibParseMeta.buildParseMetaV2(authoringMeta, PARSE_META_BUILD_DEPTH); bytes memory actual = PARSE_META; assertEq(actual, expected); }