diff --git a/contracts/src/v0.8/ccip/test/helpers/MessageHasher.sol b/contracts/src/v0.8/ccip/test/helpers/MessageHasher.sol index f0ca898a6c..19f35df796 100644 --- a/contracts/src/v0.8/ccip/test/helpers/MessageHasher.sol +++ b/contracts/src/v0.8/ccip/test/helpers/MessageHasher.sol @@ -6,6 +6,7 @@ import {Internal} from "../../libraries/Internal.sol"; /// @notice MessageHasher is a contract that utility functions to hash an Any2EVMRampMessage /// and encode various preimages for the final hash of the message. +/// @dev This is only deployed in tests and is not part of the production contracts. contract MessageHasher { function hash(Internal.Any2EVMRampMessage memory message, bytes memory onRamp) public pure returns (bytes32) { return Internal._hash(message, onRamp); @@ -48,4 +49,23 @@ contract MessageHasher { ) public pure returns (bytes memory) { return abi.encode(leafDomainSeparator, implicitMetadataHash, fixedSizeFieldsHash, dataHash, tokenAmountsHash); } + + function encodeEVMExtraArgsV1(Client.EVMExtraArgsV1 memory extraArgs) public pure returns (bytes memory) { + return Client._argsToBytes(extraArgs); + } + + function encodeEVMExtraArgsV2(Client.EVMExtraArgsV2 memory extraArgs) public pure returns (bytes memory) { + return Client._argsToBytes(extraArgs); + } + + function decodeEVMExtraArgsV1(uint256 gasLimit) public pure returns (Client.EVMExtraArgsV1 memory) { + return Client.EVMExtraArgsV1(gasLimit); + } + + function decodeEVMExtraArgsV2( + uint256 gasLimit, + bool allowOutOfOrderExecution + ) public pure returns (Client.EVMExtraArgsV2 memory) { + return Client.EVMExtraArgsV2(gasLimit, allowOutOfOrderExecution); + } } diff --git a/core/gethwrappers/ccip/generated/message_hasher/message_hasher.go b/core/gethwrappers/ccip/generated/message_hasher/message_hasher.go index 8fb8d08b6f..52434b5049 100644 --- a/core/gethwrappers/ccip/generated/message_hasher/message_hasher.go +++ b/core/gethwrappers/ccip/generated/message_hasher/message_hasher.go @@ -28,6 +28,15 @@ var ( _ = abi.ConvertType ) +type ClientEVMExtraArgsV1 struct { + GasLimit *big.Int +} + +type ClientEVMExtraArgsV2 struct { + GasLimit *big.Int + AllowOutOfOrderExecution bool +} + type InternalAny2EVMRampMessage struct { Header InternalRampMessageHeader Sender []byte @@ -53,8 +62,8 @@ type InternalRampTokenAmount struct { } var MessageHasherMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"leafDomainSeparator\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"implicitMetadataHash\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"fixedSizeFieldsHash\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"dataHash\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"tokenAmountsHash\",\"type\":\"bytes32\"}],\"name\":\"encodeFinalHashPreimage\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"messageId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"sender\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"sequenceNumber\",\"type\":\"uint64\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"nonce\",\"type\":\"uint64\"}],\"name\":\"encodeFixedSizeFieldsHashPreimage\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"any2EVMMessageHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"onRamp\",\"type\":\"bytes\"}],\"name\":\"encodeMetadataHashPreimage\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"sourcePoolAddress\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"destTokenAddress\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structInternal.RampTokenAmount[]\",\"name\":\"rampTokenAmounts\",\"type\":\"tuple[]\"}],\"name\":\"encodeTokenAmountsHashPreimage\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"messageId\",\"type\":\"bytes32\"},{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"sequenceNumber\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"nonce\",\"type\":\"uint64\"}],\"internalType\":\"structInternal.RampMessageHeader\",\"name\":\"header\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"sender\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"bytes\",\"name\":\"sourcePoolAddress\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"destTokenAddress\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structInternal.RampTokenAmount[]\",\"name\":\"tokenAmounts\",\"type\":\"tuple[]\"}],\"internalType\":\"structInternal.Any2EVMRampMessage\",\"name\":\"message\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"onRamp\",\"type\":\"bytes\"}],\"name\":\"hash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"}]", - Bin: "0x608060405234801561001057600080fd5b50610af3806100206000396000f3fe608060405234801561001057600080fd5b50600436106100675760003560e01c806399df8d051161005057806399df8d05146100b6578063a1e747df14610101578063a91d3aeb1461011457600080fd5b8063902e94a01461006c5780639511afaa14610095575b600080fd5b61007f61007a3660046105d0565b610127565b60405161008c9190610671565b60405180910390f35b6100a86100a336600461074f565b610150565b60405190815260200161008c565b61007f6100c4366004610859565b604080516020810196909652858101949094526060850192909252608084015260a0808401919091528151808403909101815260c0909201905290565b61007f61010f366004610894565b610163565b61007f6101223660046108fc565b610195565b60608160405160200161013a919061097d565b6040516020818303038152906040529050919050565b600061015c83836101cd565b9392505050565b60608484848460405160200161017c9493929190610a49565b6040516020818303038152906040529050949350505050565b60608686868686866040516020016101b296959493929190610a86565b60405160208183030381529060405290509695505050505050565b815160208082015160409283015192516000938493610213937f2425b0b9f9054c76ff151b0a175b18f37a4a4e82013a72e9f15c9caa095ed21f93909291889101610a49565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815290829052805160209182012086518051888401516060808b0151908401516080808d0151950151959761027a9794969395929491939101610a86565b604051602081830303815290604052805190602001208560400151805190602001208660a001516040516020016102b1919061097d565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181528282528051602091820120908301969096528101939093526060830191909152608082015260a081019190915260c00160405160208183030381529060405280519060200120905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516080810167ffffffffffffffff8111828210171561037c5761037c61032a565b60405290565b60405160c0810167ffffffffffffffff8111828210171561037c5761037c61032a565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156103ec576103ec61032a565b604052919050565b600082601f83011261040557600080fd5b813567ffffffffffffffff81111561041f5761041f61032a565b61045060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116016103a5565b81815284602083860101111561046557600080fd5b816020850160208301376000918101602001919091529392505050565b600082601f83011261049357600080fd5b8135602067ffffffffffffffff808311156104b0576104b061032a565b8260051b6104bf8382016103a5565b93845285810183019383810190888611156104d957600080fd5b84880192505b858310156105c4578235848111156104f75760008081fd5b88016080818b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00181131561052d5760008081fd5b610535610359565b87830135878111156105475760008081fd5b6105558d8a838701016103f4565b8252506040808401358881111561056c5760008081fd5b61057a8e8b838801016103f4565b8a84015250606080850135898111156105935760008081fd5b6105a18f8c838901016103f4565b9284019290925293909201359281019290925250825291840191908401906104df565b98975050505050505050565b6000602082840312156105e257600080fd5b813567ffffffffffffffff8111156105f957600080fd5b61060584828501610482565b949350505050565b6000815180845260005b8181101561063357602081850181015186830182015201610617565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b60208152600061015c602083018461060d565b803567ffffffffffffffff8116811461069c57600080fd5b919050565b600060a082840312156106b357600080fd5b60405160a0810181811067ffffffffffffffff821117156106d6576106d661032a565b604052823581529050806106ec60208401610684565b60208201526106fd60408401610684565b604082015261070e60608401610684565b606082015261071f60808401610684565b60808201525092915050565b803573ffffffffffffffffffffffffffffffffffffffff8116811461069c57600080fd5b6000806040838503121561076257600080fd5b823567ffffffffffffffff8082111561077a57600080fd5b90840190610140828703121561078f57600080fd5b610797610382565b6107a187846106a1565b815260a0830135828111156107b557600080fd5b6107c1888286016103f4565b60208301525060c0830135828111156107d957600080fd5b6107e5888286016103f4565b6040830152506107f760e0840161072b565b606082015261010083013560808201526101208301358281111561081a57600080fd5b61082688828601610482565b60a0830152509350602085013591508082111561084257600080fd5b5061084f858286016103f4565b9150509250929050565b600080600080600060a0868803121561087157600080fd5b505083359560208501359550604085013594606081013594506080013592509050565b600080600080608085870312156108aa57600080fd5b843593506108ba60208601610684565b92506108c860408601610684565b9150606085013567ffffffffffffffff8111156108e457600080fd5b6108f0878288016103f4565b91505092959194509250565b60008060008060008060c0878903121561091557600080fd5b86359550602087013567ffffffffffffffff81111561093357600080fd5b61093f89828a016103f4565b95505061094e6040880161072b565b935061095c60608801610684565b92506080870135915061097160a08801610684565b90509295509295509295565b600060208083018184528085518083526040925060408601915060408160051b87010184880160005b83811015610a3b577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc08984030185528151608081518186526109ea8287018261060d565b915050888201518582038a870152610a02828261060d565b9150508782015185820389870152610a1a828261060d565b606093840151969093019590955250948701949250908601906001016109a6565b509098975050505050505050565b848152600067ffffffffffffffff808616602084015280851660408401525060806060830152610a7c608083018461060d565b9695505050505050565b86815260c060208201526000610a9f60c083018861060d565b73ffffffffffffffffffffffffffffffffffffffff9690961660408301525067ffffffffffffffff9384166060820152608081019290925290911660a0909101529291505056fea164736f6c6343000818000a", + ABI: "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"}],\"name\":\"decodeEVMExtraArgsV1\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"}],\"internalType\":\"structClient.EVMExtraArgsV1\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"allowOutOfOrderExecution\",\"type\":\"bool\"}],\"name\":\"decodeEVMExtraArgsV2\",\"outputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"allowOutOfOrderExecution\",\"type\":\"bool\"}],\"internalType\":\"structClient.EVMExtraArgsV2\",\"name\":\"\",\"type\":\"tuple\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"}],\"internalType\":\"structClient.EVMExtraArgsV1\",\"name\":\"extraArgs\",\"type\":\"tuple\"}],\"name\":\"encodeEVMExtraArgsV1\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"allowOutOfOrderExecution\",\"type\":\"bool\"}],\"internalType\":\"structClient.EVMExtraArgsV2\",\"name\":\"extraArgs\",\"type\":\"tuple\"}],\"name\":\"encodeEVMExtraArgsV2\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"leafDomainSeparator\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"implicitMetadataHash\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"fixedSizeFieldsHash\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"dataHash\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"tokenAmountsHash\",\"type\":\"bytes32\"}],\"name\":\"encodeFinalHashPreimage\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"messageId\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"sender\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"uint64\",\"name\":\"sequenceNumber\",\"type\":\"uint64\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"internalType\":\"uint64\",\"name\":\"nonce\",\"type\":\"uint64\"}],\"name\":\"encodeFixedSizeFieldsHashPreimage\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"any2EVMMessageHash\",\"type\":\"bytes32\"},{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"bytes\",\"name\":\"onRamp\",\"type\":\"bytes\"}],\"name\":\"encodeMetadataHashPreimage\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"bytes\",\"name\":\"sourcePoolAddress\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"destTokenAddress\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structInternal.RampTokenAmount[]\",\"name\":\"rampTokenAmounts\",\"type\":\"tuple[]\"}],\"name\":\"encodeTokenAmountsHashPreimage\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"messageId\",\"type\":\"bytes32\"},{\"internalType\":\"uint64\",\"name\":\"sourceChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"destChainSelector\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"sequenceNumber\",\"type\":\"uint64\"},{\"internalType\":\"uint64\",\"name\":\"nonce\",\"type\":\"uint64\"}],\"internalType\":\"structInternal.RampMessageHeader\",\"name\":\"header\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"sender\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"address\",\"name\":\"receiver\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"gasLimit\",\"type\":\"uint256\"},{\"components\":[{\"internalType\":\"bytes\",\"name\":\"sourcePoolAddress\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"destTokenAddress\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"extraData\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"internalType\":\"structInternal.RampTokenAmount[]\",\"name\":\"tokenAmounts\",\"type\":\"tuple[]\"}],\"internalType\":\"structInternal.Any2EVMRampMessage\",\"name\":\"message\",\"type\":\"tuple\"},{\"internalType\":\"bytes\",\"name\":\"onRamp\",\"type\":\"bytes\"}],\"name\":\"hash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"}]", + Bin: "0x608060405234801561001057600080fd5b50610de7806100206000396000f3fe608060405234801561001057600080fd5b50600436106100a35760003560e01c8063a91d3aeb11610076578063c63641bd1161005b578063c63641bd1461019e578063c7ca9a18146101f5578063e733d2091461020857600080fd5b8063a91d3aeb14610150578063b17df7141461016357600080fd5b8063902e94a0146100a85780639511afaa146100d157806399df8d05146100f2578063a1e747df1461013d575b600080fd5b6100bb6100b63660046107d9565b61021b565b6040516100c8919061087a565b60405180910390f35b6100e46100df366004610958565b610244565b6040519081526020016100c8565b6100bb610100366004610a62565b604080516020810196909652858101949094526060850192909252608084015260a0808401919091528151808403909101815260c0909201905290565b6100bb61014b366004610a9d565b610257565b6100bb61015e366004610b05565b610289565b61018f610171366004610b86565b60408051602080820183526000909152815190810190915290815290565b604051905181526020016100c8565b6101d86101ac366004610baf565b604080518082019091526000808252602082015250604080518082019091529182521515602082015290565b6040805182518152602092830151151592810192909252016100c8565b6100bb610203366004610bdb565b6102c1565b6100bb610216366004610c2f565b6102d2565b60608160405160200161022e9190610c71565b6040516020818303038152906040529050919050565b600061025083836102dd565b9392505050565b6060848484846040516020016102709493929190610d3d565b6040516020818303038152906040529050949350505050565b60608686868686866040516020016102a696959493929190610d7a565b60405160208183030381529060405290509695505050505050565b60606102cc8261043a565b92915050565b60606102cc826104fc565b815160208082015160409283015192516000938493610323937f2425b0b9f9054c76ff151b0a175b18f37a4a4e82013a72e9f15c9caa095ed21f93909291889101610d3d565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe081840301815290829052805160209182012086518051888401516060808b0151908401516080808d0151950151959761038a9794969395929491939101610d7a565b604051602081830303815290604052805190602001208560400151805190602001208660a001516040516020016103c19190610c71565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181528282528051602091820120908301969096528101939093526060830191909152608082015260a081019190915260c00160405160208183030381529060405280519060200120905092915050565b604051815160248201526020820151151560448201526060907f181dcf1000000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff000000000000000000000000000000000000000000000000000000009093169290921790915292915050565b604051815160248201526060907f97a657c90000000000000000000000000000000000000000000000000000000090604401610479565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040516080810167ffffffffffffffff8111828210171561058557610585610533565b60405290565b60405160c0810167ffffffffffffffff8111828210171561058557610585610533565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156105f5576105f5610533565b604052919050565b600082601f83011261060e57600080fd5b813567ffffffffffffffff81111561062857610628610533565b61065960207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116016105ae565b81815284602083860101111561066e57600080fd5b816020850160208301376000918101602001919091529392505050565b600082601f83011261069c57600080fd5b8135602067ffffffffffffffff808311156106b9576106b9610533565b8260051b6106c88382016105ae565b93845285810183019383810190888611156106e257600080fd5b84880192505b858310156107cd578235848111156107005760008081fd5b88016080818b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0018113156107365760008081fd5b61073e610562565b87830135878111156107505760008081fd5b61075e8d8a838701016105fd565b825250604080840135888111156107755760008081fd5b6107838e8b838801016105fd565b8a840152506060808501358981111561079c5760008081fd5b6107aa8f8c838901016105fd565b9284019290925293909201359281019290925250825291840191908401906106e8565b98975050505050505050565b6000602082840312156107eb57600080fd5b813567ffffffffffffffff81111561080257600080fd5b61080e8482850161068b565b949350505050565b6000815180845260005b8181101561083c57602081850181015186830182015201610820565b5060006020828601015260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011685010191505092915050565b6020815260006102506020830184610816565b803567ffffffffffffffff811681146108a557600080fd5b919050565b600060a082840312156108bc57600080fd5b60405160a0810181811067ffffffffffffffff821117156108df576108df610533565b604052823581529050806108f56020840161088d565b60208201526109066040840161088d565b60408201526109176060840161088d565b60608201526109286080840161088d565b60808201525092915050565b803573ffffffffffffffffffffffffffffffffffffffff811681146108a557600080fd5b6000806040838503121561096b57600080fd5b823567ffffffffffffffff8082111561098357600080fd5b90840190610140828703121561099857600080fd5b6109a061058b565b6109aa87846108aa565b815260a0830135828111156109be57600080fd5b6109ca888286016105fd565b60208301525060c0830135828111156109e257600080fd5b6109ee888286016105fd565b604083015250610a0060e08401610934565b6060820152610100830135608082015261012083013582811115610a2357600080fd5b610a2f8882860161068b565b60a08301525093506020850135915080821115610a4b57600080fd5b50610a58858286016105fd565b9150509250929050565b600080600080600060a08688031215610a7a57600080fd5b505083359560208501359550604085013594606081013594506080013592509050565b60008060008060808587031215610ab357600080fd5b84359350610ac36020860161088d565b9250610ad16040860161088d565b9150606085013567ffffffffffffffff811115610aed57600080fd5b610af9878288016105fd565b91505092959194509250565b60008060008060008060c08789031215610b1e57600080fd5b86359550602087013567ffffffffffffffff811115610b3c57600080fd5b610b4889828a016105fd565b955050610b5760408801610934565b9350610b656060880161088d565b925060808701359150610b7a60a0880161088d565b90509295509295509295565b600060208284031215610b9857600080fd5b5035919050565b803580151581146108a557600080fd5b60008060408385031215610bc257600080fd5b82359150610bd260208401610b9f565b90509250929050565b600060408284031215610bed57600080fd5b6040516040810181811067ffffffffffffffff82111715610c1057610c10610533565b60405282358152610c2360208401610b9f565b60208201529392505050565b600060208284031215610c4157600080fd5b6040516020810181811067ffffffffffffffff82111715610c6457610c64610533565b6040529135825250919050565b600060208083018184528085518083526040925060408601915060408160051b87010184880160005b83811015610d2f577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc0898403018552815160808151818652610cde82870182610816565b915050888201518582038a870152610cf68282610816565b9150508782015185820389870152610d0e8282610816565b60609384015196909301959095525094870194925090860190600101610c9a565b509098975050505050505050565b848152600067ffffffffffffffff808616602084015280851660408401525060806060830152610d706080830184610816565b9695505050505050565b86815260c060208201526000610d9360c0830188610816565b73ffffffffffffffffffffffffffffffffffffffff9690961660408301525067ffffffffffffffff9384166060820152608081019290925290911660a0909101529291505056fea164736f6c6343000818000a", } var MessageHasherABI = MessageHasherMetaData.ABI @@ -193,6 +202,94 @@ func (_MessageHasher *MessageHasherTransactorRaw) Transact(opts *bind.TransactOp return _MessageHasher.Contract.contract.Transact(opts, method, params...) } +func (_MessageHasher *MessageHasherCaller) DecodeEVMExtraArgsV1(opts *bind.CallOpts, gasLimit *big.Int) (ClientEVMExtraArgsV1, error) { + var out []interface{} + err := _MessageHasher.contract.Call(opts, &out, "decodeEVMExtraArgsV1", gasLimit) + + if err != nil { + return *new(ClientEVMExtraArgsV1), err + } + + out0 := *abi.ConvertType(out[0], new(ClientEVMExtraArgsV1)).(*ClientEVMExtraArgsV1) + + return out0, err + +} + +func (_MessageHasher *MessageHasherSession) DecodeEVMExtraArgsV1(gasLimit *big.Int) (ClientEVMExtraArgsV1, error) { + return _MessageHasher.Contract.DecodeEVMExtraArgsV1(&_MessageHasher.CallOpts, gasLimit) +} + +func (_MessageHasher *MessageHasherCallerSession) DecodeEVMExtraArgsV1(gasLimit *big.Int) (ClientEVMExtraArgsV1, error) { + return _MessageHasher.Contract.DecodeEVMExtraArgsV1(&_MessageHasher.CallOpts, gasLimit) +} + +func (_MessageHasher *MessageHasherCaller) DecodeEVMExtraArgsV2(opts *bind.CallOpts, gasLimit *big.Int, allowOutOfOrderExecution bool) (ClientEVMExtraArgsV2, error) { + var out []interface{} + err := _MessageHasher.contract.Call(opts, &out, "decodeEVMExtraArgsV2", gasLimit, allowOutOfOrderExecution) + + if err != nil { + return *new(ClientEVMExtraArgsV2), err + } + + out0 := *abi.ConvertType(out[0], new(ClientEVMExtraArgsV2)).(*ClientEVMExtraArgsV2) + + return out0, err + +} + +func (_MessageHasher *MessageHasherSession) DecodeEVMExtraArgsV2(gasLimit *big.Int, allowOutOfOrderExecution bool) (ClientEVMExtraArgsV2, error) { + return _MessageHasher.Contract.DecodeEVMExtraArgsV2(&_MessageHasher.CallOpts, gasLimit, allowOutOfOrderExecution) +} + +func (_MessageHasher *MessageHasherCallerSession) DecodeEVMExtraArgsV2(gasLimit *big.Int, allowOutOfOrderExecution bool) (ClientEVMExtraArgsV2, error) { + return _MessageHasher.Contract.DecodeEVMExtraArgsV2(&_MessageHasher.CallOpts, gasLimit, allowOutOfOrderExecution) +} + +func (_MessageHasher *MessageHasherCaller) EncodeEVMExtraArgsV1(opts *bind.CallOpts, extraArgs ClientEVMExtraArgsV1) ([]byte, error) { + var out []interface{} + err := _MessageHasher.contract.Call(opts, &out, "encodeEVMExtraArgsV1", extraArgs) + + if err != nil { + return *new([]byte), err + } + + out0 := *abi.ConvertType(out[0], new([]byte)).(*[]byte) + + return out0, err + +} + +func (_MessageHasher *MessageHasherSession) EncodeEVMExtraArgsV1(extraArgs ClientEVMExtraArgsV1) ([]byte, error) { + return _MessageHasher.Contract.EncodeEVMExtraArgsV1(&_MessageHasher.CallOpts, extraArgs) +} + +func (_MessageHasher *MessageHasherCallerSession) EncodeEVMExtraArgsV1(extraArgs ClientEVMExtraArgsV1) ([]byte, error) { + return _MessageHasher.Contract.EncodeEVMExtraArgsV1(&_MessageHasher.CallOpts, extraArgs) +} + +func (_MessageHasher *MessageHasherCaller) EncodeEVMExtraArgsV2(opts *bind.CallOpts, extraArgs ClientEVMExtraArgsV2) ([]byte, error) { + var out []interface{} + err := _MessageHasher.contract.Call(opts, &out, "encodeEVMExtraArgsV2", extraArgs) + + if err != nil { + return *new([]byte), err + } + + out0 := *abi.ConvertType(out[0], new([]byte)).(*[]byte) + + return out0, err + +} + +func (_MessageHasher *MessageHasherSession) EncodeEVMExtraArgsV2(extraArgs ClientEVMExtraArgsV2) ([]byte, error) { + return _MessageHasher.Contract.EncodeEVMExtraArgsV2(&_MessageHasher.CallOpts, extraArgs) +} + +func (_MessageHasher *MessageHasherCallerSession) EncodeEVMExtraArgsV2(extraArgs ClientEVMExtraArgsV2) ([]byte, error) { + return _MessageHasher.Contract.EncodeEVMExtraArgsV2(&_MessageHasher.CallOpts, extraArgs) +} + func (_MessageHasher *MessageHasherCaller) EncodeFinalHashPreimage(opts *bind.CallOpts, leafDomainSeparator [32]byte, implicitMetadataHash [32]byte, fixedSizeFieldsHash [32]byte, dataHash [32]byte, tokenAmountsHash [32]byte) ([]byte, error) { var out []interface{} err := _MessageHasher.contract.Call(opts, &out, "encodeFinalHashPreimage", leafDomainSeparator, implicitMetadataHash, fixedSizeFieldsHash, dataHash, tokenAmountsHash) @@ -308,6 +405,14 @@ func (_MessageHasher *MessageHasher) Address() common.Address { } type MessageHasherInterface interface { + DecodeEVMExtraArgsV1(opts *bind.CallOpts, gasLimit *big.Int) (ClientEVMExtraArgsV1, error) + + DecodeEVMExtraArgsV2(opts *bind.CallOpts, gasLimit *big.Int, allowOutOfOrderExecution bool) (ClientEVMExtraArgsV2, error) + + EncodeEVMExtraArgsV1(opts *bind.CallOpts, extraArgs ClientEVMExtraArgsV1) ([]byte, error) + + EncodeEVMExtraArgsV2(opts *bind.CallOpts, extraArgs ClientEVMExtraArgsV2) ([]byte, error) + EncodeFinalHashPreimage(opts *bind.CallOpts, leafDomainSeparator [32]byte, implicitMetadataHash [32]byte, fixedSizeFieldsHash [32]byte, dataHash [32]byte, tokenAmountsHash [32]byte) ([]byte, error) EncodeFixedSizeFieldsHashPreimage(opts *bind.CallOpts, messageId [32]byte, sender []byte, receiver common.Address, sequenceNumber uint64, gasLimit *big.Int, nonce uint64) ([]byte, error) diff --git a/core/gethwrappers/ccip/generation/generated-wrapper-dependency-versions-do-not-edit.txt b/core/gethwrappers/ccip/generation/generated-wrapper-dependency-versions-do-not-edit.txt index c4432d6860..a8a838e6fd 100644 --- a/core/gethwrappers/ccip/generation/generated-wrapper-dependency-versions-do-not-edit.txt +++ b/core/gethwrappers/ccip/generation/generated-wrapper-dependency-versions-do-not-edit.txt @@ -16,7 +16,7 @@ evm_2_evm_onramp: ../../../contracts/solc/v0.8.24/EVM2EVMOnRamp/EVM2EVMOnRamp.ab lock_release_token_pool: ../../../contracts/solc/v0.8.24/LockReleaseTokenPool/LockReleaseTokenPool.abi ../../../contracts/solc/v0.8.24/LockReleaseTokenPool/LockReleaseTokenPool.bin c65c226e1e4d38414bd4a1b76fc8aca3cb3dd98df61268424c44564f455d3752 lock_release_token_pool_and_proxy: ../../../contracts/solc/v0.8.24/LockReleaseTokenPoolAndProxy/LockReleaseTokenPoolAndProxy.abi ../../../contracts/solc/v0.8.24/LockReleaseTokenPoolAndProxy/LockReleaseTokenPoolAndProxy.bin 8b929fab79d1caeea4c57e08cc523eb8ab45ec5c08f46da866b82c15ba94d9ad maybe_revert_message_receiver: ../../../contracts/solc/v0.8.24/MaybeRevertMessageReceiver/MaybeRevertMessageReceiver.abi ../../../contracts/solc/v0.8.24/MaybeRevertMessageReceiver/MaybeRevertMessageReceiver.bin d73956c26232ebcc4a5444429fa99cbefed960e323be9b5a24925885c2e477d5 -message_hasher: ../../../contracts/solc/v0.8.24/MessageHasher/MessageHasher.abi ../../../contracts/solc/v0.8.24/MessageHasher/MessageHasher.bin 9195ef458fee819595502b5b33263e4646f9526cbac0bd89cc322afe5a77ae19 +message_hasher: ../../../contracts/solc/v0.8.24/MessageHasher/MessageHasher.abi ../../../contracts/solc/v0.8.24/MessageHasher/MessageHasher.bin 1d5146d43e1b99cd2d6f9f06475be19087e4349f7cee0fdbbf134ba65e967c93 mock_arm_contract: ../../../contracts/solc/v0.8.24/MockRMN1_0/MockRMN.abi ../../../contracts/solc/v0.8.24/MockRMN1_0/MockRMN.bin e7a3a6c3eda5fb882e16bcc2b4340f78523acb67907bcdcaf3c8ffc51488688e mock_usdc_token_messenger: ../../../contracts/solc/v0.8.24/MockE2EUSDCTokenMessenger/MockE2EUSDCTokenMessenger.abi ../../../contracts/solc/v0.8.24/MockE2EUSDCTokenMessenger/MockE2EUSDCTokenMessenger.bin e0cf17a38b438239fc6294ddca88f86b6c39e4542aefd9815b2d92987191b8bd mock_usdc_token_transmitter: ../../../contracts/solc/v0.8.24/MockE2EUSDCTransmitter/MockE2EUSDCTransmitter.abi ../../../contracts/solc/v0.8.24/MockE2EUSDCTransmitter/MockE2EUSDCTransmitter.bin 33bdad70822e889de7c720ed20085cf9cd3f8eba8b68f26bd6535197749595fe diff --git a/core/services/ocr3/plugins/ccipevm/msghasher.go b/core/services/ocr3/plugins/ccipevm/msghasher.go index 13d0410ea3..7553475f6d 100644 --- a/core/services/ocr3/plugins/ccipevm/msghasher.go +++ b/core/services/ocr3/plugins/ccipevm/msghasher.go @@ -1,14 +1,15 @@ package ccipevm import ( + "bytes" "context" - "encoding/hex" "fmt" - "strings" + "math/big" cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccipocr3" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" @@ -23,25 +24,21 @@ var ( ANY_2_EVM_MESSAGE_HASH = utils.Keccak256Fixed([]byte("Any2EVMMessageHashV1")) messageHasherABI = types.MustGetABI(message_hasher.MessageHasherABI) + + // bytes4 public constant EVM_EXTRA_ARGS_V1_TAG = 0x97a657c9; + evmExtraArgsV1Tag = hexutil.MustDecode("0x97a657c9") + + // bytes4 public constant EVM_EXTRA_ARGS_V2_TAG = 0x181dcf10; + evmExtraArgsV2Tag = hexutil.MustDecode("0x181dcf10") ) // MessageHasherV1 implements the MessageHasher interface. // Compatible with: // - "EVM2EVMMultiOnRamp 1.6.0-dev" -type MessageHasherV1 struct { - // TODO: move these to CCIPMsg instead? - destChainSelector cciptypes.ChainSelector - onrampAddress []byte -} +type MessageHasherV1 struct{} -func NewMessageHasherV1( - onrampAddress []byte, - destChainSelector cciptypes.ChainSelector, -) *MessageHasherV1 { - return &MessageHasherV1{ - destChainSelector: destChainSelector, - onrampAddress: onrampAddress, - } +func NewMessageHasherV1() *MessageHasherV1 { + return &MessageHasherV1{} } // Hash implements the MessageHasher interface. @@ -53,79 +50,58 @@ func NewMessageHasherV1( keccak256(any_2_evm_message_hash, header.sourceChainSelector, header.destinationChainSelector, onRamp), keccak256(fixedSizeMessageFields), keccak256(messageData), - keccak256(encodedTokenAmounts), - keccak256(encodedSourceTokenData), + keccak256(encodedRampTokenAmounts), ) */ -func (h *MessageHasherV1) Hash(_ context.Context, msg cciptypes.CCIPMsg) (cciptypes.Bytes32, error) { - if len(msg.TokenAmounts) != len(msg.SourceTokenData) { - return [32]byte{}, fmt.Errorf("token amounts and source token data must have the same length") +func (h *MessageHasherV1) Hash(_ context.Context, msg cciptypes.Message) (cciptypes.Bytes32, error) { + var rampTokenAmounts []message_hasher.InternalRampTokenAmount + for _, rta := range msg.TokenAmounts { + rampTokenAmounts = append(rampTokenAmounts, message_hasher.InternalRampTokenAmount{ + SourcePoolAddress: rta.SourcePoolAddress, + DestTokenAddress: rta.DestTokenAddress, + ExtraData: rta.ExtraData, + Amount: rta.Amount.Int, + }) } - - // TODO: this is not fully correct, but will be fixed in future PRs. - // CCIPMsg is missing the source pool address and the dest token address. - rampTokenAmounts := make([]message_hasher.InternalRampTokenAmount, len(msg.TokenAmounts)) - for i, ta := range msg.TokenAmounts { - rampTokenAmounts[i] = message_hasher.InternalRampTokenAmount{ - // SourcePoolAddress: , // TODO: fill this in future PRs. - // DestTokenAddress: , // TODO: fill this in future PRs. - ExtraData: msg.SourceTokenData[i], - Amount: ta.Amount, - } - } - encodedRampTokenAmounts, err := h.abiEncode("encodeTokenAmountsHashPreimage", rampTokenAmounts) + encodedRampTokenAmounts, err := abiEncode("encodeTokenAmountsHashPreimage", rampTokenAmounts) if err != nil { return [32]byte{}, fmt.Errorf("abi encode token amounts: %w", err) } - metaDataHashInput, err := h.abiEncode( + metaDataHashInput, err := abiEncode( "encodeMetadataHashPreimage", ANY_2_EVM_MESSAGE_HASH, - uint64(msg.SourceChain), - uint64(h.destChainSelector), - h.onrampAddress, + uint64(msg.Header.SourceChainSelector), + uint64(msg.Header.DestChainSelector), + []byte(msg.Header.OnRamp), ) if err != nil { return [32]byte{}, fmt.Errorf("abi encode metadata hash input: %w", err) } - var msgID [32]byte - decoded, err := hex.DecodeString(msg.ID) + // Need to decode the extra args to get the gas limit. + // TODO: we assume that extra args is always abi-encoded for now, but we need + // to decode according to source chain selector family. We should add a family + // lookup API to the chain-selectors library. + gasLimit, err := decodeExtraArgs(msg.ExtraArgs) if err != nil { - return [32]byte{}, fmt.Errorf("decode message ID: %w", err) - } - if len(decoded) != 32 { - return [32]byte{}, fmt.Errorf("message ID must be 32 bytes") + return [32]byte{}, fmt.Errorf("decode extra args: %w", err) } - copy(msgID[:], decoded) - - // NOTE: msg.Sender is not necessarily an EVM address since this is Any2EVM. - // Accordingly, sender is defined as "bytes" in the onchain message definition - // rather than "address". - // However, its not clear how best to translate from Sender being a string representation - // to bytes. For now, we assume that the string is hex encoded, but ideally Sender would - // just be a byte array in the CCIPMsg struct that represents a sender encoded in the - // source chain family encoding scheme. - decodedSender, err := hex.DecodeString( - strings.TrimPrefix(string(msg.Sender), "0x"), - ) - if err != nil { - return [32]byte{}, fmt.Errorf("decode sender '%s': %w", msg.Sender, err) - } - fixedSizeFieldsEncoded, err := h.abiEncode( + + fixedSizeFieldsEncoded, err := abiEncode( "encodeFixedSizeFieldsHashPreimage", - msgID, - decodedSender, - common.HexToAddress(string(msg.Receiver)), - uint64(msg.SeqNum), - msg.ChainFeeLimit.Int, - msg.Nonce, + msg.Header.MessageID, + []byte(msg.Sender), + common.BytesToAddress(msg.Receiver), + uint64(msg.Header.SequenceNumber), + gasLimit, + uint64(msg.Header.Nonce), ) if err != nil { return [32]byte{}, fmt.Errorf("abi encode fixed size values: %w", err) } - packedValues, err := h.abiEncode( + packedValues, err := abiEncode( "encodeFinalHashPreimage", leafDomainSeparator, utils.Keccak256Fixed(metaDataHashInput), @@ -140,7 +116,7 @@ func (h *MessageHasherV1) Hash(_ context.Context, msg cciptypes.CCIPMsg) (ccipty return utils.Keccak256Fixed(packedValues), nil } -func (h *MessageHasherV1) abiEncode(method string, values ...interface{}) ([]byte, error) { +func abiEncode(method string, values ...interface{}) ([]byte, error) { res, err := messageHasherABI.Pack(method, values...) if err != nil { return nil, err @@ -149,5 +125,27 @@ func (h *MessageHasherV1) abiEncode(method string, values ...interface{}) ([]byt return res[4:], nil } +func decodeExtraArgs(extraArgs []byte) (gasLimit *big.Int, err error) { + var method string + if bytes.Equal(extraArgs[:4], evmExtraArgsV1Tag) { + method = "decodeEVMExtraArgsV1" + } else if bytes.Equal(extraArgs[:4], evmExtraArgsV2Tag) { + method = "decodeEVMExtraArgsV2" + } else { + return nil, fmt.Errorf("unknown extra args tag: %x", extraArgs) + } + ifaces, err := messageHasherABI.Methods[method].Inputs.UnpackValues(extraArgs[4:]) + if err != nil { + return nil, fmt.Errorf("abi decode extra args v1: %w", err) + } + // gas limit is always the first argument, and allow OOO isn't set explicitly + // on the message. + _, ok := ifaces[0].(*big.Int) + if !ok { + return nil, fmt.Errorf("expected *big.Int, got %T", ifaces[0]) + } + return ifaces[0].(*big.Int), nil +} + // Interface compliance check var _ cciptypes.MessageHasher = (*MessageHasherV1)(nil) diff --git a/core/services/ocr3/plugins/ccipevm/msghasher_test.go b/core/services/ocr3/plugins/ccipevm/msghasher_test.go index a16815a0d7..286494ba69 100644 --- a/core/services/ocr3/plugins/ccipevm/msghasher_test.go +++ b/core/services/ocr3/plugins/ccipevm/msghasher_test.go @@ -3,7 +3,6 @@ package ccipevm import ( "context" cryptorand "crypto/rand" - "encoding/hex" "fmt" "math/big" "math/rand" @@ -14,72 +13,76 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind/backends" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" - cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccipocr3" - - "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/message_hasher" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/stretchr/testify/require" ) -func TestMessageHasher_e2e(t *testing.T) { +// NOTE: these test cases are only EVM <-> EVM. +// Update these cases once we have non-EVM examples. +func TestMessageHasher_EVM2EVM(t *testing.T) { ctx := testutils.Context(t) d := testSetup(t) - // low budget "fuzz" test. - // TODO: should actually write a real fuzz test. - for i := 0; i < 5; i++ { - testHasher(ctx, t, d) + testCases := []evmExtraArgs{ + {version: "v1", gasLimit: big.NewInt(rand.Int63())}, + {version: "v2", gasLimit: big.NewInt(rand.Int63()), allowOOO: false}, + {version: "v2", gasLimit: big.NewInt(rand.Int63()), allowOOO: true}, + } + for i, tc := range testCases { + t.Run(fmt.Sprintf("tc_%d", i), func(tt *testing.T) { + testHasherEVM2EVM(ctx, tt, d, tc) + }) } } -func testHasher(ctx context.Context, t *testing.T, d *testSetupData) { - destChainSelector := rand.Uint64() - onRampAddress := testutils.NewAddress().Bytes() - ccipMsg := createCCIPMsg(t) +func testHasherEVM2EVM(ctx context.Context, t *testing.T, d *testSetupData, evmExtraArgs evmExtraArgs) { + ccipMsg := createEVM2EVMMessage(t, d.contract, evmExtraArgs) - tokenAmounts := make([]message_hasher.InternalRampTokenAmount, 0, len(ccipMsg.TokenAmounts)) - for i := range ccipMsg.TokenAmounts { + var tokenAmounts []message_hasher.InternalRampTokenAmount + for _, rta := range ccipMsg.TokenAmounts { tokenAmounts = append(tokenAmounts, message_hasher.InternalRampTokenAmount{ - // SourcePoolAddress: , // TODO: fill this in future PRs. - // DestTokenAddress: , // TODO: fill this in future PRs. - ExtraData: ccipMsg.SourceTokenData[i], - Amount: ccipMsg.TokenAmounts[i].Amount, + SourcePoolAddress: rta.SourcePoolAddress, + DestTokenAddress: rta.DestTokenAddress, + ExtraData: rta.ExtraData[:], + Amount: rta.Amount.Int, }) } evmMsg := message_hasher.InternalAny2EVMRampMessage{ Header: message_hasher.InternalRampMessageHeader{ - MessageId: mustMessageID(t, ccipMsg.ID), - SourceChainSelector: uint64(ccipMsg.SourceChain), - DestChainSelector: destChainSelector, - SequenceNumber: uint64(ccipMsg.SeqNum), - Nonce: ccipMsg.Nonce, + MessageId: ccipMsg.Header.MessageID, + SourceChainSelector: uint64(ccipMsg.Header.SourceChainSelector), + DestChainSelector: uint64(ccipMsg.Header.DestChainSelector), + SequenceNumber: uint64(ccipMsg.Header.SequenceNumber), + Nonce: ccipMsg.Header.Nonce, }, - Sender: common.HexToAddress(string(ccipMsg.Sender)).Bytes(), - Receiver: common.HexToAddress(string(ccipMsg.Receiver)), - GasLimit: ccipMsg.ChainFeeLimit.Int, + Sender: ccipMsg.Sender, + Receiver: common.BytesToAddress(ccipMsg.Receiver), + GasLimit: evmExtraArgs.gasLimit, Data: ccipMsg.Data, TokenAmounts: tokenAmounts, } - expectedHash, err := d.contract.Hash(&bind.CallOpts{Context: ctx}, evmMsg, onRampAddress) + expectedHash, err := d.contract.Hash(&bind.CallOpts{Context: ctx}, evmMsg, ccipMsg.Header.OnRamp) require.NoError(t, err) - evmMsgHasher := NewMessageHasherV1(onRampAddress, cciptypes.ChainSelector(destChainSelector)) + evmMsgHasher := NewMessageHasherV1() actualHash, err := evmMsgHasher.Hash(ctx, ccipMsg) require.NoError(t, err) require.Equal(t, fmt.Sprintf("%x", expectedHash), strings.TrimPrefix(actualHash.String(), "0x")) } -// TODO: fix this once messageID is part of CCIPMsg -func createCCIPMsg(t *testing.T) cciptypes.CCIPMsg { - // Setup random msg data +type evmExtraArgs struct { + version string + gasLimit *big.Int + allowOOO bool +} + +func createEVM2EVMMessage(t *testing.T, messageHasher *message_hasher.MessageHasher, evmExtraArgs evmExtraArgs) cciptypes.Message { messageID := utils.RandomBytes32() sourceTokenData := make([]byte, rand.Intn(2048)) @@ -88,8 +91,24 @@ func createCCIPMsg(t *testing.T) cciptypes.CCIPMsg { sourceChain := rand.Uint64() seqNum := rand.Uint64() - chainFeeLimit := rand.Uint64() nonce := rand.Uint64() + destChain := rand.Uint64() + + var extraArgsBytes []byte + if evmExtraArgs.version == "v1" { + extraArgsBytes, err = messageHasher.EncodeEVMExtraArgsV1(nil, message_hasher.ClientEVMExtraArgsV1{ + GasLimit: evmExtraArgs.gasLimit, + }) + require.NoError(t, err) + } else if evmExtraArgs.version == "v2" { + extraArgsBytes, err = messageHasher.EncodeEVMExtraArgsV2(nil, message_hasher.ClientEVMExtraArgsV2{ + GasLimit: evmExtraArgs.gasLimit, + AllowOutOfOrderExecution: evmExtraArgs.allowOOO, + }) + require.NoError(t, err) + } else { + require.FailNowf(t, "unknown extra args version", "version: %s", evmExtraArgs.version) + } messageData := make([]byte, rand.Intn(2048)) _, err = cryptorand.Read(messageData) @@ -101,43 +120,41 @@ func createCCIPMsg(t *testing.T) cciptypes.CCIPMsg { sourceTokenDatas = append(sourceTokenDatas, sourceTokenData) } - var tokenAmounts []cciptypes.TokenAmount + var tokenAmounts []cciptypes.RampTokenAmount for i := 0; i < len(sourceTokenDatas); i++ { - tokenAmounts = append(tokenAmounts, cciptypes.TokenAmount{ - // Ignored by the hasher, will be removed in future PR. - // Token: types.Account(utils.RandomAddress().String()), - Amount: big.NewInt(0).SetUint64(rand.Uint64()), + extraData := utils.RandomBytes32() + tokenAmounts = append(tokenAmounts, cciptypes.RampTokenAmount{ + SourcePoolAddress: abiEncodedAddress(t), + DestTokenAddress: abiEncodedAddress(t), + ExtraData: extraData[:], + Amount: cciptypes.NewBigInt(big.NewInt(0).SetUint64(rand.Uint64())), }) } - return cciptypes.CCIPMsg{ - CCIPMsgBaseDetails: cciptypes.CCIPMsgBaseDetails{ - ID: hex.EncodeToString(messageID[:]), - SourceChain: cciptypes.ChainSelector(sourceChain), - SeqNum: cciptypes.SeqNum(seqNum), + return cciptypes.Message{ + Header: cciptypes.RampMessageHeader{ + MessageID: messageID, + SourceChainSelector: cciptypes.ChainSelector(sourceChain), + DestChainSelector: cciptypes.ChainSelector(destChain), + SequenceNumber: cciptypes.SeqNum(seqNum), + Nonce: nonce, + OnRamp: abiEncodedAddress(t), }, - ChainFeeLimit: cciptypes.NewBigInt(big.NewInt(0).SetUint64(chainFeeLimit)), - Nonce: nonce, - Sender: types.Account(utils.RandomAddress().String()), - Receiver: types.Account(utils.RandomAddress().String()), - // TODO: remove this field if not needed, not used by the hasher - // Strict: strict, - // NOTE: not used by the hasher - // FeeToken: types.Account(utils.RandomAddress().String()), - // FeeTokenAmount: cciptypes.NewBigInt(big.NewInt(0).SetUint64(feeTokenAmount)), - Data: messageData, - TokenAmounts: tokenAmounts, - SourceTokenData: sourceTokenDatas, + Sender: abiEncodedAddress(t), + Receiver: abiEncodedAddress(t), + Data: messageData, + TokenAmounts: tokenAmounts, + FeeToken: abiEncodedAddress(t), + FeeTokenAmount: cciptypes.NewBigInt(big.NewInt(0).SetUint64(rand.Uint64())), + ExtraArgs: extraArgsBytes, } } -func mustMessageID(t *testing.T, msgIDHex string) [32]byte { - msgID, err := hex.DecodeString(msgIDHex) +func abiEncodedAddress(t *testing.T) []byte { + addr := utils.RandomAddress() + encoded, err := utils.ABIEncode(`[{"type": "address"}]`, addr) require.NoError(t, err) - require.Len(t, msgID, 32) - var msgID32 [32]byte - copy(msgID32[:], msgID) - return msgID32 + return encoded } type testSetupData struct { @@ -169,3 +186,33 @@ func testSetup(t *testing.T) *testSetupData { auth: transactor, } } + +func Test_decodeExtraArgs(t *testing.T) { + d := testSetup(t) + gasLimit := big.NewInt(rand.Int63()) + + t.Run("v1", func(t *testing.T) { + encoded, err := d.contract.EncodeEVMExtraArgsV1(nil, message_hasher.ClientEVMExtraArgsV1{ + GasLimit: gasLimit, + }) + require.NoError(t, err) + + decodedGasLimit, err := decodeExtraArgs(encoded) + require.NoError(t, err) + + require.Equal(t, gasLimit, decodedGasLimit) + }) + + t.Run("v2", func(t *testing.T) { + encoded, err := d.contract.EncodeEVMExtraArgsV2(nil, message_hasher.ClientEVMExtraArgsV2{ + GasLimit: gasLimit, + AllowOutOfOrderExecution: true, + }) + require.NoError(t, err) + + decodedGasLimit, err := decodeExtraArgs(encoded) + require.NoError(t, err) + + require.Equal(t, gasLimit, decodedGasLimit) + }) +}