diff --git a/contracts/src/Gateway.sol b/contracts/src/Gateway.sol index 7d18be0e96..b6e446bb9f 100644 --- a/contracts/src/Gateway.sol +++ b/contracts/src/Gateway.sol @@ -83,7 +83,7 @@ contract Gateway is IGatewayBase, IGatewayV1, IGatewayV2, IInitializable, IUpgra */ // Verify that a message commitment is considered finalized by our BEEFY light client. - function _verifyCommitment(bytes32 commitment, Verification.Proof calldata proof) + function _verifyCommitment(bytes32 commitment, Verification.Proof calldata proof, bool isV2) internal view virtual @@ -93,7 +93,8 @@ contract Gateway is IGatewayBase, IGatewayV1, IGatewayV2, IInitializable, IUpgra BEEFY_CLIENT, ScaleCodec.encodeU32(uint32(ParaID.unwrap(Constants.BRIDGE_HUB_PARA_ID))), commitment, - proof + proof, + isV2 ); } @@ -147,7 +148,7 @@ contract Gateway is IGatewayBase, IGatewayV1, IGatewayV2, IInitializable, IUpgra bytes32 commitment = MerkleProof.processProof(leafProof, leafHash); // Verify that the commitment is included in a parachain header finalized by BEEFY. - if (!_verifyCommitment(commitment, headerProof)) { + if (!_verifyCommitment(commitment, headerProof, false)) { revert IGatewayBase.InvalidProof(); } @@ -453,7 +454,7 @@ contract Gateway is IGatewayBase, IGatewayV1, IGatewayV2, IInitializable, IUpgra bytes32 commitment = MerkleProof.processProof(leafProof, leafHash); // Verify that the commitment is included in a parachain header finalized by BEEFY. - if (!_verifyCommitment(commitment, headerProof)) { + if (!_verifyCommitment(commitment, headerProof, true)) { revert IGatewayBase.InvalidProof(); } diff --git a/contracts/src/Verification.sol b/contracts/src/Verification.sol index 186f7e5c8b..c26db5a9ca 100644 --- a/contracts/src/Verification.sol +++ b/contracts/src/Verification.sol @@ -79,6 +79,9 @@ library Verification { /// @dev Enum variant ID for CustomDigestItem::Snowbridge bytes1 public constant DIGEST_ITEM_OTHER_SNOWBRIDGE = 0x00; + /// @dev Enum variant ID for CustomDigestItem::SnowbridgeV2 + bytes1 public constant DIGEST_ITEM_OTHER_SNOWBRIDGE_V2 = 0x01; + /// @dev Verify the message commitment by applying several proofs /// /// 1. First check that the commitment is included in the digest items of the parachain header @@ -100,13 +103,13 @@ library Verification { /// @param commitment The message commitment root expected to be contained within the /// digest of BridgeHub parachain header. /// @param proof The chain of proofs described above - function verifyCommitment(address beefyClient, bytes4 encodedParaID, bytes32 commitment, Proof calldata proof) + function verifyCommitment(address beefyClient, bytes4 encodedParaID, bytes32 commitment, Proof calldata proof, bool isV2) external view returns (bool) { // Verify that parachain header contains the commitment - if (!isCommitmentInHeaderDigest(commitment, proof.header)) { + if (!isCommitmentInHeaderDigest(commitment, proof.header, isV2)) { return false; } @@ -129,19 +132,26 @@ library Verification { } // Verify that a message commitment is in the header digest - function isCommitmentInHeaderDigest(bytes32 commitment, ParachainHeader calldata header) + function isCommitmentInHeaderDigest(bytes32 commitment, ParachainHeader calldata header, bool isV2) internal pure returns (bool) { for (uint256 i = 0; i < header.digestItems.length; i++) { if ( - header.digestItems[i].kind == DIGEST_ITEM_OTHER && header.digestItems[i].data.length == 33 + !isV2 && header.digestItems[i].kind == DIGEST_ITEM_OTHER && header.digestItems[i].data.length == 33 && header.digestItems[i].data[0] == DIGEST_ITEM_OTHER_SNOWBRIDGE && commitment == bytes32(header.digestItems[i].data[1:]) ) { return true; } + if ( + isV2 && header.digestItems[i].kind == DIGEST_ITEM_OTHER && header.digestItems[i].data.length == 33 + && header.digestItems[i].data[0] == DIGEST_ITEM_OTHER_SNOWBRIDGE_V2 + && commitment == bytes32(header.digestItems[i].data[1:]) + ) { + return true; + } } return false; } diff --git a/contracts/test/mocks/MockGateway.sol b/contracts/test/mocks/MockGateway.sol index 98e92dc939..745d118d48 100644 --- a/contracts/test/mocks/MockGateway.sol +++ b/contracts/test/mocks/MockGateway.sol @@ -60,14 +60,14 @@ contract MockGateway is Gateway { commitmentsAreVerified = value; } - function _verifyCommitment(bytes32 commitment, Verification.Proof calldata proof) + function _verifyCommitment(bytes32 commitment, Verification.Proof calldata proof, bool isV2) internal view override returns (bool) { if (BEEFY_CLIENT != address(0)) { - return super._verifyCommitment(commitment, proof); + return super._verifyCommitment(commitment, proof, isV2); } else { // for unit tests, verification is set with commitmentsAreVerified return commitmentsAreVerified; diff --git a/contracts/test/mocks/VerificationWrapper.sol b/contracts/test/mocks/VerificationWrapper.sol index 7618bb78c8..20f02fef58 100644 --- a/contracts/test/mocks/VerificationWrapper.sol +++ b/contracts/test/mocks/VerificationWrapper.sol @@ -17,6 +17,6 @@ contract VerificationWrapper { pure returns (bool) { - return Verification.isCommitmentInHeaderDigest(commitment, header); + return Verification.isCommitmentInHeaderDigest(commitment, header, false); } }