Skip to content

Commit

Permalink
imp(e2e): enable quick testing with 'SP1_PROVER=mock' (#21)
Browse files Browse the repository at this point in the history
  • Loading branch information
srdtrk authored Aug 7, 2024
1 parent 6a1567b commit 43ce11c
Show file tree
Hide file tree
Showing 6 changed files with 169 additions and 10 deletions.
2 changes: 2 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@
export MNEMONIC="YOUR_MNEMONIC"
# Private key with the permission to use the network prover
SP1_PRIVATE_KEY="PRIVATE_KEY"
# SP1_PROVER={network|local|mock}
SP1_PROVER=network
52 changes: 42 additions & 10 deletions e2e/interchaintestv8/ibc_eureka_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ func (s *IbcEurekaTestSuite) SetupSuite(ctx context.Context) {

eth, simd := s.ChainA, s.ChainB

var prover string
s.Require().True(s.Run("Set up environment", func() {
err := os.Chdir("../..")
s.Require().NoError(err)
Expand All @@ -92,9 +93,20 @@ func (s *IbcEurekaTestSuite) SetupSuite(ctx context.Context) {
s.faucet, err = crypto.HexToECDSA(testvalues.FaucetPrivateKey)
s.Require().NoError(err)

prover = os.Getenv(testvalues.EnvKeySp1Prover)
switch prover {
case "":
prover = testvalues.EnvValueSp1Prover_Network
case testvalues.EnvValueSp1Prover_Mock:
s.T().Logf("Using mock prover")
case testvalues.EnvValueSp1Prover_Network:
default:
s.Require().Fail("invalid prover type: %s", prover)
}

os.Setenv(testvalues.EnvKeyEthRPC, eth.GetHostRPCAddress())
os.Setenv(testvalues.EnvKeyTendermintRPC, simd.GetHostRPCAddress())
os.Setenv(testvalues.EnvKeySp1Prover, "network")
os.Setenv(testvalues.EnvKeySp1Prover, prover)
os.Setenv(testvalues.EnvKeyOperatorPrivateKey, hex.EncodeToString(crypto.FromECDSA(operatorKey)))
// make sure that the SP1_PRIVATE_KEY is set.
s.Require().NotEmpty(os.Getenv(testvalues.EnvKeySp1PrivateKey))
Expand Down Expand Up @@ -122,15 +134,35 @@ func (s *IbcEurekaTestSuite) SetupSuite(ctx context.Context) {
"-o", "e2e/artifacts/genesis.json",
))

stdout, stderr, err := eth.ForgeScript(ctx, s.deployer.KeyName(), ethereum.ForgeScriptOpts{
ContractRootDir: ".",
SolidityContract: "script/E2ETestDeploy.s.sol",
RawOptions: []string{
"--json",
"--sender", s.deployer.FormattedAddress(), // This, combined with the keyname, makes msg.sender the deployer
},
})
s.Require().NoError(err, fmt.Sprintf("error deploying contracts: \nstderr: %s\nstdout: %s", stderr, stdout))
var (
stdout []byte
stderr []byte
err error
)
switch prover {
case testvalues.EnvValueSp1Prover_Mock:
stdout, stderr, err = eth.ForgeScript(ctx, s.deployer.KeyName(), ethereum.ForgeScriptOpts{
ContractRootDir: ".",
SolidityContract: "script/MockE2ETestDeploy.s.sol",
RawOptions: []string{
"--json",
"--sender", s.deployer.FormattedAddress(), // This, combined with the keyname, makes msg.sender the deployer
},
})
s.Require().NoError(err, fmt.Sprintf("error deploying contracts: \nstderr: %s\nstdout: %s", stderr, stdout))
case testvalues.EnvValueSp1Prover_Network:
stdout, stderr, err = eth.ForgeScript(ctx, s.deployer.KeyName(), ethereum.ForgeScriptOpts{
ContractRootDir: ".",
SolidityContract: "script/E2ETestDeploy.s.sol",
RawOptions: []string{
"--json",
"--sender", s.deployer.FormattedAddress(), // This, combined with the keyname, makes msg.sender the deployer
},
})
s.Require().NoError(err, fmt.Sprintf("error deploying contracts: \nstderr: %s\nstdout: %s", stderr, stdout))
default:
s.Require().Fail("invalid prover type: %s", prover)
}

client, err := ethclient.Dial(eth.GetHostRPCAddress())
s.Require().NoError(err)
Expand Down
5 changes: 5 additions & 0 deletions e2e/interchaintestv8/testvalues/values.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ const (
// EnvKeySp1PrivateKey Private key for the prover network.
EnvKeySp1PrivateKey = "SP1_PRIVATE_KEY"

// EnvValueSp1Prover_Network is the prover type for the network prover.
EnvValueSp1Prover_Network = "network"
// EnvValueSp1Prover_Mock is the prover type for the mock prover.
EnvValueSp1Prover_Mock = "mock"

// FaucetPrivateKey is the private key of the faucet account.
// '0x' prefix is trimmed.
FaucetPrivateKey = "ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"
Expand Down
4 changes: 4 additions & 0 deletions script/E2ETestDeploy.s.sol
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.25 <0.9.0;

/*
This script is used for end-to-end testing with SP1_PROVER=network.
*/

import { stdJson } from "forge-std/StdJson.sol";
import { Script } from "forge-std/Script.sol";
import { SP1ICS07Tendermint } from "@cosmos/sp1-ics07-tendermint/SP1ICS07Tendermint.sol";
Expand Down
101 changes: 101 additions & 0 deletions script/MockE2ETestDeploy.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.25 <0.9.0;

/*
This script is used for local testing with SP1_PROVER=mock.
*/

import { stdJson } from "forge-std/StdJson.sol";
import { Script } from "forge-std/Script.sol";
import { SP1ICS07Tendermint } from "@cosmos/sp1-ics07-tendermint/SP1ICS07Tendermint.sol";
import { IICS07TendermintMsgs } from "@cosmos/sp1-ics07-tendermint/msgs/IICS07TendermintMsgs.sol";
import { ICS02Client } from "../src/ICS02Client.sol";
import { ICS26Router } from "../src/ICS26Router.sol";
import { ICS20Transfer } from "../src/ICS20Transfer.sol";
import { TestERC20 } from "../test/TestERC20.sol";
import { AcceptAllSP1Verifier } from "../test/AcceptAllSP1Verifier.sol";
import { Strings } from "@openzeppelin/contracts/utils/Strings.sol";
import { ICS20Lib } from "../src/utils/ICS20Lib.sol";

struct SP1ICS07TendermintGenesisJson {
bytes trustedClientState;
bytes trustedConsensusState;
bytes32 updateClientVkey;
bytes32 membershipVkey;
bytes32 ucAndMembershipVkey;
}

/// @dev See the Solidity Scripting tutorial: https://book.getfoundry.sh/tutorials/solidity-scripting
contract MockE2ETestDeploy is Script {
using stdJson for string;

string public constant E2E_FAUCET = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266";

function run() public returns (string memory) {
// Read the initialization parameters for the SP1 Tendermint contract.
SP1ICS07TendermintGenesisJson memory genesis = loadGenesis("genesis.json");
IICS07TendermintMsgs.ConsensusState memory trustedConsensusState =
abi.decode(genesis.trustedConsensusState, (IICS07TendermintMsgs.ConsensusState));
bytes32 trustedConsensusHash = keccak256(abi.encode(trustedConsensusState));

vm.startBroadcast();
address deployerAddress = msg.sender; // This is being set in the e2e test

// Deploy the SP1 ICS07 Tendermint light client
AcceptAllSP1Verifier verifier = new AcceptAllSP1Verifier();
SP1ICS07Tendermint ics07Tendermint = new SP1ICS07Tendermint(
genesis.updateClientVkey,
genesis.membershipVkey,
genesis.ucAndMembershipVkey,
address(verifier),
genesis.trustedClientState,
trustedConsensusHash
);

// Deploy IBC Eureka
ICS02Client ics02Client = new ICS02Client(deployerAddress);
ICS26Router ics26Router = new ICS26Router(address(ics02Client), deployerAddress);
ICS20Transfer ics20Transfer = new ICS20Transfer(address(ics26Router));
TestERC20 erc20 = new TestERC20();

// Wire Transfer app
ics26Router.addIBCApp("transfer", address(ics20Transfer));

// Mint some tokens
(address addr, bool ok) = ICS20Lib.hexStringToAddress(E2E_FAUCET);
require(ok, "invalid address");
erc20.mint(addr, 100_000_000_000);

vm.stopBroadcast();

string memory json = "json";
json.serialize("ics07Tendermint", Strings.toHexString(address(ics07Tendermint)));
json.serialize("ics02Client", Strings.toHexString(address(ics02Client)));
json.serialize("ics26Router", Strings.toHexString(address(ics26Router)));
json.serialize("ics20Transfer", Strings.toHexString(address(ics20Transfer)));
string memory finalJson = json.serialize("erc20", Strings.toHexString(address(erc20)));

return finalJson;
}

function loadGenesis(string memory fileName) public view returns (SP1ICS07TendermintGenesisJson memory) {
string memory root = vm.projectRoot();
string memory path = string.concat(root, "/e2e/artifacts/", fileName);
string memory json = vm.readFile(path);
bytes memory trustedClientState = json.readBytes(".trustedClientState");
bytes memory trustedConsensusState = json.readBytes(".trustedConsensusState");
bytes32 updateClientVkey = json.readBytes32(".updateClientVkey");
bytes32 membershipVkey = json.readBytes32(".membershipVkey");
bytes32 ucAndMembershipVkey = json.readBytes32(".ucAndMembershipVkey");

SP1ICS07TendermintGenesisJson memory fixture = SP1ICS07TendermintGenesisJson({
trustedClientState: trustedClientState,
trustedConsensusState: trustedConsensusState,
updateClientVkey: updateClientVkey,
membershipVkey: membershipVkey,
ucAndMembershipVkey: ucAndMembershipVkey
});

return fixture;
}
}
15 changes: 15 additions & 0 deletions test/AcceptAllSP1Verifier.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.25 <0.9.0;

// solhint-disable no-empty-blocks

import { ISP1Verifier } from "@sp1-contracts/ISP1Verifier.sol";

/// @dev This SP1 verifier accepts all proofs, for testing purposes.
/// @dev It is required due to the issues we are running into with '@sp1-contracts/SP1MockVerifier.sol'.
/// @dev This contract can be removed once the issues are resolved.
contract AcceptAllSP1Verifier is ISP1Verifier {
function verifyProof(bytes32, bytes calldata, bytes calldata) external view override {
// Accept all proofs
}
}

0 comments on commit 43ce11c

Please sign in to comment.