Merge 71e5682b4b
into 2712dd3f3f
This commit is contained in:
commit
889f2c0421
|
@ -35,7 +35,7 @@ node_modules: package-lock.json
|
|||
forge_dependencies: lib/forge-std lib/openzeppelin-contracts
|
||||
|
||||
lib/forge-std:
|
||||
forge install foundry-rs/forge-std@v1.5.5 --no-git --no-commit
|
||||
forge install foundry-rs/forge-std@v1.6.1 --no-git --no-commit
|
||||
|
||||
lib/openzeppelin-contracts:
|
||||
forge install openzeppelin/openzeppelin-contracts@0457042d93d9dfd760dbaa06a4d2f1216fdbe297 --no-git --no-commit
|
||||
|
|
|
@ -53,4 +53,20 @@ contract Getters is State {
|
|||
function nextSequence(address emitter) public view returns (uint64) {
|
||||
return _state.sequences[emitter];
|
||||
}
|
||||
|
||||
function getGuardianSetHash(uint32 index) public view returns (bytes32) {
|
||||
return _state.guardianSetHashes[index];
|
||||
}
|
||||
|
||||
function getEncodedGuardianSet(uint32 index) public view returns (bytes memory encodedGuardianSet) {
|
||||
Structs.GuardianSet memory guardianSet = getGuardianSet(index);
|
||||
|
||||
// Encode the guardian set.
|
||||
uint256 guardianCount = guardianSet.keys.length;
|
||||
for (uint256 i = 0; i < guardianCount;) {
|
||||
encodedGuardianSet = abi.encodePacked(encodedGuardianSet, guardianSet.keys[i]);
|
||||
unchecked { ++i; }
|
||||
}
|
||||
encodedGuardianSet = abi.encodePacked(encodedGuardianSet, guardianSet.expirationTime);
|
||||
}
|
||||
}
|
|
@ -107,6 +107,9 @@ abstract contract Governance is GovernanceStructs, Messages, Setters, ERC1967Upg
|
|||
// Add the new guardianSet to guardianSets
|
||||
storeGuardianSet(upgrade.newGuardianSet, upgrade.newGuardianSetIndex);
|
||||
|
||||
// Store the guardian set hash
|
||||
setGuardianSetHash(upgrade.newGuardianSetIndex);
|
||||
|
||||
// Makes the new guardianSet effective
|
||||
updateGuardianSetIndex(upgrade.newGuardianSetIndex);
|
||||
}
|
||||
|
|
|
@ -6,17 +6,56 @@ pragma experimental ABIEncoderV2;
|
|||
|
||||
import "./Getters.sol";
|
||||
import "./Structs.sol";
|
||||
import "./libraries/external/BytesLib.sol";
|
||||
import "./libraries/relayer/BytesParsing.sol";
|
||||
|
||||
|
||||
contract Messages is Getters {
|
||||
using BytesLib for bytes;
|
||||
using BytesParsing for bytes;
|
||||
|
||||
function parseAndVerifyVMOptimized(
|
||||
bytes calldata encodedVM,
|
||||
bytes calldata guardianSet,
|
||||
uint32 guardianSetIndex
|
||||
) public view returns (Structs.VM memory vm, bool valid, string memory reason) {
|
||||
// Verify that the specified guardian set is a valid.
|
||||
require(
|
||||
getGuardianSetHash(guardianSetIndex) == keccak256(guardianSet),
|
||||
"invalid guardian set"
|
||||
);
|
||||
|
||||
vm = parseVM(encodedVM);
|
||||
|
||||
// Verify that the VM is signed with the same guardian set that was specified.
|
||||
require(vm.guardianSetIndex == guardianSetIndex, "mismatched guardian set index");
|
||||
|
||||
(valid, reason) = verifyVMInternal(vm, parseGuardianSet(guardianSet), false);
|
||||
}
|
||||
|
||||
function parseGuardianSet(bytes calldata guardianSetData) public pure returns (Structs.GuardianSet memory guardianSet) {
|
||||
// Fetch the guardian set length.
|
||||
uint256 endGuardianKeyIndex = guardianSetData.length - 4;
|
||||
uint256 guardianCount = endGuardianKeyIndex / 20;
|
||||
|
||||
guardianSet = Structs.GuardianSet({
|
||||
keys : new address[](guardianCount),
|
||||
expirationTime : 0
|
||||
});
|
||||
(guardianSet.expirationTime, ) = guardianSetData.asUint32Unchecked(endGuardianKeyIndex);
|
||||
|
||||
uint256 offset = 0;
|
||||
for(uint256 i = 0; i < guardianCount;) {
|
||||
(guardianSet.keys[i], offset) = guardianSetData.asAddressUnchecked(offset);
|
||||
unchecked {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev parseAndVerifyVM serves to parse an encodedVM and wholy validate it for consumption
|
||||
function parseAndVerifyVM(bytes calldata encodedVM) public view returns (Structs.VM memory vm, bool valid, string memory reason) {
|
||||
vm = parseVM(encodedVM);
|
||||
/// setting checkHash to false as we can trust the hash field in this case given that parseVM computes and then sets the hash field above
|
||||
(valid, reason) = verifyVMInternal(vm, false);
|
||||
(valid, reason) = verifyVMInternal(vm, getGuardianSet(vm.guardianSetIndex), false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -28,7 +67,7 @@ contract Messages is Getters {
|
|||
* - it aims to verify the hash field provided against the contents of the vm
|
||||
*/
|
||||
function verifyVM(Structs.VM memory vm) public view returns (bool valid, string memory reason) {
|
||||
(valid, reason) = verifyVMInternal(vm, true);
|
||||
(valid, reason) = verifyVMInternal(vm, getGuardianSet(vm.guardianSetIndex), true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -37,10 +76,7 @@ contract Messages is Getters {
|
|||
* in the case that the vm is securely parsed and the hash field can be trusted, checkHash can be set to false
|
||||
* as the check would be redundant
|
||||
*/
|
||||
function verifyVMInternal(Structs.VM memory vm, bool checkHash) internal view returns (bool valid, string memory reason) {
|
||||
/// @dev Obtain the current guardianSet for the guardianSetIndex provided
|
||||
Structs.GuardianSet memory guardianSet = getGuardianSet(vm.guardianSetIndex);
|
||||
|
||||
function verifyVMInternal(Structs.VM memory vm, Structs.GuardianSet memory guardianSet, bool checkHash) internal view returns (bool valid, string memory reason) {
|
||||
/**
|
||||
* Verify that the hash field in the vm matches with the hash of the contents of the vm if checkHash is set
|
||||
* WARNING: This hash check is critical to ensure that the vm.hash provided matches with the hash of the body.
|
||||
|
@ -65,6 +101,8 @@ contract Messages is Getters {
|
|||
}
|
||||
}
|
||||
|
||||
uint256 guardianCount = guardianSet.keys.length;
|
||||
|
||||
/**
|
||||
* @dev Checks whether the guardianSet has zero keys
|
||||
* WARNING: This keys check is critical to ensure the guardianSet has keys present AND to ensure
|
||||
|
@ -72,7 +110,7 @@ contract Messages is Getters {
|
|||
* key length is 0 and vm.signatures length is 0, this could compromise the integrity of both vm and
|
||||
* signature verification.
|
||||
*/
|
||||
if(guardianSet.keys.length == 0){
|
||||
if(guardianCount == 0){
|
||||
return (false, "invalid guardian set");
|
||||
}
|
||||
|
||||
|
@ -87,7 +125,7 @@ contract Messages is Getters {
|
|||
* if making any changes to this, obtain additional peer review. If guardianSet key length is 0 and
|
||||
* vm.signatures length is 0, this could compromise the integrity of both vm and signature verification.
|
||||
*/
|
||||
if (vm.signatures.length < quorum(guardianSet.keys.length)){
|
||||
if (vm.signatures.length < quorum(guardianCount)){
|
||||
return (false, "no quorum");
|
||||
}
|
||||
|
||||
|
@ -110,8 +148,9 @@ contract Messages is Getters {
|
|||
*/
|
||||
function verifySignatures(bytes32 hash, Structs.Signature[] memory signatures, Structs.GuardianSet memory guardianSet) public pure returns (bool valid, string memory reason) {
|
||||
uint8 lastIndex = 0;
|
||||
uint256 sigCount = signatures.length;
|
||||
uint256 guardianCount = guardianSet.keys.length;
|
||||
for (uint i = 0; i < signatures.length; i++) {
|
||||
for (uint i = 0; i < sigCount;) {
|
||||
Structs.Signature memory sig = signatures[i];
|
||||
address signatory = ecrecover(hash, sig.v, sig.r, sig.s);
|
||||
// ecrecover returns 0 for invalid signatures. We explicitly require valid signatures to avoid unexpected
|
||||
|
@ -134,6 +173,8 @@ contract Messages is Getters {
|
|||
if(signatory != guardianSet.keys[sig.guardianIndex]){
|
||||
return (false, "VM signature invalid");
|
||||
}
|
||||
|
||||
unchecked { ++i; }
|
||||
}
|
||||
|
||||
/// If we are here, we've validated that the provided signatures are valid for the provided guardianSet
|
||||
|
@ -144,67 +185,58 @@ contract Messages is Getters {
|
|||
* @dev parseVM serves to parse an encodedVM into a vm struct
|
||||
* - it intentionally performs no validation functions, it simply parses raw into a struct
|
||||
*/
|
||||
function parseVM(bytes memory encodedVM) public pure virtual returns (Structs.VM memory vm) {
|
||||
uint index = 0;
|
||||
function parseVM(bytes memory encodedVM) public view virtual returns (Structs.VM memory vm) {
|
||||
uint256 offset = 0;
|
||||
|
||||
vm.version = encodedVM.toUint8(index);
|
||||
index += 1;
|
||||
// SECURITY: Note that currently the VM.version is not part of the hash
|
||||
// and for reasons described below it cannot be made part of the hash.
|
||||
// This means that this field's integrity is not protected and cannot be trusted.
|
||||
// This is not a problem today since there is only one accepted version, but it
|
||||
// could be a problem if we wanted to allow other versions in the future.
|
||||
require(vm.version == 1, "VM version incompatible");
|
||||
// SECURITY: Note that currently the VM.version is not part of the hash
|
||||
// and for reasons described below it cannot be made part of the hash.
|
||||
// This means that this field's integrity is not protected and cannot be trusted.
|
||||
// This is not a problem today since there is only one accepted version, but it
|
||||
// could be a problem if we wanted to allow other versions in the future.
|
||||
(vm.version, offset) = encodedVM.asUint8Unchecked(offset);
|
||||
require(vm.version == 1, "invalid payload id");
|
||||
|
||||
vm.guardianSetIndex = encodedVM.toUint32(index);
|
||||
index += 4;
|
||||
// Guardian set index.
|
||||
(vm.guardianSetIndex, offset) = encodedVM.asUint32Unchecked(offset);
|
||||
|
||||
// Parse sigs.
|
||||
uint256 signersLen;
|
||||
(signersLen, offset) = encodedVM.asUint8Unchecked(offset);
|
||||
|
||||
// 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;
|
||||
for (uint i = 0; i < signersLen;) {
|
||||
(vm.signatures[i].guardianIndex, offset) = encodedVM.asUint8Unchecked(offset);
|
||||
(vm.signatures[i].r, offset) = encodedVM.asBytes32Unchecked(offset);
|
||||
(vm.signatures[i].s, offset) = encodedVM.asBytes32Unchecked(offset);
|
||||
(vm.signatures[i].v, offset) = encodedVM.asUint8Unchecked(offset);
|
||||
|
||||
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;
|
||||
unchecked {
|
||||
vm.signatures[i].v += 27;
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Hash the body
|
||||
|
||||
SECURITY: Do not change the way the hash of a VM is computed!
|
||||
Changing it could result into two different hashes for the same observation.
|
||||
SECURITY: Do not change the way the hash of a VM is computed!
|
||||
Changing it could result into two different hashes for the same observation.
|
||||
But xDapps rely on the hash of an observation for replay protection.
|
||||
*/
|
||||
bytes memory body = encodedVM.slice(index, encodedVM.length - index);
|
||||
bytes memory body;
|
||||
(body, ) = encodedVM.sliceUnchecked(offset, encodedVM.length - offset);
|
||||
vm.hash = keccak256(abi.encodePacked(keccak256(body)));
|
||||
|
||||
// Parse the body
|
||||
vm.timestamp = encodedVM.toUint32(index);
|
||||
index += 4;
|
||||
(vm.timestamp, offset) = encodedVM.asUint32Unchecked(offset);
|
||||
(vm.nonce, offset) = encodedVM.asUint32Unchecked(offset);
|
||||
(vm.emitterChainId, offset) = encodedVM.asUint16Unchecked(offset);
|
||||
(vm.emitterAddress, offset) = encodedVM.asBytes32Unchecked(offset);
|
||||
(vm.sequence, offset) = encodedVM.asUint64Unchecked(offset);
|
||||
(vm.consistencyLevel, offset) = encodedVM.asUint8Unchecked(offset);
|
||||
(vm.payload, offset) = encodedVM.sliceUnchecked(offset, encodedVM.length - offset);
|
||||
|
||||
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);
|
||||
require(encodedVM.length == offset, "invalid payload length");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -16,10 +16,11 @@ contract Setters is State {
|
|||
|
||||
function storeGuardianSet(Structs.GuardianSet memory set, uint32 index) internal {
|
||||
uint setLength = set.keys.length;
|
||||
for (uint i = 0; i < setLength; i++) {
|
||||
for (uint i = 0; i < setLength;) {
|
||||
require(set.keys[i] != address(0), "Invalid key");
|
||||
unchecked { ++i; }
|
||||
}
|
||||
_state.guardianSets[index] = set;
|
||||
_state.guardianSets[index] = set;
|
||||
}
|
||||
|
||||
function setInitialized(address implementatiom) internal {
|
||||
|
@ -54,4 +55,21 @@ contract Setters is State {
|
|||
require(evmChainId == block.chainid, "invalid evmChainId");
|
||||
_state.evmChainId = evmChainId;
|
||||
}
|
||||
|
||||
function setGuardianSetHash(uint32 index) public {
|
||||
// Fetch the guardian set at the specified index.
|
||||
Structs.GuardianSet memory guardianSet = _state.guardianSets[index];
|
||||
|
||||
uint256 guardianCount = guardianSet.keys.length;
|
||||
bytes memory encodedGuardianSet;
|
||||
for (uint256 i = 0; i < guardianCount;) {
|
||||
encodedGuardianSet = abi.encodePacked(encodedGuardianSet, guardianSet.keys[i]);
|
||||
unchecked { i += 1; }
|
||||
}
|
||||
|
||||
// Store the hash.
|
||||
_state.guardianSetHashes[index] = keccak256(
|
||||
abi.encodePacked(encodedGuardianSet, guardianSet.expirationTime)
|
||||
);
|
||||
}
|
||||
}
|
|
@ -44,6 +44,9 @@ contract Storage {
|
|||
|
||||
// EIP-155 Chain ID
|
||||
uint256 evmChainId;
|
||||
|
||||
// Guardian set hashes.
|
||||
mapping(uint32 => bytes32) guardianSetHashes;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,50 @@ pragma solidity ^0.8.0;
|
|||
import "../contracts/Messages.sol";
|
||||
import "../contracts/Setters.sol";
|
||||
import "../contracts/Structs.sol";
|
||||
|
||||
import "forge-std/Test.sol";
|
||||
import "forge-std/Vm.sol";
|
||||
|
||||
contract WormholeSigner is Test {
|
||||
// Signer wallet.
|
||||
struct Wallet {
|
||||
address addr;
|
||||
uint256 key;
|
||||
}
|
||||
|
||||
function encodeAndSignMessage(
|
||||
Structs.VM memory vm_,
|
||||
uint256[] memory guardianKeys,
|
||||
uint32 guardianSetIndex
|
||||
) public pure returns (bytes memory signedMessage) {
|
||||
// Compute the hash of the body
|
||||
bytes memory body = abi.encodePacked(
|
||||
vm_.timestamp,
|
||||
vm_.nonce,
|
||||
vm_.emitterChainId,
|
||||
vm_.emitterAddress,
|
||||
vm_.sequence,
|
||||
vm_.consistencyLevel,
|
||||
vm_.payload
|
||||
);
|
||||
vm_.hash = keccak256(abi.encodePacked(keccak256(body)));
|
||||
|
||||
// Sign the hash with the specified guardian private keys.
|
||||
uint256 guardianCount = guardianKeys.length;
|
||||
bytes memory signatures = abi.encodePacked(uint8(guardianCount));
|
||||
for (uint256 i = 0; i < guardianCount; ++i) {
|
||||
(uint8 v, bytes32 r, bytes32 s) = vm.sign(guardianKeys[i], vm_.hash);
|
||||
signatures = abi.encodePacked(signatures, uint8(i), r, s, v - 27);
|
||||
}
|
||||
|
||||
signedMessage = abi.encodePacked(
|
||||
vm_.version,
|
||||
guardianSetIndex,
|
||||
signatures,
|
||||
body
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
contract ExportedMessages is Messages, Setters {
|
||||
function storeGuardianSetPub(Structs.GuardianSet memory set, uint32 index) public {
|
||||
|
@ -23,12 +66,15 @@ contract TestMessages is Test {
|
|||
uint256 constant testGuardian = 93941733246223705020089879371323733820373732307041878556247502674739205313440;
|
||||
|
||||
ExportedMessages messages;
|
||||
WormholeSigner wormholeSimulator;
|
||||
|
||||
Structs.GuardianSet guardianSet;
|
||||
|
||||
function setUp() public {
|
||||
messages = new ExportedMessages();
|
||||
// Guardian set with 19 guardians and wallets with each signing key.
|
||||
Structs.GuardianSet guardianSetOpt;
|
||||
uint256[] guardianKeys = new uint256[](19);
|
||||
|
||||
function setupSingleGuardian() internal {
|
||||
// initialize guardian set with one guardian
|
||||
address[] memory keys = new address[](1);
|
||||
keys[0] = vm.addr(testGuardian);
|
||||
|
@ -36,6 +82,57 @@ contract TestMessages is Test {
|
|||
require(messages.quorum(guardianSet.keys.length) == 1, "Quorum should be 1");
|
||||
}
|
||||
|
||||
function setupMultiGuardian() internal {
|
||||
// initialize guardian set with 19 guardians
|
||||
address[] memory keys = new address[](19);
|
||||
for (uint256 i = 0; i < 19; ++i) {
|
||||
// create a keypair for each guardian
|
||||
VmSafe.Wallet memory wallet = vm.createWallet(string(abi.encodePacked("guardian", i)));
|
||||
keys[i] = wallet.addr;
|
||||
guardianKeys[i] = wallet.privateKey;
|
||||
}
|
||||
guardianSetOpt = Structs.GuardianSet(keys, 0);
|
||||
require(messages.quorum(guardianSetOpt.keys.length) == 13, "Quorum should be 13");
|
||||
}
|
||||
|
||||
function setUp() public {
|
||||
console.log("here?");
|
||||
messages = new ExportedMessages();
|
||||
console.log("or?");
|
||||
wormholeSimulator = new WormholeSigner();
|
||||
setupSingleGuardian();
|
||||
setupMultiGuardian();
|
||||
}
|
||||
|
||||
function getSignedVM(
|
||||
bytes memory payload,
|
||||
bytes32 emitterAddress,
|
||||
uint16 emitterChainId,
|
||||
uint256[] memory _guardianKeys,
|
||||
uint32 guardianSetIndex
|
||||
) internal view returns (bytes memory signedTransfer) {
|
||||
// construct `TransferWithPayload` Wormhole message
|
||||
Structs.VM memory vm;
|
||||
|
||||
// set the vm values inline
|
||||
vm.version = uint8(1);
|
||||
vm.timestamp = uint32(block.timestamp);
|
||||
vm.emitterChainId = emitterChainId;
|
||||
vm.emitterAddress = emitterAddress;
|
||||
vm.sequence = messages.nextSequence(
|
||||
address(uint160(uint256(emitterAddress)))
|
||||
);
|
||||
vm.consistencyLevel = 15;
|
||||
vm.payload = payload;
|
||||
|
||||
// encode the bservation
|
||||
signedTransfer = wormholeSimulator.encodeAndSignMessage(
|
||||
vm,
|
||||
_guardianKeys,
|
||||
guardianSetIndex
|
||||
);
|
||||
}
|
||||
|
||||
function testQuorum() public {
|
||||
assertEq(messages.quorum(0), 1);
|
||||
assertEq(messages.quorum(1), 1);
|
||||
|
@ -161,4 +258,76 @@ contract TestMessages is Test {
|
|||
assertEq(valid, false);
|
||||
assertEq(reason, "vm.hash doesn't match body");
|
||||
}
|
||||
|
||||
function testParseGuardianSetOptimized(uint8 guardianCount) public view {
|
||||
vm.assume(guardianCount > 0 && guardianCount <= 19);
|
||||
|
||||
// Encode the guardian set.
|
||||
bytes memory encodedGuardianSet;
|
||||
for (uint256 i = 0; i < guardianCount; ++i) {
|
||||
encodedGuardianSet = abi.encodePacked(encodedGuardianSet, guardianSetOpt.keys[i]);
|
||||
}
|
||||
encodedGuardianSet = abi.encodePacked(encodedGuardianSet, guardianSetOpt.expirationTime);
|
||||
|
||||
// Parse the guardian set.
|
||||
Structs.GuardianSet memory parsedSet = messages.parseGuardianSet(encodedGuardianSet);
|
||||
|
||||
// Validate the results by comparing the parsed set to the original set.
|
||||
for (uint256 i = 0; i < guardianCount; ++i) {
|
||||
assert(parsedSet.keys[i] == guardianSetOpt.keys[i]);
|
||||
}
|
||||
assert(parsedSet.expirationTime == guardianSetOpt.expirationTime);
|
||||
}
|
||||
|
||||
function testParseAndVerifyVMOptimized(bytes memory payload) public {
|
||||
vm.assume(payload.length > 0 && payload.length < 1000);
|
||||
|
||||
uint16 emitterChainId = 16;
|
||||
bytes32 emitterAddress = bytes32(uint256(uint160(makeAddr("foreignEmitter"))));
|
||||
uint32 currentSetIndex = messages.getCurrentGuardianSetIndex();
|
||||
|
||||
// Set the guardian set to the optimized guardian set.
|
||||
messages.storeGuardianSetPub(guardianSetOpt, currentSetIndex);
|
||||
messages.setGuardianSetHash(currentSetIndex);
|
||||
|
||||
// Create a message with an arbitrary payload.
|
||||
bytes memory signedMessage = getSignedVM(
|
||||
payload,
|
||||
emitterAddress,
|
||||
emitterChainId,
|
||||
guardianKeys,
|
||||
currentSetIndex
|
||||
);
|
||||
|
||||
// Parse and verify the VM.
|
||||
(Structs.VM memory vm_, bool valid,) = messages.parseAndVerifyVM(signedMessage);
|
||||
assertEq(valid, true);
|
||||
|
||||
// Parse and verify the VM using the optimized endpoint.
|
||||
(Structs.VM memory vmOptimized, bool valid_,) = messages.parseAndVerifyVMOptimized(
|
||||
signedMessage,
|
||||
messages.getEncodedGuardianSet(currentSetIndex),
|
||||
currentSetIndex
|
||||
);
|
||||
assertEq(valid_, true);
|
||||
|
||||
// Validate the results by comparing the parsed VM to the optimized VM.
|
||||
assertEq(vm_.version, vmOptimized.version);
|
||||
assertEq(vm_.timestamp, vmOptimized.timestamp);
|
||||
assertEq(vm_.nonce, vmOptimized.nonce);
|
||||
assertEq(vm_.emitterChainId, vmOptimized.emitterChainId);
|
||||
assertEq(vm_.emitterAddress, vmOptimized.emitterAddress);
|
||||
assertEq(vm_.sequence, vmOptimized.sequence);
|
||||
assertEq(vm_.consistencyLevel, vmOptimized.consistencyLevel);
|
||||
assertEq(vm_.payload, vmOptimized.payload);
|
||||
assertEq(vm_.guardianSetIndex, vmOptimized.guardianSetIndex);
|
||||
assertEq(vm_.signatures.length, vmOptimized.signatures.length);
|
||||
|
||||
for (uint256 i = 0; i < vm_.signatures.length; ++i) {
|
||||
assertEq(vm_.signatures[i].guardianIndex, vmOptimized.signatures[i].guardianIndex);
|
||||
assertEq(vm_.signatures[i].r, vmOptimized.signatures[i].r);
|
||||
assertEq(vm_.signatures[i].s, vmOptimized.signatures[i].s);
|
||||
assertEq(vm_.signatures[i].v, vmOptimized.signatures[i].v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import "../contracts/Messages.sol";
|
|||
import "../contracts/Setters.sol";
|
||||
import "../contracts/Structs.sol";
|
||||
import "forge-test/rv-helpers/TestUtils.sol";
|
||||
import "../contracts/libraries/external/BytesLib.sol";
|
||||
|
||||
contract TestMessagesRV is TestUtils {
|
||||
using BytesLib for bytes;
|
||||
|
|
Loading…
Reference in New Issue