diff --git a/core/packages/contracts/scripts/ffiWrapper.ts b/core/packages/contracts/scripts/ffiWrapper.ts index 43e858b485d90..5579ddf6b6830 100755 --- a/core/packages/contracts/scripts/ffiWrapper.ts +++ b/core/packages/contracts/scripts/ffiWrapper.ts @@ -1,6 +1,6 @@ #!/usr/bin/env node import { ValidatorSet, createRandomSubset, readSetBits } from "./helpers" -import { ethers } from "ethers" +import { BigNumber, ethers } from "ethers" import fs from "fs" import type { BeefyClient } from "../types/BeefyClient" import { accounts } from "./wallets" @@ -45,9 +45,8 @@ if (command == "GenerateInitialSet") { } else { validatorSet = new ValidatorSet(validatorSetID, validatorSetSize) } - const validatorProof = validatorSet.createSignatureProof(subset[0], commitHash) const finalBitfieldLength = parseInt(process.argv[3]) - let finalBitfield: any = [] + let finalBitfield: BigNumber[] = [] for (let i = 0; i < finalBitfieldLength; i++) { finalBitfield.push(ethers.BigNumber.from(process.argv[4 + i])) } @@ -58,7 +57,6 @@ if (command == "GenerateInitialSet") { `${encoder.encode( [ "bytes32", - "tuple(uint8 v, bytes32 r, bytes32 s, uint256 index,address account,bytes32[] proof)", "tuple(uint8 v, bytes32 r, bytes32 s, uint256 index,address account,bytes32[] proof)[]", "bytes32[]", "tuple(uint8 version,uint32 parentNumber,bytes32 parentHash,uint64 nextAuthoritySetID,uint32 nextAuthoritySetLen,bytes32 nextAuthoritySetRoot,bytes32 parachainHeadsRoot)", @@ -66,7 +64,6 @@ if (command == "GenerateInitialSet") { ], [ validatorSet.root, - validatorProof, validatorFinalProofs, mmrLeafProofs, mmrLeaf, diff --git a/core/packages/contracts/src/BeefyClient.sol b/core/packages/contracts/src/BeefyClient.sol index 5c691bc8858cc..1c1152afc7a13 100644 --- a/core/packages/contracts/src/BeefyClient.sol +++ b/core/packages/contracts/src/BeefyClient.sol @@ -196,21 +196,34 @@ contract BeefyClient is Ownable { * @dev Begin submission of commitment that was signed by the current validator set * @param commitmentHash contains the commitmentHash signed by the validators * @param bitfield a bitfield claiming which validators have signed the commitment + * @param proof a proof that a single validator from currentValidatorSet has signed the commitmentHash */ - function submitInitial(bytes32 commitmentHash, uint256[] calldata bitfield) external payable { - doSubmitInitial(currentValidatorSet, commitmentHash, bitfield); + function submitInitial(bytes32 commitmentHash, uint256[] calldata bitfield, ValidatorProof calldata proof) external payable { + doSubmitInitial(currentValidatorSet, commitmentHash, bitfield, proof); } /** * @dev Begin submission of commitment that was signed by the next validator set * @param commitmentHash contains the commitmentHash signed by the validators * @param bitfield a bitfield claiming which validators have signed the commitment + * @param proof a proof that a single validator from nextValidatorSet has signed the commitmentHash */ - function submitInitialWithHandover(bytes32 commitmentHash, uint256[] calldata bitfield) external payable { - doSubmitInitial(nextValidatorSet, commitmentHash, bitfield); + function submitInitialWithHandover(bytes32 commitmentHash, uint256[] calldata bitfield, ValidatorProof calldata proof) external payable { + doSubmitInitial(nextValidatorSet, commitmentHash, bitfield, proof); } - function doSubmitInitial(ValidatorSet memory vset, bytes32 commitmentHash, uint256[] calldata bitfield) internal { + function doSubmitInitial(ValidatorSet memory vset, bytes32 commitmentHash, uint256[] calldata bitfield, ValidatorProof calldata proof) internal { + // Check if merkle proof is valid based on the validatorSetRoot and if proof is included in bitfield + if (!isValidatorInSet(vset, proof.account, proof.index, proof.proof) || !Bitfield.isSet(bitfield, proof.index)) { + revert InvalidValidatorProof(); + } + + // Check if validatorSignature is correct, ie. check if it matches + // the signature of senderPublicKey on the commitmentHash + if (ECDSA.recover(commitmentHash, proof.v, proof.r, proof.s) != proof.account) { + revert InvalidSignature(); + } + // For the initial submission, the supplied bitfield should claim that more than // two thirds of the validator set have sign the commitment if (Bitfield.countSetBits(bitfield) < vset.length - (vset.length - 1) / 3) { diff --git a/core/packages/contracts/test/BeefyClient.t.sol b/core/packages/contracts/test/BeefyClient.t.sol index 6859ceb5ebf6f..f4d39bcb459f5 100644 --- a/core/packages/contracts/test/BeefyClient.t.sol +++ b/core/packages/contracts/test/BeefyClient.t.sol @@ -60,14 +60,14 @@ contract BeefyClientTest is Test { for (uint256 i = 0; i < finalBitfield.length; i++) { inputs[i + 4] = Strings.toString(finalBitfield[i]); } - BeefyClient.ValidatorProof[] memory _proofs; - (root,, _proofs, mmrLeafProofs, mmrLeaf, leafProofOrder) = abi.decode( + BeefyClient.ValidatorProof[] memory proofs; + (root, proofs, mmrLeafProofs, mmrLeaf, leafProofOrder) = abi.decode( vm.ffi(inputs), - (bytes32, BeefyClient.ValidatorProof, BeefyClient.ValidatorProof[], bytes32[], BeefyClient.MMRLeaf, uint256) + (bytes32, BeefyClient.ValidatorProof[], bytes32[], BeefyClient.MMRLeaf, uint256) ); // Cache finalValidatorProofs to storage in order to reuse in submitFinal later - for (uint256 i = 0; i < _proofs.length; i++) { - finalValidatorProofs.push(_proofs[i]); + for (uint256 i = 0; i < proofs.length; i++) { + finalValidatorProofs.push(proofs[i]); } console.log("current validator's merkle root is: %s", Strings.toHexString(uint256(root), 32)); } @@ -83,7 +83,7 @@ contract BeefyClientTest is Test { function testSubmit() public { initialize(setId); - beefyClient.submitInitial(commitHash, bitfield); + beefyClient.submitInitial(commitHash, bitfield, finalValidatorProofs[0]); // mine random delay blocks vm.roll(block.number + randaoCommitDelay); @@ -102,7 +102,7 @@ contract BeefyClientTest is Test { function testSubmitFailInvalidSignature() public { initialize(setId); - beefyClient.submitInitial(commitHash, bitfield); + beefyClient.submitInitial(commitHash, bitfield, finalValidatorProofs[0]); // mine random delay blocks vm.roll(block.number + randaoCommitDelay); @@ -123,7 +123,7 @@ contract BeefyClientTest is Test { function testSubmitFailValidatorNotInBitfield() public { initialize(setId); - beefyClient.submitInitial(commitHash, bitfield); + beefyClient.submitInitial(commitHash, bitfield, finalValidatorProofs[0]); // mine random delay blocks vm.roll(block.number + randaoCommitDelay); @@ -145,7 +145,7 @@ contract BeefyClientTest is Test { // first round of submit should be fine testSubmit(); - beefyClient.submitInitial(commitHash, bitfield); + beefyClient.submitInitial(commitHash, bitfield, finalValidatorProofs[0]); vm.roll(block.number + randaoCommitDelay); vm.prevrandao(bytes32(uint256(difficulty))); beefyClient.commitPrevRandao(commitHash); @@ -158,7 +158,7 @@ contract BeefyClientTest is Test { function testSubmitFailWithInvalidBitfield() public { initialize(setId); - beefyClient.submitInitial(commitHash, bitfield); + beefyClient.submitInitial(commitHash, bitfield, finalValidatorProofs[0]); vm.roll(block.number + randaoCommitDelay); @@ -175,7 +175,7 @@ contract BeefyClientTest is Test { function testSubmitFailWithoutPrevRandao() public { initialize(setId); - beefyClient.submitInitial(commitHash, bitfield); + beefyClient.submitInitial(commitHash, bitfield, finalValidatorProofs[0]); BeefyClient.Commitment memory commitment = BeefyClient.Commitment(blockNumber, setId, payload); // reverted without commit PrevRandao vm.expectRevert(BeefyClient.PrevRandaoNotCaptured.selector); @@ -184,7 +184,7 @@ contract BeefyClientTest is Test { function testSubmitFailForPrevRandaoTooEarlyOrTooLate() public { initialize(setId); - beefyClient.submitInitial(commitHash, bitfield); + beefyClient.submitInitial(commitHash, bitfield, finalValidatorProofs[0]); // reverted for commit PrevRandao too early vm.expectRevert(BeefyClient.WaitPeriodNotOver.selector); beefyClient.commitPrevRandao(commitHash); @@ -197,7 +197,7 @@ contract BeefyClientTest is Test { function testSubmitFailForPrevRandaoCapturedMoreThanOnce() public { initialize(setId); - beefyClient.submitInitial(commitHash, bitfield); + beefyClient.submitInitial(commitHash, bitfield, finalValidatorProofs[0]); vm.roll(block.number + randaoCommitDelay); vm.prevrandao(bytes32(uint256(difficulty))); beefyClient.commitPrevRandao(commitHash); @@ -210,7 +210,7 @@ contract BeefyClientTest is Test { //initialize with previous set initialize(setId - 1); - beefyClient.submitInitialWithHandover(commitHash, bitfield); + beefyClient.submitInitialWithHandover(commitHash, bitfield, finalValidatorProofs[0]); vm.roll(block.number + randaoCommitDelay); @@ -229,7 +229,7 @@ contract BeefyClientTest is Test { //initialize with previous set initialize(setId - 1); - beefyClient.submitInitialWithHandover(commitHash, bitfield); + beefyClient.submitInitialWithHandover(commitHash, bitfield, finalValidatorProofs[0]); BeefyClient.Commitment memory commitment = BeefyClient.Commitment(blockNumber, setId, payload); @@ -240,9 +240,9 @@ contract BeefyClientTest is Test { } function testSubmitWithHandoverFailStaleCommitment() public { - testSubmitWithHandover(); + testSubmit(); - beefyClient.submitInitialWithHandover(commitHash, bitfield); + beefyClient.submitInitialWithHandover(commitHash, bitfield, finalValidatorProofs[0]); vm.roll(block.number + randaoCommitDelay); diff --git a/relayer/contracts/beefy_client.go b/relayer/contracts/beefy_client.go index 3dd2e9c8d1267..d0294ea157550 100644 --- a/relayer/contracts/beefy_client.go +++ b/relayer/contracts/beefy_client.go @@ -72,7 +72,7 @@ type BeefyClientValidatorSet struct { // BeefyClientMetaData contains all meta data concerning the BeefyClient contract. var BeefyClientMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_randaoCommitDelay\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_randaoCommitExpiration\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"InvalidBitfield\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidCommitment\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidMMRLeaf\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidMMRLeafProof\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSignature\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTask\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidValidatorProof\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotEnoughClaims\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PrevRandaoAlreadyCaptured\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PrevRandaoNotCaptured\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"StaleCommitment\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TicketExpired\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"WaitPeriodNotOver\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"mmrRoot\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"blockNumber\",\"type\":\"uint64\"}],\"name\":\"NewMMRRoot\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"commitmentHash\",\"type\":\"bytes32\"}],\"name\":\"commitPrevRandao\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"commitmentHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256[]\",\"name\":\"bitfield\",\"type\":\"uint256[]\"}],\"name\":\"createFinalBitfield\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"bitsToSet\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256\",\"name\":\"length\",\"type\":\"uint256\"}],\"name\":\"createInitialBitfield\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"currentValidatorSet\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"id\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"length\",\"type\":\"uint128\"},{\"internalType\":\"bytes32\",\"name\":\"root\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"_initialBeefyBlock\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"uint128\",\"name\":\"id\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"length\",\"type\":\"uint128\"},{\"internalType\":\"bytes32\",\"name\":\"root\",\"type\":\"bytes32\"}],\"internalType\":\"structBeefyClient.ValidatorSet\",\"name\":\"_initialValidatorSet\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint128\",\"name\":\"id\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"length\",\"type\":\"uint128\"},{\"internalType\":\"bytes32\",\"name\":\"root\",\"type\":\"bytes32\"}],\"internalType\":\"structBeefyClient.ValidatorSet\",\"name\":\"_nextValidatorSet\",\"type\":\"tuple\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestBeefyBlock\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestMMRRoot\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"nextValidatorSet\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"id\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"length\",\"type\":\"uint128\"},{\"internalType\":\"bytes32\",\"name\":\"root\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"randaoCommitDelay\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"randaoCommitExpiration\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"blockNumber\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"validatorSetID\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"mmrRootHash\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"prefix\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"suffix\",\"type\":\"bytes\"}],\"internalType\":\"structBeefyClient.Payload\",\"name\":\"payload\",\"type\":\"tuple\"}],\"internalType\":\"structBeefyClient.Commitment\",\"name\":\"commitment\",\"type\":\"tuple\"},{\"internalType\":\"uint256[]\",\"name\":\"bitfield\",\"type\":\"uint256[]\"},{\"components\":[{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"internalType\":\"structBeefyClient.ValidatorProof[]\",\"name\":\"proofs\",\"type\":\"tuple[]\"}],\"name\":\"submitFinal\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"blockNumber\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"validatorSetID\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"mmrRootHash\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"prefix\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"suffix\",\"type\":\"bytes\"}],\"internalType\":\"structBeefyClient.Payload\",\"name\":\"payload\",\"type\":\"tuple\"}],\"internalType\":\"structBeefyClient.Commitment\",\"name\":\"commitment\",\"type\":\"tuple\"},{\"internalType\":\"uint256[]\",\"name\":\"bitfield\",\"type\":\"uint256[]\"},{\"components\":[{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"internalType\":\"structBeefyClient.ValidatorProof[]\",\"name\":\"proofs\",\"type\":\"tuple[]\"},{\"components\":[{\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"parentNumber\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"parentHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint64\",\"name\":\"nextAuthoritySetID\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"nextAuthoritySetLen\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"nextAuthoritySetRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"parachainHeadsRoot\",\"type\":\"bytes32\"}],\"internalType\":\"structBeefyClient.MMRLeaf\",\"name\":\"leaf\",\"type\":\"tuple\"},{\"internalType\":\"bytes32[]\",\"name\":\"leafProof\",\"type\":\"bytes32[]\"},{\"internalType\":\"uint256\",\"name\":\"leafProofOrder\",\"type\":\"uint256\"}],\"name\":\"submitFinalWithHandover\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"commitmentHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256[]\",\"name\":\"bitfield\",\"type\":\"uint256[]\"}],\"name\":\"submitInitial\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"commitmentHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256[]\",\"name\":\"bitfield\",\"type\":\"uint256[]\"}],\"name\":\"submitInitialWithHandover\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"tickets\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"blockNumber\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"validatorSetLen\",\"type\":\"uint32\"},{\"internalType\":\"uint256\",\"name\":\"prevRandao\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"bitfieldHash\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"leafHash\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"},{\"internalType\":\"uint256\",\"name\":\"proofOrder\",\"type\":\"uint256\"}],\"name\":\"verifyMMRLeafProof\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", + ABI: "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_randaoCommitDelay\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_randaoCommitExpiration\",\"type\":\"uint256\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"InvalidBitfield\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidCommitment\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidMMRLeaf\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidMMRLeafProof\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidSignature\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidTask\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidValidatorProof\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"NotEnoughClaims\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PrevRandaoAlreadyCaptured\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"PrevRandaoNotCaptured\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"StaleCommitment\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"TicketExpired\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"WaitPeriodNotOver\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"bytes32\",\"name\":\"mmrRoot\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"uint64\",\"name\":\"blockNumber\",\"type\":\"uint64\"}],\"name\":\"NewMMRRoot\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"previousOwner\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnershipTransferred\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"commitmentHash\",\"type\":\"bytes32\"}],\"name\":\"commitPrevRandao\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"commitmentHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256[]\",\"name\":\"bitfield\",\"type\":\"uint256[]\"}],\"name\":\"createFinalBitfield\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256[]\",\"name\":\"bitsToSet\",\"type\":\"uint256[]\"},{\"internalType\":\"uint256\",\"name\":\"length\",\"type\":\"uint256\"}],\"name\":\"createInitialBitfield\",\"outputs\":[{\"internalType\":\"uint256[]\",\"name\":\"\",\"type\":\"uint256[]\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"currentValidatorSet\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"id\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"length\",\"type\":\"uint128\"},{\"internalType\":\"bytes32\",\"name\":\"root\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint64\",\"name\":\"_initialBeefyBlock\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"uint128\",\"name\":\"id\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"length\",\"type\":\"uint128\"},{\"internalType\":\"bytes32\",\"name\":\"root\",\"type\":\"bytes32\"}],\"internalType\":\"structBeefyClient.ValidatorSet\",\"name\":\"_initialValidatorSet\",\"type\":\"tuple\"},{\"components\":[{\"internalType\":\"uint128\",\"name\":\"id\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"length\",\"type\":\"uint128\"},{\"internalType\":\"bytes32\",\"name\":\"root\",\"type\":\"bytes32\"}],\"internalType\":\"structBeefyClient.ValidatorSet\",\"name\":\"_nextValidatorSet\",\"type\":\"tuple\"}],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestBeefyBlock\",\"outputs\":[{\"internalType\":\"uint64\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"latestMMRRoot\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"nextValidatorSet\",\"outputs\":[{\"internalType\":\"uint128\",\"name\":\"id\",\"type\":\"uint128\"},{\"internalType\":\"uint128\",\"name\":\"length\",\"type\":\"uint128\"},{\"internalType\":\"bytes32\",\"name\":\"root\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"randaoCommitDelay\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"randaoCommitExpiration\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"renounceOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"blockNumber\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"validatorSetID\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"mmrRootHash\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"prefix\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"suffix\",\"type\":\"bytes\"}],\"internalType\":\"structBeefyClient.Payload\",\"name\":\"payload\",\"type\":\"tuple\"}],\"internalType\":\"structBeefyClient.Commitment\",\"name\":\"commitment\",\"type\":\"tuple\"},{\"internalType\":\"uint256[]\",\"name\":\"bitfield\",\"type\":\"uint256[]\"},{\"components\":[{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"internalType\":\"structBeefyClient.ValidatorProof[]\",\"name\":\"proofs\",\"type\":\"tuple[]\"}],\"name\":\"submitFinal\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint32\",\"name\":\"blockNumber\",\"type\":\"uint32\"},{\"internalType\":\"uint64\",\"name\":\"validatorSetID\",\"type\":\"uint64\"},{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"mmrRootHash\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"prefix\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"suffix\",\"type\":\"bytes\"}],\"internalType\":\"structBeefyClient.Payload\",\"name\":\"payload\",\"type\":\"tuple\"}],\"internalType\":\"structBeefyClient.Commitment\",\"name\":\"commitment\",\"type\":\"tuple\"},{\"internalType\":\"uint256[]\",\"name\":\"bitfield\",\"type\":\"uint256[]\"},{\"components\":[{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"internalType\":\"structBeefyClient.ValidatorProof[]\",\"name\":\"proofs\",\"type\":\"tuple[]\"},{\"components\":[{\"internalType\":\"uint8\",\"name\":\"version\",\"type\":\"uint8\"},{\"internalType\":\"uint32\",\"name\":\"parentNumber\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"parentHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint64\",\"name\":\"nextAuthoritySetID\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"nextAuthoritySetLen\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"nextAuthoritySetRoot\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"parachainHeadsRoot\",\"type\":\"bytes32\"}],\"internalType\":\"structBeefyClient.MMRLeaf\",\"name\":\"leaf\",\"type\":\"tuple\"},{\"internalType\":\"bytes32[]\",\"name\":\"leafProof\",\"type\":\"bytes32[]\"},{\"internalType\":\"uint256\",\"name\":\"leafProofOrder\",\"type\":\"uint256\"}],\"name\":\"submitFinalWithHandover\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"commitmentHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256[]\",\"name\":\"bitfield\",\"type\":\"uint256[]\"},{\"components\":[{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"internalType\":\"structBeefyClient.ValidatorProof\",\"name\":\"proof\",\"type\":\"tuple\"}],\"name\":\"submitInitial\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"commitmentHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint256[]\",\"name\":\"bitfield\",\"type\":\"uint256[]\"},{\"components\":[{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"index\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"}],\"internalType\":\"structBeefyClient.ValidatorProof\",\"name\":\"proof\",\"type\":\"tuple\"}],\"name\":\"submitInitialWithHandover\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"tickets\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"account\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"blockNumber\",\"type\":\"uint64\"},{\"internalType\":\"uint32\",\"name\":\"validatorSetLen\",\"type\":\"uint32\"},{\"internalType\":\"uint256\",\"name\":\"prevRandao\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"bitfieldHash\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"transferOwnership\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"leafHash\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32[]\",\"name\":\"proof\",\"type\":\"bytes32[]\"},{\"internalType\":\"uint256\",\"name\":\"proofOrder\",\"type\":\"uint256\"}],\"name\":\"verifyMMRLeafProof\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", } // BeefyClientABI is the input ABI used to generate the binding from. @@ -734,46 +734,46 @@ func (_BeefyClient *BeefyClientTransactorSession) SubmitFinalWithHandover(commit return _BeefyClient.Contract.SubmitFinalWithHandover(&_BeefyClient.TransactOpts, commitment, bitfield, proofs, leaf, leafProof, leafProofOrder) } -// SubmitInitial is a paid mutator transaction binding the contract method 0xf9ba5b13. +// SubmitInitial is a paid mutator transaction binding the contract method 0x06a9eff7. // -// Solidity: function submitInitial(bytes32 commitmentHash, uint256[] bitfield) payable returns() -func (_BeefyClient *BeefyClientTransactor) SubmitInitial(opts *bind.TransactOpts, commitmentHash [32]byte, bitfield []*big.Int) (*types.Transaction, error) { - return _BeefyClient.contract.Transact(opts, "submitInitial", commitmentHash, bitfield) +// Solidity: function submitInitial(bytes32 commitmentHash, uint256[] bitfield, (uint8,bytes32,bytes32,uint256,address,bytes32[]) proof) payable returns() +func (_BeefyClient *BeefyClientTransactor) SubmitInitial(opts *bind.TransactOpts, commitmentHash [32]byte, bitfield []*big.Int, proof BeefyClientValidatorProof) (*types.Transaction, error) { + return _BeefyClient.contract.Transact(opts, "submitInitial", commitmentHash, bitfield, proof) } -// SubmitInitial is a paid mutator transaction binding the contract method 0xf9ba5b13. +// SubmitInitial is a paid mutator transaction binding the contract method 0x06a9eff7. // -// Solidity: function submitInitial(bytes32 commitmentHash, uint256[] bitfield) payable returns() -func (_BeefyClient *BeefyClientSession) SubmitInitial(commitmentHash [32]byte, bitfield []*big.Int) (*types.Transaction, error) { - return _BeefyClient.Contract.SubmitInitial(&_BeefyClient.TransactOpts, commitmentHash, bitfield) +// Solidity: function submitInitial(bytes32 commitmentHash, uint256[] bitfield, (uint8,bytes32,bytes32,uint256,address,bytes32[]) proof) payable returns() +func (_BeefyClient *BeefyClientSession) SubmitInitial(commitmentHash [32]byte, bitfield []*big.Int, proof BeefyClientValidatorProof) (*types.Transaction, error) { + return _BeefyClient.Contract.SubmitInitial(&_BeefyClient.TransactOpts, commitmentHash, bitfield, proof) } -// SubmitInitial is a paid mutator transaction binding the contract method 0xf9ba5b13. +// SubmitInitial is a paid mutator transaction binding the contract method 0x06a9eff7. // -// Solidity: function submitInitial(bytes32 commitmentHash, uint256[] bitfield) payable returns() -func (_BeefyClient *BeefyClientTransactorSession) SubmitInitial(commitmentHash [32]byte, bitfield []*big.Int) (*types.Transaction, error) { - return _BeefyClient.Contract.SubmitInitial(&_BeefyClient.TransactOpts, commitmentHash, bitfield) +// Solidity: function submitInitial(bytes32 commitmentHash, uint256[] bitfield, (uint8,bytes32,bytes32,uint256,address,bytes32[]) proof) payable returns() +func (_BeefyClient *BeefyClientTransactorSession) SubmitInitial(commitmentHash [32]byte, bitfield []*big.Int, proof BeefyClientValidatorProof) (*types.Transaction, error) { + return _BeefyClient.Contract.SubmitInitial(&_BeefyClient.TransactOpts, commitmentHash, bitfield, proof) } -// SubmitInitialWithHandover is a paid mutator transaction binding the contract method 0x0c76d7fa. +// SubmitInitialWithHandover is a paid mutator transaction binding the contract method 0x61de6237. // -// Solidity: function submitInitialWithHandover(bytes32 commitmentHash, uint256[] bitfield) payable returns() -func (_BeefyClient *BeefyClientTransactor) SubmitInitialWithHandover(opts *bind.TransactOpts, commitmentHash [32]byte, bitfield []*big.Int) (*types.Transaction, error) { - return _BeefyClient.contract.Transact(opts, "submitInitialWithHandover", commitmentHash, bitfield) +// Solidity: function submitInitialWithHandover(bytes32 commitmentHash, uint256[] bitfield, (uint8,bytes32,bytes32,uint256,address,bytes32[]) proof) payable returns() +func (_BeefyClient *BeefyClientTransactor) SubmitInitialWithHandover(opts *bind.TransactOpts, commitmentHash [32]byte, bitfield []*big.Int, proof BeefyClientValidatorProof) (*types.Transaction, error) { + return _BeefyClient.contract.Transact(opts, "submitInitialWithHandover", commitmentHash, bitfield, proof) } -// SubmitInitialWithHandover is a paid mutator transaction binding the contract method 0x0c76d7fa. +// SubmitInitialWithHandover is a paid mutator transaction binding the contract method 0x61de6237. // -// Solidity: function submitInitialWithHandover(bytes32 commitmentHash, uint256[] bitfield) payable returns() -func (_BeefyClient *BeefyClientSession) SubmitInitialWithHandover(commitmentHash [32]byte, bitfield []*big.Int) (*types.Transaction, error) { - return _BeefyClient.Contract.SubmitInitialWithHandover(&_BeefyClient.TransactOpts, commitmentHash, bitfield) +// Solidity: function submitInitialWithHandover(bytes32 commitmentHash, uint256[] bitfield, (uint8,bytes32,bytes32,uint256,address,bytes32[]) proof) payable returns() +func (_BeefyClient *BeefyClientSession) SubmitInitialWithHandover(commitmentHash [32]byte, bitfield []*big.Int, proof BeefyClientValidatorProof) (*types.Transaction, error) { + return _BeefyClient.Contract.SubmitInitialWithHandover(&_BeefyClient.TransactOpts, commitmentHash, bitfield, proof) } -// SubmitInitialWithHandover is a paid mutator transaction binding the contract method 0x0c76d7fa. +// SubmitInitialWithHandover is a paid mutator transaction binding the contract method 0x61de6237. // -// Solidity: function submitInitialWithHandover(bytes32 commitmentHash, uint256[] bitfield) payable returns() -func (_BeefyClient *BeefyClientTransactorSession) SubmitInitialWithHandover(commitmentHash [32]byte, bitfield []*big.Int) (*types.Transaction, error) { - return _BeefyClient.Contract.SubmitInitialWithHandover(&_BeefyClient.TransactOpts, commitmentHash, bitfield) +// Solidity: function submitInitialWithHandover(bytes32 commitmentHash, uint256[] bitfield, (uint8,bytes32,bytes32,uint256,address,bytes32[]) proof) payable returns() +func (_BeefyClient *BeefyClientTransactorSession) SubmitInitialWithHandover(commitmentHash [32]byte, bitfield []*big.Int, proof BeefyClientValidatorProof) (*types.Transaction, error) { + return _BeefyClient.Contract.SubmitInitialWithHandover(&_BeefyClient.TransactOpts, commitmentHash, bitfield, proof) } // TransferOwnership is a paid mutator transaction binding the contract method 0xf2fde38b. diff --git a/relayer/relays/beefy/ethereum-writer.go b/relayer/relays/beefy/ethereum-writer.go index 4d4a5c62cba7a..072605ba5f3e3 100644 --- a/relayer/relays/beefy/ethereum-writer.go +++ b/relayer/relays/beefy/ethereum-writer.go @@ -256,6 +256,7 @@ func (wr *EthereumWriter) doSubmitInitial(ctx context.Context, task *Request) (* wr.makeTxOpts(ctx), msg.CommitmentHash, msg.Bitfield, + msg.Proof, ) if err != nil { return nil, nil, fmt.Errorf("initial submit with handover: %w", err) @@ -265,6 +266,7 @@ func (wr *EthereumWriter) doSubmitInitial(ctx context.Context, task *Request) (* wr.makeTxOpts(ctx), msg.CommitmentHash, msg.Bitfield, + msg.Proof, ) if err != nil { return nil, nil, fmt.Errorf("initial submit: %w", err)