| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109 |
- // contracts/Messages.sol
- // SPDX-License-Identifier: Apache 2
- pragma solidity ^0.8.0;
- pragma experimental ABIEncoderV2;
- import "./Getters.sol";
- import "./Structs.sol";
- import "./libraries/external/BytesLib.sol";
- contract Messages is Getters {
- using BytesLib for bytes;
- function parseAndVerifyVM(bytes calldata encodedVM) public view returns (Structs.VM memory vm, bool valid, string memory reason) {
- vm = parseVM(encodedVM);
- (valid, reason) = verifyVM(vm);
- }
- function verifyVM(Structs.VM memory vm) public view returns (bool valid, string memory reason) {
- Structs.GuardianSet memory guardianSet = getGuardianSet(vm.guardianSetIndex);
- if(guardianSet.keys.length == 0){
- return (false, "invalid guardian set");
- }
- if(vm.guardianSetIndex != getCurrentGuardianSetIndex() && guardianSet.expirationTime < block.timestamp){
- return (false, "guardian set has expired");
- }
- // We're using a fixed point number transformation with 1 decimal to deal with rounding.
- if(((guardianSet.keys.length * 10 / 3) * 2) / 10 + 1 > vm.signatures.length){
- return (false, "no quorum");
- }
- // Verify signatures
- (bool signaturesValid, string memory invalidReason) = verifySignatures(vm.hash, vm.signatures, guardianSet);
- if(!signaturesValid){
- return (false, invalidReason);
- }
- return (true, "");
- }
- function verifySignatures(bytes32 hash, Structs.Signature[] memory signatures, Structs.GuardianSet memory guardianSet) public pure returns (bool valid, string memory reason) {
- uint8 lastIndex = 0;
- for (uint i = 0; i < signatures.length; i++) {
- Structs.Signature memory sig = signatures[i];
- require(i == 0 || sig.guardianIndex > lastIndex, "signature indices must be ascending");
- lastIndex = sig.guardianIndex;
- if(ecrecover(hash, sig.v, sig.r, sig.s) != guardianSet.keys[sig.guardianIndex]){
- return (false, "VM signature invalid");
- }
- }
- return (true, "");
- }
- function parseVM(bytes memory encodedVM) public pure virtual returns (Structs.VM memory vm) {
- uint index = 0;
- vm.version = encodedVM.toUint8(index);
- index += 1;
- require(vm.version == 1, "VM version incompatible");
- vm.guardianSetIndex = encodedVM.toUint32(index);
- index += 4;
- // Parse Signatures
- uint256 signersLen = encodedVM.toUint8(index);
- index += 1;
- vm.signatures = new Structs.Signature[](signersLen);
- for (uint i = 0; i < signersLen; i++) {
- vm.signatures[i].guardianIndex = encodedVM.toUint8(index);
- index += 1;
- vm.signatures[i].r = encodedVM.toBytes32(index);
- index += 32;
- vm.signatures[i].s = encodedVM.toBytes32(index);
- index += 32;
- vm.signatures[i].v = encodedVM.toUint8(index) + 27;
- index += 1;
- }
- // Hash the body
- bytes memory body = encodedVM.slice(index, encodedVM.length - index);
- vm.hash = keccak256(abi.encodePacked(keccak256(body)));
- // Parse the body
- vm.timestamp = encodedVM.toUint32(index);
- index += 4;
- vm.nonce = encodedVM.toUint32(index);
- index += 4;
- vm.emitterChainId = encodedVM.toUint16(index);
- index += 2;
- vm.emitterAddress = encodedVM.toBytes32(index);
- index += 32;
- vm.sequence = encodedVM.toUint64(index);
- index += 8;
- vm.consistencyLevel = encodedVM.toUint8(index);
- index += 1;
- vm.payload = encodedVM.slice(index, encodedVM.length - index);
- }
- }
|