diff --git a/.env.example b/.env.example index b1e2e27..1d7518f 100644 --- a/.env.example +++ b/.env.example @@ -1,5 +1,5 @@ # URL of the Tendermint RPC node -TENDERMINT_RPC_URL=https://rpc.celestia-mocha.com/ +TENDERMINT_RPC_URL=http://public-celestia-mocha4-consensus.numia.xyz/ # URL of the Ethereum RPC node # use https://ethereum-sepolia.publicnode.com/ for the Eth Sepolia testnet RPC_URL=https://ethereum-holesky-rpc.publicnode.com diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index c9787ad..83691f0 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -22,14 +22,14 @@ jobs: name: lint runs-on: ubuntu-latest steps: - - uses: actions/setup-go@v4 + - uses: actions/setup-go@v5 with: go-version: "1.22" - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: golangci-lint - uses: golangci/golangci-lint-action@v3.7.0 + uses: golangci/golangci-lint-action@v6.1.0 with: - version: v1.59 + version: v1.60 args: --timeout 5m working-directory: e2e/interchaintestv8 e2e: @@ -41,13 +41,15 @@ jobs: - TestWithSP1ICS07TendermintTestSuite/TestDeploy - TestWithSP1ICS07TendermintTestSuite/TestUpdateClient - TestWithSP1ICS07TendermintTestSuite/TestUpdateClientAndMembership + - TestWithSP1ICS07TendermintTestSuite/TestDoubleSignMisbehaviour + - TestWithSP1ICS07TendermintTestSuite/TestBreakingTimeMonotonicityMisbehaviour name: ${{ matrix.test }} runs-on: ubuntu-latest steps: - name: Checkout sources uses: actions/checkout@v4 - name: Setup Go - uses: actions/setup-go@v4 + uses: actions/setup-go@v5 with: go-version: "1.22" check-latest: true diff --git a/.github/workflows/programs.yml b/.github/workflows/programs.yml index d7ea617..921c1d1 100644 --- a/.github/workflows/programs.yml +++ b/.github/workflows/programs.yml @@ -16,6 +16,7 @@ jobs: - programs/update-client - programs/membership - programs/uc-and-membership + - programs/misbehaviour name: 'build: ${{ matrix.programs }}' runs-on: ubuntu-latest steps: diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 8a6129f..8ccc5bc 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -87,4 +87,4 @@ jobs: uses: actions-rs/cargo@v1 with: command: build - args: --workspace --exclude sp1-ics07-tendermint-update-client --exclude sp1-ics07-tendermint-membership --exclude sp1-ics07-tendermint-uc-and-membership --all-features --locked + args: --workspace --exclude sp1-ics07-tendermint-update-client --exclude sp1-ics07-tendermint-membership --exclude sp1-ics07-tendermint-uc-and-membership --exclude sp1-ics07-tendermint-misbehaviour --all-features --locked diff --git a/Cargo.lock b/Cargo.lock index ee07d04..2979fdf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5877,6 +5877,25 @@ dependencies = [ "sp1-zkvm", ] +[[package]] +name = "sp1-ics07-tendermint-misbehaviour" +version = "0.1.0" +dependencies = [ + "alloy-sol-types", + "bincode", + "ibc-client-tendermint", + "ibc-core-client", + "ibc-core-handler-types", + "ibc-core-host-types", + "ibc-primitives", + "serde", + "serde_cbor", + "sha2 0.10.8", + "sp1-ics07-tendermint-solidity", + "sp1-zkvm", + "tendermint-light-client-verifier", +] + [[package]] name = "sp1-ics07-tendermint-operator" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index e5d3b85..f7d5ba4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,6 +21,8 @@ sp1-zkvm = "1.1" sp1-ics07-tendermint-solidity = { path = "./packages/solidity/" } sp1-ics07-tendermint-update-client = { path = "./programs/update-client/" } sp1-ics07-tendermint-membership = { path = "./programs/membership/" } +sp1-ics07-tendermint-uc-and-membership = { path = "./programs/uc-and-membership/" } +sp1-ics07-tendermint-misbehaviour = { path = "./programs/misbehaviour/" } # ibc-proto ibc-proto = { version = "0.47", default-features = false } diff --git a/README.md b/README.md index 130fa59..96852dc 100644 --- a/README.md +++ b/README.md @@ -154,6 +154,12 @@ After generating the verify the proof with the SP1 EVM verifier. just test-foundry ``` +The recipe also accepts a `testname` argument that will only run the test with the given name. For example: + +```shell +just test-foundry test_success_sendTransfer +``` + ## End to End Testing There are several end-to-end tests in the `e2e/interchaintestv8` directory. These tests are written in Go and use the [`interchaintest`](https://github.com/strangelove-ventures/interchaintest) library. It spins up a local Ethereum and a Tendermint network and runs the tests found in [`e2e/interchaintestv8/sp1_ics07_test.go`](e2e/interchaintestv8/sp1_ics07_test.go). Some of the tests use the prover network to generate the proofs, so you need to provide your SP1 network private key to `.env` for these tests to pass. diff --git a/contracts/abi/SP1ICS07Tendermint.json b/contracts/abi/SP1ICS07Tendermint.json index 1928dd3..a9c7e67 100644 --- a/contracts/abi/SP1ICS07Tendermint.json +++ b/contracts/abi/SP1ICS07Tendermint.json @@ -17,6 +17,11 @@ "type": "bytes32", "internalType": "bytes32" }, + { + "name": "misbehaviourProgramVkey", + "type": "bytes32", + "internalType": "bytes32" + }, { "name": "verifier", "type": "address", @@ -61,6 +66,19 @@ ], "stateMutability": "view" }, + { + "type": "function", + "name": "MISBEHAVIOUR_PROGRAM_VKEY", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "bytes32", + "internalType": "bytes32" + } + ], + "stateMutability": "view" + }, { "type": "function", "name": "UPDATE_CLIENT_AND_MEMBERSHIP_PROGRAM_VKEY", @@ -190,7 +208,7 @@ { "name": "env", "type": "tuple", - "internalType": "struct IUpdateClientMsgs.Env", + "internalType": "struct IICS07TendermintMsgs.Env", "components": [ { "name": "chainId", @@ -406,6 +424,159 @@ ] } ] + }, + { + "name": "o7", + "type": "tuple", + "internalType": "struct IMisbehaviourMsgs.MisbehaviourOutput", + "components": [ + { + "name": "env", + "type": "tuple", + "internalType": "struct IICS07TendermintMsgs.Env", + "components": [ + { + "name": "chainId", + "type": "string", + "internalType": "string" + }, + { + "name": "trustThreshold", + "type": "tuple", + "internalType": "struct IICS07TendermintMsgs.TrustThreshold", + "components": [ + { + "name": "numerator", + "type": "uint8", + "internalType": "uint8" + }, + { + "name": "denominator", + "type": "uint8", + "internalType": "uint8" + } + ] + }, + { + "name": "trustingPeriod", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "now", + "type": "uint64", + "internalType": "uint64" + } + ] + }, + { + "name": "trustedHeight1", + "type": "tuple", + "internalType": "struct IICS02ClientMsgs.Height", + "components": [ + { + "name": "revisionNumber", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "revisionHeight", + "type": "uint32", + "internalType": "uint32" + } + ] + }, + { + "name": "trustedHeight2", + "type": "tuple", + "internalType": "struct IICS02ClientMsgs.Height", + "components": [ + { + "name": "revisionNumber", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "revisionHeight", + "type": "uint32", + "internalType": "uint32" + } + ] + }, + { + "name": "trustedConsensusState1", + "type": "tuple", + "internalType": "struct IICS07TendermintMsgs.ConsensusState", + "components": [ + { + "name": "timestamp", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "root", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "nextValidatorsHash", + "type": "bytes32", + "internalType": "bytes32" + } + ] + }, + { + "name": "trustedConsensusState2", + "type": "tuple", + "internalType": "struct IICS07TendermintMsgs.ConsensusState", + "components": [ + { + "name": "timestamp", + "type": "uint64", + "internalType": "uint64" + }, + { + "name": "root", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "nextValidatorsHash", + "type": "bytes32", + "internalType": "bytes32" + } + ] + } + ] + }, + { + "name": "o8", + "type": "tuple", + "internalType": "struct IMisbehaviourMsgs.MsgSubmitMisbehaviour", + "components": [ + { + "name": "sp1Proof", + "type": "tuple", + "internalType": "struct ISP1Msgs.SP1Proof", + "components": [ + { + "name": "vKey", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "publicValues", + "type": "bytes", + "internalType": "bytes" + }, + { + "name": "proof", + "type": "bytes", + "internalType": "bytes" + } + ] + } + ] } ], "outputs": [], @@ -557,13 +728,13 @@ "name": "misbehaviour", "inputs": [ { - "name": "", + "name": "misbehaviourMsg", "type": "bytes", "internalType": "bytes" } ], "outputs": [], - "stateMutability": "pure" + "stateMutability": "nonpayable" }, { "type": "function", diff --git a/contracts/fixtures/memberships_fixture.json b/contracts/fixtures/memberships_fixture.json index f14209b..9eecc79 100644 --- a/contracts/fixtures/memberships_fixture.json +++ b/contracts/fixtures/memberships_fixture.json @@ -1,9 +1,10 @@ { - "trustedClientState": "000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000253370000000000000000000000000000000000000000000000000000000000012750000000000000000000000000000000000000000000000000000000000001baf80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000076d6f6368612d3400000000000000000000000000000000000000000000000000", - "trustedConsensusState": "0000000000000000000000000000000000000000000000000000000066b4386ddd61735333d38ba62f9c8edb7d41b399ce6a0a0ed10d1aeaec708afec8d40472a1d4cdbc90487e9cf127cf745c0ce4e8f72e4babc77eb53db3729b8d848125cb", - "updateClientVkey": "0x0029ce4b0512b5c4254fb11a189799cddb28254f7177d549cf2dc860bc31519e", - "membershipVkey": "0x005f30ecbba088f6f6eede4ca8d4ff6ffc2b7e5f59de38edd1574aefb937afdb", - "ucAndMembershipVkey": "0x00cf1fa1df1f491548e84e88a6b617a70b7abd0c017bc7115ed08f329e05026a", - "proofHeight": "00000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000253370", - "membershipProof": "0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000900000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000066b4386ddd61735333d38ba62f9c8edb7d41b399ce6a0a0ed10d1aeaec708afec8d40472a1d4cdbc90487e9cf127cf745c0ce4e8f72e4babc77eb53db3729b8d848125cb005f30ecbba088f6f6eede4ca8d4ff6ffc2b7e5f59de38edd1574aefb937afdb000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000004400000000000000000000000000000000000000000000000000000000000000020dd61735333d38ba62f9c8edb7d41b399ce6a0a0ed10d1aeaec708afec8d40472000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000369626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000023636c69656e74732f30372d74656e6465726d696e742d302f636c69656e745374617465000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b70a2b2f6962632e6c69676874636c69656e74732e74656e6465726d696e742e76312e436c69656e7453746174651287010a1174686574612d746573746e65742d3030311204080110031a040880840722040880c60a2a02082832003a0510b7e3c60842190a090801180120012a0100120c0a02000110211804200c300142190a090801180120012a0100120c0a02000110201801200130014a07757067726164654a10757067726164656449424353746174655001580100000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000369626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000025636c69656e74732f30372d74656e6465726d696e742d3030312f636c69656e74537461746500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000364c430ff7f22ef7a7f130f690abd7fd33eed4da6fdfa7c6a4b8899c728a92a835269e05f802e5ca7f9ae355d672f60de8d45b106b4f60dafa46269146bd7179801700e0e8e0d85da862ba83f7e70febb376a092cf2f0a92911ac55c4c9ea01bfd293ca455506ad0535abd962a10ebf6114068bf037469a5b1b1d243296e84b47d31c05311614cf8be0507f992322e5f4a51a88624bd612ea3aa446bb38f34fed2e777b4b1401852f214ba716ed1b5241f2e21e2540105b25dad1e0e5c951e6c4201df162d800cad20e1460dc785d47b1143c281831a977f28be50fa83ea8463968d4e5d61f0d1995988279ba999d275a8101b3172be15588c4b779b5f9d177b49d640d52991821d38d3882ca14d10d64e7aff76d796c586ba257249169d069b236e02809ba01517acc1e0409ddd08c344f4fb4faeb1e20d5b00c0000389a3b96a94401980f211d9e1f438cd2cb922c503bccc61cff175ba0cd0a96ff6963d3a833530834b7062e538bf6c914e907f6b2b1e7181d1bdc1b45eb7defae4ea732cb11802584e826c23895796d70adaaf3d75d93bff55efb2559978ec25df6316e0bad0ce074f52332bf1420e201e1efc9d467428ff402de800943be7648d915b2e5f5386790820a15bb2065022fc1087703967b292efb12444d2a504145c6caab7209196f18c22a98a2ca941973cb2b128fe25a3ada9e073dc99fa681445482e91ee0809bbe5d200ff347e1d290ed1214f83d06c2ccc5209b3edf382487c051e4bbdfbe01e64c182af205ad392ea60b6e8d1d615085d2e0e10caa574e4336110eaef08e3e97da2fd6c192efb126c9a1213da6264781332ba9550986d6fd31e0ca7904ae2fc5072e7643157ae8201b5eca53db900e8400f67c60cf3fe0f91c86c9202e46d815011b5a74477473924a722805c6ca8b27edadd0b105c6efa1b00074f6f6906e8b861281bdce6e75e1547811721ab291058d6beecfc277e72ac8a0d454d6f29dbbbb06a114650a25e053afa051faed46790974486313712b568ab8bbcf4fff54cf8a0f05d01d8c93cc76d67ded54fac134e5aef437d66ce2d66cf880c2be56ca10451922802b647b63e61e1bf54bb755f15ee2230f43ca6299c7af01927f5d2c69891d0e0659dc75e8ee4b507be85114e620d53091cdcb39591cd42c5f3c6d16b87e1c82db4c7af87950952c3e4ad9acfa0984ce6f41b35e40e5449807437cc207ae00000000000000000000000000000000000000000000000000000000" + "trustedClientState": "000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000277162000000000000000000000000000000000000000000000000000000000012750000000000000000000000000000000000000000000000000000000000001baf80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000076d6f6368612d3400000000000000000000000000000000000000000000000000", + "trustedConsensusState": "0000000000000000000000000000000000000000000000000000000066cf585bf53cf5b309a255dd7562f62d797d6a2acc937c77b6e1ede11573df67166e2c4c424ee8cf84c0fa35a3eaf862ff1a633eb83be1022827498a79d4b6ac64310d99", + "updateClientVkey": "0x00aae7c6a541134ce5c556dd8bb23516240292e127321b5de81bc27892355622", + "membershipVkey": "0x00eae02a2c448b3242c5b37cef161b94e908fc12d861c481cff9d10217648697", + "ucAndMembershipVkey": "0x00a477c762e91e1e004d9362b4bd6a69b0f577f24b0e6db30f1b57ea87bd7011", + "misbehaviourVkey": "0x005e69d660bf31e9fb874c16897a71852b137d53659c24c3e3530537b59b176d", + "proofHeight": "00000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000277162", + "membershipProof": "0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000900000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000066cf585bf53cf5b309a255dd7562f62d797d6a2acc937c77b6e1ede11573df67166e2c4c424ee8cf84c0fa35a3eaf862ff1a633eb83be1022827498a79d4b6ac64310d9900eae02a2c448b3242c5b37cef161b94e908fc12d861c481cff9d10217648697000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000004400000000000000000000000000000000000000000000000000000000000000020f53cf5b309a255dd7562f62d797d6a2acc937c77b6e1ede11573df67166e2c4c000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000369626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000023636c69656e74732f30372d74656e6465726d696e742d302f636c69656e745374617465000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b70a2b2f6962632e6c69676874636c69656e74732e74656e6465726d696e742e76312e436c69656e7453746174651287010a1174686574612d746573746e65742d3030311204080110031a040880840722040880c60a2a02082832003a0510b7e3c60842190a090801180120012a0100120c0a02000110211804200c300142190a090801180120012a0100120c0a02000110201801200130014a07757067726164654a10757067726164656449424353746174655001580100000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000369626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000025636c69656e74732f30372d74656e6465726d696e742d3030312f636c69656e74537461746500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000364c430ff7f234f53222d8502af4fd629aeec8261d24dfe541cdca7c061647efcb09b469c601ba9068821ee74d5a538b0e234296f2ba80c9756ae56aa48f8ee3d9a897c5e690a3888a16715f963169301bccce5d0a957550da35b4e76ef7f8d2b278f7d028c290ae3b068e39c921a5e4f005e6f33ac5761c792597a73fb09203b1b19aa39e51b6019c45bb08fe8fe7876f3f038fdefe94bc20d8938c44bc08d8558232bc1731ef80c44d517987c19d57a81f72c8c3577a65b48bf0b61c92746a443f877a5aa09cc6c25236fd212a14fbdb3868a932f93b4010916a9e671dafcf1133fdc568724a818fde5393416bd1bdc2b2e2e371222577fcd72e5890f990958e51fe5727d209899fc6861814069191abfea066f376ffdade6d5e8aba03d2a4ad1ca2ed71f071f610d2e707cea34c37d0ea5ce4a3a45650353ff2b556f714af8f8aef05fb41ec7a518d2b7cd556e836c49bbe4da22f7fcc4dd60adace0ca0868e3ba91210e02ea8d56a1e6ba0b934de522ac63a7a921a6f2238c871ac85c7e4f503ff92b1208e44006fbc3ce9001c0bf1b80a67b4a636e1fddf3d997920e30e0c382c08cc12fc8064aa0628c2f1d12c3e5c4e790484bdc5e171a4457f5de784897f22de7b2061bdc6f628a191e0243dabd880cd83a38eea095ee5e8e4c82ad5aed20e70ef8018fbd7157d655c80af64d3310d36bc900f57fd28644f4374fdb7aa954fa9de1153875eb7152f3d36b065cad4eca5da4fe504bbf3a9190e85fdaff626b6b94331b4026135d35e8ac5b79be64c46e1352ea94d42bcfcc0b63cc955fe4af1585a508b39235a7498060e47b14dff26f7e5edb46d74fdb3629672ae5c6d51c81a48316726a21b7b06a07d995af2321edbdeec2b766d076d5c2f07aece27716ad86b221b0d5f1628a30c5c5f28c34e4fa860b28c6116bbc35acf3d7a9b0afccdf30da1acffb99f7f8d20aad035b932bd68b7e8aeda7189901c30d25cbd9a43d37bad90ce033066e460798eda62d04c341d56012fea502af8158f6334838a07543672d185794a382adf8a0e61233765bb83d18e721b4ce8647209986fdf8baffffc9f0109039557ce9298a33eb65bedc69b68b86cab0c22b45e31e513575486ebac66e1fd56b12cb72a812122f8360e50c0848b705dfaf4827e3408e0e6d2fb366daa60ce77cdba11d8bc23e1daae77a5bfceec21570ac5670de48ee785558c4e2c55c00000000000000000000000000000000000000000000000000000000" } \ No newline at end of file diff --git a/contracts/fixtures/misbehaviour_breaking_time_monotonicity_fixture.json b/contracts/fixtures/misbehaviour_breaking_time_monotonicity_fixture.json new file mode 100644 index 000000000..c6bebf0 --- /dev/null +++ b/contracts/fixtures/misbehaviour_breaking_time_monotonicity_fixture.json @@ -0,0 +1,9 @@ +{ + "trustedClientState": "00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000012754500000000000000000000000000000000000000000000000000000000001baf800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000673696d642d310000000000000000000000000000000000000000000000000000", + "trustedConsensusState": "0000000000000000000000000000000000000000000000000000000066d7298c18e36de14e99f7c090cfc07840e0d0d49406b46fe270c26bfa46d6facca6b631c23ec958f6b9a5e92347e1c118a571e4ef5b4a626ba839ccf58d0f5d1d36136c", + "updateClientVkey": "0x00aae7c6a541134ce5c556dd8bb23516240292e127321b5de81bc27892355622", + "membershipVkey": "0x00eae02a2c448b3242c5b37cef161b94e908fc12d861c481cff9d10217648697", + "ucAndMembershipVkey": "0x00a477c762e91e1e004d9362b4bd6a69b0f577f24b0e6db30f1b57ea87bd7011", + "misbehaviourVkey": "0x005e69d660bf31e9fb874c16897a71852b137d53659c24c3e3530537b59b176d", + "submitMsg": "00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020005e69d660bf31e9fb874c16897a71852b137d53659c24c3e3530537b59b176d000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000002e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000066d7298c18e36de14e99f7c090cfc07840e0d0d49406b46fe270c26bfa46d6facca6b631c23ec958f6b9a5e92347e1c118a571e4ef5b4a626ba839ccf58d0f5d1d36136c0000000000000000000000000000000000000000000000000000000066d7298c18e36de14e99f7c090cfc07840e0d0d49406b46fe270c26bfa46d6facca6b631c23ec958f6b9a5e92347e1c118a571e4ef5b4a626ba839ccf58d0f5d1d36136c00000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000001275450000000000000000000000000000000000000000000000000000000066d729c1000000000000000000000000000000000000000000000000000000000000000673696d642d3100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000364c430ff7f1b02ce272ad6d2caee288e6ef8c95878261a0d4b2e60a30fbc0ab1d15725a7c705b49374eba63016ee6f251223c73342f2e02eb0fc0ee60664a60193d82d98aa28672330a7cd1ed1c5f9de13720b87faf947ef525e247057bdc90b422251fe4d100b6dff846daccf23b3aeab7d244f64bd9fe606609cbeed3e4b900fb85b5fc103fdd5a22595bfacb303acb1f4be075bc92046e62dc7c926ebc0291a32fcc8cd2396c8dc7c8113a20483d3f8a659342973575746fdbc552913fd1276bb3300400ff8ff404342ecae8112aeb34760b68dfa0bb204a19ee109e7f620fff18e9fe91bd37daf0402396e08eff93277cc1510890f68f00e50c0f36b2af269719d096f15b6d8eb26ade778b4aebdd19f9fc5d31b9b0694901e3d798c8d47d35af31e292edb84b7a08370fd7251623495702b3aae81ecc1cdf3409d41b4f5e56f8b95871b8478ded39cf295e81909ca376ad8d607e21fc4efc00120c6edcb1e8197943d12dea90069ed1be080ecc2caaec85db0a25f6c1c0d4f89495a57b75463ebe36813424e449801d816aa3b1b8ab72d6dcc26e82349c8d38f3552c83aefd2861c6824ed6e73cbbf5f5f4d21e192425111229cfb0f85442f12a557ecc00c6bea3045119b74e2fa1205eb17749889d53f3d4873f404ae6376379fb05251233a7c34d52a8e80f16a59f1834d47f50abe99fadfe48d51c9c49599bfd226b41be6c19c380dddeec963b7a7b7b812f1ac8770c19688155193bec09fbb879ee3c961010f210a0a4eadddcb15d8ba8769f3097e22e3c9615c579a66a53a8acd811daad51e112712617a1033ed651ddfe7e456a114ee762bcffa9cb09ecfc4a4f9e3821b78a42eb15a151988a70901681c6cefd34e2bba7ddb3f1304b21ceff0472f711c98710116d561496c7c226549eb03b597a970fddf8b0dc8878352761a269f65e0c0de092ac0200500ee3913fd92940ffce829258b11408214faaa3ae9455402cf495d0be05939310a47b4f327bfe759b6a30805ad1132b0aa41f2bd72ed4e367637f9264f119b6e070ffd432b8368d224c3b56a675beef11d9f7c06c7337b4e993a9f034db35978455f264af60967c43bc65290456dc90deb6ecde7f415df8c897e201605b5b682999eaf78b73f0bc8030b9354a4afe53a3621846a2f90d811c1509d1f6599c122ab7d38070ded0f29a22006e9a4ce6aef6af9d945d62c96b278287700000000000000000000000000000000000000000000000000000000" +} diff --git a/contracts/fixtures/misbehaviour_double_sign_fixture.json b/contracts/fixtures/misbehaviour_double_sign_fixture.json new file mode 100644 index 000000000..8ca3591 --- /dev/null +++ b/contracts/fixtures/misbehaviour_double_sign_fixture.json @@ -0,0 +1,9 @@ +{ + "trustedClientState": "00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000012754500000000000000000000000000000000000000000000000000000000001baf800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000673696d642d310000000000000000000000000000000000000000000000000000", + "trustedConsensusState": "0000000000000000000000000000000000000000000000000000000066d7233497e36c109ac120ded59c994f09f66680ffaee70f5ee6e21e43b73dc4b2b59da8f66aa31770289a81b6b264f76f51a94e47879f9b6046f309131f0b31412e2ae2", + "updateClientVkey": "0x00aae7c6a541134ce5c556dd8bb23516240292e127321b5de81bc27892355622", + "membershipVkey": "0x00eae02a2c448b3242c5b37cef161b94e908fc12d861c481cff9d10217648697", + "ucAndMembershipVkey": "0x00a477c762e91e1e004d9362b4bd6a69b0f577f24b0e6db30f1b57ea87bd7011", + "misbehaviourVkey": "0x005e69d660bf31e9fb874c16897a71852b137d53659c24c3e3530537b59b176d", + "submitMsg": "00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020005e69d660bf31e9fb874c16897a71852b137d53659c24c3e3530537b59b176d000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000002e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000066d7233497e36c109ac120ded59c994f09f66680ffaee70f5ee6e21e43b73dc4b2b59da8f66aa31770289a81b6b264f76f51a94e47879f9b6046f309131f0b31412e2ae20000000000000000000000000000000000000000000000000000000066d7233497e36c109ac120ded59c994f09f66680ffaee70f5ee6e21e43b73dc4b2b59da8f66aa31770289a81b6b264f76f51a94e47879f9b6046f309131f0b31412e2ae200000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000001275450000000000000000000000000000000000000000000000000000000066d72387000000000000000000000000000000000000000000000000000000000000000673696d642d3100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000364c430ff7f172babb120bade756474d67e15ee54ff11d1acba1c5aacf38b8db56b8fcb065329cdd7be2e95e4bc703eef7105788d2b757505bd7005f357bf6e5fd29a60a02d2e390f3b2fd3b5b7a8398ff2bff201484142a81ec855aeade601ab495ac3ca142b0731a3d4b1c86eaec8852bd78889f70da95c1df1eb7f5ae77ad5042c6cc15e1a67bd9194e79bf28a67de9f3555dbd6528bc1d2c8db6f5e1d33fd25bc05657a042cb721031613668be99cbe662fc4e22dc756a98babf9bfb907de431f04e2fe07da27797255fc8ffce6b9df0c8f2789f305c00ca87d41fd42b102463ebdd04f0a0a3843783b650205c816790d08c5e17ab9fc36cf57d99eee50793db6c442292aa9f09c73d9d0f9ad885a757111f57c18af7043017e492bd861c8856a24fabd02741ec703a7973b7407fd0132ed07a28f8550d4c14c83a2dd55b34e0456fd982f26e96ea8fcf1d9bf33c4a98db0e2b08239bb7316ffd1189aa86f40497a630d098116b40792182e53f3ac35a883ab0847417428577bffc7ca4e7a3e1941db541234943cd04300a4255381de893e3a9e4e94913015045760527354c29906da5e02f4c2b084f903e7b76e74f6ecf74e9d28b9455adb1439ee988cd40b86e720e206cff3fcdab5018d5fac94647dcb39210a4cffad621c1baf65b54003ab733e470ce79ab384cbe4d5ade75958103543ce071e7ccf41607fed1aca34594d481a58170f5ed919cf9808d8539fcdab607596cce862381ad3b32a26a5b323aab0a0cd0b53529126e20cb8f053bb5bcc66a438fb0bcf7e8b4e54d9102705cb1d7faabc0d2a630f3c1ce5da8690c3ca6fc26df04d23169a787350b7b0d2f376a1e2d5e40089c34c64f539a1642928579e2164853e06a61361b5c4a823c198da1cf8aa7516153a4b319d43c4a85b433a82276b5b209823c50f35579a597287c911badd522bb43d811bdf1498956b6ef25280a6c6d48374d11b84d564935626bc6436ff2b1f986a8620e9bd480f210be615a066b34a76dcf573419c7dbf52f761a07725862d7a0f38d0e59f49808ba016e2d60e9b33b5c84278c3471c9d7cdc9333aacd3a23aa7b2f2f0e303fd05627f597feb94abd32e40f03ae30082656a966c3a6d7db0023a60a84f546040af80fa1380e44b52257fd52abc4ad1b99df70a5f02a01832409e303cb33d82728f2d9f29b3445ec07f0575f1bb9767ed0c777a38a89832300000000000000000000000000000000000000000000000000000000" +} diff --git a/contracts/fixtures/uc_and_memberships_fixture.json b/contracts/fixtures/uc_and_memberships_fixture.json index 322ab52..9f70570 100644 --- a/contracts/fixtures/uc_and_memberships_fixture.json +++ b/contracts/fixtures/uc_and_memberships_fixture.json @@ -1,9 +1,10 @@ { - "trustedClientState": "000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000253370000000000000000000000000000000000000000000000000000000000012750000000000000000000000000000000000000000000000000000000000001baf80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000076d6f6368612d3400000000000000000000000000000000000000000000000000", - "trustedConsensusState": "0000000000000000000000000000000000000000000000000000000066b4386ddd61735333d38ba62f9c8edb7d41b399ce6a0a0ed10d1aeaec708afec8d40472a1d4cdbc90487e9cf127cf745c0ce4e8f72e4babc77eb53db3729b8d848125cb", - "updateClientVkey": "0x0029ce4b0512b5c4254fb11a189799cddb28254f7177d549cf2dc860bc31519e", - "membershipVkey": "0x005f30ecbba088f6f6eede4ca8d4ff6ffc2b7e5f59de38edd1574aefb937afdb", - "ucAndMembershipVkey": "0x00cf1fa1df1f491548e84e88a6b617a70b7abd0c017bc7115ed08f329e05026a", - "proofHeight": "0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000025337a", - "membershipProof": "0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000ae00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000cf1fa1df1f491548e84e88a6b617a70b7abd0c017bc7115ed08f329e05026a0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000006800000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000066b4386ddd61735333d38ba62f9c8edb7d41b399ce6a0a0ed10d1aeaec708afec8d40472a1d4cdbc90487e9cf127cf745c0ce4e8f72e4babc77eb53db3729b8d848125cb0000000000000000000000000000000000000000000000000000000066b438e572e20e3f7c806f0b63f0ad2b0b4bc471e73911b1be2b9436ec1dfdc7aa322365a1d4cdbc90487e9cf127cf745c0ce4e8f72e4babc77eb53db3729b8d848125cb0000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000002533700000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000025337a00000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000001275000000000000000000000000000000000000000000000000000000000066c02d7400000000000000000000000000000000000000000000000000000000000000076d6f6368612d340000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000369626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000023636c69656e74732f30372d74656e6465726d696e742d302f636c69656e745374617465000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b70a2b2f6962632e6c69676874636c69656e74732e74656e6465726d696e742e76312e436c69656e7453746174651287010a1174686574612d746573746e65742d3030311204080110031a040880840722040880c60a2a02082832003a0510b7e3c60842190a090801180120012a0100120c0a02000110211804200c300142190a090801180120012a0100120c0a02000110201801200130014a07757067726164654a10757067726164656449424353746174655001580100000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000369626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000025636c69656e74732f30372d74656e6465726d696e742d3030312f636c69656e74537461746500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000364c430ff7f2f300a5c9ce81ee98fc05aa41664722f195f603cf49ff420538b68baabe49dfd0ba5655f6f7293f8b89946efd0fbf9bbd4a617d73ebac5c2ecf3f481886ade3e178a4bf674bf3b4b9524b214c48ed568c7abdb60d09f090ced61dd3fd1147f331d1e90742e7cb2ec21fbb045e99f0fd98c6aebc76c9618d44543a2d5b21844cb18a2318ec7182be01c74cbfeba7f56cd7e30d32f16b76f988645d82be718f293124298e3f866553ebf1012ab2ef7e0a20c26aabd3eddd6645ec3b6f844b261a6018124eb0cd7a9cbd61f3acc47a6845bceab6c0f9a97e6bab551f408b6af575b2e263f0adce3d506bc56a91842dd75eb5c119924b399e0a6fe7377e12f7f9e1e1a25eaa55ff29060c0bb29788364236c38ca01d821a40794b278ce8f2afd8c2428c01df3b5af81892ddfc2d78e4f8bfa504e9481fb39b694fdf0ed53ea72687b0e0b691b8e31a22533be7510872cf4d58043b5ed4223fe72f356677431c9f7e41ca670820e72b8eaa4d98c80d44e85c62d9636e46320f242f91a9fe8e218a8791dc745303b10490e2710514c2f28b5babbc614740d2a75a988207346ad277218010d2c4b1bb73838e518bfdeff2eab34d2bbe9c5b7f4a81fd33c35789c8f08b42954dd268f916bbc875394562990483335747b169ca43b916f3f15ae8c14e2042b54f58973c8c47a1c67635bbf4adea7d6bf1e75240bbf554f77d57ba6c36f542a5d86876496bdb2a3638ab836629374134f4e436e61aaf023c94e7451d348aa07d02058eb4443217c7b830d64b9d63ba7898fe44786d1a63ff2041498a9effa0429ebb6377d912d8b70a53b7fb1bd8540d7cc20d886628e7514dce7a3eea5e81cc1d552e8c15f0b5348dc845e25f4cacf9bffd7066d2fcaeadba30d79eb201d0084214aa2e1a4c019a3ec2fe51b288039c07ab78a6cfe25a85fdc64c4264e1803c22b45e43777a3a12626cfb23f13054521c78f8fa884be2d5a1a31e94ca9bf2f98049cd3151680c838ced9a810ae6558d63cc4a324826e583f6eeee62f42cd140a780c088a09bd17dfb2f0033ec3c342d2bfd8eed625502aa8517f930917ec07a3012f39b39a91ca765b5ed0165a114f502d14e76a6573183ecef273e275fd1c643cdaa7b5c639c98aa2bdcf2b394558331fd19f49e2283b9d4cfde16d05e522e70b4738c76a5f019ae80d17b0e5fd521b652f8acd7b690a57c1ebffdceed500000000000000000000000000000000000000000000000000000000" + "trustedClientState": "000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000277162000000000000000000000000000000000000000000000000000000000012750000000000000000000000000000000000000000000000000000000000001baf80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000076d6f6368612d3400000000000000000000000000000000000000000000000000", + "trustedConsensusState": "0000000000000000000000000000000000000000000000000000000066cf585bf53cf5b309a255dd7562f62d797d6a2acc937c77b6e1ede11573df67166e2c4c424ee8cf84c0fa35a3eaf862ff1a633eb83be1022827498a79d4b6ac64310d99", + "updateClientVkey": "0x00aae7c6a541134ce5c556dd8bb23516240292e127321b5de81bc27892355622", + "membershipVkey": "0x00eae02a2c448b3242c5b37cef161b94e908fc12d861c481cff9d10217648697", + "ucAndMembershipVkey": "0x00a477c762e91e1e004d9362b4bd6a69b0f577f24b0e6db30f1b57ea87bd7011", + "misbehaviourVkey": "0x005e69d660bf31e9fb874c16897a71852b137d53659c24c3e3530537b59b176d", + "proofHeight": "000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000002771bc", + "membershipProof": "0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000ae00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000a477c762e91e1e004d9362b4bd6a69b0f577f24b0e6db30f1b57ea87bd70110000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000006800000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000066cf585bf53cf5b309a255dd7562f62d797d6a2acc937c77b6e1ede11573df67166e2c4c424ee8cf84c0fa35a3eaf862ff1a633eb83be1022827498a79d4b6ac64310d990000000000000000000000000000000000000000000000000000000066cf5ca0b522cbede226c60cc042ae1c7511d2b646a0618a18077ce7dc37c920e24c6e1c424ee8cf84c0fa35a3eaf862ff1a633eb83be1022827498a79d4b6ac64310d99000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000277162000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000002771bc00000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000001275000000000000000000000000000000000000000000000000000000000066d721e800000000000000000000000000000000000000000000000000000000000000076d6f6368612d340000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000369626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000023636c69656e74732f30372d74656e6465726d696e742d302f636c69656e745374617465000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b70a2b2f6962632e6c69676874636c69656e74732e74656e6465726d696e742e76312e436c69656e7453746174651287010a1174686574612d746573746e65742d3030311204080110031a040880840722040880c60a2a02082832003a0510b7e3c60842190a090801180120012a0100120c0a02000110211804200c300142190a090801180120012a0100120c0a02000110201801200130014a07757067726164654a10757067726164656449424353746174655001580100000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000369626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000025636c69656e74732f30372d74656e6465726d696e742d3030312f636c69656e74537461746500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000364c430ff7f07f86b1730c37c4c9f28fd3c651e22dda0c7a91a19eeae680023c57240cac6d9151a3570d5b2853abd8f4ac3fb5afea189725cdb3758ced75961138d40109e5c1bfad9679d0f2b673314cbc389dc9b6c0373661e88d169a0d736fd98737927a404f3a26096dfd5853726c02f2e5f8f233f2e436a4492b796c3dd39cfdd145a9425f2f826b87a98df3fd053de8fe57f5ca26111449679c60f2e64af67e00b5d160d0d38a91a1e0490d55dfbf49bbfc8cfa83697e93f3040a047cdb500afa34fb20d9973474c8feb0ea8cc44b800fdd955b6200912fd4270fb291d45ac00887eb901a120b4f7c67268a900e5f1a49c9b5841a9caaf5c051b3048fc1c149b5bf5280aee72e15c70b84c9ee18fe709069fad96a94cdbe056ab5a304bfe847c0783e21b74402641a48dce103ca8d9b7797737f825308f4b12f090ef453e024e8fe5c2051dbf320459e6d64ebfda8788e54cdaa7b8cc30cbfa61f973763a738881129b1dbd172daef4bc45c1b1328639837c1366d06789386b6738d54bb1b17ec011df0e461a0b8c0cd09eaba8015aa503c342048b86a19468c97991a7464d54c30d19052f5f8d4eeb4dbaaf160f64e208bbfee04c071569b1fd34cbae41e0bd919bc3304d46c5b1895a2a3a5956d3ed8949ebf5ff5eb30b30e007fa2a7b281ac4b4480c95de28faae106fe89cad3857c6b90532923bb9c04baa395d666a38ef34224c1dffa0df9b3db5a0b237c4bceb250c68ac7d5c1c984d9d5ab4dee6aee35df1b81ba24ee6974e899eeed076374b5ba2fd80f81fed8539104732a4e9d549e71bd6297f1c6c9b2068a39b5511b1e2af7ba677c4b90714b661914154145ad2aa7f722d15b064b8025b6ca48ee94fad56cb9b8d79f07176b9c60118e4813bdcc47ecc0c9bb6112e1579f3ae872b5fe56bd8a3aa289536b688214097a6e6ac33436f512de72ed8eb1eea3271252e445f88dae947df0f6296955008d3ec159433bec9fb17d4bfed84ad2d7a62a72f1f24677d0677835d149fdcdedea070dabc0a56ebf62c5e2def51378a9f0faaface33d941e627d4522709b4eed33873f3852fbdff300a8273b1f7e5be086b9e6b0c23ad9fd6bf13fc1df699a14c32cae0fbcceac52c087288a309939c0bbbe75393138937cf18e4b676efa2b30d4f176c8d14e0bb98019e0375c5fce46b5386042ebeb9b4faab88551196b2f7f3bc2c8ba2104b95d300000000000000000000000000000000000000000000000000000000" } \ No newline at end of file diff --git a/contracts/fixtures/update_client_fixture.json b/contracts/fixtures/update_client_fixture.json index 332b029..58b136b 100644 --- a/contracts/fixtures/update_client_fixture.json +++ b/contracts/fixtures/update_client_fixture.json @@ -1,10 +1,11 @@ { - "trustedClientState": "000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000253370000000000000000000000000000000000000000000000000000000000012750000000000000000000000000000000000000000000000000000000000001baf80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000076d6f6368612d3400000000000000000000000000000000000000000000000000", - "trustedConsensusState": "0000000000000000000000000000000000000000000000000000000066b4386ddd61735333d38ba62f9c8edb7d41b399ce6a0a0ed10d1aeaec708afec8d40472a1d4cdbc90487e9cf127cf745c0ce4e8f72e4babc77eb53db3729b8d848125cb", - "updateClientVkey": "0x0029ce4b0512b5c4254fb11a189799cddb28254f7177d549cf2dc860bc31519e", - "membershipVkey": "0x005f30ecbba088f6f6eede4ca8d4ff6ffc2b7e5f59de38edd1574aefb937afdb", - "ucAndMembershipVkey": "0x00cf1fa1df1f491548e84e88a6b617a70b7abd0c017bc7115ed08f329e05026a", - "targetConsensusState": "0000000000000000000000000000000000000000000000000000000066b438e572e20e3f7c806f0b63f0ad2b0b4bc471e73911b1be2b9436ec1dfdc7aa322365a1d4cdbc90487e9cf127cf745c0ce4e8f72e4babc77eb53db3729b8d848125cb", - "targetHeight": 2438010, - "updateMsg": "000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000200029ce4b0512b5c4254fb11a189799cddb28254f7177d549cf2dc860bc31519e000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000002e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000066b4386ddd61735333d38ba62f9c8edb7d41b399ce6a0a0ed10d1aeaec708afec8d40472a1d4cdbc90487e9cf127cf745c0ce4e8f72e4babc77eb53db3729b8d848125cb0000000000000000000000000000000000000000000000000000000066b438e572e20e3f7c806f0b63f0ad2b0b4bc471e73911b1be2b9436ec1dfdc7aa322365a1d4cdbc90487e9cf127cf745c0ce4e8f72e4babc77eb53db3729b8d848125cb0000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000002533700000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000025337a00000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000001275000000000000000000000000000000000000000000000000000000000066c0310400000000000000000000000000000000000000000000000000000000000000076d6f6368612d34000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000364c430ff7f23fd82c38803280265012deb0bc076758cd7d02490abe787dfc84994bbab081c0c6a671f76af10d0667e77d9eb9f62877c9ce0870d17744af1c91708397fc65a0cd8f2f2e1f39af403949da3213d23c077f5db7c605fd866d189eb7d4292409611f420f9625387e7c522c38d64b0a0c505241fb765699b1fbf793fe6edcd4368266499ab7a835c308bec1044143073087712b2cc1bec0976ea0ae14b128c7d02209bba3f1976fe6f67634f45f7165d87a3d972a7a5630e1797adf430602378bb2225fe941e6a209c59d2c080a562682d75a35560ff2b3e0ffa7e5f564ea4468f192fbfb8bd8a90a8fe245658b76addac1373a80d550100a8fb831ba1762362ae0a52e7a3964f7144246944974cd472728e6e02d7489ed5756bb3533a96229042120cd8e706ddf8cba1c52686d3972eee7a9c793a2fb9a42a2f8c7559dafc650123a278f3c33b05b53e3724533eadd8ed9326484352fd340726ef1d5281ddb4b422519f7a98eba7b0fc184f434099e4106b9a9f6428984dfe5412bcdfc121d55b22c6706a2778ee45109417bee2815d8d7e92ebfcd4853eaf339dd6743181f29e2f7c76e23676aaef9cadc6a425e59ee4df21ca478d147980ed9e0519edf96aad20b604e0a556795e128c878471ffb7ca80aabbacaed628904c82789fb158a61d2e6366790c5ad14021fe534a83ec0fc13ceaf307995f953912cac69023872f2d1af35818730e7d2fdb11710c39e5900d46a7dee67943c33e05562ed7fc21e5531ef48441cfff6cdaf3802d31098e1b25c094d49ef530eb67954ca1ca43db7e0000fe30b126685b07c11fbafd4410ffa6e59ab343a5d3d4c4e369cf9b55872c262aab2788d99515348ece3565f657464f6fa5485c49c8b70359070b8c57e15ef81bdd711c614a5a89163dd168b20aeb8d09c665d69ca9971974bc536bf39078b52cc6dbabd2cd28a611c5b84f26c8f0af2c90ee1dc64cea90b18b18600ebe0a6c001156e59cefa490db457bd9a6712699f6e5879f81ae0a791ea45f7206eced5304aa244302683cb5e8105ecf5f8a57a52de17a3b39abde4371f31c9559415c6c0f61cbd1f3d99f0028a1efd1e4cc2262e4f6b1ddb5cc980b51f3f1736509d4f92774b8b36d1b2164da1047123612c4aff26c1d13fa93f337aa319f9e2308d0a314f4f36ec649c267db8b9fb1de19a864204079c5acce53922cdd3dfc7f874a5e00000000000000000000000000000000000000000000000000000000" + "trustedClientState": "000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000277162000000000000000000000000000000000000000000000000000000000012750000000000000000000000000000000000000000000000000000000000001baf80000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000076d6f6368612d3400000000000000000000000000000000000000000000000000", + "trustedConsensusState": "0000000000000000000000000000000000000000000000000000000066cf585bf53cf5b309a255dd7562f62d797d6a2acc937c77b6e1ede11573df67166e2c4c424ee8cf84c0fa35a3eaf862ff1a633eb83be1022827498a79d4b6ac64310d99", + "updateClientVkey": "0x00aae7c6a541134ce5c556dd8bb23516240292e127321b5de81bc27892355622", + "membershipVkey": "0x00eae02a2c448b3242c5b37cef161b94e908fc12d861c481cff9d10217648697", + "ucAndMembershipVkey": "0x00a477c762e91e1e004d9362b4bd6a69b0f577f24b0e6db30f1b57ea87bd7011", + "misbehaviourVkey": "0x005e69d660bf31e9fb874c16897a71852b137d53659c24c3e3530537b59b176d", + "targetConsensusState": "0000000000000000000000000000000000000000000000000000000066cf5ca0b522cbede226c60cc042ae1c7511d2b646a0618a18077ce7dc37c920e24c6e1c424ee8cf84c0fa35a3eaf862ff1a633eb83be1022827498a79d4b6ac64310d99", + "targetHeight": 2585020, + "updateMsg": "0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000aae7c6a541134ce5c556dd8bb23516240292e127321b5de81bc27892355622000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000002e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000066cf585bf53cf5b309a255dd7562f62d797d6a2acc937c77b6e1ede11573df67166e2c4c424ee8cf84c0fa35a3eaf862ff1a633eb83be1022827498a79d4b6ac64310d990000000000000000000000000000000000000000000000000000000066cf5ca0b522cbede226c60cc042ae1c7511d2b646a0618a18077ce7dc37c920e24c6e1c424ee8cf84c0fa35a3eaf862ff1a633eb83be1022827498a79d4b6ac64310d99000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000277162000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000002771bc00000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000001275000000000000000000000000000000000000000000000000000000000066d721d800000000000000000000000000000000000000000000000000000000000000076d6f6368612d34000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000364c430ff7f2d986b6928dbc1587da304bec2f4c45bded50226699915dc2c8f438275ec68691747e1e2c1781013305e645ed5e00c6e4498ffc8d19fdd42e7f2803a5d39681e2e46db956a99c244fc5984c35fbe713eac0c082c57a0d90f1e736637395c1d6c04a28b968cbb24ebe2edceb32a2dbf16d1c21ea02b450683c5c5fd313c72ff9029cd9bb5687bc315e11e0a510f402ef9ec977b4348b4bfe61471ab0230774f0324270af8d654f41e64515587b6f1e395b4d57bfc8de21559ff74e365d634510a01b6ede065fd0d1a9f165e69f2c90712dc92eb0149da55a14a93ef2c5ca352f8110d744c8bee1f00aa18a80de216a907be90154aa6e5841898b10d7e533fc06203dcc0247527f54636da37a6c698e14cc976ad5e5fa839e9be8d3b81b154006f24f5090149ad868cad85d86e524330a84362d7fda16e7d60f0bd8295967bbd6a184e7245dfbbec20808cb470c957d8c9abe73fe2bb3c54d42c2f49a2e8b07bcd0f9b9a712442188237670a29de7beca01ccd7b26dc91bf747ac056a9979a8c1028e28c2023ef5115b0273b8fa49e20d1ef6263ca2dda842690b67fd432f5f4152231ff11e3048ba1f6ca6182a1a552496388497e1feab2d4bf88583892be817a160cefd71022f2948ff230a73b5f8dd55c86d9c8b6095dc2ce04eb1e06698cd11e863d544de887e774415221922f84b996b8ab5b69e09976a242f7ab58e91e45154ce5831857e413e775a5289fa6b7c87a98ea011247bcb9fe56d13ca34f0f230827c0b5d781a262aef096bcad47a6623bb533520ffb42afc65c19172437d95224e14cd5e7a0a178edb04266900eb96e21887d3b1de168c2d51316ed3d2bb9730b9962b7dc67a1ec59a8aba738a619039ae5eea800343f11ce90b7e24cc00d170c88e6d980d7802f6ae1ae7c0ea4b8caf07d31b2ea0a7fee059ad9d0f722ef7c26ed0e3b53a5d14ff4d6d693a5a68045330e9954dd30dcd6048043b371cb99040ac0ee37bcb18e7533a36df26c37ca54c937868cdde8214e17c81c83d059a33e1409d02ab77553f0ade78e10d5e9e9a501e2b4dccc05b502606025b24aec5f9f00f5703682b2201f32ca25886cefad088764025ae18149b320899bdac88aa7262398b888b9ab920e49db0f8838f8c99ba09a4723e006aabea54cf3646d34467e2cdc3bd525502d5355237d910be627b476927fdd6846c28559630d9842a7a30e00000000000000000000000000000000000000000000000000000000" } \ No newline at end of file diff --git a/contracts/script/SP1ICS07Tendermint.s.sol b/contracts/script/SP1ICS07Tendermint.s.sol index 9a199d1..f959f3e 100644 --- a/contracts/script/SP1ICS07Tendermint.s.sol +++ b/contracts/script/SP1ICS07Tendermint.s.sol @@ -13,6 +13,7 @@ struct SP1ICS07TendermintGenesisJson { bytes32 updateClientVkey; bytes32 membershipVkey; bytes32 ucAndMembershipVkey; + bytes32 misbehaviourVkey; } contract SP1TendermintScript is Script, IICS07TendermintMsgs { @@ -36,6 +37,7 @@ contract SP1TendermintScript is Script, IICS07TendermintMsgs { genesis.updateClientVkey, genesis.membershipVkey, genesis.ucAndMembershipVkey, + genesis.misbehaviourVkey, address(verifier), genesis.trustedClientState, trustedConsensusHash @@ -61,13 +63,15 @@ contract SP1TendermintScript is Script, IICS07TendermintMsgs { bytes32 updateClientVkey = json.readBytes32(".updateClientVkey"); bytes32 membershipVkey = json.readBytes32(".membershipVkey"); bytes32 ucAndMembershipVkey = json.readBytes32(".ucAndMembershipVkey"); + bytes32 misbehaviourVkey = json.readBytes32(".misbehaviourVkey"); SP1ICS07TendermintGenesisJson memory fixture = SP1ICS07TendermintGenesisJson({ trustedClientState: trustedClientState, trustedConsensusState: trustedConsensusState, updateClientVkey: updateClientVkey, membershipVkey: membershipVkey, - ucAndMembershipVkey: ucAndMembershipVkey + ucAndMembershipVkey: ucAndMembershipVkey, + misbehaviourVkey: misbehaviourVkey }); return fixture; diff --git a/contracts/script/genesis.json b/contracts/script/genesis.json index 28ecab2..25744b6 100644 --- a/contracts/script/genesis.json +++ b/contracts/script/genesis.json @@ -1,7 +1,8 @@ { "trustedClientState": "00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000012754500000000000000000000000000000000000000000000000000000000001baf800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000673696d642d310000000000000000000000000000000000000000000000000000", - "trustedConsensusState": "0000000000000000000000000000000000000000000000000000000066afad81234b002d78b03df426a7e156ffe511253e9f874ed7feccc14d8d0002b1deba3a3e100db17d609c05af9bb099133aeea97349259ce45c581128ac8ffb51662a5a", - "updateClientVkey": "0x00d8ae8feed5fd1f82dbf7862b219cd74c516e5d09ee5ec9024b439e95f5a3e2", - "membershipVkey": "0x001ae64fb3c0ac2e5a62e4941b26edf05798f0dc3417ae105e4bd1c443de6188", - "ucAndMembershipVkey": "0x008ddefe335385fdfe8e6eefcebe2f9519cb27e95afd392537657bb4525883f9" + "trustedConsensusState": "0000000000000000000000000000000000000000000000000000000066d7298c18e36de14e99f7c090cfc07840e0d0d49406b46fe270c26bfa46d6facca6b631c23ec958f6b9a5e92347e1c118a571e4ef5b4a626ba839ccf58d0f5d1d36136c", + "updateClientVkey": "0x00aae7c6a541134ce5c556dd8bb23516240292e127321b5de81bc27892355622", + "membershipVkey": "0x00eae02a2c448b3242c5b37cef161b94e908fc12d861c481cff9d10217648697", + "ucAndMembershipVkey": "0x00a477c762e91e1e004d9362b4bd6a69b0f577f24b0e6db30f1b57ea87bd7011", + "misbehaviourVkey": "0x005e69d660bf31e9fb874c16897a71852b137d53659c24c3e3530537b59b176d" } \ No newline at end of file diff --git a/contracts/src/ISP1ICS07Tendermint.sol b/contracts/src/ISP1ICS07Tendermint.sol index b90496f..519f11c 100644 --- a/contracts/src/ISP1ICS07Tendermint.sol +++ b/contracts/src/ISP1ICS07Tendermint.sol @@ -20,6 +20,10 @@ interface ISP1ICS07Tendermint is ILightClient { /// @return The verification key for the update client and membership program. function UPDATE_CLIENT_AND_MEMBERSHIP_PROGRAM_VKEY() external view returns (bytes32); + /// @notice Immutable misbehaviour program verification key. + /// @return The verification key for the misbehaviour program. + function MISBEHAVIOUR_PROGRAM_VKEY() external view returns (bytes32); + /// @notice Immutable SP1 verifier contract address. /// @return The SP1 verifier contract. function VERIFIER() external view returns (ISP1Verifier); diff --git a/contracts/src/SP1ICS07Tendermint.sol b/contracts/src/SP1ICS07Tendermint.sol index 8f431b8..ea02b4d 100644 --- a/contracts/src/SP1ICS07Tendermint.sol +++ b/contracts/src/SP1ICS07Tendermint.sol @@ -5,6 +5,7 @@ import { IICS07TendermintMsgs } from "./msgs/IICS07TendermintMsgs.sol"; import { IUpdateClientMsgs } from "./msgs/IUpdateClientMsgs.sol"; import { IMembershipMsgs } from "./msgs/IMembershipMsgs.sol"; import { IUpdateClientAndMembershipMsgs } from "./msgs/IUcAndMembershipMsgs.sol"; +import { IMisbehaviourMsgs } from "./msgs/IMisbehaviourMsgs.sol"; import { ISP1Verifier } from "@sp1-contracts/ISP1Verifier.sol"; import { ISP1ICS07TendermintErrors } from "./errors/ISP1ICS07TendermintErrors.sol"; import { ISP1ICS07Tendermint } from "./ISP1ICS07Tendermint.sol"; @@ -21,6 +22,7 @@ contract SP1ICS07Tendermint is IUpdateClientMsgs, IMembershipMsgs, IUpdateClientAndMembershipMsgs, + IMisbehaviourMsgs, ISP1ICS07TendermintErrors, ILightClientMsgs, ISP1ICS07Tendermint @@ -32,6 +34,8 @@ contract SP1ICS07Tendermint is /// @inheritdoc ISP1ICS07Tendermint bytes32 public immutable UPDATE_CLIENT_AND_MEMBERSHIP_PROGRAM_VKEY; /// @inheritdoc ISP1ICS07Tendermint + bytes32 public immutable MISBEHAVIOUR_PROGRAM_VKEY; + /// @inheritdoc ISP1ICS07Tendermint ISP1Verifier public immutable VERIFIER; /// @notice The ICS07Tendermint client state @@ -47,6 +51,7 @@ contract SP1ICS07Tendermint is /// @param updateClientProgramVkey The verification key for the update client program. /// @param membershipProgramVkey The verification key for the verify (non)membership program. /// @param updateClientAndMembershipProgramVkey The verification key for the update client and membership program. + /// @param misbehaviourProgramVkey The verification key for the misbehaviour program. /// @param verifier The address of the SP1 verifier contract. /// @param _clientState The encoded initial client state. /// @param _consensusState The encoded initial consensus state. @@ -54,6 +59,7 @@ contract SP1ICS07Tendermint is bytes32 updateClientProgramVkey, bytes32 membershipProgramVkey, bytes32 updateClientAndMembershipProgramVkey, + bytes32 misbehaviourProgramVkey, address verifier, bytes memory _clientState, bytes32 _consensusState @@ -61,6 +67,7 @@ contract SP1ICS07Tendermint is UPDATE_CLIENT_PROGRAM_VKEY = updateClientProgramVkey; MEMBERSHIP_PROGRAM_VKEY = membershipProgramVkey; UPDATE_CLIENT_AND_MEMBERSHIP_PROGRAM_VKEY = updateClientAndMembershipProgramVkey; + MISBEHAVIOUR_PROGRAM_VKEY = misbehaviourProgramVkey; VERIFIER = ISP1Verifier(verifier); clientState = abi.decode(_clientState, (ClientState)); @@ -135,9 +142,20 @@ contract SP1ICS07Tendermint is /// @notice The entrypoint for misbehaviour. /// @inheritdoc ILightClient - function misbehaviour(bytes calldata) public pure { - // TODO: Not yet implemented. (#56) - revert FeatureNotSupported(); + function misbehaviour(bytes calldata misbehaviourMsg) public { + MsgSubmitMisbehaviour memory msgSubmitMisbehaviour = abi.decode(misbehaviourMsg, (MsgSubmitMisbehaviour)); + if (msgSubmitMisbehaviour.sp1Proof.vKey != MISBEHAVIOUR_PROGRAM_VKEY) { + revert VerificationKeyMismatch(MISBEHAVIOUR_PROGRAM_VKEY, msgSubmitMisbehaviour.sp1Proof.vKey); + } + + MisbehaviourOutput memory output = abi.decode(msgSubmitMisbehaviour.sp1Proof.publicValues, (MisbehaviourOutput)); + + validateMisbehaviourOutput(output); + + verifySP1Proof(msgSubmitMisbehaviour.sp1Proof); + + // If the misbehaviour and proof is valid, the client needs to be frozen + clientState.isFrozen = true; } /// @notice The entrypoint for upgrading the client. @@ -331,43 +349,75 @@ contract SP1ICS07Tendermint is if (clientState.isFrozen) { revert FrozenClientState(); } - if (output.env.now > block.timestamp) { - revert ProofIsInTheFuture(block.timestamp, output.env.now); + validateEnv(output.env); + + bytes32 outputConsensusStateHash = keccak256(abi.encode(output.trustedConsensusState)); + bytes32 trustedConsensusStateHash = getConsensusStateHash(output.trustedHeight.revisionHeight); + if (outputConsensusStateHash != trustedConsensusStateHash) { + revert ConsensusStateHashMismatch(trustedConsensusStateHash, outputConsensusStateHash); } - if (block.timestamp - output.env.now > ALLOWED_SP1_CLOCK_DRIFT) { - revert ProofIsTooOld(block.timestamp, output.env.now); + } + + /// @notice Validates the SP1ICS07MisbehaviourOutput public values. + /// @param output The public values. + function validateMisbehaviourOutput(MisbehaviourOutput memory output) private view { + if (clientState.isFrozen) { + revert FrozenClientState(); + } + validateEnv(output.env); + + // make sure the trusted consensus state from header 1 is known (trusted) by matching it with the the one in the + // mapping + bytes32 outputConsensusStateHash1 = keccak256(abi.encode(output.trustedConsensusState1)); + bytes32 trustedConsensusState1 = getConsensusStateHash(output.trustedHeight1.revisionHeight); + if (outputConsensusStateHash1 != trustedConsensusState1) { + revert ConsensusStateHashMismatch(trustedConsensusState1, outputConsensusStateHash1); + } + + // make sure the trusted consensus state from header 2 is known (trusted) by matching it with the the one in the + // mapping + bytes32 outputConsensusStateHash2 = keccak256(abi.encode(output.trustedConsensusState2)); + bytes32 trustedConsensusState2 = getConsensusStateHash(output.trustedHeight2.revisionHeight); + if (outputConsensusStateHash2 != trustedConsensusState2) { + revert ConsensusStateHashMismatch(trustedConsensusState2, outputConsensusStateHash2); + } + } + + /// @notice Validates the Env public values. + /// @param env The public values. + function validateEnv(Env memory env) private view { + if (env.now > block.timestamp) { + revert ProofIsInTheFuture(block.timestamp, env.now); + } + if (block.timestamp - env.now > ALLOWED_SP1_CLOCK_DRIFT) { + revert ProofIsTooOld(block.timestamp, env.now); } - if (keccak256(bytes(output.env.chainId)) != keccak256(bytes(clientState.chainId))) { - revert ChainIdMismatch(clientState.chainId, output.env.chainId); + if (keccak256(bytes(env.chainId)) != keccak256(bytes(clientState.chainId))) { + revert ChainIdMismatch(clientState.chainId, env.chainId); } if ( - output.env.trustThreshold.numerator != clientState.trustLevel.numerator - || output.env.trustThreshold.denominator != clientState.trustLevel.denominator + env.trustThreshold.numerator != clientState.trustLevel.numerator + || env.trustThreshold.denominator != clientState.trustLevel.denominator ) { revert TrustThresholdMismatch( clientState.trustLevel.numerator, clientState.trustLevel.denominator, - output.env.trustThreshold.numerator, - output.env.trustThreshold.denominator + env.trustThreshold.numerator, + env.trustThreshold.denominator ); } - if (output.env.trustingPeriod != clientState.trustingPeriod) { - revert TrustingPeriodMismatch(clientState.trustingPeriod, output.env.trustingPeriod); + if (env.trustingPeriod != clientState.trustingPeriod) { + revert TrustingPeriodMismatch(clientState.trustingPeriod, env.trustingPeriod); } - if (output.env.trustingPeriod > clientState.unbondingPeriod) { - revert TrustingPeriodTooLong(output.env.trustingPeriod, clientState.unbondingPeriod); - } - - bytes32 outputConsensusStateHash = keccak256(abi.encode(output.trustedConsensusState)); - bytes32 trustedConsensusStateHash = getConsensusStateHash(output.trustedHeight.revisionHeight); - if (outputConsensusStateHash != trustedConsensusStateHash) { - revert ConsensusStateHashMismatch(trustedConsensusStateHash, outputConsensusStateHash); + if (env.trustingPeriod > clientState.unbondingPeriod) { + revert TrustingPeriodTooLong(env.trustingPeriod, clientState.unbondingPeriod); } } /// @notice Checks for basic misbehaviour. - /// @dev This function checks if the consensus state at the new height is different than the one in the mapping. - /// @dev This function does not check timestamp misbehaviour (a niche case). + /// @dev This function checks if the consensus state at the new height is different than the one in the mapping + /// @dev or if the timestamp is not increasing. + /// @dev If any of these conditions are met, it returns a Misbehaviour UpdateResult. /// @param output The public values of the update client program. /// @return The result of the update. function checkUpdateResult(UpdateClientOutput memory output) private view returns (UpdateResult) { @@ -375,8 +425,12 @@ contract SP1ICS07Tendermint is if (consensusStateHash == bytes32(0)) { // No consensus state at the new height, so no misbehaviour return UpdateResult.Update; - } else if (consensusStateHash != keccak256(abi.encode(output.newConsensusState))) { + } else if ( + consensusStateHash != keccak256(abi.encode(output.newConsensusState)) + || output.trustedConsensusState.timestamp >= output.newConsensusState.timestamp + ) { // The consensus state at the new height is different than the one in the mapping + // or the timestamp is not increasing return UpdateResult.Misbehaviour; } else { // The consensus state at the new height is the same as the one in the mapping @@ -397,19 +451,23 @@ contract SP1ICS07Tendermint is /// @param o4 The MembershipProof. /// @param o5 The SP1MembershipProof. /// @param o6 The SP1MembershipAndUpdateClientProof. + /// @param o7 The MisbehaviourOutput. + /// @param o8 The MsgSubmitMisbehaviour. function abiPublicTypes( MembershipOutput memory o1, UcAndMembershipOutput memory o2, MsgUpdateClient memory o3, MembershipProof memory o4, SP1MembershipProof memory o5, - SP1MembershipAndUpdateClientProof memory o6 + SP1MembershipAndUpdateClientProof memory o6, + MisbehaviourOutput memory o7, + MsgSubmitMisbehaviour memory o8 ) public pure // solhint-disable-next-line no-empty-blocks { - // This is a dummy function to generate the ABI for MembershipOutput + // This is a dummy function to generate the ABI for outputs // so that it can be used in the SP1 verifier contract. // The function is not used in the contract. } diff --git a/contracts/src/msgs/IICS07TendermintMsgs.sol b/contracts/src/msgs/IICS07TendermintMsgs.sol index 09958b7..dbc4a45 100644 --- a/contracts/src/msgs/IICS07TendermintMsgs.sol +++ b/contracts/src/msgs/IICS07TendermintMsgs.sol @@ -42,4 +42,17 @@ interface IICS07TendermintMsgs is IICS02ClientMsgs { bytes32 root; bytes32 nextValidatorsHash; } + + /// @notice The environment output for the sp1 program. + /// @param chainId The chain ID of the chain that the client is tracking. + /// @param trustThreshold Fraction of validator overlap needed to update header + /// @param trustingPeriod Duration of the period since the `LatestTimestamp` during which the + /// submitted headers are valid for upgrade in seconds. + /// @param now Timestamp in seconds. + struct Env { + string chainId; + TrustThreshold trustThreshold; + uint32 trustingPeriod; + uint64 now; + } } diff --git a/contracts/src/msgs/IMisbehaviourMsgs.sol b/contracts/src/msgs/IMisbehaviourMsgs.sol new file mode 100644 index 000000000..b08458d --- /dev/null +++ b/contracts/src/msgs/IMisbehaviourMsgs.sol @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.25; + +import { IICS07TendermintMsgs } from "./IICS07TendermintMsgs.sol"; +import { ISP1Msgs } from "./ISP1Msgs.sol"; + +/// @title Misbehaviour Program Messages +/// @author gjermundgaraba +/// @notice Defines shared types for the misbehaviour program. +interface IMisbehaviourMsgs is IICS07TendermintMsgs, ISP1Msgs { + /// @notice The message that is submitted to the misbehaviour function. + /// @param sp1Proof The SP1 proof for updating the client. + struct MsgSubmitMisbehaviour { + SP1Proof sp1Proof; + } + + /// @notice The public value output for the sp1 misbehaviour program. + /// @param env The validation environment. + /// @param trustedHeight1 The trusted height of header 1 + /// @param trustedHeight2 The trusted height of header 2 + /// @param trustedConsensusState1 The trusted consensus state of header 1 + /// @param trustedConsensusState2 The trusted consensus state of header 2 + struct MisbehaviourOutput { + Env env; + Height trustedHeight1; + Height trustedHeight2; + ConsensusState trustedConsensusState1; + ConsensusState trustedConsensusState2; + } +} diff --git a/contracts/src/msgs/IUpdateClientMsgs.sol b/contracts/src/msgs/IUpdateClientMsgs.sol index 3738ba0..ba44b85 100644 --- a/contracts/src/msgs/IUpdateClientMsgs.sol +++ b/contracts/src/msgs/IUpdateClientMsgs.sol @@ -27,17 +27,4 @@ interface IUpdateClientMsgs is IICS07TendermintMsgs, ISP1Msgs { Height trustedHeight; Height newHeight; } - - /// @notice The environment output for the sp1 program. - /// @param chainId The chain ID of the chain that the client is tracking. - /// @param trustThreshold Fraction of validator overlap needed to update header - /// @param trustingPeriod Duration of the period since the `LatestTimestamp` during which the - /// submitted headers are valid for upgrade in seconds. - /// @param now Timestamp in seconds. - struct Env { - string chainId; - TrustThreshold trustThreshold; - uint32 trustingPeriod; - uint64 now; - } } diff --git a/contracts/test/Misbehaviour.t.sol b/contracts/test/Misbehaviour.t.sol new file mode 100644 index 000000000..9a6816d --- /dev/null +++ b/contracts/test/Misbehaviour.t.sol @@ -0,0 +1,216 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.25; + +// solhint-disable-next-line no-global-import +import "forge-std/console.sol"; +import { SP1ICS07Tendermint } from "../src/SP1ICS07Tendermint.sol"; +import { SP1ICS07TendermintTest } from "./SP1ICS07TendermintTest.sol"; +import { IMisbehaviourMsgs } from "../src/msgs/IMisbehaviourMsgs.sol"; +import { SP1Verifier } from "@sp1-contracts/v1.1.0/SP1Verifier.sol"; +import { stdJson } from "forge-std/StdJson.sol"; + +struct SP1ICS07MisbehaviourFixtureJson { + bytes trustedClientState; + bytes trustedConsensusState; + bytes submitMsg; +} + +contract SP1ICS07MisbehaviourTest is SP1ICS07TendermintTest { + using stdJson for string; + + SP1ICS07MisbehaviourFixtureJson public fixture; + MsgSubmitMisbehaviour public submitMsg; + MisbehaviourOutput public output; + + Env public env; + + function setUpMisbehaviour(string memory fileName) public { + string memory root = vm.projectRoot(); + string memory path = string.concat(root, "/contracts/fixtures/", fileName); + string memory json = vm.readFile(path); + bytes memory trustedClientStateBz = json.readBytes(".trustedClientState"); + bytes memory trustedConsensusStateBz = json.readBytes(".trustedConsensusState"); + bytes memory submitMsgBz = json.readBytes(".submitMsg"); + + fixture = SP1ICS07MisbehaviourFixtureJson({ + trustedClientState: trustedClientStateBz, + trustedConsensusState: trustedConsensusStateBz, + submitMsg: submitMsgBz + }); + + setUpTest(fileName); + + submitMsg = abi.decode(fixture.submitMsg, (IMisbehaviourMsgs.MsgSubmitMisbehaviour)); + output = abi.decode(submitMsg.sp1Proof.publicValues, (IMisbehaviourMsgs.MisbehaviourOutput)); + env = output.env; + } + + function test_ValidDoubleSignMisbehaviour() public { + setUpMisbehaviour("misbehaviour_double_sign_fixture.json"); + + // set a correct timestamp + vm.warp(env.now); + ics07Tendermint.misbehaviour(fixture.submitMsg); + + // to console + console.log("Misbehaviour gas used: ", vm.lastCallGas().gasTotalUsed); + + // verify that the client is frozen + ClientState memory clientState = ics07Tendermint.getClientState(); + assertTrue(clientState.isFrozen); + } + + function test_ValidBreakingTimeMonotonicityMisbehaviour() public { + setUpMisbehaviour("misbehaviour_breaking_time_monotonicity_fixture.json"); + + // set a correct timestamp + vm.warp(env.now); + ics07Tendermint.misbehaviour(fixture.submitMsg); + + // to console + console.log("Misbehaviour gas used: ", vm.lastCallGas().gasTotalUsed); + + // verify that the client is frozen + ClientState memory clientState = ics07Tendermint.getClientState(); + assertTrue(clientState.isFrozen); + } + + function test_InvalidMisbehaviour() public { + setUpMisbehaviour("misbehaviour_double_sign_fixture.json"); + + // proof is in the future + vm.warp(env.now - 300); + vm.expectRevert(abi.encodeWithSelector(ProofIsInTheFuture.selector, block.timestamp, env.now)); + ics07Tendermint.misbehaviour(fixture.submitMsg); + + // proof is too old + vm.warp(env.now + ics07Tendermint.ALLOWED_SP1_CLOCK_DRIFT() + 300); + vm.expectRevert(abi.encodeWithSelector(ProofIsTooOld.selector, block.timestamp, env.now)); + ics07Tendermint.misbehaviour(fixture.submitMsg); + + // set a correct timestamp + vm.warp(env.now + 300); + + // wrong vkey + MsgSubmitMisbehaviour memory badSubmitMsg = cloneSubmitMsg(); + badSubmitMsg.sp1Proof.vKey = bytes32(0); + bytes memory submitMsgBz = abi.encode(badSubmitMsg); + vm.expectRevert( + abi.encodeWithSelector( + VerificationKeyMismatch.selector, + ics07Tendermint.MISBEHAVIOUR_PROGRAM_VKEY(), + badSubmitMsg.sp1Proof.vKey + ) + ); + ics07Tendermint.misbehaviour(submitMsgBz); + + // chain id mismatch + badSubmitMsg = cloneSubmitMsg(); + MisbehaviourOutput memory badOutput = cloneOutput(); + badOutput.env.chainId = "bad-chain-id"; + badSubmitMsg.sp1Proof.publicValues = abi.encode(badOutput); + submitMsgBz = abi.encode(badSubmitMsg); + vm.expectRevert(abi.encodeWithSelector(ChainIdMismatch.selector, output.env.chainId, badOutput.env.chainId)); + ics07Tendermint.misbehaviour(submitMsgBz); + + // trust threshold mismatch + badSubmitMsg = cloneSubmitMsg(); + badOutput = cloneOutput(); + badOutput.env.trustThreshold = TrustThreshold({ numerator: 1, denominator: 2 }); + badSubmitMsg.sp1Proof.publicValues = abi.encode(badOutput); + submitMsgBz = abi.encode(badSubmitMsg); + vm.expectRevert( + abi.encodeWithSelector( + TrustThresholdMismatch.selector, output.env.trustThreshold, badOutput.env.trustThreshold + ) + ); + ics07Tendermint.misbehaviour(submitMsgBz); + + // trusting period mismatch + badSubmitMsg = cloneSubmitMsg(); + badOutput = cloneOutput(); + badOutput.env.trustingPeriod = 1; + badSubmitMsg.sp1Proof.publicValues = abi.encode(badOutput); + submitMsgBz = abi.encode(badSubmitMsg); + vm.expectRevert( + abi.encodeWithSelector( + TrustingPeriodMismatch.selector, output.env.trustingPeriod, badOutput.env.trustingPeriod + ) + ); + ics07Tendermint.misbehaviour(submitMsgBz); + + // trusting period too long + // we need to set up a new misconfigured client where the trusting period is longer than the unbonding period + ClientState memory clientState = ics07Tendermint.getClientState(); + ClientState memory badClientState = ClientState({ + chainId: clientState.chainId, + trustLevel: clientState.trustLevel, + latestHeight: clientState.latestHeight, + trustingPeriod: clientState.unbondingPeriod + 1, + unbondingPeriod: clientState.unbondingPeriod, + isFrozen: clientState.isFrozen + }); + bytes32 trustedConsensusState = ics07Tendermint.getConsensusStateHash(clientState.latestHeight.revisionHeight); + SP1ICS07Tendermint badClient = new SP1ICS07Tendermint( + ics07Tendermint.UPDATE_CLIENT_PROGRAM_VKEY(), + ics07Tendermint.MEMBERSHIP_PROGRAM_VKEY(), + ics07Tendermint.UPDATE_CLIENT_AND_MEMBERSHIP_PROGRAM_VKEY(), + ics07Tendermint.MISBEHAVIOUR_PROGRAM_VKEY(), + address(ics07Tendermint.VERIFIER()), + abi.encode(badClientState), + trustedConsensusState + ); + badOutput = cloneOutput(); + badOutput.env.trustingPeriod = badClientState.trustingPeriod; + badSubmitMsg = cloneSubmitMsg(); + badSubmitMsg.sp1Proof.publicValues = abi.encode(badOutput); + submitMsgBz = abi.encode(badSubmitMsg); + vm.expectRevert( + abi.encodeWithSelector( + TrustingPeriodTooLong.selector, badClientState.trustingPeriod, badClientState.unbondingPeriod + ) + ); + badClient.misbehaviour(submitMsgBz); + + // invalid proof + badSubmitMsg = cloneSubmitMsg(); + badOutput = cloneOutput(); + badOutput.env.now = badOutput.env.now + 1; + badSubmitMsg.sp1Proof.publicValues = abi.encode(badOutput); + submitMsgBz = abi.encode(badSubmitMsg); + vm.expectRevert(abi.encodeWithSelector(SP1Verifier.InvalidProof.selector)); + ics07Tendermint.misbehaviour(submitMsgBz); + + // client state is frozen + ics07Tendermint.misbehaviour(fixture.submitMsg); // freeze the client + vm.expectRevert(abi.encodeWithSelector(FrozenClientState.selector)); + ics07Tendermint.misbehaviour(fixture.submitMsg); + } + + function cloneSubmitMsg() private view returns (MsgSubmitMisbehaviour memory) { + MsgSubmitMisbehaviour memory clone = MsgSubmitMisbehaviour({ + sp1Proof: SP1Proof({ + vKey: submitMsg.sp1Proof.vKey, + publicValues: submitMsg.sp1Proof.publicValues, + proof: submitMsg.sp1Proof.proof + }) + }); + return clone; + } + + function cloneOutput() private view returns (MisbehaviourOutput memory) { + MisbehaviourOutput memory clone = MisbehaviourOutput({ + env: Env({ + chainId: output.env.chainId, + trustThreshold: output.env.trustThreshold, + trustingPeriod: output.env.trustingPeriod, + now: output.env.now + }), + trustedHeight1: output.trustedHeight1, + trustedHeight2: output.trustedHeight2, + trustedConsensusState1: output.trustedConsensusState1, + trustedConsensusState2: output.trustedConsensusState2 + }); + return clone; + } +} diff --git a/contracts/test/SP1ICS07TendermintTest.sol b/contracts/test/SP1ICS07TendermintTest.sol index a01bdac..7726c32 100644 --- a/contracts/test/SP1ICS07TendermintTest.sol +++ b/contracts/test/SP1ICS07TendermintTest.sol @@ -9,7 +9,9 @@ import { IICS07TendermintMsgs } from "../src/msgs/IICS07TendermintMsgs.sol"; import { IUpdateClientMsgs } from "../src/msgs/IUpdateClientMsgs.sol"; import { IMembershipMsgs } from "../src/msgs/IMembershipMsgs.sol"; import { IUpdateClientAndMembershipMsgs } from "../src/msgs/IUcAndMembershipMsgs.sol"; +import { IMisbehaviourMsgs } from "../src/msgs/IMisbehaviourMsgs.sol"; import { SP1ICS07Tendermint } from "../src/SP1ICS07Tendermint.sol"; +import { ISP1ICS07TendermintErrors } from "../src/errors/ISP1ICS07TendermintErrors.sol"; import { SP1Verifier } from "@sp1-contracts/v1.1.0/SP1Verifier.sol"; import { SP1MockVerifier } from "@sp1-contracts/SP1MockVerifier.sol"; import { ILightClientMsgs } from "solidity-ibc/msgs/ILightClientMsgs.sol"; @@ -20,6 +22,7 @@ struct SP1ICS07GenesisFixtureJson { bytes32 updateClientVkey; bytes32 membershipVkey; bytes32 ucAndMembershipVkey; + bytes32 misbehaviourVkey; } abstract contract SP1ICS07TendermintTest is @@ -28,6 +31,8 @@ abstract contract SP1ICS07TendermintTest is IUpdateClientMsgs, IMembershipMsgs, IUpdateClientAndMembershipMsgs, + IMisbehaviourMsgs, + ISP1ICS07TendermintErrors, ILightClientMsgs { using stdJson for string; @@ -51,6 +56,7 @@ abstract contract SP1ICS07TendermintTest is genesisFixture.updateClientVkey, genesisFixture.membershipVkey, genesisFixture.ucAndMembershipVkey, + genesisFixture.misbehaviourVkey, address(verifier), genesisFixture.trustedClientState, trustedConsensusHash @@ -61,6 +67,7 @@ abstract contract SP1ICS07TendermintTest is genesisFixture.updateClientVkey, genesisFixture.membershipVkey, genesisFixture.ucAndMembershipVkey, + genesisFixture.misbehaviourVkey, address(mockVerifier), genesisFixture.trustedClientState, trustedConsensusHash @@ -82,13 +89,15 @@ abstract contract SP1ICS07TendermintTest is bytes32 updateClientVkey = json.readBytes32(".updateClientVkey"); bytes32 membershipVkey = json.readBytes32(".membershipVkey"); bytes32 ucAndMembershipVkey = json.readBytes32(".ucAndMembershipVkey"); + bytes32 misbehaviourVkey = json.readBytes32(".misbehaviourVkey"); SP1ICS07GenesisFixtureJson memory fix = SP1ICS07GenesisFixtureJson({ trustedClientState: trustedClientState, trustedConsensusState: trustedConsensusState, updateClientVkey: updateClientVkey, membershipVkey: membershipVkey, - ucAndMembershipVkey: ucAndMembershipVkey + ucAndMembershipVkey: ucAndMembershipVkey, + misbehaviourVkey: misbehaviourVkey }); return fix; diff --git a/e2e/interchaintestv8/.golangci.yml b/e2e/interchaintestv8/.golangci.yml index 8396ad4..f3ce579 100644 --- a/e2e/interchaintestv8/.golangci.yml +++ b/e2e/interchaintestv8/.golangci.yml @@ -7,7 +7,7 @@ linters: disable-all: true enable: - dogsled - - exportloopref + - copyloopvar - errcheck - gci - goconst @@ -51,6 +51,10 @@ issues: max-same-issues: 10000 linters-settings: + gosec: + excludes: + # Flags for potentially-unsafe casting of ints, similar problem to globally-disabled G103 + - G115 gci: sections: - standard # Standard section: captures all standard packages. @@ -65,7 +69,6 @@ linters-settings: - prefix(github.com/CosmWasm/wasmd) - prefix(github.com/strangelove-ventures/interchaintest) - prefix(github.com/srdtrk/sp1-ics07-tendermint/e2e/v8) - custom-order: true dogsled: max-blank-identifiers: 3 diff --git a/e2e/interchaintestv8/chainconfig/chain_config.go b/e2e/interchaintestv8/chainconfig/chain_config.go index 6fd0b19..78f117f 100644 --- a/e2e/interchaintestv8/chainconfig/chain_config.go +++ b/e2e/interchaintestv8/chainconfig/chain_config.go @@ -2,13 +2,13 @@ package chainconfig import ( interchaintest "github.com/strangelove-ventures/interchaintest/v8" - "github.com/strangelove-ventures/interchaintest/v8/chain/ethereum" + "github.com/strangelove-ventures/interchaintest/v8/chain/ethereum/foundry" "github.com/strangelove-ventures/interchaintest/v8/ibc" ) var DefaultChainSpecs = []*interchaintest.ChainSpec{ // -- ETH -- - {ChainConfig: ethereum.DefaultEthereumAnvilChainConfig("ethereum")}, + {ChainConfig: foundry.DefaultEthereumAnvilChainConfig("ethereum")}, // -- IBC-Go -- { ChainConfig: ibc.ChainConfig{ diff --git a/e2e/interchaintestv8/e2esuite/suite.go b/e2e/interchaintestv8/e2esuite/suite.go index 973c66f..f56814f 100644 --- a/e2e/interchaintestv8/e2esuite/suite.go +++ b/e2e/interchaintestv8/e2esuite/suite.go @@ -12,7 +12,7 @@ import ( interchaintest "github.com/strangelove-ventures/interchaintest/v8" "github.com/strangelove-ventures/interchaintest/v8/chain/cosmos" - "github.com/strangelove-ventures/interchaintest/v8/chain/ethereum" + "github.com/strangelove-ventures/interchaintest/v8/chain/ethereum/foundry" "github.com/strangelove-ventures/interchaintest/v8/ibc" "github.com/strangelove-ventures/interchaintest/v8/testreporter" @@ -24,7 +24,7 @@ import ( type TestSuite struct { suite.Suite - ChainA *ethereum.EthereumChain + ChainA *foundry.AnvilChain ChainB *cosmos.CosmosChain UserA ibc.Wallet UserB ibc.Wallet @@ -37,6 +37,7 @@ type TestSuite struct { // SetupSuite sets up the chains, relayer, user accounts, clients, and connections func (s *TestSuite) SetupSuite(ctx context.Context) { chainSpecs := chainconfig.DefaultChainSpecs + chainSpecs[0].AdditionalStartArgs = append(chainSpecs[0].AdditionalStartArgs, "--steps-tracing") if len(chainSpecs) != 2 { panic("TestSuite requires exactly 2 chain specs") @@ -51,7 +52,7 @@ func (s *TestSuite) SetupSuite(ctx context.Context) { chains, err := cf.Chains(t.Name()) s.Require().NoError(err) - s.ChainA = chains[0].(*ethereum.EthereumChain) + s.ChainA = chains[0].(*foundry.AnvilChain) s.ChainB = chains[1].(*cosmos.CosmosChain) s.ExecRep = testreporter.NewNopReporter().RelayerExecReporter(t) diff --git a/e2e/interchaintestv8/e2esuite/utils.go b/e2e/interchaintestv8/e2esuite/utils.go index 1d68741..0a18e13 100644 --- a/e2e/interchaintestv8/e2esuite/utils.go +++ b/e2e/interchaintestv8/e2esuite/utils.go @@ -3,6 +3,8 @@ package e2esuite import ( "context" "crypto/ecdsa" + "encoding/base64" + "encoding/json" "fmt" "math/big" "regexp" @@ -18,8 +20,18 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/tx" + "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cometbft/cometbft/crypto/tmhash" + cometproto "github.com/cometbft/cometbft/proto/tendermint/types" + comettypes "github.com/cometbft/cometbft/types" + comettime "github.com/cometbft/cometbft/types/time" + + tmclient "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint" + ibctesting "github.com/cosmos/ibc-go/v8/testing" + ibcmocks "github.com/cosmos/ibc-go/v8/testing/mock" + "github.com/strangelove-ventures/interchaintest/v8/chain/cosmos" "github.com/strangelove-ventures/interchaintest/v8/chain/ethereum" "github.com/strangelove-ventures/interchaintest/v8/ibc" @@ -133,6 +145,132 @@ func (s *TestSuite) GetTxReciept(ctx context.Context, chain *ethereum.EthereumCh return receipt != nil, nil }) + + // TODO: This should check if the tx was actually successful and return a bool or err on that basis + s.Require().NoError(err) return receipt } + +// CreateTMClientHeader creates a new tendermint client header for the given chain, block height, and timestamp. +// It uses the given oldHeader as a base to create the new header with a new hash, and sign using the existing validators +// It can be used to for instance test misbehaviour +// Partially based on https://github.com/cosmos/relayer/blob/f9aaf3dd0ebfe99fbe98d190a145861d7df93804/interchaintest/misbehaviour_test.go#L38 +func (s *TestSuite) CreateTMClientHeader( + ctx context.Context, + chain *cosmos.CosmosChain, + blockHeight int64, + timestamp time.Time, + oldHeader tmclient.Header, +) tmclient.Header { + var privVals []comettypes.PrivValidator + var validators []*comettypes.Validator + for _, chainVal := range chain.Validators { + keyBz, err := chainVal.ReadFile(ctx, "config/priv_validator_key.json") + s.Require().NoError(err) + var privValidatorKeyFile cosmos.PrivValidatorKeyFile + err = json.Unmarshal(keyBz, &privValidatorKeyFile) + s.Require().NoError(err) + decodedKeyBz, err := base64.StdEncoding.DecodeString(privValidatorKeyFile.PrivKey.Value) + s.Require().NoError(err) + + privKey := &ed25519.PrivKey{ + Key: decodedKeyBz, + } + + privVal := ibcmocks.PV{PrivKey: privKey} + privVals = append(privVals, privVal) + + pubKey, err := privVal.GetPubKey() + s.Require().NoError(err) + + val := comettypes.NewValidator(pubKey, oldHeader.ValidatorSet.Proposer.VotingPower) + validators = append(validators, val) + + } + + valSet := comettypes.NewValidatorSet(validators) + vsetHash := valSet.Hash() + + // Make sure all the signers are in the correct order as expected by the validator set + signers := make([]comettypes.PrivValidator, valSet.Size()) + for i := range signers { + _, val := valSet.GetByIndex(int32(i)) + + for _, pv := range privVals { + pk, err := pv.GetPubKey() + s.Require().NoError(err) + + if pk.Equals(val.PubKey) { + signers[i] = pv + break + } + } + + if signers[i] == nil { + s.Require().FailNow("could not find signer for validator") + } + } + + tmHeader := comettypes.Header{ + Version: oldHeader.Header.Version, + ChainID: oldHeader.Header.ChainID, + Height: blockHeight, + Time: timestamp, + LastBlockID: ibctesting.MakeBlockID(make([]byte, tmhash.Size), 10_000, make([]byte, tmhash.Size)), + LastCommitHash: oldHeader.Header.LastCommitHash, + DataHash: tmhash.Sum([]byte("data_hash")), + ValidatorsHash: vsetHash, + NextValidatorsHash: vsetHash, + ConsensusHash: tmhash.Sum([]byte("consensus_hash")), + AppHash: tmhash.Sum([]byte("app_hash")), + LastResultsHash: tmhash.Sum([]byte("last_results_hash")), + EvidenceHash: tmhash.Sum([]byte("evidence_hash")), + ProposerAddress: valSet.Proposer.Address, + } + + hhash := tmHeader.Hash() + blockID := ibctesting.MakeBlockID(hhash, oldHeader.Commit.BlockID.PartSetHeader.Total, tmhash.Sum([]byte("part_set"))) + voteSet := comettypes.NewVoteSet(oldHeader.Header.ChainID, blockHeight, 1, cometproto.PrecommitType, valSet) + + voteProto := &comettypes.Vote{ + ValidatorAddress: nil, + ValidatorIndex: -1, + Height: blockHeight, + Round: 1, + Timestamp: comettime.Now(), + Type: cometproto.PrecommitType, + BlockID: blockID, + } + + for i, sign := range signers { + pv, err := sign.GetPubKey() + s.Require().NoError(err) + addr := pv.Address() + vote := voteProto.Copy() + vote.ValidatorAddress = addr + vote.ValidatorIndex = int32(i) + _, err = comettypes.SignAndCheckVote(vote, sign, oldHeader.Header.ChainID, false) + s.Require().NoError(err) + added, err := voteSet.AddVote(vote) + s.Require().NoError(err) + s.Require().True(added) + } + extCommit := voteSet.MakeExtendedCommit(comettypes.DefaultABCIParams()) + commit := extCommit.ToCommit() + + signedHeader := &cometproto.SignedHeader{ + Header: tmHeader.ToProto(), + Commit: commit.ToProto(), + } + + valSetProto, err := valSet.ToProto() + s.Require().NoError(err) + + return tmclient.Header{ + SignedHeader: signedHeader, + ValidatorSet: valSetProto, + TrustedHeight: oldHeader.TrustedHeight, + TrustedValidators: oldHeader.TrustedValidators, + } +} diff --git a/e2e/interchaintestv8/go.mod b/e2e/interchaintestv8/go.mod index decac5d..6673cbd 100644 --- a/e2e/interchaintestv8/go.mod +++ b/e2e/interchaintestv8/go.mod @@ -8,24 +8,24 @@ require ( cosmossdk.io/api v0.7.5 cosmossdk.io/math v1.3.0 cosmossdk.io/x/tx v0.13.3 - cosmossdk.io/x/upgrade v0.1.2 + cosmossdk.io/x/upgrade v0.1.3 github.com/CosmWasm/wasmd v0.50.0 - github.com/cosmos/cosmos-sdk v0.50.7 - github.com/cosmos/gogoproto v1.4.12 + github.com/cosmos/cosmos-sdk v0.50.8 + github.com/cosmos/gogoproto v1.5.0 github.com/cosmos/ibc-go/v8 v8.4.0 github.com/docker/docker v24.0.9+incompatible github.com/ethereum/go-ethereum v1.14.6 - github.com/strangelove-ventures/interchaintest/v8 v8.3.0 + github.com/strangelove-ventures/interchaintest/v8 v8.7.0 github.com/stretchr/testify v1.9.0 go.uber.org/zap v1.27.0 - google.golang.org/grpc v1.64.0 + google.golang.org/grpc v1.65.0 google.golang.org/protobuf v1.34.1 ) require ( cloud.google.com/go v0.112.1 // indirect cloud.google.com/go/compute v1.25.1 // indirect - cloud.google.com/go/compute/metadata v0.2.3 // indirect + cloud.google.com/go/compute/metadata v0.3.0 // indirect cloud.google.com/go/iam v1.1.6 // indirect cloud.google.com/go/storage v1.38.0 // indirect cosmossdk.io/client/v2 v2.0.0-beta.1 // indirect @@ -41,7 +41,7 @@ require ( filippo.io/edwards25519 v1.0.0 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect github.com/99designs/keyring v1.2.2 // indirect - github.com/BurntSushi/toml v1.3.2 // indirect + github.com/BurntSushi/toml v1.4.0 // indirect github.com/ChainSafe/go-schnorrkel v1.0.0 // indirect github.com/ChainSafe/go-schnorrkel/1 v0.0.0-00010101000000-000000000000 // indirect github.com/ComposableFi/go-subkey/v2 v2.0.0-tm03420 // indirect @@ -71,7 +71,7 @@ require ( github.com/cockroachdb/pebble v1.1.1 // indirect github.com/cockroachdb/redact v1.1.5 // indirect github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect - github.com/cometbft/cometbft v0.38.7 // indirect + github.com/cometbft/cometbft v0.38.10 // indirect github.com/cometbft/cometbft-db v0.10.0 // indirect github.com/consensys/bavard v0.1.13 // indirect github.com/consensys/gnark-crypto v0.12.1 // indirect @@ -119,7 +119,7 @@ require ( github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect github.com/gogo/googleapis v1.4.1 // indirect github.com/gogo/protobuf v1.3.3 // indirect - github.com/golang/glog v1.2.0 // indirect + github.com/golang/glog v1.2.1 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/mock v1.6.0 // indirect github.com/golang/protobuf v1.5.4 // indirect @@ -141,13 +141,13 @@ require ( github.com/gtank/merlin v0.1.1 // indirect github.com/gtank/ristretto255 v0.1.2 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect - github.com/hashicorp/go-getter v1.7.3 // indirect + github.com/hashicorp/go-getter v1.7.4 // indirect github.com/hashicorp/go-hclog v1.5.0 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect github.com/hashicorp/go-metrics v0.5.3 // indirect github.com/hashicorp/go-plugin v1.5.2 // indirect github.com/hashicorp/go-safetemp v1.0.0 // indirect - github.com/hashicorp/go-version v1.6.0 // indirect + github.com/hashicorp/go-version v1.7.0 // indirect github.com/hashicorp/golang-lru v1.0.2 // indirect github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect github.com/hashicorp/hcl v1.0.0 // indirect @@ -163,7 +163,7 @@ require ( github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/jmhodges/levigo v1.0.0 // indirect github.com/klauspost/compress v1.17.7 // indirect - github.com/klauspost/cpuid/v2 v2.2.5 // indirect + github.com/klauspost/cpuid/v2 v2.2.7 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect github.com/lib/pq v1.10.7 // indirect @@ -177,7 +177,7 @@ require ( github.com/mimoo/StrobeGo v0.0.0-20220103164710-9a04d6ca976b // indirect github.com/minio/highwayhash v1.0.2 // indirect github.com/minio/sha256-simd v1.0.1 // indirect - github.com/misko9/go-substrate-rpc-client/v4 v4.0.0-20230913220906-b988ea7da0c2 // indirect + github.com/misko9/go-substrate-rpc-client/v4 v4.0.0-20240603204351-26b456ae3afe // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/go-testing-interface v1.14.1 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect @@ -198,7 +198,7 @@ require ( github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.0-rc2 // indirect github.com/pelletier/go-toml v1.9.5 // indirect - github.com/pelletier/go-toml/v2 v2.2.0 // indirect + github.com/pelletier/go-toml/v2 v2.2.2 // indirect github.com/petermattis/goid v0.0.0-20231207134359-e60b3f734c67 // indirect github.com/pierrec/xxHash v0.1.5 // indirect github.com/pkg/errors v0.9.1 // indirect @@ -228,6 +228,9 @@ require ( github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect github.com/tendermint/go-amino v0.16.0 // indirect github.com/tidwall/btree v1.7.0 // indirect + github.com/tidwall/gjson v1.17.1 // indirect + github.com/tidwall/match v1.1.1 // indirect + github.com/tidwall/pretty v1.2.0 // indirect github.com/tklauser/go-sysconf v0.3.12 // indirect github.com/tklauser/numcpus v0.6.1 // indirect github.com/tyler-smith/go-bip32 v1.0.0 // indirect @@ -243,22 +246,22 @@ require ( go.opentelemetry.io/otel/metric v1.24.0 // indirect go.opentelemetry.io/otel/trace v1.24.0 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/crypto v0.22.0 // indirect + golang.org/x/crypto v0.24.0 // indirect golang.org/x/exp v0.0.0-20240404231335-c0f41cb1a7a0 // indirect - golang.org/x/mod v0.17.0 // indirect - golang.org/x/net v0.24.0 // indirect - golang.org/x/oauth2 v0.18.0 // indirect + golang.org/x/mod v0.18.0 // indirect + golang.org/x/net v0.26.0 // indirect + golang.org/x/oauth2 v0.20.0 // indirect golang.org/x/sync v0.7.0 // indirect - golang.org/x/sys v0.20.0 // indirect - golang.org/x/term v0.19.0 // indirect - golang.org/x/text v0.14.0 // indirect + golang.org/x/sys v0.21.0 // indirect + golang.org/x/term v0.21.0 // indirect + golang.org/x/text v0.16.0 // indirect golang.org/x/time v0.5.0 // indirect - golang.org/x/tools v0.20.0 // indirect + golang.org/x/tools v0.22.0 // indirect google.golang.org/api v0.169.0 // indirect google.golang.org/appengine v1.6.8 // indirect google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect gopkg.in/yaml.v2 v2.4.0 // indirect @@ -266,10 +269,10 @@ require ( gotest.tools/v3 v3.5.1 // indirect lukechampine.com/blake3 v1.2.1 // indirect modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 // indirect - modernc.org/libc v1.41.0 // indirect + modernc.org/libc v1.52.1 // indirect modernc.org/mathutil v1.6.0 // indirect - modernc.org/memory v1.7.2 // indirect - modernc.org/sqlite v1.29.5 // indirect + modernc.org/memory v1.8.0 // indirect + modernc.org/sqlite v1.30.1 // indirect modernc.org/strutil v1.2.0 // indirect modernc.org/token v1.1.0 // indirect nhooyr.io/websocket v1.8.7 // indirect diff --git a/e2e/interchaintestv8/go.sum b/e2e/interchaintestv8/go.sum index 7874d6c..bff6797 100644 --- a/e2e/interchaintestv8/go.sum +++ b/e2e/interchaintestv8/go.sum @@ -72,6 +72,8 @@ cloud.google.com/go/compute v1.25.1 h1:ZRpHJedLtTpKgr3RV1Fx23NuaAEN1Zfx9hw1u4aJd cloud.google.com/go/compute v1.25.1/go.mod h1:oopOIR53ly6viBYxaDhBfJwzUAxf1zE//uf3IB011ls= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc= +cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= cloud.google.com/go/containeranalysis v0.5.1/go.mod h1:1D92jd8gRR/c0fGMlymRgxWD3Qw9C1ff6/T7mLgVL8I= cloud.google.com/go/containeranalysis v0.6.0/go.mod h1:HEJoiEIu+lEXM+k7+qLCci0h33lX3ZqoYFdmPcoO7s4= cloud.google.com/go/datacatalog v1.3.0/go.mod h1:g9svFY6tuR+j+hrTw3J2dNcmI0dzmSiyOzm8kpLq0a0= @@ -212,6 +214,8 @@ cosmossdk.io/x/tx v0.13.3 h1:Ha4mNaHmxBc6RMun9aKuqul8yHiL78EKJQ8g23Zf73g= cosmossdk.io/x/tx v0.13.3/go.mod h1:I8xaHv0rhUdIvIdptKIqzYy27+n2+zBVaxO6fscFhys= cosmossdk.io/x/upgrade v0.1.2 h1:O2FGb0mVSXl7P6BQm9uV3hRVKom1zBLDGhd4G8jysJg= cosmossdk.io/x/upgrade v0.1.2/go.mod h1:P+e4/ZNd8km7lTAX5hC2pXz/042YDcB7gzKTHuY53nc= +cosmossdk.io/x/upgrade v0.1.3 h1:q4XpXc6zp0dX6x74uBtfN6+J7ikaQev5Bla6Q0ADLK8= +cosmossdk.io/x/upgrade v0.1.3/go.mod h1:jOdQhnaY5B8CDUoUbed23/Lre0Dk+r6BMQE40iKlVVQ= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= filippo.io/edwards25519 v1.0.0 h1:0wAIcmJUqRdI8IJ/3eGi5/HwXZWPujYXXlkrQogz0Ek= filippo.io/edwards25519 v1.0.0/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= @@ -224,6 +228,8 @@ github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg6 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0= +github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d h1:nalkkPQcITbvhmL4+C4cKA87NW0tfm3Kl9VXRoPywFg= github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d/go.mod h1:URdX5+vg25ts3aCh8H5IFZybJYKWhJHYMTnf+ULtoC4= @@ -365,6 +371,8 @@ github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1: github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= github.com/cometbft/cometbft v0.38.7 h1:ULhIOJ9+LgSy6nLekhq9ae3juX3NnQUMMPyVdhZV6Hk= github.com/cometbft/cometbft v0.38.7/go.mod h1:HIyf811dFMI73IE0F7RrnY/Fr+d1+HuJAgtkEpQjCMY= +github.com/cometbft/cometbft v0.38.10 h1:2ePuglchT+j0Iao+cfmt/nw5U7K2lnGDzXSUPGVdXaU= +github.com/cometbft/cometbft v0.38.10/go.mod h1:jHPx9vQpWzPHEAiYI/7EDKaB1NXhK6o3SArrrY8ExKc= github.com/cometbft/cometbft-db v0.10.0 h1:VMBQh88zXn64jXVvj39tlu/IgsGR84T7ImjS523DCiU= github.com/cometbft/cometbft-db v0.10.0/go.mod h1:7RR7NRv99j7keWJ5IkE9iZibUTKYdtepXTp7Ra0FxKk= github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ= @@ -387,6 +395,8 @@ github.com/cosmos/cosmos-proto v1.0.0-beta.5 h1:eNcayDLpip+zVLRLYafhzLvQlSmyab+R github.com/cosmos/cosmos-proto v1.0.0-beta.5/go.mod h1:hQGLpiIUloJBMdQMMWb/4wRApmI9hjHH05nefC0Ojec= github.com/cosmos/cosmos-sdk v0.50.7 h1:LsBGKxifENR/DN4E1RZaitsyL93HU44x0p8EnMHp4V4= github.com/cosmos/cosmos-sdk v0.50.7/go.mod h1:84xDDJEHttRT7NDGwBaUOLVOMN0JNE9x7NbsYIxXs1s= +github.com/cosmos/cosmos-sdk v0.50.8 h1:2UJHssUaGHTl4/dFp8xyREKAnfiRU6VVfqtKG9n8w5g= +github.com/cosmos/cosmos-sdk v0.50.8/go.mod h1:Zb+DgHtiByNwgj71IlJBXwOq6dLhtyAq3AgqpXm/jHo= github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y= github.com/cosmos/go-bip39 v1.0.0 h1:pcomnQdrdH22njcAatO0yWojsUnCO3y2tNoV1cb6hHY= github.com/cosmos/go-bip39 v1.0.0/go.mod h1:RNJv0H/pOIVgxw6KS7QeX2a0Uo0aKUlfhZ4xuwvCdJw= @@ -395,6 +405,8 @@ github.com/cosmos/gogogateway v1.2.0/go.mod h1:iQpLkGWxYcnCdz5iAdLcRBSw3h7NXeOkZ github.com/cosmos/gogoproto v1.4.2/go.mod h1:cLxOsn1ljAHSV527CHOtaIP91kK6cCrZETRBrkzItWU= github.com/cosmos/gogoproto v1.4.12 h1:vB6Lbe/rtnYGjQuFxkPiPYiCybqFT8QvLipDZP8JpFE= github.com/cosmos/gogoproto v1.4.12/go.mod h1:LnZob1bXRdUoqMMtwYlcR3wjiElmlC+FkjaZRv1/eLY= +github.com/cosmos/gogoproto v1.5.0 h1:SDVwzEqZDDBoslaeZg+dGE55hdzHfgUA40pEanMh52o= +github.com/cosmos/gogoproto v1.5.0/go.mod h1:iUM31aofn3ymidYG6bUR5ZFrk+Om8p5s754eMUcyp8I= github.com/cosmos/iavl v1.1.2 h1:zL9FK7C4L/P4IF1Dm5fIwz0WXCnn7Bp1M2FxH0ayM7Y= github.com/cosmos/iavl v1.1.2/go.mod h1:jLeUvm6bGT1YutCaL2fIar/8vGUE8cPZvh/gXEWDaDM= github.com/cosmos/ibc-go/modules/capability v1.0.0 h1:r/l++byFtn7jHYa09zlAdSeevo8ci1mVZNO9+V0xsLE= @@ -580,6 +592,8 @@ github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v1.2.0 h1:uCdmnmatrKCgMBlM4rMuJZWOkPDqdbZPnrMXDY4gI68= github.com/golang/glog v1.2.0/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= +github.com/golang/glog v1.2.1 h1:OptwRhECazUx5ix5TTWC3EZhsZEHWcYWY4FQHTIubm4= +github.com/golang/glog v1.2.1/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -735,6 +749,8 @@ github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9n github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-getter v1.7.3 h1:bN2+Fw9XPFvOCjB0UOevFIMICZ7G2XSQHzfvLUyOM5E= github.com/hashicorp/go-getter v1.7.3/go.mod h1:W7TalhMmbPmsSMdNjD0ZskARur/9GJ17cfHTRtXV744= +github.com/hashicorp/go-getter v1.7.4 h1:3yQjWuxICvSpYwqSayAdKRFcvBl1y/vogCxczWSmix0= +github.com/hashicorp/go-getter v1.7.4/go.mod h1:W7TalhMmbPmsSMdNjD0ZskARur/9GJ17cfHTRtXV744= github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= @@ -759,6 +775,8 @@ github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/b github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= +github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= @@ -839,6 +857,8 @@ github.com/klauspost/compress v1.17.7 h1:ehO88t2UGzQK66LMdE8tibEd1ErmzZjNEqWkjLA github.com/klauspost/compress v1.17.7/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= +github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= @@ -902,6 +922,8 @@ github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dz github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= github.com/misko9/go-substrate-rpc-client/v4 v4.0.0-20230913220906-b988ea7da0c2 h1:G/cVeTAbB9S/6FSWWqpFV0v49hiuHLbJPu9hTZ0UR2A= github.com/misko9/go-substrate-rpc-client/v4 v4.0.0-20230913220906-b988ea7da0c2/go.mod h1:Q5BxOd9FxJqYp4vCiLGVdetecPcWTmUQIu0bRigYosU= +github.com/misko9/go-substrate-rpc-client/v4 v4.0.0-20240603204351-26b456ae3afe h1:0fcCSfvBgbagEsEMkZuxgA3Ex7IN9i1Hon0fwgMLpQw= +github.com/misko9/go-substrate-rpc-client/v4 v4.0.0-20240603204351-26b456ae3afe/go.mod h1:Q5BxOd9FxJqYp4vCiLGVdetecPcWTmUQIu0bRigYosU= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= @@ -1015,6 +1037,8 @@ github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3v github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml/v2 v2.2.0 h1:QLgLl2yMN7N+ruc31VynXs1vhMZa7CeHHejIeBAsoHo= github.com/pelletier/go-toml/v2 v2.2.0/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= +github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= +github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o= github.com/petermattis/goid v0.0.0-20231207134359-e60b3f734c67 h1:jik8PHtAIsPlCRJjJzl4udgEf7hawInF9texMeO2jrU= @@ -1142,6 +1166,8 @@ github.com/status-im/keycard-go v0.2.0 h1:QDLFswOQu1r5jsycloeQh3bVU8n/NatHHaZobt github.com/status-im/keycard-go v0.2.0/go.mod h1:wlp8ZLbsmrF6g6WjugPAx+IzoLrkdf9+mHxBEeo3Hbg= github.com/strangelove-ventures/interchaintest/v8 v8.3.0 h1:1XyATc0JkvzDhBS71CdpM5z1t6bmO9PgH/5/nffoM9Q= github.com/strangelove-ventures/interchaintest/v8 v8.3.0/go.mod h1:5goHQtgWO9khoUO/SfR//w3uaw/uYVriDR1OY6PyydM= +github.com/strangelove-ventures/interchaintest/v8 v8.7.0 h1:MAs3mCLQUHJELUa4nm+ZKkKMKQUV34icHUdlt2QVpfc= +github.com/strangelove-ventures/interchaintest/v8 v8.7.0/go.mod h1:d20jXQmPAzE4U9zop+nkMPk40l21CJzi/ZqwrgAixwU= github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= @@ -1175,6 +1201,12 @@ github.com/tendermint/go-amino v0.16.0 h1:GyhmgQKvqF82e2oZeuMSp9JTN0N09emoSZlb2l github.com/tendermint/go-amino v0.16.0/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoMC9Sphe2ZwGME= github.com/tidwall/btree v1.7.0 h1:L1fkJH/AuEh5zBnnBbmTwQ5Lt+bRJ5A8EWecslvo9iI= github.com/tidwall/btree v1.7.0/go.mod h1:twD9XRA5jj9VUQGELzDO4HPQTNJsoWWfYEL+EUQ2cKY= +github.com/tidwall/gjson v1.17.1 h1:wlYEnwqAHgzmhNUFfw7Xalt2JzQvsMx2Se4PcoFCT/U= +github.com/tidwall/gjson v1.17.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= +github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= +github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= +github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= @@ -1276,6 +1308,8 @@ golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= +golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= +golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -1317,6 +1351,8 @@ golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0= +golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1378,6 +1414,8 @@ golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfS golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= +golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= +golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1405,6 +1443,8 @@ golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri golang.org/x/oauth2 v0.1.0/go.mod h1:G9FE4dLTsbXUu90h/Pf85g4w1D+SSAgR+q46nJZ8M4A= golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI= golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8= +golang.org/x/oauth2 v0.20.0 h1:4mQdhULixXKP1rwYBW0vAijoXnkTG0BLCDRzfe1idMo= +golang.org/x/oauth2 v0.20.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1524,11 +1564,15 @@ golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= +golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q= golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= +golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA= +golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1542,6 +1586,8 @@ golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1610,6 +1656,8 @@ golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY= golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg= +golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA= +golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1792,8 +1840,12 @@ google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de h1:F6qOa9AZTYJXOUE google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:VUhTRKeHn9wwcdrk73nvdC9gF178Tzhmt/qyaFcPLSo= google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237 h1:RFiFrvy37/mpSpdySBDrUdipW/dHwsRwh3J3+A9VgT4= google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237/go.mod h1:Z5Iiy3jtmioajWHDGFk7CeugTyHtPvMHA4UTmUkyalE= +google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157 h1:7whR9kGa5LUwFtpLm2ArCEejtnxlGeLbAyjFY8sGNFw= +google.golang.org/genproto/googleapis/api v0.0.0-20240528184218-531527333157/go.mod h1:99sLkeliLXfdj2J75X3Ho+rrVCaJze0uwN7zDDkjPVU= google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda h1:LI5DOvAxUPMv/50agcLLoo+AdWc1irS9Rzz4vPuD1V4= google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157 h1:Zy9XzmMEflZ/MAaA7vNcoebnRAld7FsPW1EeBB7V0m8= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240528184218-531527333157/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= @@ -1837,6 +1889,8 @@ google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCD google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY= google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg= +google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= +google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= @@ -1911,12 +1965,18 @@ modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 h1:5D53IMaUuA5InSeMu9eJtlQX modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4= modernc.org/libc v1.41.0 h1:g9YAc6BkKlgORsUWj+JwqoB1wU3o4DE3bM3yvA3k+Gk= modernc.org/libc v1.41.0/go.mod h1:w0eszPsiXoOnoMJgrXjglgLuDy/bt5RR4y3QzUUeodY= +modernc.org/libc v1.52.1 h1:uau0VoiT5hnR+SpoWekCKbLqm7v6dhRL3hI+NQhgN3M= +modernc.org/libc v1.52.1/go.mod h1:HR4nVzFDSDizP620zcMCgjb1/8xk2lg5p/8yjfGv1IQ= modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4= modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo= modernc.org/memory v1.7.2 h1:Klh90S215mmH8c9gO98QxQFsY+W451E8AnzjoE2ee1E= modernc.org/memory v1.7.2/go.mod h1:NO4NVCQy0N7ln+T9ngWqOQfi7ley4vpwvARR+Hjw95E= +modernc.org/memory v1.8.0 h1:IqGTL6eFMaDZZhEWwcREgeMXYwmW83LYW8cROZYkg+E= +modernc.org/memory v1.8.0/go.mod h1:XPZ936zp5OMKGWPqbD3JShgd/ZoQ7899TUuQqxY+peU= modernc.org/sqlite v1.29.5 h1:8l/SQKAjDtZFo9lkJLdk8g9JEOeYRG4/ghStDCCTiTE= modernc.org/sqlite v1.29.5/go.mod h1:S02dvcmm7TnTRvGhv8IGYyLnIt7AS2KPaB1F/71p75U= +modernc.org/sqlite v1.30.1 h1:YFhPVfu2iIgUf9kuA1CR7iiHdcEEsI2i+yjRYHscyxk= +modernc.org/sqlite v1.30.1/go.mod h1:DUmsiWQDaAvU4abhc/N+djlom/L2o8f7gZ95RCvyoLU= modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA= modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0= modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= diff --git a/e2e/interchaintestv8/operator/operator.go b/e2e/interchaintestv8/operator/operator.go index 5246653..deb35df 100644 --- a/e2e/interchaintestv8/operator/operator.go +++ b/e2e/interchaintestv8/operator/operator.go @@ -1,9 +1,11 @@ package operator import ( + "encoding/base64" "encoding/hex" "encoding/json" "errors" + "fmt" "os" "os/exec" "strconv" @@ -11,17 +13,36 @@ import ( abi "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/cosmos/cosmos-sdk/codec" + + tmclient "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint" + "github.com/srdtrk/sp1-ics07-tendermint/e2e/v8/types/sp1ics07tendermint" ) +type GenesisFixture struct { + TrustedClientState string `json:"trustedClientState"` + TrustedConsensusState string `json:"trustedConsensusState"` + UpdateClientVkey string `json:"updateClientVkey"` + MembershipVkey string `json:"membershipVkey"` + UcAndMembershipVkey string `json:"ucAndMembershipVkey"` + MisbehaviourVKey string `json:"misbehaviourVKey"` +} + // membershipFixture is a struct that contains the membership proof and proof height type membershipFixture struct { + GenesisFixture // hex encoded height ProofHeight string `json:"proofHeight"` // hex encoded proof MembershipProof string `json:"membershipProof"` } +type misbehaviourFixture struct { + GenesisFixture + SubmitMsg string `json:"submitMsg"` +} + // RunGenesis is a function that runs the genesis script to generate genesis.json func RunGenesis(args ...string) error { args = append([]string{"genesis"}, args...) @@ -42,23 +63,20 @@ func StartOperator(args ...string) error { func UpdateClientAndMembershipProof(trusted_height, target_height uint64, paths string, args ...string) (*sp1ics07tendermint.IICS02ClientMsgsHeight, []byte, error) { args = append([]string{"fixtures", "update-client-and-membership", "--trusted-block", strconv.FormatUint(trusted_height, 10), "--target-block", strconv.FormatUint(target_height, 10), "--key-paths", paths}, args...) - stdout, err := exec.Command("target/release/operator", args...).Output() + output, err := exec.Command("target/release/operator", args...).CombinedOutput() if err != nil { return nil, nil, err } - // NOTE: writing stdout to os.Stdout after execution due to how `.Output()` works - os.Stdout.Write(stdout) - // eliminate non-json characters - jsonStartIdx := strings.Index(string(stdout), "{") + jsonStartIdx := strings.Index(string(output), "{") if jsonStartIdx == -1 { panic("no json found in output") } - stdout = stdout[jsonStartIdx:] + output = output[jsonStartIdx:] var membership membershipFixture - err = json.Unmarshal(stdout, &membership) + err = json.Unmarshal(output, &membership) if err != nil { return nil, nil, err } @@ -99,3 +117,179 @@ func UpdateClientAndMembershipProof(trusted_height, target_height uint64, paths return height, proofBz, nil } + +// MisbehaviourProof is a function that generates a misbehaviour proof and returns the submit message +func MisbehaviourProof(cdc codec.Codec, misbehaviour tmclient.Misbehaviour, writeFixtureName string, args ...string) ([]byte, error) { + misbehaviourBz, err := marshalMisbehaviour(cdc, misbehaviour) + if err != nil { + return nil, err + } + + // write misbehaviour to file for the operator to use + misbehaviourFileName := "misbehaviour.json" + if err := os.WriteFile(misbehaviourFileName, misbehaviourBz, 0o600); err != nil { + return nil, err + } + defer os.Remove(misbehaviourFileName) + + args = append([]string{"fixtures", "misbehaviour", "--misbehaviour-path", misbehaviourFileName}, args...) + output, err := exec.Command("target/release/operator", args...).CombinedOutput() + if err != nil { + return nil, fmt.Errorf("operator misbehaviour failed: %w, output: %s", err, output) + } + + // eliminate non-json characters + jsonStartIdx := strings.Index(string(output), "{") + if jsonStartIdx == -1 { + panic("no json found in output") + } + output = output[jsonStartIdx:] + + var misbehaviourFixture misbehaviourFixture + err = json.Unmarshal(output, &misbehaviourFixture) + if err != nil { + return nil, err + } + + if writeFixtureName != "" { + fixtureFileName := fmt.Sprintf("contracts/fixtures/misbehaviour_%s_fixture.json", writeFixtureName) + if err := os.WriteFile(fixtureFileName, output, 0o600); err != nil { + return nil, err + } + } + + submitMsgBz, err := hex.DecodeString(misbehaviourFixture.SubmitMsg) + if err != nil { + return nil, err + } + + return submitMsgBz, nil +} + +// TODO: This is a mighty ugly piece of code. Hopefully there is a better way to do this. +// marshalMisbehaviour takes a MisbehaviourProof struct and marshals it into a JSON byte slice that can be unmarshalled by the operator. +// It first marshals to JSON directly, and then modifies all the incompatible types (mostly base64 encoded bytes) to be hex encoded. +// Ideally, we can update the types in the operator to be more compatible with the type we have here. +// It might be enough to get out a new version of the rust crate "ibc-proto" and update the operator to use it. +func marshalMisbehaviour(cdc codec.Codec, misbehaviour tmclient.Misbehaviour) ([]byte, error) { + misbehaviour.ClientId = "07-tendermint-0" // We just have to set it to something to make the unmarshalling to work :P + bzIntermediary, err := cdc.MarshalJSON(&misbehaviour) + if err != nil { + return nil, err + } + var jsonIntermediary map[string]interface{} + if err := json.Unmarshal(bzIntermediary, &jsonIntermediary); err != nil { + return nil, err + } + headerHexPaths := []string{ + "validator_set.proposer.address", + "trusted_validators.proposer.address", + "signed_header.header.last_block_id.hash", + "signed_header.header.last_block_id.part_set_header.hash", + "signed_header.header.app_hash", + "signed_header.header.consensus_hash", + "signed_header.header.data_hash", + "signed_header.header.evidence_hash", + "signed_header.header.last_commit_hash", + "signed_header.header.last_results_hash", + "signed_header.header.next_validators_hash", + "signed_header.header.proposer_address", + "signed_header.header.validators_hash", + "signed_header.commit.block_id.hash", + "signed_header.commit.block_id.part_set_header.hash", + } + + var hexPaths []string + for _, path := range headerHexPaths { + hexPaths = append(hexPaths, "header_1."+path) + hexPaths = append(hexPaths, "header_2."+path) + } + + for _, path := range hexPaths { + pathParts := strings.Split(path, ".") + tmpIntermediary := jsonIntermediary + for i := 0; i < len(pathParts)-1; i++ { + var ok bool + tmpIntermediary, ok = tmpIntermediary[pathParts[i]].(map[string]interface{}) + if !ok { + fmt.Printf("path not found: %s\n", path) + continue + } + } + base64str, ok := tmpIntermediary[pathParts[len(pathParts)-1]].(string) + if !ok { + return nil, fmt.Errorf("path not found: %s", path) + } + bz, err := base64.StdEncoding.DecodeString(base64str) + if err != nil { + return nil, err + } + tmpIntermediary[pathParts[len(pathParts)-1]] = hex.EncodeToString(bz) + } + + validators1 := jsonIntermediary["header_1"].(map[string]interface{})["validator_set"].(map[string]interface{})["validators"].([]interface{}) + validators2 := jsonIntermediary["header_2"].(map[string]interface{})["validator_set"].(map[string]interface{})["validators"].([]interface{}) + trustedValidators1 := jsonIntermediary["header_1"].(map[string]interface{})["trusted_validators"].(map[string]interface{})["validators"].([]interface{}) + trustedValidators2 := jsonIntermediary["header_2"].(map[string]interface{})["trusted_validators"].(map[string]interface{})["validators"].([]interface{}) + validators := validators1 + validators = append(validators, validators2...) + validators = append(validators, trustedValidators1...) + validators = append(validators, trustedValidators2...) + for _, val := range validators { + val := val.(map[string]interface{}) + valAddressBase64Str, ok := val["address"].(string) + if !ok { + return nil, fmt.Errorf("address not found in path: %s", val) + } + valAddressBz, err := base64.StdEncoding.DecodeString(valAddressBase64Str) + if err != nil { + return nil, err + } + val["address"] = hex.EncodeToString(valAddressBz) + + pubKey, ok := val["pub_key"].(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("pub_key not found in path: %s", val) + } + ed25519PubKey := pubKey["ed25519"].(string) + pubKey["type"] = "tendermint/PubKeyEd25519" + pubKey["value"] = ed25519PubKey + } + + var pubKeys []map[string]interface{} + pubKeys = append(pubKeys, jsonIntermediary["header_1"].(map[string]interface{})["validator_set"].(map[string]interface{})["proposer"].(map[string]interface{})["pub_key"].(map[string]interface{})) + pubKeys = append(pubKeys, jsonIntermediary["header_1"].(map[string]interface{})["trusted_validators"].(map[string]interface{})["proposer"].(map[string]interface{})["pub_key"].(map[string]interface{})) + pubKeys = append(pubKeys, jsonIntermediary["header_2"].(map[string]interface{})["validator_set"].(map[string]interface{})["proposer"].(map[string]interface{})["pub_key"].(map[string]interface{})) + pubKeys = append(pubKeys, jsonIntermediary["header_2"].(map[string]interface{})["trusted_validators"].(map[string]interface{})["proposer"].(map[string]interface{})["pub_key"].(map[string]interface{})) + + for _, proposerPubKey := range pubKeys { + ed25519PubKey := proposerPubKey["ed25519"].(string) + proposerPubKey["type"] = "tendermint/PubKeyEd25519" + proposerPubKey["value"] = ed25519PubKey + } + + header1Sigs := jsonIntermediary["header_1"].(map[string]interface{})["signed_header"].(map[string]interface{})["commit"].(map[string]interface{})["signatures"].([]interface{}) + header2Sigs := jsonIntermediary["header_2"].(map[string]interface{})["signed_header"].(map[string]interface{})["commit"].(map[string]interface{})["signatures"].([]interface{}) + sigs := header1Sigs + sigs = append(sigs, header2Sigs...) + for _, sig := range sigs { + sig := sig.(map[string]interface{}) + if sig["block_id_flag"] == "BLOCK_ID_FLAG_COMMIT" { + sig["block_id_flag"] = 2 + } else { + return nil, fmt.Errorf("unexpected block_id_flag: %s", sig["block_id_flag"]) + } + + valAddressBase64Str, ok := sig["validator_address"].(string) + if !ok { + return nil, fmt.Errorf("validator_address not found") + } + valAddressBz, err := base64.StdEncoding.DecodeString(valAddressBase64Str) + if err != nil { + return nil, err + } + sig["validator_address"] = hex.EncodeToString(valAddressBz) + } + + return json.Marshal(jsonIntermediary) +} diff --git a/e2e/interchaintestv8/sp1_ics07_test.go b/e2e/interchaintestv8/sp1_ics07_test.go index 768ade2..25bc867 100644 --- a/e2e/interchaintestv8/sp1_ics07_test.go +++ b/e2e/interchaintestv8/sp1_ics07_test.go @@ -7,6 +7,7 @@ import ( "os" "strconv" "testing" + "time" "github.com/stretchr/testify/suite" @@ -15,11 +16,14 @@ import ( "github.com/ethereum/go-ethereum/ethclient" transfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" + ibcclientutils "github.com/cosmos/ibc-go/v8/modules/core/02-client/client/utils" + clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" ibchost "github.com/cosmos/ibc-go/v8/modules/core/24-host" ibcexported "github.com/cosmos/ibc-go/v8/modules/core/exported" + tmclient "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint" ibctesting "github.com/cosmos/ibc-go/v8/testing" - "github.com/strangelove-ventures/interchaintest/v8/chain/ethereum" + "github.com/strangelove-ventures/interchaintest/v8/chain/ethereum/foundry" "github.com/strangelove-ventures/interchaintest/v8/ibc" "github.com/strangelove-ventures/interchaintest/v8/testutil" @@ -34,6 +38,9 @@ import ( type SP1ICS07TendermintTestSuite struct { e2esuite.TestSuite + // Whether to generate fixtures for the solidity tests + generateFixtures bool + // The private key of a test account key *ecdsa.PrivateKey // The SP1ICS07Tendermint contract @@ -62,6 +69,9 @@ func (s *SP1ICS07TendermintTestSuite) SetupSuite(ctx context.Context) { os.Setenv(testvalues.EnvKeyTendermintRPC, simd.GetHostRPCAddress()) os.Setenv(testvalues.EnvKeySp1Prover, "network") os.Setenv(testvalues.EnvKeyPrivateKey, hexPrivateKey) + if os.Getenv(testvalues.EnvKeyGenerateFixtures) == testvalues.EnvValueGenerateFixtures_True { + s.generateFixtures = true + } // make sure that the SP1_PRIVATE_KEY is set. s.Require().NotEmpty(os.Getenv(testvalues.EnvKeySp1PrivateKey)) @@ -78,7 +88,7 @@ func (s *SP1ICS07TendermintTestSuite) SetupSuite(ctx context.Context) { "-o", "contracts/script/genesis.json", )) - stdout, _, err := eth.ForgeScript(ctx, s.UserA.KeyName(), ethereum.ForgeScriptOpts{ + stdout, _, err := eth.ForgeScript(ctx, s.UserA.KeyName(), foundry.ForgeScriptOpts{ ContractRootDir: ".", SolidityContract: "contracts/script/SP1ICS07Tendermint.s.sol", RawOptions: []string{"--json"}, @@ -138,6 +148,10 @@ func (s *SP1ICS07TendermintTestSuite) TestUpdateClient() { _, simd := s.ChainA, s.ChainB + if s.generateFixtures { + s.T().Log("Generate fixtures is set to true, but TestUpdateClient does not support it (yet)") + } + s.Require().True(s.Run("Update client", func() { clientState, err := s.contract.GetClientState(nil) s.Require().NoError(err) @@ -163,6 +177,7 @@ func (s *SP1ICS07TendermintTestSuite) TestUpdateClient() { })) } +// TestUpdateClientAndMembership tests the update client and membership functionality func (s *SP1ICS07TendermintTestSuite) TestUpdateClientAndMembership() { ctx := context.Background() @@ -170,6 +185,10 @@ func (s *SP1ICS07TendermintTestSuite) TestUpdateClientAndMembership() { eth, simd := s.ChainA, s.ChainB + if s.generateFixtures { + s.T().Log("Generate fixtures is set to true, but TestUpdateClientAndMembership does not support it (yet)") + } + s.Require().True(s.Run("Update and verify non-membership", func() { s.Require().NoError(testutil.WaitForBlocks(ctx, 5, simd)) @@ -203,7 +222,7 @@ func (s *SP1ICS07TendermintTestSuite) TestUpdateClientAndMembership() { s.Require().NoError(err) // wait until transaction is included in a block - _ = s.GetTxReciept(ctx, eth, tx.Hash()) + _ = s.GetTxReciept(ctx, eth.EthereumChain, tx.Hash()) clientState, err = s.contract.GetClientState(nil) s.Require().NoError(err) @@ -214,3 +233,160 @@ func (s *SP1ICS07TendermintTestSuite) TestUpdateClientAndMembership() { s.Require().False(clientState.IsFrozen) })) } + +// TestDoubleSignMisbehaviour tests the misbehaviour functionality +// Partially based on https://github.com/cosmos/relayer/blob/f9aaf3dd0ebfe99fbe98d190a145861d7df93804/interchaintest/misbehaviour_test.go#L38 +func (s *SP1ICS07TendermintTestSuite) TestDoubleSignMisbehaviour() { + ctx := context.Background() + + s.SetupSuite(ctx) + + eth, simd := s.ChainA, s.ChainB + _ = eth + + var height clienttypes.Height + var trustedHeader tmclient.Header + s.Require().True(s.Run("Get trusted header", func() { + var latestHeight int64 + var err error + trustedHeader, latestHeight, err = ibcclientutils.QueryTendermintHeader(simd.Validators[0].CliContext()) + s.Require().NoError(err) + s.Require().NotZero(latestHeight) + + height = clienttypes.NewHeight(clienttypes.ParseChainID(simd.Config().ChainID), uint64(latestHeight)) + + clientState, err := s.contract.GetClientState(nil) + s.Require().NoError(err) + trustedHeight := clienttypes.NewHeight(uint64(clientState.LatestHeight.RevisionNumber), uint64(clientState.LatestHeight.RevisionHeight)) + + trustedHeader.TrustedHeight = trustedHeight + trustedHeader.TrustedValidators = trustedHeader.ValidatorSet + })) + + s.Require().True(s.Run("Invalid misbehaviour", func() { + // Create a new valid header + newHeader := s.CreateTMClientHeader( + ctx, + simd, + int64(height.RevisionHeight+1), + trustedHeader.GetTime().Add(time.Minute), + trustedHeader, + ) + + invalidMisbehaviour := tmclient.Misbehaviour{ + Header1: &newHeader, + Header2: &trustedHeader, + } + + // The proof should fail because this is not misbehaviour (valid header for a new block) + _, err := operator.MisbehaviourProof(simd.GetCodec(), invalidMisbehaviour, "", + "--trust-level", testvalues.DefaultTrustLevel.String(), + "--trusting-period", strconv.Itoa(testvalues.DefaultTrustPeriod)) + s.Require().ErrorContains(err, "Misbehaviour is not detected") + })) + + s.Require().True(s.Run("Valid misbehaviour", func() { + // create a duplicate header (with a different hash) + newHeader := s.CreateTMClientHeader( + ctx, + simd, + int64(height.RevisionHeight), + trustedHeader.GetTime().Add(time.Minute), + trustedHeader, + ) + + misbehaviour := tmclient.Misbehaviour{ + Header1: &newHeader, + Header2: &trustedHeader, + } + + submitMsg, err := operator.MisbehaviourProof(simd.GetCodec(), misbehaviour, "double_sign", + "--trust-level", testvalues.DefaultTrustLevel.String(), + "--trusting-period", strconv.Itoa(testvalues.DefaultTrustPeriod)) + s.Require().NoError(err) + + tx, err := s.contract.Misbehaviour(s.GetTransactOpts(s.key), submitMsg) + s.Require().NoError(err) + + // wait until transaction is included in a block + _ = s.GetTxReciept(ctx, eth.EthereumChain, tx.Hash()) + + clientState, err := s.contract.GetClientState(nil) + s.Require().NoError(err) + s.Require().True(clientState.IsFrozen) + })) +} + +// TestBreakingTimeMonotonicityMisbehaviour tests the misbehaviour functionality +// Partially based on https://github.com/cosmos/relayer/blob/f9aaf3dd0ebfe99fbe98d190a145861d7df93804/interchaintest/misbehaviour_test.go#L38 +func (s *SP1ICS07TendermintTestSuite) TestBreakingTimeMonotonicityMisbehaviour() { + ctx := context.Background() + + s.SetupSuite(ctx) + + eth, simd := s.ChainA, s.ChainB + _ = eth + + var height clienttypes.Height + var trustedHeader tmclient.Header + s.Require().True(s.Run("Get trusted header", func() { + var latestHeight int64 + var err error + trustedHeader, latestHeight, err = ibcclientutils.QueryTendermintHeader(simd.Validators[0].CliContext()) + s.Require().NoError(err) + s.Require().NotZero(latestHeight) + + height = clienttypes.NewHeight(clienttypes.ParseChainID(simd.Config().ChainID), uint64(latestHeight)) + + clientState, err := s.contract.GetClientState(nil) + s.Require().NoError(err) + trustedHeight := clienttypes.NewHeight(uint64(clientState.LatestHeight.RevisionNumber), uint64(clientState.LatestHeight.RevisionHeight)) + + trustedHeader.TrustedHeight = trustedHeight + trustedHeader.TrustedValidators = trustedHeader.ValidatorSet + })) + + s.Require().True(s.Run("Valid misbehaviour", func() { + // we have a trusted height n from trustedHeader + // we now create two new headers n+1 and n+2 where both have time later than n + // but n+2 has time earlier than n+1, which breaks time monotonicity + + // n+1 + header2 := s.CreateTMClientHeader( + ctx, + simd, + int64(height.RevisionHeight+1), + trustedHeader.GetTime().Add(time.Minute), + trustedHeader, + ) + + // n+2 (with time earlier than n+1 and still after n) + header1 := s.CreateTMClientHeader( + ctx, + simd, + int64(height.RevisionHeight+2), + trustedHeader.GetTime().Add(time.Minute).Add(-30*time.Second), + trustedHeader, + ) + + misbehaviour := tmclient.Misbehaviour{ + Header1: &header1, + Header2: &header2, + } + + submitMsg, err := operator.MisbehaviourProof(simd.GetCodec(), misbehaviour, "breaking_time_monotonicity", + "--trust-level", testvalues.DefaultTrustLevel.String(), + "--trusting-period", strconv.Itoa(testvalues.DefaultTrustPeriod)) + s.Require().NoError(err) + + tx, err := s.contract.Misbehaviour(s.GetTransactOpts(s.key), submitMsg) + s.Require().NoError(err) + + // wait until transaction is included in a block + _ = s.GetTxReciept(ctx, eth.EthereumChain, tx.Hash()) + + clientState, err := s.contract.GetClientState(nil) + s.Require().NoError(err) + s.Require().True(clientState.IsFrozen) + })) +} diff --git a/e2e/interchaintestv8/testvalues/values.go b/e2e/interchaintestv8/testvalues/values.go index baad74c..0f7d609 100644 --- a/e2e/interchaintestv8/testvalues/values.go +++ b/e2e/interchaintestv8/testvalues/values.go @@ -3,8 +3,6 @@ package testvalues import ( "time" - "cosmossdk.io/math" - ibctm "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint" "github.com/strangelove-ventures/interchaintest/v8/chain/ethereum" @@ -26,11 +24,15 @@ const ( EnvKeySp1Prover = "SP1_PROVER" // Private key for the prover network. EnvKeySp1PrivateKey = "SP1_PRIVATE_KEY" + // EnvKeyGenerateFixtures Generate fixtures for the solidity tests if set to true. + EnvKeyGenerateFixtures = "GENERATE_FIXTURES" // The log level for the Rust logger. EnvKeyRustLog = "RUST_LOG" // Log level for the Rust logger. EnvValueRustLog_Info = "info" + // EnvValueGenerateFixtures_True is the value to set to generate fixtures for the solidity tests. + EnvValueGenerateFixtures_True = "true" ) var ( @@ -42,7 +44,7 @@ var ( VotingPeriod = time.Second * 30 // StartingEthBalance is the amount of ETH to give to each user at the start of the test. - StartingEthBalance = math.NewInt(5 * ethereum.ETHER) + StartingEthBalance = ethereum.ETHER.MulRaw(5) // DefaultTrustLevel is the trust level used by the SP1ICS07Tendermint contract. DefaultTrustLevel = ibctm.Fraction{Numerator: 2, Denominator: 3}.ToTendermint() diff --git a/e2e/interchaintestv8/types/sp1ics07tendermint/contract.go b/e2e/interchaintestv8/types/sp1ics07tendermint/contract.go index 4a59468..9f6ae13 100644 --- a/e2e/interchaintestv8/types/sp1ics07tendermint/contract.go +++ b/e2e/interchaintestv8/types/sp1ics07tendermint/contract.go @@ -52,6 +52,14 @@ type IICS07TendermintMsgsConsensusState struct { NextValidatorsHash [32]byte } +// IICS07TendermintMsgsEnv is an auto generated low-level Go binding around an user-defined struct. +type IICS07TendermintMsgsEnv struct { + ChainId string + TrustThreshold IICS07TendermintMsgsTrustThreshold + TrustingPeriod uint32 + Now uint64 +} + // IICS07TendermintMsgsTrustThreshold is an auto generated low-level Go binding around an user-defined struct. type IICS07TendermintMsgsTrustThreshold struct { Numerator uint8 @@ -95,6 +103,20 @@ type IMembershipMsgsSP1MembershipProof struct { TrustedConsensusState IICS07TendermintMsgsConsensusState } +// IMisbehaviourMsgsMisbehaviourOutput is an auto generated low-level Go binding around an user-defined struct. +type IMisbehaviourMsgsMisbehaviourOutput struct { + Env IICS07TendermintMsgsEnv + TrustedHeight1 IICS02ClientMsgsHeight + TrustedHeight2 IICS02ClientMsgsHeight + TrustedConsensusState1 IICS07TendermintMsgsConsensusState + TrustedConsensusState2 IICS07TendermintMsgsConsensusState +} + +// IMisbehaviourMsgsMsgSubmitMisbehaviour is an auto generated low-level Go binding around an user-defined struct. +type IMisbehaviourMsgsMsgSubmitMisbehaviour struct { + Sp1Proof ISP1MsgsSP1Proof +} + // ISP1MsgsSP1Proof is an auto generated low-level Go binding around an user-defined struct. type ISP1MsgsSP1Proof struct { VKey [32]byte @@ -108,14 +130,6 @@ type IUpdateClientAndMembershipMsgsUcAndMembershipOutput struct { KvPairs []IMembershipMsgsKVPair } -// IUpdateClientMsgsEnv is an auto generated low-level Go binding around an user-defined struct. -type IUpdateClientMsgsEnv struct { - ChainId string - TrustThreshold IICS07TendermintMsgsTrustThreshold - TrustingPeriod uint32 - Now uint64 -} - // IUpdateClientMsgsMsgUpdateClient is an auto generated low-level Go binding around an user-defined struct. type IUpdateClientMsgsMsgUpdateClient struct { Sp1Proof ISP1MsgsSP1Proof @@ -125,14 +139,14 @@ type IUpdateClientMsgsMsgUpdateClient struct { type IUpdateClientMsgsUpdateClientOutput struct { TrustedConsensusState IICS07TendermintMsgsConsensusState NewConsensusState IICS07TendermintMsgsConsensusState - Env IUpdateClientMsgsEnv + Env IICS07TendermintMsgsEnv TrustedHeight IICS02ClientMsgsHeight NewHeight IICS02ClientMsgsHeight } // ContractMetaData contains all meta data concerning the Contract contract. var ContractMetaData = &bind.MetaData{ - ABI: "[{\"type\":\"constructor\",\"inputs\":[{\"name\":\"updateClientProgramVkey\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"membershipProgramVkey\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"updateClientAndMembershipProgramVkey\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"verifier\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_clientState\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"_consensusState\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"ALLOWED_SP1_CLOCK_DRIFT\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint16\",\"internalType\":\"uint16\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"MEMBERSHIP_PROGRAM_VKEY\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"UPDATE_CLIENT_AND_MEMBERSHIP_PROGRAM_VKEY\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"UPDATE_CLIENT_PROGRAM_VKEY\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"VERIFIER\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractISP1Verifier\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"abiPublicTypes\",\"inputs\":[{\"name\":\"o1\",\"type\":\"tuple\",\"internalType\":\"structIMembershipMsgs.MembershipOutput\",\"components\":[{\"name\":\"commitmentRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"kvPairs\",\"type\":\"tuple[]\",\"internalType\":\"structIMembershipMsgs.KVPair[]\",\"components\":[{\"name\":\"path\",\"type\":\"bytes[]\",\"internalType\":\"bytes[]\"},{\"name\":\"value\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]}]},{\"name\":\"o2\",\"type\":\"tuple\",\"internalType\":\"structIUpdateClientAndMembershipMsgs.UcAndMembershipOutput\",\"components\":[{\"name\":\"updateClientOutput\",\"type\":\"tuple\",\"internalType\":\"structIUpdateClientMsgs.UpdateClientOutput\",\"components\":[{\"name\":\"trustedConsensusState\",\"type\":\"tuple\",\"internalType\":\"structIICS07TendermintMsgs.ConsensusState\",\"components\":[{\"name\":\"timestamp\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"root\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"nextValidatorsHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"name\":\"newConsensusState\",\"type\":\"tuple\",\"internalType\":\"structIICS07TendermintMsgs.ConsensusState\",\"components\":[{\"name\":\"timestamp\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"root\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"nextValidatorsHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"name\":\"env\",\"type\":\"tuple\",\"internalType\":\"structIUpdateClientMsgs.Env\",\"components\":[{\"name\":\"chainId\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"trustThreshold\",\"type\":\"tuple\",\"internalType\":\"structIICS07TendermintMsgs.TrustThreshold\",\"components\":[{\"name\":\"numerator\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"denominator\",\"type\":\"uint8\",\"internalType\":\"uint8\"}]},{\"name\":\"trustingPeriod\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"now\",\"type\":\"uint64\",\"internalType\":\"uint64\"}]},{\"name\":\"trustedHeight\",\"type\":\"tuple\",\"internalType\":\"structIICS02ClientMsgs.Height\",\"components\":[{\"name\":\"revisionNumber\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"revisionHeight\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]},{\"name\":\"newHeight\",\"type\":\"tuple\",\"internalType\":\"structIICS02ClientMsgs.Height\",\"components\":[{\"name\":\"revisionNumber\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"revisionHeight\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}]},{\"name\":\"kvPairs\",\"type\":\"tuple[]\",\"internalType\":\"structIMembershipMsgs.KVPair[]\",\"components\":[{\"name\":\"path\",\"type\":\"bytes[]\",\"internalType\":\"bytes[]\"},{\"name\":\"value\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]}]},{\"name\":\"o3\",\"type\":\"tuple\",\"internalType\":\"structIUpdateClientMsgs.MsgUpdateClient\",\"components\":[{\"name\":\"sp1Proof\",\"type\":\"tuple\",\"internalType\":\"structISP1Msgs.SP1Proof\",\"components\":[{\"name\":\"vKey\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"publicValues\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"proof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]}]},{\"name\":\"o4\",\"type\":\"tuple\",\"internalType\":\"structIMembershipMsgs.MembershipProof\",\"components\":[{\"name\":\"proofType\",\"type\":\"uint8\",\"internalType\":\"enumIMembershipMsgs.MembershipProofType\"},{\"name\":\"proof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]},{\"name\":\"o5\",\"type\":\"tuple\",\"internalType\":\"structIMembershipMsgs.SP1MembershipProof\",\"components\":[{\"name\":\"sp1Proof\",\"type\":\"tuple\",\"internalType\":\"structISP1Msgs.SP1Proof\",\"components\":[{\"name\":\"vKey\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"publicValues\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"proof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]},{\"name\":\"trustedConsensusState\",\"type\":\"tuple\",\"internalType\":\"structIICS07TendermintMsgs.ConsensusState\",\"components\":[{\"name\":\"timestamp\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"root\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"nextValidatorsHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]}]},{\"name\":\"o6\",\"type\":\"tuple\",\"internalType\":\"structIMembershipMsgs.SP1MembershipAndUpdateClientProof\",\"components\":[{\"name\":\"sp1Proof\",\"type\":\"tuple\",\"internalType\":\"structISP1Msgs.SP1Proof\",\"components\":[{\"name\":\"vKey\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"publicValues\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"proof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]}]}],\"outputs\":[],\"stateMutability\":\"pure\"},{\"type\":\"function\",\"name\":\"getClientState\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structIICS07TendermintMsgs.ClientState\",\"components\":[{\"name\":\"chainId\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"trustLevel\",\"type\":\"tuple\",\"internalType\":\"structIICS07TendermintMsgs.TrustThreshold\",\"components\":[{\"name\":\"numerator\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"denominator\",\"type\":\"uint8\",\"internalType\":\"uint8\"}]},{\"name\":\"latestHeight\",\"type\":\"tuple\",\"internalType\":\"structIICS02ClientMsgs.Height\",\"components\":[{\"name\":\"revisionNumber\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"revisionHeight\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]},{\"name\":\"trustingPeriod\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"unbondingPeriod\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"isFrozen\",\"type\":\"bool\",\"internalType\":\"bool\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getConsensusStateHash\",\"inputs\":[{\"name\":\"revisionHeight\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"membership\",\"inputs\":[{\"name\":\"msgMembership\",\"type\":\"tuple\",\"internalType\":\"structILightClientMsgs.MsgMembership\",\"components\":[{\"name\":\"proof\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"proofHeight\",\"type\":\"tuple\",\"internalType\":\"structIICS02ClientMsgs.Height\",\"components\":[{\"name\":\"revisionNumber\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"revisionHeight\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]},{\"name\":\"path\",\"type\":\"bytes[]\",\"internalType\":\"bytes[]\"},{\"name\":\"value\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]}],\"outputs\":[{\"name\":\"timestamp\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"misbehaviour\",\"inputs\":[{\"name\":\"\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"pure\"},{\"type\":\"function\",\"name\":\"updateClient\",\"inputs\":[{\"name\":\"updateMsg\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint8\",\"internalType\":\"enumILightClientMsgs.UpdateResult\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"upgradeClient\",\"inputs\":[{\"name\":\"\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"pure\"},{\"type\":\"error\",\"name\":\"CannotHandleMisbehavior\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ChainIdMismatch\",\"inputs\":[{\"name\":\"expected\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"actual\",\"type\":\"string\",\"internalType\":\"string\"}]},{\"type\":\"error\",\"name\":\"ConsensusStateHashMismatch\",\"inputs\":[{\"name\":\"expected\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"actual\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"type\":\"error\",\"name\":\"ConsensusStateNotFound\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ConsensusStateRootMismatch\",\"inputs\":[{\"name\":\"expected\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"actual\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"type\":\"error\",\"name\":\"FeatureNotSupported\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"FrozenClientState\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"LengthIsOutOfRange\",\"inputs\":[{\"name\":\"length\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"min\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"max\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"type\":\"error\",\"name\":\"MembershipProofKeyNotFound\",\"inputs\":[{\"name\":\"path\",\"type\":\"bytes[]\",\"internalType\":\"bytes[]\"}]},{\"type\":\"error\",\"name\":\"MembershipProofValueMismatch\",\"inputs\":[{\"name\":\"expected\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"actual\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]},{\"type\":\"error\",\"name\":\"ProofHeightMismatch\",\"inputs\":[{\"name\":\"expectedRevisionNumber\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"expectedRevisionHeight\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"actualRevisionNumber\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"actualRevisionHeight\",\"type\":\"uint64\",\"internalType\":\"uint64\"}]},{\"type\":\"error\",\"name\":\"ProofIsInTheFuture\",\"inputs\":[{\"name\":\"now\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"proofTimestamp\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"type\":\"error\",\"name\":\"ProofIsTooOld\",\"inputs\":[{\"name\":\"now\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"proofTimestamp\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"type\":\"error\",\"name\":\"TrustThresholdMismatch\",\"inputs\":[{\"name\":\"expectedNumerator\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"expectedDenominator\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"actualNumerator\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"actualDenominator\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"type\":\"error\",\"name\":\"TrustingPeriodMismatch\",\"inputs\":[{\"name\":\"expected\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"actual\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"type\":\"error\",\"name\":\"TrustingPeriodTooLong\",\"inputs\":[{\"name\":\"trustingPeriod\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"unbondingPeriod\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"type\":\"error\",\"name\":\"UnknownMembershipProofType\",\"inputs\":[{\"name\":\"proofType\",\"type\":\"uint8\",\"internalType\":\"uint8\"}]},{\"type\":\"error\",\"name\":\"VerificationKeyMismatch\",\"inputs\":[{\"name\":\"expected\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"actual\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]}]", + ABI: "[{\"type\":\"constructor\",\"inputs\":[{\"name\":\"updateClientProgramVkey\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"membershipProgramVkey\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"updateClientAndMembershipProgramVkey\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"misbehaviourProgramVkey\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"verifier\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_clientState\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"_consensusState\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"ALLOWED_SP1_CLOCK_DRIFT\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint16\",\"internalType\":\"uint16\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"MEMBERSHIP_PROGRAM_VKEY\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"MISBEHAVIOUR_PROGRAM_VKEY\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"UPDATE_CLIENT_AND_MEMBERSHIP_PROGRAM_VKEY\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"UPDATE_CLIENT_PROGRAM_VKEY\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"VERIFIER\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"contractISP1Verifier\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"abiPublicTypes\",\"inputs\":[{\"name\":\"o1\",\"type\":\"tuple\",\"internalType\":\"structIMembershipMsgs.MembershipOutput\",\"components\":[{\"name\":\"commitmentRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"kvPairs\",\"type\":\"tuple[]\",\"internalType\":\"structIMembershipMsgs.KVPair[]\",\"components\":[{\"name\":\"path\",\"type\":\"bytes[]\",\"internalType\":\"bytes[]\"},{\"name\":\"value\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]}]},{\"name\":\"o2\",\"type\":\"tuple\",\"internalType\":\"structIUpdateClientAndMembershipMsgs.UcAndMembershipOutput\",\"components\":[{\"name\":\"updateClientOutput\",\"type\":\"tuple\",\"internalType\":\"structIUpdateClientMsgs.UpdateClientOutput\",\"components\":[{\"name\":\"trustedConsensusState\",\"type\":\"tuple\",\"internalType\":\"structIICS07TendermintMsgs.ConsensusState\",\"components\":[{\"name\":\"timestamp\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"root\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"nextValidatorsHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"name\":\"newConsensusState\",\"type\":\"tuple\",\"internalType\":\"structIICS07TendermintMsgs.ConsensusState\",\"components\":[{\"name\":\"timestamp\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"root\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"nextValidatorsHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"name\":\"env\",\"type\":\"tuple\",\"internalType\":\"structIICS07TendermintMsgs.Env\",\"components\":[{\"name\":\"chainId\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"trustThreshold\",\"type\":\"tuple\",\"internalType\":\"structIICS07TendermintMsgs.TrustThreshold\",\"components\":[{\"name\":\"numerator\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"denominator\",\"type\":\"uint8\",\"internalType\":\"uint8\"}]},{\"name\":\"trustingPeriod\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"now\",\"type\":\"uint64\",\"internalType\":\"uint64\"}]},{\"name\":\"trustedHeight\",\"type\":\"tuple\",\"internalType\":\"structIICS02ClientMsgs.Height\",\"components\":[{\"name\":\"revisionNumber\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"revisionHeight\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]},{\"name\":\"newHeight\",\"type\":\"tuple\",\"internalType\":\"structIICS02ClientMsgs.Height\",\"components\":[{\"name\":\"revisionNumber\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"revisionHeight\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]}]},{\"name\":\"kvPairs\",\"type\":\"tuple[]\",\"internalType\":\"structIMembershipMsgs.KVPair[]\",\"components\":[{\"name\":\"path\",\"type\":\"bytes[]\",\"internalType\":\"bytes[]\"},{\"name\":\"value\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]}]},{\"name\":\"o3\",\"type\":\"tuple\",\"internalType\":\"structIUpdateClientMsgs.MsgUpdateClient\",\"components\":[{\"name\":\"sp1Proof\",\"type\":\"tuple\",\"internalType\":\"structISP1Msgs.SP1Proof\",\"components\":[{\"name\":\"vKey\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"publicValues\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"proof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]}]},{\"name\":\"o4\",\"type\":\"tuple\",\"internalType\":\"structIMembershipMsgs.MembershipProof\",\"components\":[{\"name\":\"proofType\",\"type\":\"uint8\",\"internalType\":\"enumIMembershipMsgs.MembershipProofType\"},{\"name\":\"proof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]},{\"name\":\"o5\",\"type\":\"tuple\",\"internalType\":\"structIMembershipMsgs.SP1MembershipProof\",\"components\":[{\"name\":\"sp1Proof\",\"type\":\"tuple\",\"internalType\":\"structISP1Msgs.SP1Proof\",\"components\":[{\"name\":\"vKey\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"publicValues\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"proof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]},{\"name\":\"trustedConsensusState\",\"type\":\"tuple\",\"internalType\":\"structIICS07TendermintMsgs.ConsensusState\",\"components\":[{\"name\":\"timestamp\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"root\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"nextValidatorsHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]}]},{\"name\":\"o6\",\"type\":\"tuple\",\"internalType\":\"structIMembershipMsgs.SP1MembershipAndUpdateClientProof\",\"components\":[{\"name\":\"sp1Proof\",\"type\":\"tuple\",\"internalType\":\"structISP1Msgs.SP1Proof\",\"components\":[{\"name\":\"vKey\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"publicValues\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"proof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]}]},{\"name\":\"o7\",\"type\":\"tuple\",\"internalType\":\"structIMisbehaviourMsgs.MisbehaviourOutput\",\"components\":[{\"name\":\"env\",\"type\":\"tuple\",\"internalType\":\"structIICS07TendermintMsgs.Env\",\"components\":[{\"name\":\"chainId\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"trustThreshold\",\"type\":\"tuple\",\"internalType\":\"structIICS07TendermintMsgs.TrustThreshold\",\"components\":[{\"name\":\"numerator\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"denominator\",\"type\":\"uint8\",\"internalType\":\"uint8\"}]},{\"name\":\"trustingPeriod\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"now\",\"type\":\"uint64\",\"internalType\":\"uint64\"}]},{\"name\":\"trustedHeight1\",\"type\":\"tuple\",\"internalType\":\"structIICS02ClientMsgs.Height\",\"components\":[{\"name\":\"revisionNumber\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"revisionHeight\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]},{\"name\":\"trustedHeight2\",\"type\":\"tuple\",\"internalType\":\"structIICS02ClientMsgs.Height\",\"components\":[{\"name\":\"revisionNumber\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"revisionHeight\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]},{\"name\":\"trustedConsensusState1\",\"type\":\"tuple\",\"internalType\":\"structIICS07TendermintMsgs.ConsensusState\",\"components\":[{\"name\":\"timestamp\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"root\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"nextValidatorsHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"name\":\"trustedConsensusState2\",\"type\":\"tuple\",\"internalType\":\"structIICS07TendermintMsgs.ConsensusState\",\"components\":[{\"name\":\"timestamp\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"root\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"nextValidatorsHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]}]},{\"name\":\"o8\",\"type\":\"tuple\",\"internalType\":\"structIMisbehaviourMsgs.MsgSubmitMisbehaviour\",\"components\":[{\"name\":\"sp1Proof\",\"type\":\"tuple\",\"internalType\":\"structISP1Msgs.SP1Proof\",\"components\":[{\"name\":\"vKey\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"publicValues\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"proof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]}]}],\"outputs\":[],\"stateMutability\":\"pure\"},{\"type\":\"function\",\"name\":\"getClientState\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"tuple\",\"internalType\":\"structIICS07TendermintMsgs.ClientState\",\"components\":[{\"name\":\"chainId\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"trustLevel\",\"type\":\"tuple\",\"internalType\":\"structIICS07TendermintMsgs.TrustThreshold\",\"components\":[{\"name\":\"numerator\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"denominator\",\"type\":\"uint8\",\"internalType\":\"uint8\"}]},{\"name\":\"latestHeight\",\"type\":\"tuple\",\"internalType\":\"structIICS02ClientMsgs.Height\",\"components\":[{\"name\":\"revisionNumber\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"revisionHeight\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]},{\"name\":\"trustingPeriod\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"unbondingPeriod\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"isFrozen\",\"type\":\"bool\",\"internalType\":\"bool\"}]}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"getConsensusStateHash\",\"inputs\":[{\"name\":\"revisionHeight\",\"type\":\"uint32\",\"internalType\":\"uint32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"membership\",\"inputs\":[{\"name\":\"msgMembership\",\"type\":\"tuple\",\"internalType\":\"structILightClientMsgs.MsgMembership\",\"components\":[{\"name\":\"proof\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"proofHeight\",\"type\":\"tuple\",\"internalType\":\"structIICS02ClientMsgs.Height\",\"components\":[{\"name\":\"revisionNumber\",\"type\":\"uint32\",\"internalType\":\"uint32\"},{\"name\":\"revisionHeight\",\"type\":\"uint32\",\"internalType\":\"uint32\"}]},{\"name\":\"path\",\"type\":\"bytes[]\",\"internalType\":\"bytes[]\"},{\"name\":\"value\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]}],\"outputs\":[{\"name\":\"timestamp\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"misbehaviour\",\"inputs\":[{\"name\":\"misbehaviourMsg\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"updateClient\",\"inputs\":[{\"name\":\"updateMsg\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[{\"name\":\"\",\"type\":\"uint8\",\"internalType\":\"enumILightClientMsgs.UpdateResult\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"upgradeClient\",\"inputs\":[{\"name\":\"\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"pure\"},{\"type\":\"error\",\"name\":\"CannotHandleMisbehavior\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ChainIdMismatch\",\"inputs\":[{\"name\":\"expected\",\"type\":\"string\",\"internalType\":\"string\"},{\"name\":\"actual\",\"type\":\"string\",\"internalType\":\"string\"}]},{\"type\":\"error\",\"name\":\"ConsensusStateHashMismatch\",\"inputs\":[{\"name\":\"expected\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"actual\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"type\":\"error\",\"name\":\"ConsensusStateNotFound\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ConsensusStateRootMismatch\",\"inputs\":[{\"name\":\"expected\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"actual\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]},{\"type\":\"error\",\"name\":\"FeatureNotSupported\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"FrozenClientState\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"LengthIsOutOfRange\",\"inputs\":[{\"name\":\"length\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"min\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"max\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"type\":\"error\",\"name\":\"MembershipProofKeyNotFound\",\"inputs\":[{\"name\":\"path\",\"type\":\"bytes[]\",\"internalType\":\"bytes[]\"}]},{\"type\":\"error\",\"name\":\"MembershipProofValueMismatch\",\"inputs\":[{\"name\":\"expected\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"actual\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]},{\"type\":\"error\",\"name\":\"ProofHeightMismatch\",\"inputs\":[{\"name\":\"expectedRevisionNumber\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"expectedRevisionHeight\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"actualRevisionNumber\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"actualRevisionHeight\",\"type\":\"uint64\",\"internalType\":\"uint64\"}]},{\"type\":\"error\",\"name\":\"ProofIsInTheFuture\",\"inputs\":[{\"name\":\"now\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"proofTimestamp\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"type\":\"error\",\"name\":\"ProofIsTooOld\",\"inputs\":[{\"name\":\"now\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"proofTimestamp\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"type\":\"error\",\"name\":\"TrustThresholdMismatch\",\"inputs\":[{\"name\":\"expectedNumerator\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"expectedDenominator\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"actualNumerator\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"actualDenominator\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"type\":\"error\",\"name\":\"TrustingPeriodMismatch\",\"inputs\":[{\"name\":\"expected\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"actual\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"type\":\"error\",\"name\":\"TrustingPeriodTooLong\",\"inputs\":[{\"name\":\"trustingPeriod\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"unbondingPeriod\",\"type\":\"uint256\",\"internalType\":\"uint256\"}]},{\"type\":\"error\",\"name\":\"UnknownMembershipProofType\",\"inputs\":[{\"name\":\"proofType\",\"type\":\"uint8\",\"internalType\":\"uint8\"}]},{\"type\":\"error\",\"name\":\"VerificationKeyMismatch\",\"inputs\":[{\"name\":\"expected\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"actual\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}]}]", } // ContractABI is the input ABI used to generate the binding from. @@ -343,6 +357,37 @@ func (_Contract *ContractCallerSession) MEMBERSHIPPROGRAMVKEY() ([32]byte, error return _Contract.Contract.MEMBERSHIPPROGRAMVKEY(&_Contract.CallOpts) } +// MISBEHAVIOURPROGRAMVKEY is a free data retrieval call binding the contract method 0x314d4dff. +// +// Solidity: function MISBEHAVIOUR_PROGRAM_VKEY() view returns(bytes32) +func (_Contract *ContractCaller) MISBEHAVIOURPROGRAMVKEY(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _Contract.contract.Call(opts, &out, "MISBEHAVIOUR_PROGRAM_VKEY") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// MISBEHAVIOURPROGRAMVKEY is a free data retrieval call binding the contract method 0x314d4dff. +// +// Solidity: function MISBEHAVIOUR_PROGRAM_VKEY() view returns(bytes32) +func (_Contract *ContractSession) MISBEHAVIOURPROGRAMVKEY() ([32]byte, error) { + return _Contract.Contract.MISBEHAVIOURPROGRAMVKEY(&_Contract.CallOpts) +} + +// MISBEHAVIOURPROGRAMVKEY is a free data retrieval call binding the contract method 0x314d4dff. +// +// Solidity: function MISBEHAVIOUR_PROGRAM_VKEY() view returns(bytes32) +func (_Contract *ContractCallerSession) MISBEHAVIOURPROGRAMVKEY() ([32]byte, error) { + return _Contract.Contract.MISBEHAVIOURPROGRAMVKEY(&_Contract.CallOpts) +} + // UPDATECLIENTANDMEMBERSHIPPROGRAMVKEY is a free data retrieval call binding the contract method 0x0225293e. // // Solidity: function UPDATE_CLIENT_AND_MEMBERSHIP_PROGRAM_VKEY() view returns(bytes32) @@ -436,12 +481,12 @@ func (_Contract *ContractCallerSession) VERIFIER() (common.Address, error) { return _Contract.Contract.VERIFIER(&_Contract.CallOpts) } -// AbiPublicTypes is a free data retrieval call binding the contract method 0x342467e1. +// AbiPublicTypes is a free data retrieval call binding the contract method 0x4ad51d79. // -// Solidity: function abiPublicTypes((bytes32,(bytes[],bytes)[]) o1, (((uint64,bytes32,bytes32),(uint64,bytes32,bytes32),(string,(uint8,uint8),uint32,uint64),(uint32,uint32),(uint32,uint32)),(bytes[],bytes)[]) o2, ((bytes32,bytes,bytes)) o3, (uint8,bytes) o4, ((bytes32,bytes,bytes),(uint64,bytes32,bytes32)) o5, ((bytes32,bytes,bytes)) o6) pure returns() -func (_Contract *ContractCaller) AbiPublicTypes(opts *bind.CallOpts, o1 IMembershipMsgsMembershipOutput, o2 IUpdateClientAndMembershipMsgsUcAndMembershipOutput, o3 IUpdateClientMsgsMsgUpdateClient, o4 IMembershipMsgsMembershipProof, o5 IMembershipMsgsSP1MembershipProof, o6 IMembershipMsgsSP1MembershipAndUpdateClientProof) error { +// Solidity: function abiPublicTypes((bytes32,(bytes[],bytes)[]) o1, (((uint64,bytes32,bytes32),(uint64,bytes32,bytes32),(string,(uint8,uint8),uint32,uint64),(uint32,uint32),(uint32,uint32)),(bytes[],bytes)[]) o2, ((bytes32,bytes,bytes)) o3, (uint8,bytes) o4, ((bytes32,bytes,bytes),(uint64,bytes32,bytes32)) o5, ((bytes32,bytes,bytes)) o6, ((string,(uint8,uint8),uint32,uint64),(uint32,uint32),(uint32,uint32),(uint64,bytes32,bytes32),(uint64,bytes32,bytes32)) o7, ((bytes32,bytes,bytes)) o8) pure returns() +func (_Contract *ContractCaller) AbiPublicTypes(opts *bind.CallOpts, o1 IMembershipMsgsMembershipOutput, o2 IUpdateClientAndMembershipMsgsUcAndMembershipOutput, o3 IUpdateClientMsgsMsgUpdateClient, o4 IMembershipMsgsMembershipProof, o5 IMembershipMsgsSP1MembershipProof, o6 IMembershipMsgsSP1MembershipAndUpdateClientProof, o7 IMisbehaviourMsgsMisbehaviourOutput, o8 IMisbehaviourMsgsMsgSubmitMisbehaviour) error { var out []interface{} - err := _Contract.contract.Call(opts, &out, "abiPublicTypes", o1, o2, o3, o4, o5, o6) + err := _Contract.contract.Call(opts, &out, "abiPublicTypes", o1, o2, o3, o4, o5, o6, o7, o8) if err != nil { return err @@ -451,18 +496,18 @@ func (_Contract *ContractCaller) AbiPublicTypes(opts *bind.CallOpts, o1 IMembers } -// AbiPublicTypes is a free data retrieval call binding the contract method 0x342467e1. +// AbiPublicTypes is a free data retrieval call binding the contract method 0x4ad51d79. // -// Solidity: function abiPublicTypes((bytes32,(bytes[],bytes)[]) o1, (((uint64,bytes32,bytes32),(uint64,bytes32,bytes32),(string,(uint8,uint8),uint32,uint64),(uint32,uint32),(uint32,uint32)),(bytes[],bytes)[]) o2, ((bytes32,bytes,bytes)) o3, (uint8,bytes) o4, ((bytes32,bytes,bytes),(uint64,bytes32,bytes32)) o5, ((bytes32,bytes,bytes)) o6) pure returns() -func (_Contract *ContractSession) AbiPublicTypes(o1 IMembershipMsgsMembershipOutput, o2 IUpdateClientAndMembershipMsgsUcAndMembershipOutput, o3 IUpdateClientMsgsMsgUpdateClient, o4 IMembershipMsgsMembershipProof, o5 IMembershipMsgsSP1MembershipProof, o6 IMembershipMsgsSP1MembershipAndUpdateClientProof) error { - return _Contract.Contract.AbiPublicTypes(&_Contract.CallOpts, o1, o2, o3, o4, o5, o6) +// Solidity: function abiPublicTypes((bytes32,(bytes[],bytes)[]) o1, (((uint64,bytes32,bytes32),(uint64,bytes32,bytes32),(string,(uint8,uint8),uint32,uint64),(uint32,uint32),(uint32,uint32)),(bytes[],bytes)[]) o2, ((bytes32,bytes,bytes)) o3, (uint8,bytes) o4, ((bytes32,bytes,bytes),(uint64,bytes32,bytes32)) o5, ((bytes32,bytes,bytes)) o6, ((string,(uint8,uint8),uint32,uint64),(uint32,uint32),(uint32,uint32),(uint64,bytes32,bytes32),(uint64,bytes32,bytes32)) o7, ((bytes32,bytes,bytes)) o8) pure returns() +func (_Contract *ContractSession) AbiPublicTypes(o1 IMembershipMsgsMembershipOutput, o2 IUpdateClientAndMembershipMsgsUcAndMembershipOutput, o3 IUpdateClientMsgsMsgUpdateClient, o4 IMembershipMsgsMembershipProof, o5 IMembershipMsgsSP1MembershipProof, o6 IMembershipMsgsSP1MembershipAndUpdateClientProof, o7 IMisbehaviourMsgsMisbehaviourOutput, o8 IMisbehaviourMsgsMsgSubmitMisbehaviour) error { + return _Contract.Contract.AbiPublicTypes(&_Contract.CallOpts, o1, o2, o3, o4, o5, o6, o7, o8) } -// AbiPublicTypes is a free data retrieval call binding the contract method 0x342467e1. +// AbiPublicTypes is a free data retrieval call binding the contract method 0x4ad51d79. // -// Solidity: function abiPublicTypes((bytes32,(bytes[],bytes)[]) o1, (((uint64,bytes32,bytes32),(uint64,bytes32,bytes32),(string,(uint8,uint8),uint32,uint64),(uint32,uint32),(uint32,uint32)),(bytes[],bytes)[]) o2, ((bytes32,bytes,bytes)) o3, (uint8,bytes) o4, ((bytes32,bytes,bytes),(uint64,bytes32,bytes32)) o5, ((bytes32,bytes,bytes)) o6) pure returns() -func (_Contract *ContractCallerSession) AbiPublicTypes(o1 IMembershipMsgsMembershipOutput, o2 IUpdateClientAndMembershipMsgsUcAndMembershipOutput, o3 IUpdateClientMsgsMsgUpdateClient, o4 IMembershipMsgsMembershipProof, o5 IMembershipMsgsSP1MembershipProof, o6 IMembershipMsgsSP1MembershipAndUpdateClientProof) error { - return _Contract.Contract.AbiPublicTypes(&_Contract.CallOpts, o1, o2, o3, o4, o5, o6) +// Solidity: function abiPublicTypes((bytes32,(bytes[],bytes)[]) o1, (((uint64,bytes32,bytes32),(uint64,bytes32,bytes32),(string,(uint8,uint8),uint32,uint64),(uint32,uint32),(uint32,uint32)),(bytes[],bytes)[]) o2, ((bytes32,bytes,bytes)) o3, (uint8,bytes) o4, ((bytes32,bytes,bytes),(uint64,bytes32,bytes32)) o5, ((bytes32,bytes,bytes)) o6, ((string,(uint8,uint8),uint32,uint64),(uint32,uint32),(uint32,uint32),(uint64,bytes32,bytes32),(uint64,bytes32,bytes32)) o7, ((bytes32,bytes,bytes)) o8) pure returns() +func (_Contract *ContractCallerSession) AbiPublicTypes(o1 IMembershipMsgsMembershipOutput, o2 IUpdateClientAndMembershipMsgsUcAndMembershipOutput, o3 IUpdateClientMsgsMsgUpdateClient, o4 IMembershipMsgsMembershipProof, o5 IMembershipMsgsSP1MembershipProof, o6 IMembershipMsgsSP1MembershipAndUpdateClientProof, o7 IMisbehaviourMsgsMisbehaviourOutput, o8 IMisbehaviourMsgsMsgSubmitMisbehaviour) error { + return _Contract.Contract.AbiPublicTypes(&_Contract.CallOpts, o1, o2, o3, o4, o5, o6, o7, o8) } // GetClientState is a free data retrieval call binding the contract method 0xef913a4b. @@ -527,35 +572,6 @@ func (_Contract *ContractCallerSession) GetConsensusStateHash(revisionHeight uin return _Contract.Contract.GetConsensusStateHash(&_Contract.CallOpts, revisionHeight) } -// Misbehaviour is a free data retrieval call binding the contract method 0xddba6537. -// -// Solidity: function misbehaviour(bytes ) pure returns() -func (_Contract *ContractCaller) Misbehaviour(opts *bind.CallOpts, arg0 []byte) error { - var out []interface{} - err := _Contract.contract.Call(opts, &out, "misbehaviour", arg0) - - if err != nil { - return err - } - - return err - -} - -// Misbehaviour is a free data retrieval call binding the contract method 0xddba6537. -// -// Solidity: function misbehaviour(bytes ) pure returns() -func (_Contract *ContractSession) Misbehaviour(arg0 []byte) error { - return _Contract.Contract.Misbehaviour(&_Contract.CallOpts, arg0) -} - -// Misbehaviour is a free data retrieval call binding the contract method 0xddba6537. -// -// Solidity: function misbehaviour(bytes ) pure returns() -func (_Contract *ContractCallerSession) Misbehaviour(arg0 []byte) error { - return _Contract.Contract.Misbehaviour(&_Contract.CallOpts, arg0) -} - // UpgradeClient is a free data retrieval call binding the contract method 0x8a8e4c5d. // // Solidity: function upgradeClient(bytes ) pure returns() @@ -606,6 +622,27 @@ func (_Contract *ContractTransactorSession) Membership(msgMembership ILightClien return _Contract.Contract.Membership(&_Contract.TransactOpts, msgMembership) } +// Misbehaviour is a paid mutator transaction binding the contract method 0xddba6537. +// +// Solidity: function misbehaviour(bytes misbehaviourMsg) returns() +func (_Contract *ContractTransactor) Misbehaviour(opts *bind.TransactOpts, misbehaviourMsg []byte) (*types.Transaction, error) { + return _Contract.contract.Transact(opts, "misbehaviour", misbehaviourMsg) +} + +// Misbehaviour is a paid mutator transaction binding the contract method 0xddba6537. +// +// Solidity: function misbehaviour(bytes misbehaviourMsg) returns() +func (_Contract *ContractSession) Misbehaviour(misbehaviourMsg []byte) (*types.Transaction, error) { + return _Contract.Contract.Misbehaviour(&_Contract.TransactOpts, misbehaviourMsg) +} + +// Misbehaviour is a paid mutator transaction binding the contract method 0xddba6537. +// +// Solidity: function misbehaviour(bytes misbehaviourMsg) returns() +func (_Contract *ContractTransactorSession) Misbehaviour(misbehaviourMsg []byte) (*types.Transaction, error) { + return _Contract.Contract.Misbehaviour(&_Contract.TransactOpts, misbehaviourMsg) +} + // UpdateClient is a paid mutator transaction binding the contract method 0x0bece356. // // Solidity: function updateClient(bytes updateMsg) returns(uint8) diff --git a/justfile b/justfile index b0257be..e04d617 100644 --- a/justfile +++ b/justfile @@ -8,6 +8,8 @@ build-programs: @echo "ELF created at 'elf/membership-riscv32im-succinct-zkvm-elf'" cd programs/uc-and-membership && ~/.sp1/bin/cargo-prove prove build --elf-name uc-and-membership-riscv32im-succinct-zkvm-elf @echo "ELF created at 'elf/uc-and-membership-riscv32im-succinct-zkvm-elf'" + cd programs/misbehaviour && ~/.sp1/bin/cargo-prove prove build --elf-name misbehaviour-riscv32im-succinct-zkvm-elf + @echo "ELF created at 'elf/misbehaviour-riscv32im-succinct-zkvm-elf'" # Build the operator executable using `cargo build` command build-operator: @@ -29,18 +31,15 @@ install-operator: @echo "Installed the operator executable" # Run the Solidity tests using `forge test` command -test-foundry: - forge test -vvv +test-foundry testname=".\\*": + forge test -vvv --match-test ^{{testname}}\(.\*\)\$ # Run the Rust tests using `cargo test` command (excluding the sp1-ics07-tendermint-update-client crate) test-cargo: - cargo test --workspace --exclude sp1-ics07-tendermint-update-client --exclude sp1-ics07-tendermint-membership --exclude sp1-ics07-tendermint-uc-and-membership --locked --all-features + cargo test --workspace --exclude sp1-ics07-tendermint-update-client --exclude sp1-ics07-tendermint-membership --exclude sp1-ics07-tendermint-uc-and-membership --exclude sp1-ics07-tendermint-misbehaviour --locked --all-features # Generate the `genesis.json` file using $TENDERMINT_RPC_URL in the `.env` file -genesis: - @echo "Generating the genesis file for the Celestia Mocha testnet" - @echo "Building the program..." - just build-programs +genesis: build-programs @echo "Generating the genesis file..." RUST_LOG=info cargo run --bin operator --release -- genesis -o contracts/script/genesis.json @@ -48,21 +47,25 @@ genesis: # The prover parameter should be one of: ["mock", "network", "local"] # This generates the fixtures for all programs in parallel using GNU parallel. # If prover is set to network, this command requires the `SP1_PRIVATE_KEY` environment variable to be set. -fixtures prover: - @echo "Generating fixtures for the Celestia Mocha testnet" - @echo "Building the operator..." - just build-operator +fixtures prover: build-operator @echo "Generating fixtures... This may take a while (up to 20 minutes)" + TENDERMINT_RPC_URL="${TENDERMINT_RPC_URL%/}" && \ + CURRENT_HEIGHT=$(curl "$TENDERMINT_RPC_URL"/block | jq -r ".result.block.header.height") && \ + TRUSTED_HEIGHT=$(($CURRENT_HEIGHT-100)) && \ + TARGET_HEIGHT=$(($CURRENT_HEIGHT-10)) && \ + echo "For celestia fixtures, trusted block: $TRUSTED_HEIGHT, target block: $TARGET_HEIGHT, from $TENDERMINT_RPC_URL" && \ parallel --progress --shebang --ungroup -j 4 ::: \ - "RUST_LOG=info SP1_PROVER={{prover}} TENDERMINT_RPC_URL='https://rpc.celestia-mocha.com/' ./target/release/operator fixtures update-client --trusted-block 2438000 --target-block 2438010 -o 'contracts/fixtures/update_client_fixture.json'" \ - "sleep 15 && RUST_LOG=info SP1_PROVER={{prover}} TENDERMINT_RPC_URL='https://rpc.celestia-mocha.com/' ./target/release/operator fixtures update-client-and-membership --key-paths clients/07-tendermint-0/clientState,clients/07-tendermint-001/clientState --trusted-block 2438000 --target-block 2438010 -o 'contracts/fixtures/uc_and_memberships_fixture.json'" \ - "sleep 30 && RUST_LOG=info SP1_PROVER={{prover}} TENDERMINT_RPC_URL='https://rpc.celestia-mocha.com/' ./target/release/operator fixtures membership --key-paths clients/07-tendermint-0/clientState,clients/07-tendermint-001/clientState --trusted-block 2438000 -o 'contracts/fixtures/memberships_fixture.json'" + "RUST_LOG=info SP1_PROVER={{prover}} ./target/release/operator fixtures update-client --trusted-block $TRUSTED_HEIGHT --target-block $TARGET_HEIGHT -o 'contracts/fixtures/update_client_fixture.json'" \ + "sleep 15 && RUST_LOG=info SP1_PROVER={{prover}} ./target/release/operator fixtures update-client-and-membership --key-paths clients/07-tendermint-0/clientState,clients/07-tendermint-001/clientState --trusted-block $TRUSTED_HEIGHT --target-block $TARGET_HEIGHT -o 'contracts/fixtures/uc_and_memberships_fixture.json'" \ + "sleep 30 && RUST_LOG=info SP1_PROVER={{prover}} ./target/release/operator fixtures membership --key-paths clients/07-tendermint-0/clientState,clients/07-tendermint-001/clientState --trusted-block $TRUSTED_HEIGHT -o 'contracts/fixtures/memberships_fixture.json'" + cd e2e/interchaintestv8 && RUST_LOG=info SP1_PROVER=network GENERATE_FIXTURES=true go test -v -run '^TestWithSP1ICS07TendermintTestSuite/TestDoubleSignMisbehaviour$' -timeout 40m + cd e2e/interchaintestv8 && RUST_LOG=info SP1_PROVER=network GENERATE_FIXTURES=true go test -v -run '^TestWithSP1ICS07TendermintTestSuite/TestBreakingTimeMonotonicityMisbehaviour' -timeout 40m @echo "Fixtures generated at 'contracts/fixtures'" # Generate the `SP1ICS07Tendermint.json` file containing the ABI of the SP1ICS07Tendermint contract # Requires `jq` to be installed on the system # Requires `abigen` to be installed on the system to generate the go bindings for e2e tests -generate-abi: +generate-abi: clean cd contracts && forge install && forge build jq '.abi' contracts/out/SP1ICS07Tendermint.sol/SP1ICS07Tendermint.json > contracts/abi/SP1ICS07Tendermint.json @echo "ABI file created at 'contracts/abi/SP1ICS07Tendermint.json'" @@ -71,11 +74,9 @@ generate-abi: @echo "Done." # Deploy the SP1ICS07Tendermint contract to the Eth Sepolia testnet if the `.env` file is present -deploy-contracts: +deploy-contracts: genesis @echo "Deploying the SP1ICS07Tendermint contract" - just genesis cd contracts && forge install - @echo "Deploying the contract..." cd contracts && forge script script/SP1ICS07Tendermint.s.sol --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast # Run the operator using the `cargo run --bin operator` command. @@ -94,16 +95,23 @@ test-e2e testname: lint: @echo "Linting the Rust code..." cargo fmt --all -- --check + cargo clippy @echo "Linting the Solidity code..." forge fmt --check && bun solhint -w 0 -c .solhint.json 'contracts/**/*.sol' && bun natspec-smells --enforceInheritdoc false --include 'contracts/src/**/*.sol' @echo "Linting the Go code..." cd e2e/interchaintestv8 && golangci-lint run -# Fix the Rust, Solidity, and Go code using `cargo fmt`, `forge fmt`, and `golanci-lint` commands +# Fix the Rust, Solidity, and Go code using `cargo fmt`, `forge fmt`, 'clippy' and `golanci-lint` commands lint-fix: @echo "Fixing the Rust code..." cargo fmt --all + cargo clippy --fix --allow-dirty --allow-staged @echo "Fixing the Solidity code..." forge fmt && bun solhint -w 0 -c .solhint.json 'contracts/**/*.sol' && bun natspec-smells --enforceInheritdoc false --include 'contracts/src/**/*.sol' @echo "Fixing the Go code..." cd e2e/interchaintestv8 && golangci-lint run --fix + +clean: + @echo "Cleaning up cache and build artifacts..." + cargo clean + cd contracts && rm -rf cache out diff --git a/operator/build.rs b/operator/build.rs index 40e6607..6e764ba 100644 --- a/operator/build.rs +++ b/operator/build.rs @@ -11,7 +11,6 @@ fn main() { ..Default::default() }, ); - // Build the membership program. build_program_with_args( "../programs/membership", @@ -20,7 +19,6 @@ fn main() { ..Default::default() }, ); - // Build the uc-and-membership program. build_program_with_args( "../programs/uc-and-membership", @@ -29,4 +27,12 @@ fn main() { ..Default::default() }, ); + // Build the misbehaviour program. + build_program_with_args( + "../programs/misbehaviour", + BuildArgs { + elf_name: "misbehaviour-riscv32im-succinct-zkvm-elf".to_string(), + ..Default::default() + }, + ) } diff --git a/operator/src/bin/operator.rs b/operator/src/bin/operator.rs index 898cb9c..0b06c62 100644 --- a/operator/src/bin/operator.rs +++ b/operator/src/bin/operator.rs @@ -3,7 +3,7 @@ use sp1_ics07_tendermint_operator::{ cli::command::{fixtures, Commands, OperatorCli}, runners::{ self, - fixtures::{membership, uc_and_mem, update_client}, + fixtures::{membership, misbehaviour, uc_and_mem, update_client}, }, }; use sp1_sdk::utils::setup_logger; @@ -27,6 +27,7 @@ async fn main() -> anyhow::Result<()> { fixtures::Cmds::UpdateClient(args) => update_client::run(args).await, fixtures::Cmds::Membership(args) => membership::run(args).await, fixtures::Cmds::UpdateClientAndMembership(args) => uc_and_mem::run(args).await, + fixtures::Cmds::Misbehaviour(args) => misbehaviour::run(args).await, }, } } diff --git a/operator/src/cli/command.rs b/operator/src/cli/command.rs index a8d6ec0..f27f910 100644 --- a/operator/src/cli/command.rs +++ b/operator/src/cli/command.rs @@ -107,6 +107,8 @@ pub mod fixtures { Membership(MembershipCmd), /// The subcommand to generate the update client and verify (non)membership fixtures. UpdateClientAndMembership(UpdateClientAndMembershipCmd), + /// The subcommand to generate the misbehaviour fixtures. + Misbehaviour(MisbehaviourCmd), } /// The arguments for the `UpdateClient` fixture executable. @@ -175,6 +177,23 @@ pub mod fixtures { #[clap(flatten)] pub trust_options: super::TrustOptions, } + + /// The arguments for the `Misbehaviour` fixture executable. + #[derive(Parser, Debug, Clone)] + #[command(about = "Generate the misbehaviour fixture")] + pub struct MisbehaviourCmd { + /// Path to the misbehaviour json file. + #[clap(long)] + pub misbehaviour_path: String, + + /// Fixture path. If not provided, the output will be written to stdout. + #[clap(long, short = 'o', value_parser = super::parse_output_path, default_value = "-")] + pub output_path: super::OutputPath, + + /// Trust options + #[clap(flatten)] + pub trust_options: super::TrustOptions, + } } #[allow(clippy::unnecessary_wraps)] diff --git a/operator/src/programs.rs b/operator/src/programs.rs index e9720ba..df7f12e 100644 --- a/operator/src/programs.rs +++ b/operator/src/programs.rs @@ -25,6 +25,9 @@ pub struct MembershipProgram; /// SP1 ICS07 Tendermint update client and verify (non)membership program. pub struct UpdateClientAndMembershipProgram; +/// SP1 ICS07 Tendermint misbehaviour program. +pub struct MisbehaviourProgram; + impl SP1Program for UpdateClientProgram { const ELF: &'static [u8] = include_bytes!("../../elf/update-client-riscv32im-succinct-zkvm-elf"); @@ -38,3 +41,7 @@ impl SP1Program for UpdateClientAndMembershipProgram { const ELF: &'static [u8] = include_bytes!("../../elf/uc-and-membership-riscv32im-succinct-zkvm-elf"); } + +impl SP1Program for MisbehaviourProgram { + const ELF: &'static [u8] = include_bytes!("../../elf/misbehaviour-riscv32im-succinct-zkvm-elf"); +} diff --git a/operator/src/prover.rs b/operator/src/prover.rs index ba6cbb6..079bcd1 100644 --- a/operator/src/prover.rs +++ b/operator/src/prover.rs @@ -1,9 +1,10 @@ //! Prover for SP1 ICS07 Tendermint programs. use crate::programs::{ - MembershipProgram, SP1Program, UpdateClientAndMembershipProgram, UpdateClientProgram, + MembershipProgram, MisbehaviourProgram, SP1Program, UpdateClientAndMembershipProgram, + UpdateClientProgram, }; -use ibc_client_tendermint::types::Header; +use ibc_client_tendermint::types::{Header, Misbehaviour}; use ibc_core_commitment_types::merkle::MerkleProof; use ibc_proto::Protobuf; use sp1_ics07_tendermint_solidity::sp1_ics07_tendermint::{ @@ -190,3 +191,46 @@ impl SP1ICS07TendermintProver { proof } } + +impl SP1ICS07TendermintProver { + /// Generate a proof of a misbehaviour. + /// + /// # Panics + /// Panics if the proof cannot be generated or the proof is invalid. + #[must_use] + pub fn generate_proof( + &self, + contract_env: &Env, + misbehaviour: &Misbehaviour, + trusted_consensus_state_1: &SolConsensusState, + trusted_consensus_state_2: &SolConsensusState, + ) -> SP1ProofWithPublicValues { + let encoded_1 = bincode::serialize(contract_env).unwrap(); + let encoded_2 = serde_cbor::to_vec(misbehaviour).unwrap(); + let encoded_3 = bincode::serialize(trusted_consensus_state_1).unwrap(); + let encoded_4 = bincode::serialize(trusted_consensus_state_2).unwrap(); + + let mut stdin = SP1Stdin::new(); + stdin.write_vec(encoded_1); + stdin.write_vec(encoded_2); + stdin.write_vec(encoded_3); + stdin.write_vec(encoded_4); + + // Generate the proof. Depending on SP1_PROVER env variable, this may be a mock, local or + // network proof. + let proof = self + .prover_client + .prove(&self.pkey, stdin) + .plonk() + .run() + .expect("proving failed"); + + // Verify proof. + self.prover_client + .verify(&proof, &self.vkey) + .expect("Verification failed"); + + // Return the proof. + proof + } +} diff --git a/operator/src/runners/fixtures/misbehaviour.rs b/operator/src/runners/fixtures/misbehaviour.rs new file mode 100644 index 000000000..d4dc29c --- /dev/null +++ b/operator/src/runners/fixtures/misbehaviour.rs @@ -0,0 +1,141 @@ +//! Runner for generating `misbehaviour` fixtures + +use crate::cli::command::fixtures::MisbehaviourCmd; +use crate::cli::command::OutputPath; +use crate::helpers::light_block::LightBlockExt; +use crate::programs::MisbehaviourProgram; +use crate::prover::SP1ICS07TendermintProver; +use crate::rpc::TendermintRpcExt; +use crate::runners::genesis::SP1ICS07TendermintGenesis; +use alloy_sol_types::SolValue; +use ibc_client_tendermint::types::Misbehaviour; +use ibc_proto::ibc::lightclients::tendermint::v1::Misbehaviour as RawMisbehaviour; +use serde::{Deserialize, Serialize}; +use serde_with::serde_as; +use sp1_ics07_tendermint_solidity::sp1_ics07_tendermint::{ + ClientState, ConsensusState, Env, MsgSubmitMisbehaviour, SP1Proof, +}; +use sp1_sdk::HashableKey; +use std::path::PathBuf; +use tendermint_rpc::HttpClient; + +/// The fixture data to be used in [`SP1ICS07SubmitMisbehaviourFixture`] tests. +#[serde_as] +#[derive(Debug, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +struct SP1ICS07SubmitMisbehaviourFixture { + /// The genesis data. + #[serde(flatten)] + genesis: SP1ICS07TendermintGenesis, + + /// The encoded submit misbehaviour client message. + #[serde_as(as = "serde_with::hex::Hex")] + submit_msg: Vec, +} + +/// Writes the proof data for misbehaviour to the given fixture path. +#[allow(clippy::missing_errors_doc, clippy::missing_panics_doc)] +pub async fn run(args: MisbehaviourCmd) -> anyhow::Result<()> { + let path = args.misbehaviour_path; + let misbehaviour_bz = std::fs::read(path)?; + // deserialize from json + let raw_misbehaviour: RawMisbehaviour = serde_json::from_slice(&misbehaviour_bz)?; + + let tm_rpc_client = HttpClient::from_env(); + + // get light block for trusted height of header 1 + #[allow(clippy::cast_possible_truncation)] + let trusted_light_block_1 = tm_rpc_client + .get_light_block(Some( + raw_misbehaviour + .clone() + .header_1 + .unwrap() + .trusted_height + .unwrap() + .revision_height as u32, + )) + .await?; + #[allow(clippy::cast_possible_truncation)] + // get light block for trusted height of header 2 + let trusted_light_block_2 = tm_rpc_client + .get_light_block(Some( + raw_misbehaviour + .clone() + .header_2 + .unwrap() + .trusted_height + .unwrap() + .revision_height as u32, + )) + .await?; + + // use trusted light block 1 to instantiate a new SP1 tendermint client with light block 1 as initial trusted consensus state + let genesis_1 = SP1ICS07TendermintGenesis::from_env( + &trusted_light_block_1, + args.trust_options.trusting_period, + args.trust_options.trust_level, + ) + .await?; + // use trusted light block 2 to instantiate a new SP1 tendermint client with light block 2 as initial trusted consensus state + let genesis_2 = SP1ICS07TendermintGenesis::from_env( + &trusted_light_block_2, + args.trust_options.trusting_period, + args.trust_options.trust_level, + ) + .await?; + + // use the clients to convert the Tendermint light blocks into the IBC Tendermint trusted consensus states + let trusted_consensus_state_1 = + ConsensusState::abi_decode(&genesis_1.trusted_consensus_state, false)?; + let trusted_consensus_state_2 = + ConsensusState::abi_decode(&genesis_2.trusted_consensus_state, false)?; + + // use the client state from genesis_2 as the client state since they will both be the same + let trusted_client_state_2 = ClientState::abi_decode(&genesis_2.trusted_client_state, false)?; + + let verify_misbehaviour_prover = SP1ICS07TendermintProver::::default(); + + // construct contract env from the client state, which will be used by the light client contract + let contract_env = Env { + chainId: trusted_light_block_2.chain_id()?.to_string(), + trustThreshold: trusted_client_state_2.trustLevel, + trustingPeriod: trusted_client_state_2.trustingPeriod, + now: std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH)? + .as_secs(), + }; + + let misbehaviour: Misbehaviour = Misbehaviour::try_from(raw_misbehaviour).unwrap(); + let proof_data = verify_misbehaviour_prover.generate_proof( + &contract_env, + &misbehaviour, + &trusted_consensus_state_1, + &trusted_consensus_state_2, + ); + + let submit_msg = MsgSubmitMisbehaviour { + sp1Proof: SP1Proof::new( + &verify_misbehaviour_prover.vkey.bytes32(), + proof_data.bytes(), + proof_data.public_values.to_vec(), + ), + }; + + let fixture = SP1ICS07SubmitMisbehaviourFixture { + genesis: genesis_2, + submit_msg: submit_msg.abi_encode(), + }; + + match args.output_path { + OutputPath::File(path) => { + // Save the proof data to the file path. + std::fs::write(PathBuf::from(path), serde_json::to_string_pretty(&fixture)?)?; + } + OutputPath::Stdout => { + println!("{}", serde_json::to_string_pretty(&fixture)?); + } + } + + Ok(()) +} diff --git a/operator/src/runners/fixtures/mod.rs b/operator/src/runners/fixtures/mod.rs index 7e40869..898d44b 100644 --- a/operator/src/runners/fixtures/mod.rs +++ b/operator/src/runners/fixtures/mod.rs @@ -1,5 +1,6 @@ //! Runners for generating fixtures for testing of the programs. pub mod membership; +pub mod misbehaviour; pub mod uc_and_mem; pub mod update_client; diff --git a/operator/src/runners/genesis.rs b/operator/src/runners/genesis.rs index d8fc6b5..a11a9e9 100644 --- a/operator/src/runners/genesis.rs +++ b/operator/src/runners/genesis.rs @@ -4,7 +4,8 @@ use crate::{ cli::command::{genesis::Args, OutputPath}, helpers::light_block::LightBlockExt, programs::{ - MembershipProgram, SP1Program, UpdateClientAndMembershipProgram, UpdateClientProgram, + MembershipProgram, MisbehaviourProgram, SP1Program, UpdateClientAndMembershipProgram, + UpdateClientProgram, }, rpc::TendermintRpcExt, }; @@ -34,6 +35,8 @@ pub struct SP1ICS07TendermintGenesis { membership_vkey: String, /// The encoded key for [`UpdateClientAndMembershipProgram`]. uc_and_membership_vkey: String, + /// The encoded key for [`MisbehaviourProgram`]. + misbehaviour_vkey: String, } impl SP1ICS07TendermintGenesis { @@ -81,6 +84,7 @@ impl SP1ICS07TendermintGenesis { update_client_vkey: UpdateClientProgram::get_vkey().bytes32(), membership_vkey: MembershipProgram::get_vkey().bytes32(), uc_and_membership_vkey: UpdateClientAndMembershipProgram::get_vkey().bytes32(), + misbehaviour_vkey: MisbehaviourProgram::get_vkey().bytes32(), }) } } diff --git a/packages/solidity/src/lib.rs b/packages/solidity/src/lib.rs index accf8f2..b0cdd32 100644 --- a/packages/solidity/src/lib.rs +++ b/packages/solidity/src/lib.rs @@ -13,7 +13,7 @@ use time::OffsetDateTime; alloy_sol_types::sol!( #[sol(rpc)] #[derive(serde::Deserialize, serde::Serialize)] - #[allow(missing_docs, clippy::pedantic)] + #[allow(missing_docs, clippy::pedantic, warnings)] sp1_ics07_tendermint, "../../contracts/abi/SP1ICS07Tendermint.json" ); diff --git a/programs/misbehaviour/Cargo.toml b/programs/misbehaviour/Cargo.toml new file mode 100644 index 000000000..c10f183 --- /dev/null +++ b/programs/misbehaviour/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "sp1-ics07-tendermint-misbehaviour" +description = "Check for misbehaviour program for sp1-ics07-tendermint" +version = { workspace = true } +authors = { workspace = true } +edition = { workspace = true } +repository = { workspace = true } +license = { workspace = true } + +[dependencies] +sp1-zkvm = { workspace = true } +sp1-ics07-tendermint-solidity = { workspace = true } +tendermint-light-client-verifier = { workspace = true } +ibc-client-tendermint = { workspace = true } +ibc-core-host-types = { workspace = true } +ibc-core-client = { workspace = true } +ibc-primitives = { workspace = true } +ibc-core-handler-types = { workspace = true } +serde = { workspace = true } +sha2 = { workspace = true } +alloy-sol-types = { workspace = true } +serde_cbor = { workspace = true } +bincode = { workspace = true } diff --git a/programs/misbehaviour/src/lib.rs b/programs/misbehaviour/src/lib.rs new file mode 100644 index 000000000..ea36766 --- /dev/null +++ b/programs/misbehaviour/src/lib.rs @@ -0,0 +1,118 @@ +//! The crate that contains the types and utilities for `sp1-ics07-tendermint-update-client` +//! program. +#![deny(missing_docs, clippy::nursery, clippy::pedantic, warnings)] + +pub mod types; + +use ibc_client_tendermint::client_state::{ + check_for_misbehaviour_on_misbehavior, verify_misbehaviour, +}; +use ibc_client_tendermint::types::{ConsensusState, Misbehaviour, TENDERMINT_CLIENT_TYPE}; +use ibc_core_host_types::identifiers::{ChainId, ClientId}; +use sp1_ics07_tendermint_solidity::sp1_ics07_tendermint; +use sp1_ics07_tendermint_solidity::sp1_ics07_tendermint::{Env, MisbehaviourOutput}; +use std::collections::HashMap; +use std::time::Duration; +use tendermint_light_client_verifier::options::Options; +use tendermint_light_client_verifier::ProdVerifier; + +/// The main function of the program without the zkVM wrapper. +#[allow(clippy::missing_panics_doc)] +#[must_use] +pub fn check_for_misbehaviour( + env: Env, + misbehaviour: &Misbehaviour, + trusted_consensus_state_1: ConsensusState, + trusted_consensus_state_2: ConsensusState, +) -> MisbehaviourOutput { + let client_id = ClientId::new(TENDERMINT_CLIENT_TYPE, 0).unwrap(); + let chain_id = env.clone().chainId; + assert_eq!( + chain_id, + misbehaviour + .header1() + .signed_header + .header + .chain_id + .to_string() + ); + + // Insert the two trusted consensus states into the trusted consensus state map that exists in the ClientValidationContext that is expected by verifyMisbehaviour + // Since we are mocking the existence of prior trusted consensus states, we are only filling in the two consensus states that are passed in into the map + let mut trusted_consensus_state_map = HashMap::new(); + trusted_consensus_state_map.insert( + misbehaviour.header1().trusted_height.revision_height(), + &trusted_consensus_state_1, + ); + trusted_consensus_state_map.insert( + misbehaviour.header2().trusted_height.revision_height(), + &trusted_consensus_state_2, + ); + let ctx = + types::validation::MisbehaviourValidationContext::new(&env, trusted_consensus_state_map); + + let options = Options { + trust_threshold: env.trustThreshold.clone().into(), + trusting_period: Duration::from_secs(env.trustingPeriod.into()), + clock_drift: Duration::default(), + }; + + // Call into ibc-rs verify_misbehaviour function to verify that both headers are valid given their respective trusted consensus states + verify_misbehaviour::<_, sha2::Sha256>( + &ctx, + misbehaviour, + &client_id, + &ChainId::new(chain_id.as_str()).unwrap(), + &options, + &ProdVerifier::default(), + ) + .unwrap(); + + // Call into ibc-rs check_for_misbehaviour_on_misbehaviour method to ensure that the misbehaviour is valid + // i.e. the headers are same height but different commits, or headers are not monotonically increasing in time + let is_misbehaviour = + check_for_misbehaviour_on_misbehavior(misbehaviour.header1(), misbehaviour.header2()) + .unwrap(); + + assert!(is_misbehaviour, "Misbehaviour is not detected"); + + let output_trusted_height_1 = sp1_ics07_tendermint::Height { + revisionNumber: misbehaviour + .header1() + .trusted_height + .revision_height() + .try_into() + .unwrap(), + revisionHeight: misbehaviour + .header1() + .trusted_height + .revision_height() + .try_into() + .unwrap(), + }; + let output_trusted_height_2 = sp1_ics07_tendermint::Height { + revisionNumber: misbehaviour + .header2() + .trusted_height + .revision_height() + .try_into() + .unwrap(), + revisionHeight: misbehaviour + .header2() + .trusted_height + .revision_height() + .try_into() + .unwrap(), + }; + + // The prover takes in the trusted headers as an input but does not maintain its own internal state + // Thus, the verifier must ensure that the trusted headers that were used in the proof are trusted consensus + // states stored in its own internal state before it can accept the misbehaviour proof as valid. + MisbehaviourOutput { + env, + trustedHeight1: output_trusted_height_1, + trustedHeight2: output_trusted_height_2, + trustedConsensusState1: trusted_consensus_state_1.into(), + trustedConsensusState2: trusted_consensus_state_2.into(), + } +} diff --git a/programs/misbehaviour/src/main.rs b/programs/misbehaviour/src/main.rs new file mode 100644 index 000000000..4963f1b --- /dev/null +++ b/programs/misbehaviour/src/main.rs @@ -0,0 +1,50 @@ +//! A program that verifies a misbehaviour evidence. + +#![deny(missing_docs, clippy::nursery, clippy::pedantic, warnings)] +#![allow(clippy::no_mangle_with_rust_abi)] +// These two lines are necessary for the program to properly compile. +// +// Under the hood, we wrap your main function with some extra code so that it behaves properly +// inside the zkVM. +#![no_main] +sp1_zkvm::entrypoint!(main); + +use alloy_sol_types::SolValue; +use ibc_client_tendermint::types::Misbehaviour; +use sp1_ics07_tendermint_misbehaviour::check_for_misbehaviour; +use sp1_ics07_tendermint_solidity::sp1_ics07_tendermint::{ + ConsensusState as SolConsensusState, Env, +}; + +/// The main function of the program. +/// +/// # Panics +/// Panics if the verification fails. +pub fn main() { + let encoded_1 = sp1_zkvm::io::read_vec(); + let encoded_2 = sp1_zkvm::io::read_vec(); + let encoded_3 = sp1_zkvm::io::read_vec(); + let encoded_4 = sp1_zkvm::io::read_vec(); + + // input 1: environment + let env = bincode::deserialize::(&encoded_1).unwrap(); + // input 2: the misbehaviour evidence + let misbehaviour = serde_cbor::from_slice::(&encoded_2).unwrap(); + // input 3: header 1 trusted consensus state + let trusted_consensus_state_1 = bincode::deserialize::(&encoded_3) + .unwrap() + .into(); + // input 4: header 2 trusted consensus state + let trusted_consensus_state_2 = bincode::deserialize::(&encoded_4) + .unwrap() + .into(); + + let output = check_for_misbehaviour( + env, + &misbehaviour, + trusted_consensus_state_1, + trusted_consensus_state_2, + ); + + sp1_zkvm::io::commit_slice(&output.abi_encode()); +} diff --git a/programs/misbehaviour/src/types/mod.rs b/programs/misbehaviour/src/types/mod.rs new file mode 100644 index 000000000..c63405d --- /dev/null +++ b/programs/misbehaviour/src/types/mod.rs @@ -0,0 +1,3 @@ +//! Containes types used in the program. + +pub mod validation; diff --git a/programs/misbehaviour/src/types/validation.rs b/programs/misbehaviour/src/types/validation.rs new file mode 100644 index 000000000..8fd0ce5 --- /dev/null +++ b/programs/misbehaviour/src/types/validation.rs @@ -0,0 +1,100 @@ +//! Contains types and traits for `verify_misbehaviour` validation within the program. + +use ibc_client_tendermint::{ + client_state::ClientState as ClientStateWrapper, + consensus_state::ConsensusState as ConsensusStateWrapper, types::ConsensusState, +}; +use ibc_core_client::context::{ClientValidationContext, ExtClientValidationContext}; +use ibc_core_handler_types::error::ContextError; +use ibc_primitives::Timestamp; +use sp1_ics07_tendermint_solidity::sp1_ics07_tendermint::Env; +use std::collections::HashMap; + +/// The client validation context. +pub struct MisbehaviourValidationContext<'a, 'b> { + env: &'a Env, + trusted_consensus_states: HashMap, +} + +impl<'a, 'b> MisbehaviourValidationContext<'a, 'b> { + /// Create a new instance of the client validation context. + #[must_use] + pub const fn new( + env: &'a Env, + trusted_consensus_states: HashMap, + ) -> Self { + Self { + env, + trusted_consensus_states, + } + } +} + +impl<'a, 'b> ClientValidationContext for MisbehaviourValidationContext<'a, 'b> { + type ClientStateRef = ClientStateWrapper; + type ConsensusStateRef = ConsensusStateWrapper; + + fn consensus_state( + &self, + client_cons_state_path: &ibc_core_host_types::path::ClientConsensusStatePath, + ) -> Result { + let height = client_cons_state_path.revision_height; + let trusted_consensus_state = self.trusted_consensus_states[&height]; + + Ok(trusted_consensus_state.clone().into()) + } + + fn client_state( + &self, + _client_id: &ibc_core_host_types::identifiers::ClientId, + ) -> Result { + // not needed by the `verify_header` function + unimplemented!() + } + + fn client_update_meta( + &self, + _client_id: &ibc_core_host_types::identifiers::ClientId, + _height: &ibc_core_client::types::Height, + ) -> Result<(Timestamp, ibc_core_client::types::Height), ContextError> { + // not needed by the `verify_header` function + unimplemented!() + } +} + +impl<'a, 'b> ExtClientValidationContext for MisbehaviourValidationContext<'a, 'b> { + fn host_timestamp(&self) -> Result { + Ok(Timestamp::from_nanoseconds(self.env.now * 1_000_000_000)) + } + + fn host_height(&self) -> Result { + // not needed by the `verify_header` function + unimplemented!() + } + + fn consensus_state_heights( + &self, + _client_id: &ibc_core_host_types::identifiers::ClientId, + ) -> Result, ContextError> { + // not needed by the `verify_header` function + unimplemented!() + } + + fn next_consensus_state( + &self, + _client_id: &ibc_core_host_types::identifiers::ClientId, + _height: &ibc_core_client::types::Height, + ) -> Result, ContextError> { + // not needed by the `verify_header` function + unimplemented!() + } + + fn prev_consensus_state( + &self, + _client_id: &ibc_core_host_types::identifiers::ClientId, + _height: &ibc_core_client::types::Height, + ) -> Result, ContextError> { + // not needed by the `verify_header` function + unimplemented!() + } +}