165 lines
6.0 KiB
Solidity
165 lines
6.0 KiB
Solidity
// test/Messages.sol
|
|
// SPDX-License-Identifier: Apache 2
|
|
|
|
pragma solidity ^0.8.0;
|
|
|
|
import "../contracts/Messages.sol";
|
|
import "../contracts/Setters.sol";
|
|
import "../contracts/Structs.sol";
|
|
import "forge-std/Test.sol";
|
|
|
|
contract ExportedMessages is Messages, Setters {
|
|
function storeGuardianSetPub(Structs.GuardianSet memory set, uint32 index) public {
|
|
return super.storeGuardianSet(set, index);
|
|
}
|
|
}
|
|
|
|
contract TestMessages is Test {
|
|
address constant testGuardianPub = 0xbeFA429d57cD18b7F8A4d91A2da9AB4AF05d0FBe;
|
|
|
|
// A valid VM with one signature from the testGuardianPublic key
|
|
bytes validVM = hex"01000000000100867b55fec41778414f0683e80a430b766b78801b7070f9198ded5e62f48ac7a44b379a6cf9920e42dbd06c5ebf5ec07a934a00a572aefc201e9f91c33ba766d900000003e800000001000b0000000000000000000000000000000000000000000000000000000000000eee00000000000005390faaaa";
|
|
|
|
uint256 constant testGuardian = 93941733246223705020089879371323733820373732307041878556247502674739205313440;
|
|
|
|
ExportedMessages messages;
|
|
|
|
Structs.GuardianSet guardianSet;
|
|
|
|
function setUp() public {
|
|
messages = new ExportedMessages();
|
|
|
|
// initialize guardian set with one guardian
|
|
address[] memory keys = new address[](1);
|
|
keys[0] = vm.addr(testGuardian);
|
|
guardianSet = Structs.GuardianSet(keys, 0);
|
|
require(messages.quorum(guardianSet.keys.length) == 1, "Quorum should be 1");
|
|
}
|
|
|
|
function testQuorum() public {
|
|
assertEq(messages.quorum(0), 1);
|
|
assertEq(messages.quorum(1), 1);
|
|
assertEq(messages.quorum(2), 2);
|
|
assertEq(messages.quorum(3), 3);
|
|
assertEq(messages.quorum(4), 3);
|
|
assertEq(messages.quorum(5), 4);
|
|
assertEq(messages.quorum(6), 5);
|
|
assertEq(messages.quorum(7), 5);
|
|
assertEq(messages.quorum(8), 6);
|
|
assertEq(messages.quorum(9), 7);
|
|
assertEq(messages.quorum(10), 7);
|
|
assertEq(messages.quorum(11), 8);
|
|
assertEq(messages.quorum(12), 9);
|
|
assertEq(messages.quorum(19), 13);
|
|
assertEq(messages.quorum(20), 14);
|
|
}
|
|
|
|
function testQuorumCanAlwaysBeReached(uint256 numGuardians) public {
|
|
vm.assume(numGuardians > 0);
|
|
|
|
if (numGuardians >= 256) {
|
|
vm.expectRevert("too many guardians");
|
|
}
|
|
// test that quorums is never greater than the number of guardians
|
|
assert(messages.quorum(numGuardians) <= numGuardians);
|
|
}
|
|
|
|
// This test ensures that submitting more signatures than expected will
|
|
// trigger a "guardian index out of bounds" error.
|
|
function testCannotVerifySignaturesWithOutOfBoundsSignature(bytes memory encoded) public {
|
|
vm.assume(encoded.length > 0);
|
|
|
|
bytes32 message = keccak256(encoded);
|
|
|
|
// First generate a legitimate signature.
|
|
Structs.Signature memory goodSignature = Structs.Signature(message, 0, 0, 0);
|
|
(goodSignature.v, goodSignature.r, goodSignature.s) = vm.sign(testGuardian, message);
|
|
assertEq(ecrecover(message, goodSignature.v, goodSignature.r, goodSignature.s), vm.addr(testGuardian));
|
|
|
|
// Reuse legitimate signature above for the next signature. This will
|
|
// bypass the "invalid signature" revert.
|
|
Structs.Signature memory outOfBoundsSignature = goodSignature;
|
|
outOfBoundsSignature.guardianIndex = 1;
|
|
|
|
// Attempt to verify signatures.
|
|
Structs.Signature[] memory sigs = new Structs.Signature[](2);
|
|
sigs[0] = goodSignature;
|
|
sigs[1] = outOfBoundsSignature;
|
|
|
|
vm.expectRevert("guardian index out of bounds");
|
|
messages.verifySignatures(message, sigs, guardianSet);
|
|
}
|
|
|
|
// This test ensures that submitting an invalid signature fails when
|
|
// verifySignatures is called. Calling ecrecover should fail.
|
|
function testCannotVerifySignaturesWithInvalidSignature(bytes memory encoded) public {
|
|
vm.assume(encoded.length > 0);
|
|
|
|
bytes32 message = keccak256(encoded);
|
|
|
|
// Generate an invalid signature.
|
|
Structs.Signature memory badSignature = Structs.Signature(message, 0, 0, 0);
|
|
assertEq(ecrecover(message, badSignature.v, badSignature.r, badSignature.s), address(0));
|
|
|
|
// Attempt to verify signatures.
|
|
Structs.Signature[] memory sigs = new Structs.Signature[](2);
|
|
sigs[0] = badSignature;
|
|
|
|
vm.expectRevert("ecrecover failed with signature");
|
|
messages.verifySignatures(message, sigs, guardianSet);
|
|
}
|
|
|
|
function testVerifySignatures(bytes memory encoded) public {
|
|
vm.assume(encoded.length > 0);
|
|
|
|
bytes32 message = keccak256(encoded);
|
|
|
|
// Generate legitimate signature.
|
|
Structs.Signature memory goodSignature;
|
|
(goodSignature.v, goodSignature.r, goodSignature.s) = vm.sign(testGuardian, message);
|
|
assertEq(ecrecover(message, goodSignature.v, goodSignature.r, goodSignature.s), vm.addr(testGuardian));
|
|
goodSignature.guardianIndex = 0;
|
|
|
|
// Attempt to verify signatures.
|
|
Structs.Signature[] memory sigs = new Structs.Signature[](1);
|
|
sigs[0] = goodSignature;
|
|
|
|
(bool valid, string memory reason) = messages.verifySignatures(message, sigs, guardianSet);
|
|
assertEq(valid, true);
|
|
assertEq(bytes(reason).length, 0);
|
|
}
|
|
|
|
// This test checks the possibility of getting a unsigned message verified through verifyVM
|
|
function testHashMismatchedVMIsNotVerified() public {
|
|
// Set the initial guardian set
|
|
address[] memory initialGuardians = new address[](1);
|
|
initialGuardians[0] = testGuardianPub;
|
|
|
|
// Create a guardian set
|
|
Structs.GuardianSet memory initialGuardianSet = Structs.GuardianSet({
|
|
keys: initialGuardians,
|
|
expirationTime: 0
|
|
});
|
|
|
|
messages.storeGuardianSetPub(initialGuardianSet, uint32(0));
|
|
|
|
// Confirm that the test VM is valid
|
|
(Structs.VM memory parsedValidVm, bool valid, string memory reason) = messages.parseAndVerifyVM(validVM);
|
|
require(valid, reason);
|
|
assertEq(valid, true);
|
|
assertEq(reason, "");
|
|
|
|
// Manipulate the payload of the vm
|
|
Structs.VM memory invalidVm = parsedValidVm;
|
|
invalidVm.payload = abi.encodePacked(
|
|
parsedValidVm.payload,
|
|
"malicious bytes in payload"
|
|
);
|
|
|
|
// Confirm that the verifyVM fails on invalid VM
|
|
(valid, reason) = messages.verifyVM(invalidVm);
|
|
assertEq(valid, false);
|
|
assertEq(reason, "vm.hash doesn't match body");
|
|
}
|
|
}
|