This commit is contained in:
derpy-duck 2023-02-10 23:32:44 +00:00 committed by chase-45
parent 0998f557da
commit 991e88eac2
2 changed files with 133 additions and 79 deletions

View File

@ -25,31 +25,33 @@ contract MockRelayerIntegration is IWormholeReceiver {
// map that stores payloads from received VAAs
mapping(bytes32 => bytes) verifiedPayloads;
bytes message;
// mapping of other MockRelayerIntegration contracts
mapping(uint16 => bytes32) registeredContracts;
bytes[] messages;
struct FurtherInstructions {
bool keepSending;
bytes newMessage;
bytes[] newMessages;
uint16[] chains;
uint32[] gasLimits;
}
struct Message {
bytes text;
FurtherInstructions furtherInstructions;
}
constructor(address _wormholeCore, address _coreRelayer) {
wormhole = IWormhole(_wormholeCore);
relayer = IWormholeRelayer(_coreRelayer);
owner = msg.sender;
}
function sendMessage(bytes memory _message, uint16 targetChainId, address destination) public payable {
sendMessage(_message, targetChainId, destination, destination);
}
function sendMessage(bytes memory _message, uint16 targetChainId, address destination, address refundAddress)
public
payable
{
executeSend(abi.encodePacked(uint8(0), _message), targetChainId, destination, refundAddress, 0, 1);
sendMessageGeneral(_message, targetChainId, destination, refundAddress, 0, 1);
}
function sendMessageWithForwardedResponse(
@ -58,7 +60,21 @@ contract MockRelayerIntegration is IWormholeReceiver {
address destination,
address refundAddress
) public payable {
executeSend(abi.encodePacked(uint8(1), _message), targetChainId, destination, refundAddress, 0, 1);
uint16[] memory chains = new uint16[](1);
chains[0] = wormhole.chainId();
uint32[] memory gasLimits = new uint32[](1);
gasLimits[0] = 1000000;
bytes[] memory newMessages = new bytes[](1);
newMessages[0] = bytes("received!");
FurtherInstructions memory instructions = FurtherInstructions({
keepSending: true,
newMessages: newMessages,
chains: chains,
gasLimits: gasLimits
});
wormhole.publishMessage{value: wormhole.messageFee()}(1, _message, 200);
wormhole.publishMessage{value: wormhole.messageFee()}(1, encodeFurtherInstructions(instructions), 200);
executeSend(targetChainId, destination, refundAddress, 0, 1);
}
function sendMessageGeneral(
@ -69,18 +85,18 @@ contract MockRelayerIntegration is IWormholeReceiver {
uint256 receiverValue,
uint32 nonce
) public payable {
executeSend(fullMessage, targetChainId, destination, refundAddress, receiverValue, nonce);
wormhole.publishMessage{value: wormhole.messageFee()}(nonce, fullMessage, 200);
wormhole.publishMessage{value: wormhole.messageFee()}(1, abi.encodePacked(uint8(0)), 200);
executeSend(targetChainId, destination, refundAddress, receiverValue, nonce);
}
function executeSend(
bytes memory fullMessage,
uint16 targetChainId,
address destination,
address refundAddress,
uint256 receiverValue,
uint32 nonce
) internal {
wormhole.publishMessage{value: wormhole.messageFee()}(nonce, fullMessage, 200);
IWormholeRelayer.Send memory request = IWormholeRelayer.Send({
targetChain: targetChainId,
@ -97,46 +113,49 @@ contract MockRelayerIntegration is IWormholeReceiver {
function receiveWormholeMessages(bytes[] memory wormholeObservations, bytes[] memory) public payable override {
// loop through the array of wormhole observations from the batch and store each payload
uint256 numObservations = wormholeObservations.length;
for (uint256 i = 0; i < numObservations - 1;) {
messages = new bytes[](wormholeObservations.length - 2);
for (uint256 i = 0; i < numObservations - 2; i++) {
(IWormhole.VM memory parsed, bool valid, string memory reason) =
wormhole.parseAndVerifyVM(wormholeObservations[i]);
require(valid, reason);
require(registeredContracts[parsed.emitterChainId] == parsed.emitterAddress);
messages[i] = parsed.payload;
}
bool forward = (parsed.payload.toUint8(0) == 1);
verifiedPayloads[parsed.hash] = parsed.payload.slice(1, parsed.payload.length - 1);
message = parsed.payload.slice(1, parsed.payload.length - 1);
if (forward) {
wormhole.publishMessage{value: wormhole.messageFee()}(
parsed.nonce, abi.encodePacked(uint8(0), bytes("received!")), 200
);
(IWormhole.VM memory parsed, bool valid, string memory reason) =
wormhole.parseAndVerifyVM(wormholeObservations[wormholeObservations.length - 2]);
FurtherInstructions memory instructions = decodeFurtherInstructions(parsed.payload);
uint256 maxTransactionFee =
relayer.quoteGas(parsed.emitterChainId, 500000, relayer.getDefaultRelayProvider());
IWormholeRelayer.Send memory request = IWormholeRelayer.Send({
targetChain: parsed.emitterChainId,
targetAddress: parsed.emitterAddress,
refundAddress: parsed.emitterAddress,
maxTransactionFee: maxTransactionFee,
if(instructions.keepSending) {
for(uint16 i=0; i<instructions.newMessages.length; i++) {
wormhole.publishMessage(parsed.nonce, instructions.newMessages[i], 200);
}
ICoreRelayer.DeliveryRequest[] memory deliveryRequests = new ICoreRelayer.DeliveryRequest[](instructions.chains.length);
for(uint16 i=0; i<instructions.chains.length; i++) {
deliveryRequests[i] = ICoreRelayer.DeliveryRequest({
targetChain: instructions.chains[i],
targetAddress: registeredContracts[instructions.chains[i]],
refundAddress: registeredContracts[instructions.chains[i]],
maxTransactionFee: relayer.quoteGas(instructions.chains[i], instructions.gasLimits[i], relayer.getDefaultRelayProvider()),
receiverValue: 0,
relayParameters: relayer.getDefaultRelayParams()
});
relayer.forward(request, parsed.nonce, relayer.getDefaultRelayProvider());
}
unchecked {
i += 1;
}
IWormholeRelayer.SendContainer memory container = Iwormhole.SendContainer(1, address(relayer.getDefaultRelayProvider()), deliveryRequests);
relayer.multichainForward(container, deliveryRequests[0].targetChain, parsed.nonce);
}
}
function getPayload(bytes32 hash) public view returns (bytes memory) {
return verifiedPayloads[hash];
}
function getMessage() public view returns (bytes memory) {
return message;
function getFirstMessage() public view returns (bytes memory) {
if(messages.length == 0) {
return new bytes(0);
}
return messages[0];
}
function clearPayload(bytes32 hash) public {
@ -151,30 +170,54 @@ contract MockRelayerIntegration is IWormholeReceiver {
return bytes32(uint256(uint160(address(this))));
}
function encodeMessage(Message message) public view returns (bytes encodedMessage) {
encodedMessage = abi.encodePacked(uint16(message.text.length), message.text, uint8(0));
function registerEmitter(uint16 chainId, bytes32 emitterAddress) public {
require(msg.sender == owner);
registeredContracts[chainId] = emitterAddress;
}
function encodeMessage(Message message, ForwardingInstructions forwardingInstructions) public view returns (bytes encodedMessage) {
encodedMessage = abi.encodePacked(encodeMessage(message), uint8(forwardingInstructions.keepSending), uint16(forwardingInstructions.newMessage.length), uint16(forwardingInstuctions.chains.length));
for(uint16 i=0; i<forwardingInstructions.chains.length; i++) {
encodedMessage = abi.encodePacked(encodedMessage, forwardingInstructions.chains[i], forwardingInstructions.gasLimits[i]);
function encodeFurtherInstructions(FurtherInstructions memory furtherInstructions) public view returns (bytes memory encodedFurtherInstructions) {
encodedFurtherInstructions = abi.encodePacked(furtherInstructions.keepSending ? uint8(1) : uint8(0), uint16(furtherInstructions.newMessages.length));
for(uint16 i=0; i<furtherInstructions.newMessages.length; i++) {
encodedFurtherInstructions = abi.encodePacked(encodedFurtherInstructions, uint16(furtherInstructions.newMessages[i].length), furtherInstructions.newMessages[i]);
}
encodedFurtherInstructions = abi.encodePacked(encodedFurtherInstructions, uint16(furtherInstructions.chains.length));
for(uint16 i=0; i<furtherInstructions.chains.length; i++) {
encodedFurtherInstructions = abi.encodePacked(encodedFurtherInstructions, furtherInstructions.chains[i], furtherInstructions.gasLimits[i]);
}
}
function decodeMessage(bytes encodedMessage) public view returns (Message message) {
function decodeFurtherInstructions(bytes memory encodedFurtherInstructions) public view returns (FurtherInstructions memory furtherInstructions) {
uint256 index = 0;
uint16 length = encodedMessage.toUint16(index);
index += 2;
message.text = encodedMessage.slice(index, length);
index += length;
message.forwardingInstructions.keepSending = encodedMessage.toUint8(index) == 1;
furtherInstructions.keepSending = encodedFurtherInstructions.toUint8(index) == 1;
index += 1;
length = encodedMessage.toUint16(index);
if(!furtherInstructions.keepSending) {
return furtherInstructions;
}
uint16 length = encodedFurtherInstructions.toUint16(index);
index += 2;
uint16[] chains = new uint16[](length);
uint32[] gasLimits = new uint32[](length);
message.forwardingInstructions.
furtherInstructions.newMessages = new bytes[](length);
for(uint16 i=0; i<length; i++) {
uint16 msgLength = encodedFurtherInstructions.toUint16(index);
index += 2;
furtherInstructions.newMessages[i] = encodedFurtherInstructions.slice(index, msgLength);
index += msgLength;
}
length = encodedFurtherInstructions.toUint16(index);
index += 2;
uint16[] memory chains = new uint16[](length);
uint32[] memory gasLimits = new uint32[](length);
for(uint16 i=0; i<length; i++) {
chains[i] = encodedFurtherInstructions.toUint16(index);
index += 2;
gasLimits[i] = encodedFurtherInstructions.toUint32(index);
index += 4;
}
furtherInstructions.chains = chains;
furtherInstructions.gasLimits = gasLimits;
}

View File

@ -288,6 +288,7 @@ contract TestCoreRelayer is Test {
map[i].coreRelayerFull, i, j, bytes32(uint256(uint160(address(map[j].coreRelayer))))
);
map[i].relayProvider.updateMaximumBudget(j, maxBudget);
map[i].integration.registerEmitter(j, bytes32(uint256(uint160(address(map[j].integration)))));
}
}
}
@ -345,9 +346,9 @@ contract TestCoreRelayer is Test {
message, setup.targetChainId, address(setup.target.integration), address(setup.target.refundAddress)
);
genericRelayer(setup.sourceChainId, 2);
genericRelayer(setup.sourceChainId, 3);
assertTrue(keccak256(setup.target.integration.getMessage()) == keccak256(message));
assertTrue(keccak256(setup.target.integration.getFirstMessage()) == keccak256(message));
}
function testFundsCorrect(GasParameters memory gasParams, FeeParameters memory feeParams, bytes memory message)
@ -368,7 +369,7 @@ contract TestCoreRelayer is Test {
) + 2 * setup.source.wormhole.messageFee() + receiverValueSource;
setup.source.integration.sendMessageGeneral{value: payment}(
abi.encodePacked(uint8(0), message),
message,
setup.targetChainId,
address(setup.target.integration),
address(setup.target.refundAddress),
@ -376,9 +377,9 @@ contract TestCoreRelayer is Test {
1
);
genericRelayer(setup.sourceChainId, 2);
genericRelayer(setup.sourceChainId, 3);
assertTrue(keccak256(setup.target.integration.getMessage()) == keccak256(message));
assertTrue(keccak256(setup.target.integration.getFirstMessage()) == keccak256(message));
uint256 USDcost = uint256(payment) * feeParams.sourceNativePrice
- (setup.target.refundAddress.balance - refundAddressBalance) * feeParams.targetNativePrice;
@ -431,7 +432,7 @@ contract TestCoreRelayer is Test {
) + 2 * setup.source.wormhole.messageFee() + receiverValueSource;
setup.source.integration.sendMessageGeneral{value: payment}(
abi.encodePacked(uint8(0), message),
message,
setup.targetChainId,
address(setup.target.integration),
address(setup.target.refundAddress),
@ -439,7 +440,7 @@ contract TestCoreRelayer is Test {
1
);
genericRelayer(setup.sourceChainId, 2);
genericRelayer(setup.sourceChainId, 3);
uint256 USDcost = uint256(payment) * feeParams.sourceNativePrice
- (setup.target.refundAddress.balance - refundAddressBalance) * feeParams.targetNativePrice;
@ -487,13 +488,13 @@ contract TestCoreRelayer is Test {
message, setup.targetChainId, address(setup.target.integration), address(setup.target.refundAddress)
);
genericRelayer(setup.sourceChainId, 2);
genericRelayer(setup.sourceChainId, 3);
assertTrue(keccak256(setup.target.integration.getMessage()) == keccak256(message));
assertTrue(keccak256(setup.target.integration.getFirstMessage()) == keccak256(message));
genericRelayer(setup.targetChainId, 2);
genericRelayer(setup.targetChainId, 3);
assertTrue(keccak256(setup.source.integration.getMessage()) == keccak256(bytes("received!")));
assertTrue(keccak256(setup.source.integration.getFirstMessage()) == keccak256(bytes("received!")));
}
function testRedelivery(GasParameters memory gasParams, FeeParameters memory feeParams, bytes memory message)
@ -517,10 +518,10 @@ contract TestCoreRelayer is Test {
message, setup.targetChainId, address(setup.target.integration), address(setup.target.refundAddress)
);
genericRelayer(setup.sourceChainId, 2);
genericRelayer(setup.sourceChainId, 3);
assertTrue(
(keccak256(setup.target.integration.getMessage()) != keccak256(message))
(keccak256(setup.target.integration.getFirstMessage()) != keccak256(message))
|| (keccak256(message) == keccak256(bytes("")))
);
Vm.Log[] memory logs = vm.getRecordedLogs();
@ -548,7 +549,7 @@ contract TestCoreRelayer is Test {
genericRelayer(setup.sourceChainId, 1);
assertTrue(keccak256(setup.target.integration.getMessage()) == keccak256(message));
assertTrue(keccak256(setup.target.integration.getFirstMessage()) == keccak256(message));
}
function testApplicationBudgetFeeWithRedelivery(
@ -574,10 +575,10 @@ contract TestCoreRelayer is Test {
message, setup.targetChainId, address(setup.target.integration), address(setup.target.refundAddress)
);
genericRelayer(setup.sourceChainId, 2);
genericRelayer(setup.sourceChainId, 3);
assertTrue(
(keccak256(setup.target.integration.getMessage()) != keccak256(message))
(keccak256(setup.target.integration.getFirstMessage()) != keccak256(message))
|| (keccak256(message) == keccak256(bytes("")))
);
@ -607,7 +608,7 @@ contract TestCoreRelayer is Test {
genericRelayer(setup.sourceChainId, 1);
assertTrue(keccak256(setup.target.integration.getMessage()) == keccak256(message));
assertTrue(keccak256(setup.target.integration.getFirstMessage()) == keccak256(message));
assertTrue(address(setup.target.integration).balance >= oldBalance + feeParams.receiverValueTarget);
@ -633,7 +634,7 @@ contract TestCoreRelayer is Test {
genericRelayer(setup.sourceChainId, 1);
assertTrue(keccak256(setup.target.integration.getMessage()) == keccak256(message));
assertTrue(keccak256(setup.target.integration.getFirstMessage()) == keccak256(message));
assertTrue(address(setup.target.integration).balance < oldBalance + feeParams.receiverValueTarget);
}
@ -658,9 +659,9 @@ contract TestCoreRelayer is Test {
message, setup.targetChainId, address(setup.target.integration), address(setup.target.refundAddress)
);
genericRelayer(setup.sourceChainId, 2);
genericRelayer(setup.sourceChainId, 3);
assertTrue(keccak256(setup.target.integration.getMessage()) == keccak256(message));
assertTrue(keccak256(setup.target.integration.getFirstMessage()) == keccak256(message));
vm.getRecordedLogs();
@ -670,9 +671,9 @@ contract TestCoreRelayer is Test {
secondMessage, setup.targetChainId, address(setup.target.integration), address(setup.target.refundAddress)
);
genericRelayer(setup.sourceChainId, 2);
genericRelayer(setup.sourceChainId, 3);
assertTrue(keccak256(setup.target.integration.getMessage()) == keccak256(secondMessage));
assertTrue(keccak256(setup.target.integration.getFirstMessage()) == keccak256(secondMessage));
}
function testRevertNonceZero(GasParameters memory gasParams, FeeParameters memory feeParams, bytes memory message)
@ -689,8 +690,13 @@ contract TestCoreRelayer is Test {
);
vm.expectRevert(abi.encodeWithSignature("NonceIsZero()"));
<<<<<<< HEAD
setup.source.integration.sendMessageGeneral{value: maxTransactionFee + 2 * wormholeFee}(
abi.encodePacked(uint8(0), message),
=======
setup.source.integration.sendMessageGeneral{value: computeBudget + 2 * wormholeFee}(
message,
>>>>>>> 74457f4 (Bugfixes)
setup.targetChainId,
address(setup.target.integration),
address(setup.target.refundAddress),
@ -763,10 +769,10 @@ contract TestCoreRelayer is Test {
+ 2 * setup.source.wormhole.messageFee()
}(message, setup.targetChainId, address(setup.target.integration), address(setup.target.refundAddress));
genericRelayer(setup.sourceChainId, 2);
genericRelayer(setup.sourceChainId, 3);
assertTrue(
(keccak256(setup.target.integration.getMessage()) != keccak256(message))
(keccak256(setup.target.integration.getFirstMessage()) != keccak256(message))
|| (keccak256(message) == keccak256(bytes("")))
);
@ -978,12 +984,17 @@ contract TestCoreRelayer is Test {
vm.deal(setup.target.relayer, type(uint256).max);
assertTrue(
(keccak256(setup.target.integration.getMessage()) != keccak256(message))
(keccak256(setup.target.integration.getFirstMessage()) != keccak256(message))
|| (keccak256(message) == keccak256(bytes("")))
);
vm.prank(setup.target.relayer);
<<<<<<< HEAD
setup.target.coreRelayerFull.redeliverSingle{value: stack.budget}(stack.package);
assertTrue(keccak256(setup.target.integration.getMessage()) == keccak256(message));
=======
setup.target.coreRelayer.redeliverSingle{value: stack.budget}(stack.package);
assertTrue(keccak256(setup.target.integration.getFirstMessage()) == keccak256(message));
>>>>>>> 74457f4 (Bugfixes)
}
/**
@ -1026,9 +1037,9 @@ contract TestCoreRelayer is Test {
value: stack.paymentNotEnough + setup.source.wormhole.messageFee()
}(message, setup.targetChainId, address(setup.target.integration), address(setup.target.refundAddress));
genericRelayer(setup.sourceChainId, 2);
genericRelayer(setup.sourceChainId, 3);
assertTrue(keccak256(setup.target.integration.getMessage()) == keccak256(message));
assertTrue(keccak256(setup.target.integration.getFirstMessage()) == keccak256(message));
stack.entries = vm.getRecordedLogs();
stack.actualVM = relayerWormholeSimulator.fetchSignedMessageFromLogs(