diff --git a/evm/script/deploy.sh b/evm/script/deploy.sh index 24e4ded88..2883f006f 100755 --- a/evm/script/deploy.sh +++ b/evm/script/deploy.sh @@ -1,9 +1,10 @@ +#!/bin/bash if [ "$1" = "local" ]; then echo "Deploying locally" # load local .env source .env # deploy - HOST="ethereum" forge script script/DeployIsmp.s.sol:DeployScript --rpc-url "$GOERLI_RPC_URL" --broadcast --verify -vvvv --sender="$ADMIN" + HOST="ethereum" forge script script/DeployIsmp.s.sol:DeployScript --rpc-url "$GOERLI_RPC_URL" --broadcast -vvvv --sender="$ADMIN" else echo "Deploying to $1" # load prod .env diff --git a/evm/src/beefy/ZkBeefy.sol b/evm/src/beefy/ZkBeefy.sol index 2d0d8d59c..d628505d0 100644 --- a/evm/src/beefy/ZkBeefy.sol +++ b/evm/src/beefy/ZkBeefy.sol @@ -52,7 +52,6 @@ contract ZkBeefyV1 is IConsensusClient { function verifyConsensus(bytes memory encodedState, bytes memory encodedProof) external - view returns (bytes memory, IntermediateState memory) { BeefyConsensusState memory consensusState = abi.decode(encodedState, (BeefyConsensusState)); @@ -69,7 +68,6 @@ contract ZkBeefyV1 is IConsensusClient { /// by this consensus proof. function verifyConsensus(BeefyConsensusState memory trustedState, BeefyConsensusProof memory proof) internal - view returns (BeefyConsensusState memory, IntermediateState memory) { // verify mmr root proofs @@ -87,7 +85,6 @@ contract ZkBeefyV1 is IConsensusClient { /// using a merkle multi proof and a merkle commitment to the total authorities. function verifyMmrUpdateProof(BeefyConsensusState memory trustedState, PlonkConsensusProof memory relayProof) internal - view returns (BeefyConsensusState memory, bytes32) { uint256 latestHeight = relayProof.commitment.blockNumber; @@ -131,7 +128,7 @@ contract ZkBeefyV1 is IConsensusClient { // check BEEFY proof require(_verifier.verify(relayProof.proof, inputs), "ZkBEEFY: Invalid plonk proof"); - verifyMmrLeaf(relayProof, mmrRoot); + verifyMmrLeaf(trustedState, relayProof, mmrRoot); if (relayProof.latestMmrLeaf.nextAuthoritySet.id > trustedState.nextAuthoritySet.id) { trustedState.currentAuthoritySet = trustedState.nextAuthoritySet; @@ -144,15 +141,16 @@ contract ZkBeefyV1 is IConsensusClient { } /// Stack too deep, sigh solidity - function verifyMmrLeaf(PlonkConsensusProof memory relay, bytes32 mmrRoot) internal pure { - bytes32 temp = keccak256(Codec.Encode(relay.latestMmrLeaf)); - // bag peaks from right to left - uint256 i = relay.mmrProof.length; - for (; i > 0; i--) { - temp = keccak256(bytes.concat(temp, relay.mmrProof[i - 1])); - } + function verifyMmrLeaf(BeefyConsensusState memory trustedState, PlonkConsensusProof memory relay, bytes32 mmrRoot) + internal + { + bytes32 hash = keccak256(Codec.Encode(relay.latestMmrLeaf)); + uint256 leafCount = leafIndex(trustedState.beefyActivationBlock, relay.latestMmrLeaf.parentNumber) + 1; - require(temp == mmrRoot, "Invalid Mmr Proof"); + MmrLeaf[] memory leaves = new MmrLeaf[](1); + leaves[0] = MmrLeaf(relay.latestMmrLeaf.kIndex, relay.latestMmrLeaf.leafIndex, hash); + + require(MerkleMountainRange.VerifyProof(mmrRoot, relay.mmrProof, leaves, leafCount), "Invalid Mmr Proof"); } /// Verifies that some parachain header has been finalized, given the current trusted consensus state. @@ -192,4 +190,13 @@ contract ZkBeefyV1 is IConsensusClient { return IntermediateState(para.id, header.number, StateCommitment(timestamp, commitment, header.stateRoot)); } + + /// Calculates the mmr leaf index for a block whose parent number is given. + function leafIndex(uint256 activationBlock, uint256 parentNumber) private pure returns (uint256) { + if (activationBlock == 0) { + return parentNumber; + } else { + return parentNumber - activationBlock; + } + } } diff --git a/evm/test/ZkBeefyTest.sol b/evm/test/ZkBeefyTest.sol new file mode 100644 index 000000000..6959391c6 --- /dev/null +++ b/evm/test/ZkBeefyTest.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity 0.8.17; + +import "forge-std/Test.sol"; + +import {ZkBeefyV1, BeefyConsensusState} from "../src/beefy/ZkBeefy.sol"; +import {RococoVerifier} from "../src/beefy/verifiers/RococoVerifier.sol"; + +contract BeefyConsensusClientTest is Test { + ZkBeefyV1 internal beefy; + + function setUp() public virtual { + RococoVerifier verifier = new RococoVerifier(); + beefy = new ZkBeefyV1(2000, verifier); + } + + function testBeefyProof() public { + bytes memory proof = + hex"00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000ce00000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008755e1942b2aad1859ad315aaaa081a458e59466244a64acbed651f67f493ae25701870000000000000000000000000000000000000000000000000000000000003b53000000000000000000000000000000000000000000000000000000000000006eab34ddb838b4f3f271d56c3fc2678c88cd735d9946ba100cb91ee698a53b44d3aa12de07c3b034ed158b9d6ed625e56e8fc20611e9b4790b1481a63ccec0894c000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000004d4a6500000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000420000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000008755e20000000000000000000000000000000000000000000000000000000000003b52000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000206d680000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002043a2200c22127a11c6f9d6bc880de0cf9bbc5aa901d4235e7659943d38a8007e000000000000000000000000000000000000000000000000000000000000000bcdb32ad5cea2b0454fd8b3ff6307fa02fa6a435dbbc46dd2e0080b83eaa868ae5f053506d1054f84c6b7d350a03a83459591c4eec55d20fffd4b7c3b0a2e97a177de647be78b26c08ac6f538c94f2ce8f672603e2c78fc40441e5615f0d53ec1697c5ed32e1a9dce29ea5f94775a80a44aff3e62896c1a9f641bedd287488f9ea8c1623be7595ff68e168e65381dc49d6b8d00c404ff29a146f9b2bb6be2d2ad9ad42ffa93c51ba9fcc546026bbd05a59c59e32f874c18191b15cac9bde151b952caca1673be722c4de79dc51f77baff0824152c14d864532e592cfa26d608a03b9bd93710a5beb3466c41936ba2424091f7d07d91d018a6d8e7cc048f818b556540f73acf8c111513a2bb3bcbb8c52bfd4186e577c7081c8d9fbf79b09d883656b6f35c4e6b535aad5805fdce54ede948ddd807ed7d4caf8354b94b21bf8d0ca5b5ddc9822f6efff4cb05b28dbba19f3517ec755421179427db3139c014f6000000000000000000000000000000000000000000000000000000000000000860018247c70b697bc76583275854839658774c4466100d089b298f75fa67bea7da2db6f324bb52811f172d609eb909fa55cb3b72d8c80480869c0d795533c347a21bc172689ad14a46fefffc30a92a06be2f1f17635e130d94449f4e5653f23c402f355b56c098baaab9a2bad2433ed41d079002078ba5da26ca991c28a9a2d0d50e7e98441d9a9a142dfd53bec66fc3bfa1f321d19ec98cbdaeffdf74fcb4b8af0df5c1f1bfbc3805cafa72a0f57071bd956cee42a81624dc039d4e35ec8fea103038dda4afcd938f00e1d437b1e4eb5864f4f9327271c5d41db5a772bbb817581fba844fe23a866f9bde1ba3cbbac200bbb375f900bda9d83acbb6bf7aa79590289b0e178b3f2e473221c50c46fb7e46afb047f42c5d09f04ca57d24c34d01df1c427609a7d50e553ccd480b3f965a904ef329e76b9f8c248f1aef84aa9134442a6191543b3cb0291692ae290b5e810a47ab9d4a9812c0e561e1dd4c21f3d4112142400cc6b40172ce2b79afbcfff84714583783bbe3ef5815751b11f11111592ccd95ee549f066e4550f86033ed531643294862ac8e9bd38b67817294ea8ed42aa3ea0d1984c076145f1795b4b0ec94cfebf48d6d6269c61d752131cfd8b6b90f832e18228746e22ec7714b9ca554b49e2d881b7e621d638a00a676646b4a0118bb63bc6f7d85c882b3e6cacbf1671108a0263ab15b631ba6215f10c8ee22632d5c50226e8d0706d0faf30535c6b51d2006919c01a0d6fafbd08c6899e01cd31c9f60ac08163711d98f0b380e450aaef1f50b6d4fdfcf3b84619ff4d8f8f3332a8b10f2eea5395896d14be632539d970db2297d18168b2c6043cf61a7068122065153a2188ce09cc3f91ecfa96a6a2b3b9100c8e78bba4ba0edc8c009cf647426207cb486c6e42d23c3db3b0b50bea14faa8ccc30d4301c72eb059dd1538a140c64d169b88d038b5d16bbda1237b9113cf9f0c444a33fec4ea73c275f71c9e5238a5197f6851855d76e38acbf99f360889bfe8cbd65a9cec4993d9fbe48f2fa226b7a4cafeb0bb07274dcda0ec76053c71f84abe58e43aa22469757b61846990cdd271be8a2ed5633a421ef9c83c99e472bd23249427eb5f58de129da8a348f09eaf1fa26f8325e52a62363363f69a140c7798d8133e846674bef6b06981e4c2c9d30c2427e85059bec94d8919e6aac45d475eb577c82d8b3983ba5326af2d5300c6daba3091ec6ba9687b812b541117c3cd53a0562238aae8ea1f4bf0591a606acd05ca9e929e5036d1f8089929aff7819c3e94a13414d7f4e2d4393c08493138f94e6736193763a4c14e51dd254d2a133f91f87bab8b054c9aab2c4f61adb0de7b379879deb46cd5531102a1242d83425df25643eb1293a23c9ee9eb554d82bc0844b281d1a31a077cf70f0307e6354420bfdba4bd159336cdf2d98d1a4f3046ecf3778b6559ebd1837f3018618ff7345ea2ffce54187edab2949265dd7a9059ec0dc8d912e5fed660a5b66f422ab11649e4946e13364ffe6fd24ebdd582d0f106f55c9812eabacae42c100aad5399dc01c664d263bb73c33c36cd05870442d278d2a0564f657fce98043586db9550095142787f0bb39bb619a271f2d872422f9178fc60bf164c3e55acbe1bbfda94d71a806b22291c3065350f25b64da4917b0325495d0b13d741e22792a75316c0895738c81c8923f4cc686776be9738a0e8e2f0facb9ae0617a6711bf7eb33a953315a7f06adc91371da35c24db2514222f660c4fdb00905cc4c829665407db401983af9e9293bcab520d89e8d12419a0311206dfb35e29825f2e6d8cb66477e40166740bfd7b278807d2709f98b02e01d766ea6f65e4e3d719a8e56593c375c84b1c35d2301f36ca022ebcea5703424217d6940ec4ad04a8917217d6346244f23afc77e32fcb9896717a696aba58ac02f6ff9cc98994241ab0baf96bacf4a01d7c2096d3016a34b7acc2a5f305c44190f0c2b0202f89f481fdf0defc075ccbb349ea7ebc03e15236d521334fee464910cbc0ccdbb1fefa85e9194df8fe3b6372c9aa7c245505bcff2af38e366b0d0d014ebb4686691ef9d3f548c9dcebc0176607baaad457cbd95cbbc099115ff6f3e052a6933ec6d9a8f7047b72a76c6d0cb2cc722fca17111d319e737cb9966d04305a7bc3d56ff76b8e2760a71c152f6e10c66d6bef4289def68a2769e1702e5d0284ad6600650873acdbcd5a4501ffb354ce68136589d069e581cbc5562d387c0202157054b1f7230e89abc9c785cff3e9fc239990cc3f50e91af3a93afc7da99281a8b6cb153cf1cec70c92309587cb387399251730ec24c8c80836f701e7cb31894f85f162bfb6928f680c51a9760a5d5305a3df3df33b28f981ea37bbabcb4003dd9051f3d8407abc2e26fe87bd74613e13eb33a73030a14663958b4e6afcc0f0a166a55c2f87b841ba87dd33c460058c2c8b566202cbff65c96bb8657f9331baabb8cded80dc58cfe1eeddfb58b8a2e97371e951d46a7159659810a09a1682ff53adfc06d4dbf05ed8b70df831c88b81da38b4a21047204cf8ae8b6181076021aea3cf69f2b4f1b1401724c90a63780cdb721f5dc519909bf29249be4c7251ddbbe5df1a5f70171a727f3e8e0514768ee1cdae3cec8cd212f6bd2965ab932156ee2476bd8e9262be97758b8ace4e890ced9ce8bbc543d145db568a37bb075253b50e3fe364eaf08ee8123af51895bbcd7d184fe4a00b495031da6a4c326a92f511e9a22b39ecdbc469b66cfe25a76a0c492d23df0798e2cf7bf2d4c9b65301e7ac76b789bd8f98b84b7a3787b4a03dbcf62a3ab0957ffa4eaef190077696d2679c5a48882a564d8a03b3c70f7f1a74f843699f5d4134a8098a06d85b084d1131afd178bbc3502641532c8c5eba16cd6294b348e09a77a45513b96ede9cffd0163ddcc6e61c475c42b7846e914d5ea205223d8c01762e79520d8e00296f5350e3fb0b8b2138495b6c55262afd021668f46c66580a9151d4cca823060e4251100000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000007d0000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000baef7cf3c41418e8b91ab4a62b0f61e9d7412c10d0459feb80d4db3a19eee54e75f29968000f969604f0444e069652e3d4a69e12ff83403f71d255946f7ce864b0b444219619ba0a4c43620f43cb720eabd7d83accde9780609467cbd2d7834ee259f09f8508066175726120038350080000000005617572610101d63af09482a0f01fd7ba59aadd4b3f47e882f72b751ed5cc7e99b19b25500042c7e13d45dcd9739c359f275bc57004099d416f1d8a75484b51e2a2b37cdbcf87000000000000000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000002c00000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000067ed65077fd16778ebc2324ccd9ba83dc4a3fa5f4b2f2ab81acb13a97e3e9f3b50000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000239713bbc4b67acccd08215ca1b73eea64f425aec497aa6b1ff78eb970df016f600000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000e8c79f35cd625e77a137a3c15f73fe93ef07d8b6839fa4fb56821881866363970000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000115849513fc4f20fd17f0964b912261d87fab01930058ab84e17bf5372fe2791d00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001e50653f89a025569f05d1160c4e0ae5d9ea06d0b9afcd4356e5927ebb0c1ff9d00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001e75cde1ce400af5a68ca2df7e9eca3d6d89b78955d093e2c0dd02a0c5fc9c5440000000000000000000000000000000000000000000000000000000000000000"; + bytes memory state = + hex"00000000000000000000000000000000000000000000000000000000008752da00000000000000000000000000000000000000000000000000000000003a0b7c0000000000000000000000000000000000000000000000000000000000003b51000000000000000000000000000000000000000000000000000000000000006eab34ddb838b4f3f271d56c3fc2678c88cd735d9946ba100cb91ee698a53b44d30000000000000000000000000000000000000000000000000000000000003b52000000000000000000000000000000000000000000000000000000000000006eab34ddb838b4f3f271d56c3fc2678c88cd735d9946ba100cb91ee698a53b44d3"; + + beefy.verifyConsensus(state, proof); + } +} diff --git a/parachain/node/Cargo.toml b/parachain/node/Cargo.toml index 8f0ebfd40..09547e4b3 100644 --- a/parachain/node/Cargo.toml +++ b/parachain/node/Cargo.toml @@ -6,9 +6,6 @@ description = "The Hyperbridge coprocessor node" edition = "2021" build = "build.rs" -[package.metadata.dist] -features = ["sepolia"] - [dependencies] # crates.io clap = { version = "4.0.32", features = ["derive"] } diff --git a/scripts/ignore_plonk.sh b/scripts/ignore_plonk.sh index e382b864e..e9f26836f 100755 --- a/scripts/ignore_plonk.sh +++ b/scripts/ignore_plonk.sh @@ -3,10 +3,12 @@ mv ./evm/src/beefy/verifiers/KusamaVerifier.sol ./evm/src/beefy/verifiers/Kusama mv ./evm/src/beefy/verifiers/PolkadotVerifier.sol ./evm/src/beefy/verifiers/PolkadotVerifier mv ./evm/src/beefy/verifiers/RococoVerifier.sol ./evm/src/beefy/verifiers/RococoVerifier mv ./evm/test/PlonkTest.sol ./evm/test/PlonkTest +mv ./evm/test/ZkBeefyTest.sol ./evm/test/ZkBeefyTest eval $1 mv ./evm/src/beefy/verifiers/KusamaVerifier ./evm/src/beefy/verifiers/KusamaVerifier.sol mv ./evm/src/beefy/verifiers/PolkadotVerifier ./evm/src/beefy/verifiers/PolkadotVerifier.sol mv ./evm/src/beefy/verifiers/RococoVerifier ./evm/src/beefy/verifiers/RococoVerifier.sol -mv ./evm/test/PlonkTest ./evm/test/PlonkTest.sol \ No newline at end of file +mv ./evm/test/PlonkTest ./evm/test/PlonkTest.sol +mv ./evm/test/ZkBeefyTest ./evm/test/ZkBeefyTest.sol