Commit 21e1291a authored by Michael Amadi's avatar Michael Amadi Committed by GitHub

make custom process bash function (#12704)

* make custom process bash function

* rm Executables.sol, fix failing test

* fixes

* fixes...
parent fd1e0622
...@@ -67,11 +67,7 @@ abstract contract Artifacts { ...@@ -67,11 +67,7 @@ abstract contract Artifacts {
/// as well as the JSON files that contain addresses in the `superchain-registry` /// as well as the JSON files that contain addresses in the `superchain-registry`
/// repo. The JSON key is the name of the contract and the value is an address. /// repo. The JSON key is the name of the contract and the value is an address.
function _loadAddresses(string memory _path) internal { function _loadAddresses(string memory _path) internal {
string[] memory commands = new string[](3); string memory json = Process.bash(string.concat("jq -cr < ", _path));
commands[0] = "bash";
commands[1] = "-c";
commands[2] = string.concat("jq -cr < ", _path);
string memory json = string(Process.run(commands));
string[] memory keys = vm.parseJsonKeys(json, ""); string[] memory keys = vm.parseJsonKeys(json, "");
for (uint256 i; i < keys.length; i++) { for (uint256 i; i < keys.length; i++) {
string memory key = keys[i]; string memory key = keys[i];
......
...@@ -642,11 +642,7 @@ contract L2Genesis is Deployer { ...@@ -642,11 +642,7 @@ contract L2Genesis is Deployer {
/// @notice Sorts the allocs by address /// @notice Sorts the allocs by address
function sortJsonByKeys(string memory _path) internal { function sortJsonByKeys(string memory _path) internal {
string[] memory commands = new string[](3); Process.bash(string.concat("cat <<< $(jq -S '.' ", _path, ") > ", _path));
commands[0] = "bash";
commands[1] = "-c";
commands[2] = string.concat("cat <<< $(jq -S '.' ", _path, ") > ", _path);
Process.run(commands);
} }
/// @notice Funds the default dev accounts with ether /// @notice Funds the default dev accounts with ether
......
...@@ -9,11 +9,8 @@ import { Process } from "scripts/libraries/Process.sol"; ...@@ -9,11 +9,8 @@ import { Process } from "scripts/libraries/Process.sol";
contract SemverLock is Script { contract SemverLock is Script {
function run() public { function run() public {
// First, find all contracts with a Semver inheritance. // First, find all contracts with a Semver inheritance.
string[] memory commands = new string[](3); string memory rawFiles =
commands[0] = "bash"; Process.bash("grep -rl '@custom:semver' src | jq -Rs 'split(\"\\n\") | map(select(length > 0))'");
commands[1] = "-c";
commands[2] = "grep -rl '@custom:semver' src | jq -Rs 'split(\"\\n\") | map(select(length > 0))'";
string memory rawFiles = string(Process.run(commands));
string[] memory files = vm.parseJsonStringArray(rawFiles, ""); string[] memory files = vm.parseJsonStringArray(rawFiles, "");
writeSemverLock(files); writeSemverLock(files);
...@@ -30,22 +27,21 @@ contract SemverLock is Script { ...@@ -30,22 +27,21 @@ contract SemverLock is Script {
string memory fileContents = string(Process.run(commands)); string memory fileContents = string(Process.run(commands));
// Grab the contract name // Grab the contract name
commands = new string[](3); string memory contractName =
commands[0] = "bash"; Process.bash(string.concat("echo \"", _files[i], "\"| sed -E 's|src/.*/(.+)\\.sol|\\1|'"));
commands[1] = "-c";
commands[2] = string.concat("echo \"", _files[i], "\"| sed -E \'s|src/.*/(.+)\\.sol|\\1|\'");
string memory contractName = string(Process.run(commands));
commands[2] = "forge config --json | jq -r .out"; string memory artifactsDir = Process.bash("forge config --json | jq -r .out");
string memory artifactsDir = string(Process.run(commands));
// Handle the case where there are multiple artifacts for a contract. This happens // Handle the case where there are multiple artifacts for a contract. This happens
// when the same contract is compiled with multiple compiler versions. // when the same contract is compiled with multiple compiler versions.
string memory contractArtifactDir = string.concat(artifactsDir, "/", contractName, ".sol"); string memory contractArtifactDir = string.concat(artifactsDir, "/", contractName, ".sol");
commands[2] = string.concat( string memory artifactFiles = Process.bash(
"ls -1 --color=never ", contractArtifactDir, " | jq -R -s -c 'split(\"\n\") | map(select(length > 0))'" string.concat(
"ls -1 --color=never ",
contractArtifactDir,
" | jq -R -s -c 'split(\"\n\") | map(select(length > 0))'"
)
); );
string memory artifactFiles = string(Process.run(commands));
string[] memory files = stdJson.readStringArray(artifactFiles, ""); string[] memory files = stdJson.readStringArray(artifactFiles, "");
require(files.length > 0, string.concat("SemverLock: no artifacts found for ", contractName)); require(files.length > 0, string.concat("SemverLock: no artifacts found for ", contractName));
......
...@@ -995,17 +995,13 @@ contract Deploy is Deployer { ...@@ -995,17 +995,13 @@ contract Deploy is Deployer {
function _loadDevnetStMipsAbsolutePrestate() internal returns (Claim mipsAbsolutePrestate_) { function _loadDevnetStMipsAbsolutePrestate() internal returns (Claim mipsAbsolutePrestate_) {
// Fetch the absolute prestate dump // Fetch the absolute prestate dump
string memory filePath = string.concat(vm.projectRoot(), "/../../op-program/bin/prestate-proof.json"); string memory filePath = string.concat(vm.projectRoot(), "/../../op-program/bin/prestate-proof.json");
string[] memory commands = new string[](3); if (bytes(Process.bash(string.concat("[[ -f ", filePath, " ]] && echo \"present\""))).length == 0) {
commands[0] = "bash";
commands[1] = "-c";
commands[2] = string.concat("[[ -f ", filePath, " ]] && echo \"present\"");
if (Process.run(commands).length == 0) {
revert( revert(
"Deploy: cannon prestate dump not found, generate it with `make cannon-prestate` in the monorepo root" "Deploy: cannon prestate dump not found, generate it with `make cannon-prestate` in the monorepo root"
); );
} }
commands[2] = string.concat("cat ", filePath, " | jq -r .pre"); mipsAbsolutePrestate_ =
mipsAbsolutePrestate_ = Claim.wrap(abi.decode(Process.run(commands), (bytes32))); Claim.wrap(abi.decode(bytes(Process.bash(string.concat("cat ", filePath, " | jq -r .pre"))), (bytes32)));
console.log( console.log(
"[Cannon Dispute Game] Using devnet MIPS Absolute prestate: %s", "[Cannon Dispute Game] Using devnet MIPS Absolute prestate: %s",
vm.toString(Claim.unwrap(mipsAbsolutePrestate_)) vm.toString(Claim.unwrap(mipsAbsolutePrestate_))
...@@ -1017,17 +1013,13 @@ contract Deploy is Deployer { ...@@ -1017,17 +1013,13 @@ contract Deploy is Deployer {
function _loadDevnetMtMipsAbsolutePrestate() internal returns (Claim mipsAbsolutePrestate_) { function _loadDevnetMtMipsAbsolutePrestate() internal returns (Claim mipsAbsolutePrestate_) {
// Fetch the absolute prestate dump // Fetch the absolute prestate dump
string memory filePath = string.concat(vm.projectRoot(), "/../../op-program/bin/prestate-proof-mt.json"); string memory filePath = string.concat(vm.projectRoot(), "/../../op-program/bin/prestate-proof-mt.json");
string[] memory commands = new string[](3); if (bytes(Process.bash(string.concat("[[ -f ", filePath, " ]] && echo \"present\""))).length == 0) {
commands[0] = "bash";
commands[1] = "-c";
commands[2] = string.concat("[[ -f ", filePath, " ]] && echo \"present\"");
if (Process.run(commands).length == 0) {
revert( revert(
"Deploy: MT-Cannon prestate dump not found, generate it with `make cannon-prestate-mt` in the monorepo root" "Deploy: MT-Cannon prestate dump not found, generate it with `make cannon-prestate-mt` in the monorepo root"
); );
} }
commands[2] = string.concat("cat ", filePath, " | jq -r .pre"); mipsAbsolutePrestate_ =
mipsAbsolutePrestate_ = Claim.wrap(abi.decode(Process.run(commands), (bytes32))); Claim.wrap(abi.decode(bytes(Process.bash(string.concat("cat ", filePath, " | jq -r .pre"))), (bytes32)));
console.log( console.log(
"[MT-Cannon Dispute Game] Using devnet MIPS2 Absolute prestate: %s", "[MT-Cannon Dispute Game] Using devnet MIPS2 Absolute prestate: %s",
vm.toString(Claim.unwrap(mipsAbsolutePrestate_)) vm.toString(Claim.unwrap(mipsAbsolutePrestate_))
......
...@@ -4,7 +4,6 @@ pragma solidity 0.8.15; ...@@ -4,7 +4,6 @@ pragma solidity 0.8.15;
import { Script } from "forge-std/Script.sol"; import { Script } from "forge-std/Script.sol";
import { console2 as console } from "forge-std/console2.sol"; import { console2 as console } from "forge-std/console2.sol";
import { stdJson } from "forge-std/StdJson.sol"; import { stdJson } from "forge-std/StdJson.sol";
import { Executables } from "scripts/libraries/Executables.sol";
import { Process } from "scripts/libraries/Process.sol"; import { Process } from "scripts/libraries/Process.sol";
import { Config, Fork, ForkUtils } from "scripts/libraries/Config.sol"; import { Config, Fork, ForkUtils } from "scripts/libraries/Config.sol";
...@@ -211,12 +210,9 @@ contract DeployConfig is Script { ...@@ -211,12 +210,9 @@ contract DeployConfig is Script {
function l2OutputOracleStartingTimestamp() public returns (uint256) { function l2OutputOracleStartingTimestamp() public returns (uint256) {
if (_l2OutputOracleStartingTimestamp < 0) { if (_l2OutputOracleStartingTimestamp < 0) {
bytes32 tag = l1StartingBlockTag(); bytes32 tag = l1StartingBlockTag();
string[] memory cmd = new string[](3); string memory cmd = string.concat("cast block ", vm.toString(tag), " --json | jq .timestamp");
cmd[0] = Executables.bash; string memory res = Process.bash(cmd);
cmd[1] = "-c"; return stdJson.readUint(res, "");
cmd[2] = string.concat("cast block ", vm.toString(tag), " --json | ", Executables.jq, " .timestamp");
bytes memory res = Process.run(cmd);
return stdJson.readUint(string(res), "");
} }
return uint256(_l2OutputOracleStartingTimestamp); return uint256(_l2OutputOracleStartingTimestamp);
} }
...@@ -263,11 +259,8 @@ contract DeployConfig is Script { ...@@ -263,11 +259,8 @@ contract DeployConfig is Script {
} }
function _getBlockByTag(string memory _tag) internal returns (bytes32) { function _getBlockByTag(string memory _tag) internal returns (bytes32) {
string[] memory cmd = new string[](3); string memory cmd = string.concat("cast block ", _tag, " --json | jq -r .hash");
cmd[0] = Executables.bash; bytes memory res = bytes(Process.bash(cmd));
cmd[1] = "-c";
cmd[2] = string.concat("cast block ", _tag, " --json | ", Executables.jq, " -r .hash");
bytes memory res = Process.run(cmd);
return abi.decode(res, (bytes32)); return abi.decode(res, (bytes32));
} }
......
...@@ -5,8 +5,8 @@ import { Script } from "forge-std/Script.sol"; ...@@ -5,8 +5,8 @@ import { Script } from "forge-std/Script.sol";
import { Artifacts } from "scripts/Artifacts.s.sol"; import { Artifacts } from "scripts/Artifacts.s.sol";
import { Config } from "scripts/libraries/Config.sol"; import { Config } from "scripts/libraries/Config.sol";
import { DeployConfig } from "scripts/deploy/DeployConfig.s.sol"; import { DeployConfig } from "scripts/deploy/DeployConfig.s.sol";
import { Executables } from "scripts/libraries/Executables.sol";
import { console } from "forge-std/console.sol"; import { console } from "forge-std/console.sol";
import { Process } from "scripts/libraries/Process.sol";
/// @title Deployer /// @title Deployer
/// @author tynes /// @author tynes
...@@ -19,11 +19,20 @@ abstract contract Deployer is Script, Artifacts { ...@@ -19,11 +19,20 @@ abstract contract Deployer is Script, Artifacts {
function setUp() public virtual override { function setUp() public virtual override {
Artifacts.setUp(); Artifacts.setUp();
console.log("Commit hash: %s", Executables.gitCommitHash()); console.log("Commit hash: %s", gitCommitHash());
vm.etch(address(cfg), vm.getDeployedCode("DeployConfig.s.sol:DeployConfig")); vm.etch(address(cfg), vm.getDeployedCode("DeployConfig.s.sol:DeployConfig"));
vm.label(address(cfg), "DeployConfig"); vm.label(address(cfg), "DeployConfig");
vm.allowCheatcodes(address(cfg)); vm.allowCheatcodes(address(cfg));
cfg.read(Config.deployConfigPath()); cfg.read(Config.deployConfigPath());
} }
/// @notice Returns the commit hash of HEAD. If no git repository is
/// found, it will return the contents of the .gitcommit file. Otherwise,
/// it will return an error. The .gitcommit file is used to store the
/// git commit of the contracts when they are packaged into docker images
/// in order to avoid the need to have a git repository in the image.
function gitCommitHash() internal returns (string memory) {
return Process.bash("cast abi-encode 'f(string)' $(git rev-parse HEAD || cat .gitcommit)");
}
} }
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { Vm } from "forge-std/Vm.sol";
import { Process } from "scripts/libraries/Process.sol";
/// @notice The executables used in ffi commands. These are set here
/// to have a single source of truth in case absolute paths
/// need to be used.
library Executables {
/// @notice Foundry cheatcode VM.
Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code")))));
string internal constant bash = "bash";
string internal constant jq = "jq";
string internal constant forge = "forge";
string internal constant echo = "echo";
string internal constant sed = "sed";
string internal constant find = "find";
string internal constant ls = "ls";
string internal constant git = "git";
/// @notice Returns the commit hash of HEAD. If no git repository is
/// found, it will return the contents of the .gitcommit file. Otherwise,
/// it will return an error. The .gitcommit file is used to store the
/// git commit of the contracts when they are packaged into docker images
/// in order to avoid the need to have a git repository in the image.
function gitCommitHash() internal returns (string memory) {
string[] memory commands = new string[](3);
commands[0] = bash;
commands[1] = "-c";
commands[2] = "cast abi-encode 'f(string)' $(git rev-parse HEAD || cat .gitcommit)";
return abi.decode(Process.run(commands), (string));
}
}
...@@ -4,7 +4,6 @@ pragma solidity ^0.8.0; ...@@ -4,7 +4,6 @@ pragma solidity ^0.8.0;
import { Vm } from "forge-std/Vm.sol"; import { Vm } from "forge-std/Vm.sol";
import { stdJson } from "forge-std/StdJson.sol"; import { stdJson } from "forge-std/StdJson.sol";
import { LibString } from "@solady/utils/LibString.sol"; import { LibString } from "@solady/utils/LibString.sol";
import { Executables } from "scripts/libraries/Executables.sol";
import { Process } from "scripts/libraries/Process.sol"; import { Process } from "scripts/libraries/Process.sol";
/// @notice Contains information about a storage slot. Mirrors the layout of the storage /// @notice Contains information about a storage slot. Mirrors the layout of the storage
...@@ -37,14 +36,7 @@ library ForgeArtifacts { ...@@ -37,14 +36,7 @@ library ForgeArtifacts {
/// @notice Removes the semantic versioning from a contract name. The semver will exist if the contract is compiled /// @notice Removes the semantic versioning from a contract name. The semver will exist if the contract is compiled
/// more than once with different versions of the compiler. /// more than once with different versions of the compiler.
function _stripSemver(string memory _name) internal returns (string memory out_) { function _stripSemver(string memory _name) internal returns (string memory out_) {
string[] memory cmd = new string[](3); out_ = Process.bash(string.concat("echo ", _name, " | sed -E 's/[.][0-9]+\\.[0-9]+\\.[0-9]+//g'"));
cmd[0] = Executables.bash;
cmd[1] = "-c";
cmd[2] = string.concat(
Executables.echo, " ", _name, " | ", Executables.sed, " -E 's/[.][0-9]+\\.[0-9]+\\.[0-9]+//g'"
);
bytes memory res = Process.run(cmd);
out_ = string(res);
} }
/// @notice Builds the fully qualified name of a contract. Assumes that the /// @notice Builds the fully qualified name of a contract. Assumes that the
...@@ -56,48 +48,33 @@ library ForgeArtifacts { ...@@ -56,48 +48,33 @@ library ForgeArtifacts {
/// @notice Returns the storage layout for a deployed contract. /// @notice Returns the storage layout for a deployed contract.
function getStorageLayout(string memory _name) internal returns (string memory layout_) { function getStorageLayout(string memory _name) internal returns (string memory layout_) {
string[] memory cmd = new string[](3); layout_ = Process.bash(string.concat("jq -r '.storageLayout' < ", _getForgeArtifactPath(_name)));
cmd[0] = Executables.bash;
cmd[1] = "-c";
cmd[2] = string.concat(Executables.jq, " -r '.storageLayout' < ", _getForgeArtifactPath(_name));
bytes memory res = Process.run(cmd);
layout_ = string(res);
} }
/// @notice Returns the abi from a the forge artifact /// @notice Returns the abi from a the forge artifact
function getAbi(string memory _name) internal returns (string memory abi_) { function getAbi(string memory _name) internal returns (string memory abi_) {
string[] memory cmd = new string[](3); abi_ = Process.bash(string.concat("jq -r '.abi' < ", _getForgeArtifactPath(_name)));
cmd[0] = Executables.bash;
cmd[1] = "-c";
cmd[2] = string.concat(Executables.jq, " -r '.abi' < ", _getForgeArtifactPath(_name));
bytes memory res = Process.run(cmd);
abi_ = string(res);
} }
/// @notice Returns the methodIdentifiers from the forge artifact /// @notice Returns the methodIdentifiers from the forge artifact
function getMethodIdentifiers(string memory _name) internal returns (string[] memory ids_) { function getMethodIdentifiers(string memory _name) internal returns (string[] memory ids_) {
string[] memory cmd = new string[](3); string memory res = Process.bash({
cmd[0] = Executables.bash; _command: string.concat("jq '.methodIdentifiers // {} | keys ' < ", _getForgeArtifactPath(_name)),
cmd[1] = "-c"; _allowEmpty: true
cmd[2] = string.concat(Executables.jq, " '.methodIdentifiers // {} | keys ' < ", _getForgeArtifactPath(_name)); });
bytes memory res = Process.run(cmd, true); ids_ = stdJson.readStringArray(res, "");
ids_ = stdJson.readStringArray(string(res), "");
} }
/// @notice Returns the kind of contract (i.e. library, contract, or interface). /// @notice Returns the kind of contract (i.e. library, contract, or interface).
/// @param _name The name of the contract to get the kind of. /// @param _name The name of the contract to get the kind of.
/// @return kind_ The kind of contract ("library", "contract", or "interface"). /// @return kind_ The kind of contract ("library", "contract", or "interface").
function getContractKind(string memory _name) internal returns (string memory kind_) { function getContractKind(string memory _name) internal returns (string memory kind_) {
string[] memory cmd = new string[](3); kind_ = Process.bash(
cmd[0] = Executables.bash; string.concat(
cmd[1] = "-c"; "jq -r '.ast.nodes[] | select(.nodeType == \"ContractDefinition\") | .contractKind' < ",
cmd[2] = string.concat( _getForgeArtifactPath(_name)
Executables.jq, )
" -r '.ast.nodes[] | select(.nodeType == \"ContractDefinition\") | .contractKind' < ",
_getForgeArtifactPath(_name)
); );
bytes memory res = Process.run(cmd);
kind_ = string(res);
} }
/// @notice Returns whether or not a contract is proxied. /// @notice Returns whether or not a contract is proxied.
...@@ -109,19 +86,14 @@ library ForgeArtifacts { ...@@ -109,19 +86,14 @@ library ForgeArtifacts {
// contract. We should consider determining whether a contract is proxied based on the // contract. We should consider determining whether a contract is proxied based on the
// deployment script since it's the source of truth for that. Current deployment script // deployment script since it's the source of truth for that. Current deployment script
// does not make this easy but an updated script should likely make this possible. // does not make this easy but an updated script should likely make this possible.
string[] memory cmd = new string[](3); string memory res = Process.bash(
cmd[0] = Executables.bash; string.concat(
cmd[1] = "-c"; "jq -r '.rawMetadata' ",
cmd[2] = string.concat( _getForgeArtifactPath(_name),
Executables.jq, " | jq -r '.output.devdoc' | jq -r 'has(\"custom:proxied\")'"
" -r '.rawMetadata' ", )
_getForgeArtifactPath(_name),
" | ",
Executables.jq,
" -r '.output.devdoc' | jq -r 'has(\"custom:proxied\")'"
); );
bytes memory res = Process.run(cmd); out_ = stdJson.readBool(res, "");
out_ = stdJson.readBool(string(res), "");
} }
/// @notice Returns whether or not a contract is predeployed. /// @notice Returns whether or not a contract is predeployed.
...@@ -130,27 +102,18 @@ library ForgeArtifacts { ...@@ -130,27 +102,18 @@ library ForgeArtifacts {
function isPredeployedContract(string memory _name) internal returns (bool out_) { function isPredeployedContract(string memory _name) internal returns (bool out_) {
// TODO: Similar to the above, using the `@custom:predeployed` tag is not reliable but // TODO: Similar to the above, using the `@custom:predeployed` tag is not reliable but
// functional for now. Deployment script should make this easier to determine. // functional for now. Deployment script should make this easier to determine.
string[] memory cmd = new string[](3); string memory res = Process.bash(
cmd[0] = Executables.bash; string.concat(
cmd[1] = "-c"; "jq -r '.rawMetadata' ",
cmd[2] = string.concat( _getForgeArtifactPath(_name),
Executables.jq, " | jq -r '.output.devdoc' | jq -r 'has(\"custom:predeploy\")'"
" -r '.rawMetadata' ", )
_getForgeArtifactPath(_name),
" | ",
Executables.jq,
" -r '.output.devdoc' | jq -r 'has(\"custom:predeploy\")'"
); );
bytes memory res = Process.run(cmd); out_ = stdJson.readBool(res, "");
out_ = stdJson.readBool(string(res), "");
} }
function _getForgeArtifactDirectory(string memory _name) internal returns (string memory dir_) { function _getForgeArtifactDirectory(string memory _name) internal returns (string memory dir_) {
string[] memory cmd = new string[](3); string memory res = Process.bash("forge config --json | jq -r .out");
cmd[0] = Executables.bash;
cmd[1] = "-c";
cmd[2] = string.concat(Executables.forge, " config --json | ", Executables.jq, " -r .out");
bytes memory res = Process.run(cmd);
string memory contractName = _stripSemver(_name); string memory contractName = _stripSemver(_name);
dir_ = string.concat(vm.projectRoot(), "/", string(res), "/", contractName, ".sol"); dir_ = string.concat(vm.projectRoot(), "/", string(res), "/", contractName, ".sol");
} }
...@@ -164,19 +127,10 @@ library ForgeArtifacts { ...@@ -164,19 +127,10 @@ library ForgeArtifacts {
return path; return path;
} }
string[] memory cmd = new string[](3); string memory res = Process.bash(
cmd[0] = Executables.bash; string.concat("ls -1 --color=never ", directory, " | jq -R -s -c 'split(\"\n\") | map(select(length > 0))'")
cmd[1] = "-c";
cmd[2] = string.concat(
Executables.ls,
" -1 --color=never ",
directory,
" | ",
Executables.jq,
" -R -s -c 'split(\"\n\") | map(select(length > 0))'"
); );
bytes memory res = Process.run(cmd); string[] memory files = stdJson.readStringArray(res, "");
string[] memory files = stdJson.readStringArray(string(res), "");
out_ = string.concat(directory, "/", files[0]); out_ = string.concat(directory, "/", files[0]);
} }
...@@ -198,23 +152,19 @@ library ForgeArtifacts { ...@@ -198,23 +152,19 @@ library ForgeArtifacts {
slotType = "t_bool"; slotType = "t_bool";
} }
string[] memory command = new string[](3); bytes memory rawSlot = vm.parseJson(
command[0] = Executables.bash; Process.bash(
command[1] = "-c"; string.concat(
command[2] = string.concat( "echo '",
Executables.echo, storageLayout,
" '", "' | jq '.storage[] | select(.label == \"",
storageLayout, slotName,
"'", "\" and .type == \"",
" | ", slotType,
Executables.jq, "\")'"
" '.storage[] | select(.label == \"", )
slotName, )
"\" and .type == \"",
slotType,
"\")'"
); );
bytes memory rawSlot = vm.parseJson(string(Process.run(command)));
slot_ = abi.decode(rawSlot, (StorageSlot)); slot_ = abi.decode(rawSlot, (StorageSlot));
} }
...@@ -245,25 +195,19 @@ library ForgeArtifacts { ...@@ -245,25 +195,19 @@ library ForgeArtifacts {
} }
} }
string[] memory command = new string[](3); contractNames_ = abi.decode(
command[0] = Executables.bash; vm.parseJson(
command[1] = "-c"; Process.bash(
command[2] = string.concat( string.concat(
Executables.find, "find ",
" ", _path,
_path, bytes(pathExcludesPat).length > 0 ? string.concat(" ! \\( ", pathExcludesPat, " \\)") : "",
bytes(pathExcludesPat).length > 0 ? string.concat(" ! \\( ", pathExcludesPat, " \\)") : "", " -type f -exec basename {} \\; | sed 's/\\.[^.]*$//' | jq -R -s 'split(\"\n\")[:-1]'"
" -type f ", )
"-exec basename {} \\;", )
" | ", ),
Executables.sed, (string[])
" 's/\\.[^.]*$//'",
" | ",
Executables.jq,
" -R -s 'split(\"\n\")[:-1]'"
); );
contractNames_ = abi.decode(vm.parseJson(string(Process.run(command))), (string[]));
} }
/// @notice Returns the function ABIs of all L1 contracts. /// @notice Returns the function ABIs of all L1 contracts.
......
...@@ -10,6 +10,25 @@ library Process { ...@@ -10,6 +10,25 @@ library Process {
/// @notice Foundry cheatcode VM. /// @notice Foundry cheatcode VM.
Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code"))))); Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code")))));
/// @notice Executes a bash command in a subprocess and returns its output as a string. Will revert if the command
/// returns no output.
/// @param _command The bash command to execute
function bash(string memory _command) internal returns (string memory stdout_) {
stdout_ = bash({ _command: _command, _allowEmpty: false });
}
/// @notice Executes a bash command in a subprocess and returns its output as a string. Will 'optionally' revert if
/// the command returns no output.
/// @param _command The bash command to execute
/// @param _allowEmpty Allow empty output.
function bash(string memory _command, bool _allowEmpty) internal returns (string memory stdout_) {
string[] memory command = new string[](3);
command[0] = "bash";
command[1] = "-c";
command[2] = _command;
stdout_ = string(run({ _command: command, _allowEmpty: _allowEmpty }));
}
/// @notice Run a command in a subprocess. Fails if no output is returned. /// @notice Run a command in a subprocess. Fails if no output is returned.
/// @param _command Command to run. /// @param _command Command to run.
function run(string[] memory _command) internal returns (bytes memory stdout_) { function run(string[] memory _command) internal returns (bytes memory stdout_) {
......
...@@ -22,32 +22,21 @@ contract L2GenesisTest is Test { ...@@ -22,32 +22,21 @@ contract L2GenesisTest is Test {
/// @notice Creates a temp file and returns the path to it. /// @notice Creates a temp file and returns the path to it.
function tmpfile() internal returns (string memory) { function tmpfile() internal returns (string memory) {
string[] memory commands = new string[](3); return Process.bash("mktemp");
commands[0] = "bash";
commands[1] = "-c";
commands[2] = "mktemp";
bytes memory result = Process.run(commands);
return string(result);
} }
/// @notice Deletes a file at a given filesystem path. Does not force delete /// @notice Deletes a file at a given filesystem path. Does not force delete
/// and does not recursively delete. /// and does not recursively delete.
function deleteFile(string memory path) internal { function deleteFile(string memory path) internal {
string[] memory commands = new string[](3); Process.bash(string.concat("rm ", path), true);
commands[0] = "bash";
commands[1] = "-c";
commands[2] = string.concat("rm ", path);
Process.run({ _command: commands, _allowEmpty: true });
} }
/// @notice Returns the number of top level keys in a JSON object at a given /// @notice Returns the number of top level keys in a JSON object at a given
/// file path. /// file path.
function getJSONKeyCount(string memory path) internal returns (uint256) { function getJSONKeyCount(string memory path) internal returns (uint256) {
string[] memory commands = new string[](3); bytes memory result =
commands[0] = "bash"; bytes(Process.bash(string.concat("jq 'keys | length' < ", path, " | xargs cast abi-encode 'f(uint256)'")));
commands[1] = "-c"; return abi.decode(result, (uint256));
commands[2] = string.concat("jq 'keys | length' < ", path, " | xargs cast abi-encode 'f(uint256)'");
return abi.decode(Process.run(commands), (uint256));
} }
/// @notice Helper function to run a function with a temporary dump file. /// @notice Helper function to run a function with a temporary dump file.
...@@ -59,43 +48,44 @@ contract L2GenesisTest is Test { ...@@ -59,43 +48,44 @@ contract L2GenesisTest is Test {
/// @notice Helper function for reading the number of storage keys for a given account. /// @notice Helper function for reading the number of storage keys for a given account.
function getStorageKeysCount(string memory _path, address _addr) internal returns (uint256) { function getStorageKeysCount(string memory _path, address _addr) internal returns (uint256) {
string[] memory commands = new string[](3); return vm.parseUint(
commands[0] = "bash"; Process.bash(
commands[1] = "-c"; string.concat("jq -r '.[\"", vm.toLowercase(vm.toString(_addr)), "\"].storage | length' < ", _path)
commands[2] = )
string.concat("jq -r '.[\"", vm.toLowercase(vm.toString(_addr)), "\"].storage | length' < ", _path); );
return vm.parseUint(string(Process.run(commands)));
} }
/// @notice Returns the number of accounts that contain particular code at a given path to a genesis file. /// @notice Returns the number of accounts that contain particular code at a given path to a genesis file.
function getCodeCount(string memory path, string memory name) internal returns (uint256) { function getCodeCount(string memory path, string memory name) internal returns (uint256) {
bytes memory code = vm.getDeployedCode(name); bytes memory code = vm.getDeployedCode(name);
string[] memory commands = new string[](3); bytes memory result = bytes(
commands[0] = "bash"; Process.bash(
commands[1] = "-c"; string.concat(
commands[2] = string.concat( "jq -r 'map_values(select(.code == \"",
"jq -r 'map_values(select(.code == \"", vm.toString(code),
vm.toString(code), "\")) | length' < ",
"\")) | length' < ", path,
path, " | xargs cast abi-encode 'f(uint256)'"
" | xargs cast abi-encode 'f(uint256)'" )
)
); );
return abi.decode(Process.run(commands), (uint256)); return abi.decode(result, (uint256));
} }
/// @notice Returns the number of accounts that have a particular slot set. /// @notice Returns the number of accounts that have a particular slot set.
function getPredeployCountWithSlotSet(string memory path, bytes32 slot) internal returns (uint256) { function getPredeployCountWithSlotSet(string memory path, bytes32 slot) internal returns (uint256) {
string[] memory commands = new string[](3); bytes memory result = bytes(
commands[0] = "bash"; Process.bash(
commands[1] = "-c"; string.concat(
commands[2] = string.concat( "jq 'map_values(.storage | select(has(\"",
"jq 'map_values(.storage | select(has(\"", vm.toString(slot),
vm.toString(slot), "\"))) | keys | length' < ",
"\"))) | keys | length' < ", path,
path, " | xargs cast abi-encode 'f(uint256)'"
" | xargs cast abi-encode 'f(uint256)'" )
)
); );
return abi.decode(Process.run(commands), (uint256)); return abi.decode(result, (uint256));
} }
/// @notice Returns the number of accounts that have a particular slot set to a particular value. /// @notice Returns the number of accounts that have a particular slot set to a particular value.
...@@ -107,19 +97,20 @@ contract L2GenesisTest is Test { ...@@ -107,19 +97,20 @@ contract L2GenesisTest is Test {
internal internal
returns (uint256) returns (uint256)
{ {
string[] memory commands = new string[](3); bytes memory result = bytes(
commands[0] = "bash"; Process.bash(
commands[1] = "-c"; string.concat(
commands[2] = string.concat( "jq 'map_values(.storage | select(.\"",
"jq 'map_values(.storage | select(.\"", vm.toString(slot),
vm.toString(slot), "\" == \"",
"\" == \"", vm.toString(value),
vm.toString(value), "\")) | length' < ",
"\")) | length' < ", path,
path, " | xargs cast abi-encode 'f(uint256)'"
" | xargs cast abi-encode 'f(uint256)'" )
)
); );
return abi.decode(Process.run(commands), (uint256)); return abi.decode(result, (uint256));
} }
/// @notice Tests the genesis predeploys setup using a temp file for the case where useInterop is false. /// @notice Tests the genesis predeploys setup using a temp file for the case where useInterop is false.
......
...@@ -5,7 +5,6 @@ pragma solidity 0.8.15; ...@@ -5,7 +5,6 @@ pragma solidity 0.8.15;
import { Bridge_Initializer } from "test/setup/Bridge_Initializer.sol"; import { Bridge_Initializer } from "test/setup/Bridge_Initializer.sol";
// Scripts // Scripts
import { Executables } from "scripts/libraries/Executables.sol";
import { ForgeArtifacts } from "scripts/libraries/ForgeArtifacts.sol"; import { ForgeArtifacts } from "scripts/libraries/ForgeArtifacts.sol";
import { Process } from "scripts/libraries/Process.sol"; import { Process } from "scripts/libraries/Process.sol";
...@@ -432,21 +431,14 @@ contract Initializer_Test is Bridge_Initializer { ...@@ -432,21 +431,14 @@ contract Initializer_Test is Bridge_Initializer {
} }
// Construct the query for the initialize function in the contract's ABI. // Construct the query for the initialize function in the contract's ABI.
string[] memory command = new string[](3); string memory cmd = string.concat(
command[0] = Executables.bash; "echo '",
command[1] = "-c";
command[2] = string.concat(
Executables.echo,
" '",
ForgeArtifacts.getAbi(contractName), ForgeArtifacts.getAbi(contractName),
"'", "' | jq '.[] | select(.name == \"initialize\" and .type == \"function\")'"
" | ",
Executables.jq,
" '.[] | select(.name == \"initialize\" and .type == \"function\")'"
); );
// If the contract does not have an `initialize()` function, skip it. // If the contract does not have an `initialize()` function, skip it.
if (Process.run(command).length == 0) { if (bytes(Process.bash(cmd)).length == 0) {
continue; continue;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment