diff --git a/contracts/bindings/gen_examplewarp.go b/contracts/bindings/gen_examplewarp.go deleted file mode 100644 index fa0533458f..0000000000 --- a/contracts/bindings/gen_examplewarp.go +++ /dev/null @@ -1,369 +0,0 @@ -// Code generated - DO NOT EDIT. -// This file is a generated binding and any manual changes will be lost. - -package bindings - -import ( - "errors" - "math/big" - "strings" - - ethereum "github.com/ava-labs/libevm" - "github.com/ava-labs/libevm/accounts/abi" - "github.com/ava-labs/libevm/accounts/abi/bind" - "github.com/ava-labs/libevm/common" - "github.com/ava-labs/libevm/core/types" - "github.com/ava-labs/libevm/event" -) - -// Reference imports to suppress errors if they are not otherwise used. -var ( - _ = errors.New - _ = big.NewInt - _ = strings.NewReader - _ = ethereum.NotFound - _ = bind.Bind - _ = common.Big1 - _ = types.BloomLookup - _ = event.NewSubscription - _ = abi.ConvertType -) - -// ExampleWarpMetaData contains all meta data concerning the ExampleWarp contract. -var ExampleWarpMetaData = &bind.MetaData{ - ABI: "[{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"payload\",\"type\":\"bytes\"}],\"name\":\"sendWarpMessage\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"blockchainID\",\"type\":\"bytes32\"}],\"name\":\"validateGetBlockchainID\",\"outputs\":[],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"index\",\"type\":\"uint32\"}],\"name\":\"validateInvalidWarpBlockHash\",\"outputs\":[],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"index\",\"type\":\"uint32\"}],\"name\":\"validateInvalidWarpMessage\",\"outputs\":[],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"index\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"sourceChainID\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"blockHash\",\"type\":\"bytes32\"}],\"name\":\"validateWarpBlockHash\",\"outputs\":[],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"index\",\"type\":\"uint32\"},{\"internalType\":\"bytes32\",\"name\":\"sourceChainID\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"originSenderAddress\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"payload\",\"type\":\"bytes\"}],\"name\":\"validateWarpMessage\",\"outputs\":[],\"stateMutability\":\"view\",\"type\":\"function\"}]", - Bin: "0x60806040527302000000000000000000000000000000000000055f5f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055503480156061575f5ffd5b50610d158061006f5f395ff3fe608060405234801561000f575f5ffd5b5060043610610060575f3560e01c806315f0c959146100645780635bd05f061461008057806377ca84db1461009c578063e519286f146100b8578063ee5b48eb146100d4578063f25ec06a146100f0575b5f5ffd5b61007e60048036038101906100799190610672565b61010c565b005b61009a60048036038101906100959190610791565b6101a6565b005b6100b660048036038101906100b19190610815565b6102cf565b005b6100d260048036038101906100cd9190610840565b61039d565b005b6100ee60048036038101906100e99190610890565b610468565b005b61010a60048036038101906101059190610815565b610508565b005b5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16634213cf786040518163ffffffff1660e01b8152600401602060405180830381865afa158015610175573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061019991906108ef565b81146101a3575f5ffd5b50565b5f5f5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16636f825350886040518263ffffffff1660e01b81526004016102019190610929565b5f60405180830381865afa15801561021b573d5f5f3e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906102439190610b48565b9150915080610250575f5ffd5b85825f01511461025e575f5ffd5b8473ffffffffffffffffffffffffffffffffffffffff16826020015173ffffffffffffffffffffffffffffffffffffffff1614610299575f5ffd5b83836040516102a9929190610bde565b6040518091039020826040015180519060200120146102c6575f5ffd5b50505050505050565b5f5f5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663ce7f5929846040518263ffffffff1660e01b815260040161032a9190610929565b606060405180830381865afa158015610345573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103699190610c43565b915091508015610377575f5ffd5b5f5f1b825f015114610387575f5ffd5b5f5f1b826020015114610398575f5ffd5b505050565b5f5f5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663ce7f5929866040518263ffffffff1660e01b81526004016103f89190610929565b606060405180830381865afa158015610413573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104379190610c43565b9150915080610444575f5ffd5b83825f015114610452575f5ffd5b82826020015114610461575f5ffd5b5050505050565b5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663ee5b48eb83836040518363ffffffff1660e01b81526004016104c3929190610cbd565b6020604051808303815f875af11580156104df573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061050391906108ef565b505050565b5f5f5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16636f825350846040518263ffffffff1660e01b81526004016105639190610929565b5f60405180830381865afa15801561057d573d5f5f3e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906105a59190610b48565b9150915080156105b3575f5ffd5b5f5f1b825f0151146105c3575f5ffd5b5f73ffffffffffffffffffffffffffffffffffffffff16826020015173ffffffffffffffffffffffffffffffffffffffff16146105fe575f5ffd5b60405180602001604052805f8152508051906020012082604001518051906020012014610629575f5ffd5b505050565b5f604051905090565b5f5ffd5b5f5ffd5b5f819050919050565b6106518161063f565b811461065b575f5ffd5b50565b5f8135905061066c81610648565b92915050565b5f6020828403121561068757610686610637565b5b5f6106948482850161065e565b91505092915050565b5f63ffffffff82169050919050565b6106b58161069d565b81146106bf575f5ffd5b50565b5f813590506106d0816106ac565b92915050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6106ff826106d6565b9050919050565b61070f816106f5565b8114610719575f5ffd5b50565b5f8135905061072a81610706565b92915050565b5f5ffd5b5f5ffd5b5f5ffd5b5f5f83601f84011261075157610750610730565b5b8235905067ffffffffffffffff81111561076e5761076d610734565b5b60208301915083600182028301111561078a57610789610738565b5b9250929050565b5f5f5f5f5f608086880312156107aa576107a9610637565b5b5f6107b7888289016106c2565b95505060206107c88882890161065e565b94505060406107d98882890161071c565b935050606086013567ffffffffffffffff8111156107fa576107f961063b565b5b6108068882890161073c565b92509250509295509295909350565b5f6020828403121561082a57610829610637565b5b5f610837848285016106c2565b91505092915050565b5f5f5f6060848603121561085757610856610637565b5b5f610864868287016106c2565b93505060206108758682870161065e565b92505060406108868682870161065e565b9150509250925092565b5f5f602083850312156108a6576108a5610637565b5b5f83013567ffffffffffffffff8111156108c3576108c261063b565b5b6108cf8582860161073c565b92509250509250929050565b5f815190506108e981610648565b92915050565b5f6020828403121561090457610903610637565b5b5f610911848285016108db565b91505092915050565b6109238161069d565b82525050565b5f60208201905061093c5f83018461091a565b92915050565b5f5ffd5b5f601f19601f8301169050919050565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b61098c82610946565b810181811067ffffffffffffffff821117156109ab576109aa610956565b5b80604052505050565b5f6109bd61062e565b90506109c98282610983565b919050565b5f5ffd5b5f815190506109e081610706565b92915050565b5f5ffd5b5f67ffffffffffffffff821115610a0457610a03610956565b5b610a0d82610946565b9050602081019050919050565b8281835e5f83830152505050565b5f610a3a610a35846109ea565b6109b4565b905082815260208101848484011115610a5657610a556109e6565b5b610a61848285610a1a565b509392505050565b5f82601f830112610a7d57610a7c610730565b5b8151610a8d848260208601610a28565b91505092915050565b5f60608284031215610aab57610aaa610942565b5b610ab560606109b4565b90505f610ac4848285016108db565b5f830152506020610ad7848285016109d2565b602083015250604082015167ffffffffffffffff811115610afb57610afa6109ce565b5b610b0784828501610a69565b60408301525092915050565b5f8115159050919050565b610b2781610b13565b8114610b31575f5ffd5b50565b5f81519050610b4281610b1e565b92915050565b5f5f60408385031215610b5e57610b5d610637565b5b5f83015167ffffffffffffffff811115610b7b57610b7a61063b565b5b610b8785828601610a96565b9250506020610b9885828601610b34565b9150509250929050565b5f81905092915050565b828183375f83830152505050565b5f610bc58385610ba2565b9350610bd2838584610bac565b82840190509392505050565b5f610bea828486610bba565b91508190509392505050565b5f60408284031215610c0b57610c0a610942565b5b610c1560406109b4565b90505f610c24848285016108db565b5f830152506020610c37848285016108db565b60208301525092915050565b5f5f60608385031215610c5957610c58610637565b5b5f610c6685828601610bf6565b9250506040610c7785828601610b34565b9150509250929050565b5f82825260208201905092915050565b5f610c9c8385610c81565b9350610ca9838584610bac565b610cb283610946565b840190509392505050565b5f6020820190508181035f830152610cd6818486610c91565b9050939250505056fea26469706673582212203aa2f3f51e0713d8d1f446f157ef2504c89940d33ec5cba0e160a28e6af1a1b664736f6c634300081e0033", -} - -// ExampleWarpABI is the input ABI used to generate the binding from. -// Deprecated: Use ExampleWarpMetaData.ABI instead. -var ExampleWarpABI = ExampleWarpMetaData.ABI - -// ExampleWarpBin is the compiled bytecode used for deploying new contracts. -// Deprecated: Use ExampleWarpMetaData.Bin instead. -var ExampleWarpBin = ExampleWarpMetaData.Bin - -// DeployExampleWarp deploys a new Ethereum contract, binding an instance of ExampleWarp to it. -func DeployExampleWarp(auth *bind.TransactOpts, backend bind.ContractBackend) (common.Address, *types.Transaction, *ExampleWarp, error) { - parsed, err := ExampleWarpMetaData.GetAbi() - if err != nil { - return common.Address{}, nil, nil, err - } - if parsed == nil { - return common.Address{}, nil, nil, errors.New("GetABI returned nil") - } - - address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(ExampleWarpBin), backend) - if err != nil { - return common.Address{}, nil, nil, err - } - return address, tx, &ExampleWarp{ExampleWarpCaller: ExampleWarpCaller{contract: contract}, ExampleWarpTransactor: ExampleWarpTransactor{contract: contract}, ExampleWarpFilterer: ExampleWarpFilterer{contract: contract}}, nil -} - -// ExampleWarp is an auto generated Go binding around an Ethereum contract. -type ExampleWarp struct { - ExampleWarpCaller // Read-only binding to the contract - ExampleWarpTransactor // Write-only binding to the contract - ExampleWarpFilterer // Log filterer for contract events -} - -// ExampleWarpCaller is an auto generated read-only Go binding around an Ethereum contract. -type ExampleWarpCaller struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// ExampleWarpTransactor is an auto generated write-only Go binding around an Ethereum contract. -type ExampleWarpTransactor struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// ExampleWarpFilterer is an auto generated log filtering Go binding around an Ethereum contract events. -type ExampleWarpFilterer struct { - contract *bind.BoundContract // Generic contract wrapper for the low level calls -} - -// ExampleWarpSession is an auto generated Go binding around an Ethereum contract, -// with pre-set call and transact options. -type ExampleWarpSession struct { - Contract *ExampleWarp // Generic contract binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// ExampleWarpCallerSession is an auto generated read-only Go binding around an Ethereum contract, -// with pre-set call options. -type ExampleWarpCallerSession struct { - Contract *ExampleWarpCaller // Generic contract caller binding to set the session for - CallOpts bind.CallOpts // Call options to use throughout this session -} - -// ExampleWarpTransactorSession is an auto generated write-only Go binding around an Ethereum contract, -// with pre-set transact options. -type ExampleWarpTransactorSession struct { - Contract *ExampleWarpTransactor // Generic contract transactor binding to set the session for - TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session -} - -// ExampleWarpRaw is an auto generated low-level Go binding around an Ethereum contract. -type ExampleWarpRaw struct { - Contract *ExampleWarp // Generic contract binding to access the raw methods on -} - -// ExampleWarpCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. -type ExampleWarpCallerRaw struct { - Contract *ExampleWarpCaller // Generic read-only contract binding to access the raw methods on -} - -// ExampleWarpTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. -type ExampleWarpTransactorRaw struct { - Contract *ExampleWarpTransactor // Generic write-only contract binding to access the raw methods on -} - -// NewExampleWarp creates a new instance of ExampleWarp, bound to a specific deployed contract. -func NewExampleWarp(address common.Address, backend bind.ContractBackend) (*ExampleWarp, error) { - contract, err := bindExampleWarp(address, backend, backend, backend) - if err != nil { - return nil, err - } - return &ExampleWarp{ExampleWarpCaller: ExampleWarpCaller{contract: contract}, ExampleWarpTransactor: ExampleWarpTransactor{contract: contract}, ExampleWarpFilterer: ExampleWarpFilterer{contract: contract}}, nil -} - -// NewExampleWarpCaller creates a new read-only instance of ExampleWarp, bound to a specific deployed contract. -func NewExampleWarpCaller(address common.Address, caller bind.ContractCaller) (*ExampleWarpCaller, error) { - contract, err := bindExampleWarp(address, caller, nil, nil) - if err != nil { - return nil, err - } - return &ExampleWarpCaller{contract: contract}, nil -} - -// NewExampleWarpTransactor creates a new write-only instance of ExampleWarp, bound to a specific deployed contract. -func NewExampleWarpTransactor(address common.Address, transactor bind.ContractTransactor) (*ExampleWarpTransactor, error) { - contract, err := bindExampleWarp(address, nil, transactor, nil) - if err != nil { - return nil, err - } - return &ExampleWarpTransactor{contract: contract}, nil -} - -// NewExampleWarpFilterer creates a new log filterer instance of ExampleWarp, bound to a specific deployed contract. -func NewExampleWarpFilterer(address common.Address, filterer bind.ContractFilterer) (*ExampleWarpFilterer, error) { - contract, err := bindExampleWarp(address, nil, nil, filterer) - if err != nil { - return nil, err - } - return &ExampleWarpFilterer{contract: contract}, nil -} - -// bindExampleWarp binds a generic wrapper to an already deployed contract. -func bindExampleWarp(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { - parsed, err := ExampleWarpMetaData.GetAbi() - if err != nil { - return nil, err - } - return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_ExampleWarp *ExampleWarpRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _ExampleWarp.Contract.ExampleWarpCaller.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_ExampleWarp *ExampleWarpRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _ExampleWarp.Contract.ExampleWarpTransactor.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_ExampleWarp *ExampleWarpRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _ExampleWarp.Contract.ExampleWarpTransactor.contract.Transact(opts, method, params...) -} - -// Call invokes the (constant) contract method with params as input values and -// sets the output to result. The result type might be a single field for simple -// returns, a slice of interfaces for anonymous returns and a struct for named -// returns. -func (_ExampleWarp *ExampleWarpCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { - return _ExampleWarp.Contract.contract.Call(opts, result, method, params...) -} - -// Transfer initiates a plain transaction to move funds to the contract, calling -// its default method if one is available. -func (_ExampleWarp *ExampleWarpTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { - return _ExampleWarp.Contract.contract.Transfer(opts) -} - -// Transact invokes the (paid) contract method with params as input values. -func (_ExampleWarp *ExampleWarpTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { - return _ExampleWarp.Contract.contract.Transact(opts, method, params...) -} - -// ValidateGetBlockchainID is a free data retrieval call binding the contract method 0x15f0c959. -// -// Solidity: function validateGetBlockchainID(bytes32 blockchainID) view returns() -func (_ExampleWarp *ExampleWarpCaller) ValidateGetBlockchainID(opts *bind.CallOpts, blockchainID [32]byte) error { - var out []interface{} - err := _ExampleWarp.contract.Call(opts, &out, "validateGetBlockchainID", blockchainID) - - if err != nil { - return err - } - - return err - -} - -// ValidateGetBlockchainID is a free data retrieval call binding the contract method 0x15f0c959. -// -// Solidity: function validateGetBlockchainID(bytes32 blockchainID) view returns() -func (_ExampleWarp *ExampleWarpSession) ValidateGetBlockchainID(blockchainID [32]byte) error { - return _ExampleWarp.Contract.ValidateGetBlockchainID(&_ExampleWarp.CallOpts, blockchainID) -} - -// ValidateGetBlockchainID is a free data retrieval call binding the contract method 0x15f0c959. -// -// Solidity: function validateGetBlockchainID(bytes32 blockchainID) view returns() -func (_ExampleWarp *ExampleWarpCallerSession) ValidateGetBlockchainID(blockchainID [32]byte) error { - return _ExampleWarp.Contract.ValidateGetBlockchainID(&_ExampleWarp.CallOpts, blockchainID) -} - -// ValidateInvalidWarpBlockHash is a free data retrieval call binding the contract method 0x77ca84db. -// -// Solidity: function validateInvalidWarpBlockHash(uint32 index) view returns() -func (_ExampleWarp *ExampleWarpCaller) ValidateInvalidWarpBlockHash(opts *bind.CallOpts, index uint32) error { - var out []interface{} - err := _ExampleWarp.contract.Call(opts, &out, "validateInvalidWarpBlockHash", index) - - if err != nil { - return err - } - - return err - -} - -// ValidateInvalidWarpBlockHash is a free data retrieval call binding the contract method 0x77ca84db. -// -// Solidity: function validateInvalidWarpBlockHash(uint32 index) view returns() -func (_ExampleWarp *ExampleWarpSession) ValidateInvalidWarpBlockHash(index uint32) error { - return _ExampleWarp.Contract.ValidateInvalidWarpBlockHash(&_ExampleWarp.CallOpts, index) -} - -// ValidateInvalidWarpBlockHash is a free data retrieval call binding the contract method 0x77ca84db. -// -// Solidity: function validateInvalidWarpBlockHash(uint32 index) view returns() -func (_ExampleWarp *ExampleWarpCallerSession) ValidateInvalidWarpBlockHash(index uint32) error { - return _ExampleWarp.Contract.ValidateInvalidWarpBlockHash(&_ExampleWarp.CallOpts, index) -} - -// ValidateInvalidWarpMessage is a free data retrieval call binding the contract method 0xf25ec06a. -// -// Solidity: function validateInvalidWarpMessage(uint32 index) view returns() -func (_ExampleWarp *ExampleWarpCaller) ValidateInvalidWarpMessage(opts *bind.CallOpts, index uint32) error { - var out []interface{} - err := _ExampleWarp.contract.Call(opts, &out, "validateInvalidWarpMessage", index) - - if err != nil { - return err - } - - return err - -} - -// ValidateInvalidWarpMessage is a free data retrieval call binding the contract method 0xf25ec06a. -// -// Solidity: function validateInvalidWarpMessage(uint32 index) view returns() -func (_ExampleWarp *ExampleWarpSession) ValidateInvalidWarpMessage(index uint32) error { - return _ExampleWarp.Contract.ValidateInvalidWarpMessage(&_ExampleWarp.CallOpts, index) -} - -// ValidateInvalidWarpMessage is a free data retrieval call binding the contract method 0xf25ec06a. -// -// Solidity: function validateInvalidWarpMessage(uint32 index) view returns() -func (_ExampleWarp *ExampleWarpCallerSession) ValidateInvalidWarpMessage(index uint32) error { - return _ExampleWarp.Contract.ValidateInvalidWarpMessage(&_ExampleWarp.CallOpts, index) -} - -// ValidateWarpBlockHash is a free data retrieval call binding the contract method 0xe519286f. -// -// Solidity: function validateWarpBlockHash(uint32 index, bytes32 sourceChainID, bytes32 blockHash) view returns() -func (_ExampleWarp *ExampleWarpCaller) ValidateWarpBlockHash(opts *bind.CallOpts, index uint32, sourceChainID [32]byte, blockHash [32]byte) error { - var out []interface{} - err := _ExampleWarp.contract.Call(opts, &out, "validateWarpBlockHash", index, sourceChainID, blockHash) - - if err != nil { - return err - } - - return err - -} - -// ValidateWarpBlockHash is a free data retrieval call binding the contract method 0xe519286f. -// -// Solidity: function validateWarpBlockHash(uint32 index, bytes32 sourceChainID, bytes32 blockHash) view returns() -func (_ExampleWarp *ExampleWarpSession) ValidateWarpBlockHash(index uint32, sourceChainID [32]byte, blockHash [32]byte) error { - return _ExampleWarp.Contract.ValidateWarpBlockHash(&_ExampleWarp.CallOpts, index, sourceChainID, blockHash) -} - -// ValidateWarpBlockHash is a free data retrieval call binding the contract method 0xe519286f. -// -// Solidity: function validateWarpBlockHash(uint32 index, bytes32 sourceChainID, bytes32 blockHash) view returns() -func (_ExampleWarp *ExampleWarpCallerSession) ValidateWarpBlockHash(index uint32, sourceChainID [32]byte, blockHash [32]byte) error { - return _ExampleWarp.Contract.ValidateWarpBlockHash(&_ExampleWarp.CallOpts, index, sourceChainID, blockHash) -} - -// ValidateWarpMessage is a free data retrieval call binding the contract method 0x5bd05f06. -// -// Solidity: function validateWarpMessage(uint32 index, bytes32 sourceChainID, address originSenderAddress, bytes payload) view returns() -func (_ExampleWarp *ExampleWarpCaller) ValidateWarpMessage(opts *bind.CallOpts, index uint32, sourceChainID [32]byte, originSenderAddress common.Address, payload []byte) error { - var out []interface{} - err := _ExampleWarp.contract.Call(opts, &out, "validateWarpMessage", index, sourceChainID, originSenderAddress, payload) - - if err != nil { - return err - } - - return err - -} - -// ValidateWarpMessage is a free data retrieval call binding the contract method 0x5bd05f06. -// -// Solidity: function validateWarpMessage(uint32 index, bytes32 sourceChainID, address originSenderAddress, bytes payload) view returns() -func (_ExampleWarp *ExampleWarpSession) ValidateWarpMessage(index uint32, sourceChainID [32]byte, originSenderAddress common.Address, payload []byte) error { - return _ExampleWarp.Contract.ValidateWarpMessage(&_ExampleWarp.CallOpts, index, sourceChainID, originSenderAddress, payload) -} - -// ValidateWarpMessage is a free data retrieval call binding the contract method 0x5bd05f06. -// -// Solidity: function validateWarpMessage(uint32 index, bytes32 sourceChainID, address originSenderAddress, bytes payload) view returns() -func (_ExampleWarp *ExampleWarpCallerSession) ValidateWarpMessage(index uint32, sourceChainID [32]byte, originSenderAddress common.Address, payload []byte) error { - return _ExampleWarp.Contract.ValidateWarpMessage(&_ExampleWarp.CallOpts, index, sourceChainID, originSenderAddress, payload) -} - -// SendWarpMessage is a paid mutator transaction binding the contract method 0xee5b48eb. -// -// Solidity: function sendWarpMessage(bytes payload) returns() -func (_ExampleWarp *ExampleWarpTransactor) SendWarpMessage(opts *bind.TransactOpts, payload []byte) (*types.Transaction, error) { - return _ExampleWarp.contract.Transact(opts, "sendWarpMessage", payload) -} - -// SendWarpMessage is a paid mutator transaction binding the contract method 0xee5b48eb. -// -// Solidity: function sendWarpMessage(bytes payload) returns() -func (_ExampleWarp *ExampleWarpSession) SendWarpMessage(payload []byte) (*types.Transaction, error) { - return _ExampleWarp.Contract.SendWarpMessage(&_ExampleWarp.TransactOpts, payload) -} - -// SendWarpMessage is a paid mutator transaction binding the contract method 0xee5b48eb. -// -// Solidity: function sendWarpMessage(bytes payload) returns() -func (_ExampleWarp *ExampleWarpTransactorSession) SendWarpMessage(payload []byte) (*types.Transaction, error) { - return _ExampleWarp.Contract.SendWarpMessage(&_ExampleWarp.TransactOpts, payload) -} diff --git a/contracts/contracts/interfaces/IWarpMessenger.sol b/contracts/contracts/interfaces/IWarpMessenger.sol deleted file mode 100644 index 7f96b34070..0000000000 --- a/contracts/contracts/interfaces/IWarpMessenger.sol +++ /dev/null @@ -1,48 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.24; - -struct WarpMessage { - bytes32 sourceChainID; - address originSenderAddress; - bytes payload; -} - -struct WarpBlockHash { - bytes32 sourceChainID; - bytes32 blockHash; -} - -interface IWarpMessenger { - event SendWarpMessage(address indexed sender, bytes32 indexed messageID, bytes message); - - // sendWarpMessage emits a request for the subnet to send a warp message from [msg.sender] - // with the specified parameters. - // This emits a SendWarpMessage log from the precompile. When the corresponding block is accepted - // the Accept hook of the Warp precompile is invoked with all accepted logs emitted by the Warp - // precompile. - // Each validator then adds the UnsignedWarpMessage encoded in the log to the set of messages - // it is willing to sign for an off-chain relayer to aggregate Warp signatures. - function sendWarpMessage(bytes calldata payload) external returns (bytes32 messageID); - - // getVerifiedWarpMessage parses the pre-verified warp message in the - // predicate storage slots as a WarpMessage and returns it to the caller. - // If the message exists and passes verification, returns the verified message - // and true. - // Otherwise, returns false and the empty value for the message. - function getVerifiedWarpMessage(uint32 index) external view returns (WarpMessage calldata message, bool valid); - - // getVerifiedWarpBlockHash parses the pre-verified WarpBlockHash message in the - // predicate storage slots as a WarpBlockHash message and returns it to the caller. - // If the message exists and passes verification, returns the verified message - // and true. - // Otherwise, returns false and the empty value for the message. - function getVerifiedWarpBlockHash( - uint32 index - ) external view returns (WarpBlockHash calldata warpBlockHash, bool valid); - - // getBlockchainID returns the snow.Context BlockchainID of this chain. - // This blockchainID is the hash of the transaction that created this blockchain on the P-Chain - // and is not related to the Ethereum ChainID. - function getBlockchainID() external view returns (bytes32 blockchainID); -} diff --git a/contracts/index.ts b/contracts/index.ts index fb69b71c8a..9c7bf2d23c 100644 --- a/contracts/index.ts +++ b/contracts/index.ts @@ -1 +1 @@ -export { test } from './test/utils'; +export { Roles } from './test/utils'; diff --git a/contracts/test/utils.ts b/contracts/test/utils.ts index aa85b66733..5d272d7d98 100644 --- a/contracts/test/utils.ts +++ b/contracts/test/utils.ts @@ -1,7 +1,3 @@ -import { ethers } from "hardhat" -import { Overrides } from "ethers" -import assert from "assert" - /* * * The `test` function is a wrapper around Mocha's `it` function. It provides a normalized framework for running the @@ -37,96 +33,10 @@ import assert from "assert" */ // Below are the types that help define all the different ways to call `test` -type FnNameOrObject = string | string[] | MethodObject | MethodObject[] - -// Limit `from` property to be a `string` instead of `string | Promise` -type CallOverrides = Overrides & { from?: string } - -type MethodObject = { method: string, debug?: boolean, overrides?: CallOverrides, shouldFail?: boolean } - -// This type is after all default values have been applied -type MethodWithDebugAndOverrides = MethodObject & { debug: boolean, overrides: CallOverrides, shouldFail: boolean } - -// `test` is used very similarly to `it` from Mocha -export const test = (name, fnNameOrObject, overrides = {}) => it(name, buildTestFn(fnNameOrObject, overrides)) -// `test.only` is used very similarly to `it.only` from Mocha, it will isolate all tests marked with `test.only` -test.only = (name, fnNameOrObject, overrides = {}) => it.only(name, buildTestFn(fnNameOrObject, overrides)) -// `test.debug` is used to apply `debug: true` to all DSTest contract method calls in the test -test.debug = (name, fnNameOrObject, overrides = {}) => it.only(name, buildTestFn(fnNameOrObject, overrides, true)) -// `test.skip` is used very similarly to `it.skip` from Mocha, it will skip all tests marked with `test.skip` -test.skip = (name, fnNameOrObject, overrides = {}) => it.skip(name, buildTestFn(fnNameOrObject, overrides)) - -// `buildTestFn` is a higher-order function. It returns a function that can be used as the test function for `it` -const buildTestFn = (fnNameOrObject: FnNameOrObject, overrides = {}, debug = false) => { - // normalize the input to an array of objects - const fnObjects: MethodWithDebugAndOverrides[] = (Array.isArray(fnNameOrObject) ? fnNameOrObject : [fnNameOrObject]).map(fnNameOrObject => { - fnNameOrObject = typeof fnNameOrObject === 'string' ? { method: fnNameOrObject } : fnNameOrObject - // assign all default values and overrides - fnNameOrObject.overrides = Object.assign({}, overrides, fnNameOrObject.overrides ?? {}) - fnNameOrObject.debug = fnNameOrObject.debug ?? debug - fnNameOrObject.shouldFail = fnNameOrObject.shouldFail ?? false - - return fnNameOrObject as MethodWithDebugAndOverrides - }) - - // only `step_` prefixed functions can be called on the `DSTest` contracts to clearly separate tests and helpers - assert(fnObjects.every(({ method }) => method.startsWith('step_')), "Solidity test functions must be prefixed with 'step_'") - - // return the test function that will be used by `it` - // this function must be defined with the `function` keyword so that `this` is bound to the Mocha context - return async function () { - // `Array.prototype.reduce` is used here to ensure that the test functions are called in order. - // Each test function waits for its predecessor to complete before starting - return fnObjects.reduce((p: Promise, fn) => p.then(async () => { - const contract = fn.overrides.from - ? this.testContract.connect(await ethers.getSigner(fn.overrides.from)) - : this.testContract - const tx = await contract[fn.method](fn.overrides).catch(err => { - if (fn.shouldFail) { - if (fn.debug){ - console.error(`smart contract call failed with error:\n${err}\n`) - } - - return { failed: true } - } - - console.error("smart contract call failed with error:", err) - throw err - }) - - // no more assertions necessary if the method-call should fail and did fail - if (tx.failed && fn.shouldFail) return - - const txReceipt = await tx.wait().catch(err => { - if (fn.debug) console.error(`tx failed with error:\n${err}\n`) - return err.receipt - }) - - // `txReceipt.status` will be `0` if the transaction failed. - // `contract.failed` will return `true` if any of the `DSTest` assertions failed. - const failed = txReceipt.status === 0 ? true : await contract.failed.staticCall() - if (fn.debug || failed) { - console.log('') - - if (!txReceipt.events) console.warn('WARNING: No parseable events found in tx-receipt\n') - - // If `DSTest` assertions failed, the contract will emit logs describing the assertion failure(s). - txReceipt - .events - ?.filter(event => fn.debug || event.event?.startsWith('log')) - .map(event => event.args?.forEach(arg => console.log(arg))) - - console.log('') - } - - assert(!failed, `${fn.method} failed`) - }), Promise.resolve()) - } -} export const Roles = { None: 0, Enabled: 1, Admin: 2, Manager: 3, -} +} \ No newline at end of file diff --git a/contracts/test/warp.ts b/contracts/test/warp.ts deleted file mode 100644 index 32fb54da22..0000000000 --- a/contracts/test/warp.ts +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (C) 2019-2025, Ava Labs, Inc. All rights reserved. -// See the file LICENSE for licensing terms. - -import { expect } from "chai"; -import { ethers } from "hardhat"; -import { Contract, Signer } from "ethers"; -import { IWarpMessenger } from "typechain-types"; - -const WARP_ADDRESS = "0x0200000000000000000000000000000000000005"; -let senderAddress = process.env["SENDER_ADDRESS"]; -// Expected to be a hex string -let payload = process.env["PAYLOAD"]; -let expectedUnsignedMessage = process.env["EXPECTED_UNSIGNED_MESSAGE"]; -let sourceID = process.env["SOURCE_CHAIN_ID"]; - -describe("IWarpMessenger", function () { - let owner: Signer; - let contract: IWarpMessenger; - before(async function () { - owner = await ethers.getSigner(senderAddress); - contract = await ethers.getContractAt("IWarpMessenger", WARP_ADDRESS, owner) - }); - - it("contract should be to send warp message", async function () { - console.log(`Sending warp message with payload ${payload}, expected unsigned message ${expectedUnsignedMessage}`); - - // Get ID of payload by taking sha256 of unsigned message - let messageID = ethers.sha256(expectedUnsignedMessage); - let tx = await contract.sendWarpMessage(payload) - let receipt = await tx.wait() - await expect(receipt) - .to.emit(contract, 'SendWarpMessage') - .withArgs(senderAddress, messageID, expectedUnsignedMessage); - }) - - it("should be able to fetch correct blockchain ID", async function () { - let blockchainID = await contract.getBlockchainID(); - expect(blockchainID).to.be.equal(sourceID); - }) -}) diff --git a/contracts/contracts/ExampleWarp.sol b/plugin/evm/ExampleWarp.sol similarity index 97% rename from contracts/contracts/ExampleWarp.sol rename to plugin/evm/ExampleWarp.sol index 9c2d8f560a..1e7a44867d 100644 --- a/contracts/contracts/ExampleWarp.sol +++ b/plugin/evm/ExampleWarp.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.24; pragma experimental ABIEncoderV2; -import "./interfaces/IWarpMessenger.sol"; +import "precompile/contracts/warp/warpbindings/IWarpMessenger.sol"; contract ExampleWarp { address constant WARP_ADDRESS = 0x0200000000000000000000000000000000000005; diff --git a/precompile/contracts/warp/warpbindings/IWarpMessenger.sol b/precompile/contracts/warp/warpbindings/IWarpMessenger.sol new file mode 100644 index 0000000000..cbf1683cc2 --- /dev/null +++ b/precompile/contracts/warp/warpbindings/IWarpMessenger.sol @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.24; + +struct WarpMessage { + bytes32 sourceChainID; + address originSenderAddress; + bytes payload; +} + +struct WarpBlockHash { + bytes32 sourceChainID; + bytes32 blockHash; +} + +interface IWarpMessenger { + event SendWarpMessage( + address indexed sender, + bytes32 indexed messageID, + bytes message + ); + + // sendWarpMessage emits a request for the subnet to send a warp message from [msg.sender] + // with the specified parameters. + // This emits a SendWarpMessage log from the precompile. When the corresponding block is accepted + // the Accept hook of the Warp precompile is invoked with all accepted logs emitted by the Warp + // precompile. + // Each validator then adds the UnsignedWarpMessage encoded in the log to the set of messages + // it is willing to sign for an off-chain relayer to aggregate Warp signatures. + function sendWarpMessage( + bytes calldata payload + ) external returns (bytes32 messageID); + + // getVerifiedWarpMessage parses the pre-verified warp message in the + // predicate storage slots as a WarpMessage and returns it to the caller. + // If the message exists and passes verification, returns the verified message + // and true. + // Otherwise, returns false and the empty value for the message. + function getVerifiedWarpMessage( + uint32 index + ) external view returns (WarpMessage calldata message, bool valid); + + // getVerifiedWarpBlockHash parses the pre-verified WarpBlockHash message in the + // predicate storage slots as a WarpBlockHash message and returns it to the caller. + // If the message exists and passes verification, returns the verified message + // and true. + // Otherwise, returns false and the empty value for the message. + function getVerifiedWarpBlockHash( + uint32 index + ) external view returns (WarpBlockHash calldata warpBlockHash, bool valid); + + // getBlockchainID returns the snow.Context BlockchainID of this chain. + // This blockchainID is the hash of the transaction that created this blockchain on the P-Chain + // and is not related to the Ethereum ChainID. + function getBlockchainID() external view returns (bytes32 blockchainID); +} diff --git a/precompile/contracts/warp/warpbindings/compile.go b/precompile/contracts/warp/warpbindings/compile.go new file mode 100644 index 0000000000..62cbdd5931 --- /dev/null +++ b/precompile/contracts/warp/warpbindings/compile.go @@ -0,0 +1,12 @@ +// Copyright (C) 2019-2025, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package warpbindings + +// Step 1: Compile Solidity contract to generate ABI and bin files +//go:generate solc-v0.8.30 -o artifacts --overwrite --abi --bin --evm-version cancun IWarpMessenger.sol +// Step 2: Generate Go bindings from the compiled artifacts +//go:generate go run github.com/ava-labs/libevm/cmd/abigen --pkg warpbindings --type IWarpMessenger --abi artifacts/IWarpMessenger.abi --bin artifacts/IWarpMessenger.bin --out gen_iwarpmessenger_binding.go +// Step 3: Replace import paths in generated binding to use subnet-evm instead of libevm +// This is necessary because the libevm bindings package is not compatible with the subnet-evm simulated backend, which is used for testing. +//go:generate sh -c "sed -i.bak -e 's|github.com/ava-labs/libevm/accounts/abi|github.com/ava-labs/subnet-evm/accounts/abi|g' -e 's|github.com/ava-labs/libevm/accounts/abi/bind|github.com/ava-labs/subnet-evm/accounts/abi/bind|g' gen_iwarpmessenger_binding.go && rm -f gen_iwarpmessenger_binding.go.bak" diff --git a/precompile/contracts/warp/warpbindings/gen_iwarpmessenger_binding.go b/precompile/contracts/warp/warpbindings/gen_iwarpmessenger_binding.go new file mode 100644 index 0000000000..72669f1377 --- /dev/null +++ b/precompile/contracts/warp/warpbindings/gen_iwarpmessenger_binding.go @@ -0,0 +1,490 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package warpbindings + +import ( + "errors" + "math/big" + "strings" + + ethereum "github.com/ava-labs/libevm" + "github.com/ava-labs/subnet-evm/accounts/abi" + "github.com/ava-labs/subnet-evm/accounts/abi/bind" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/core/types" + "github.com/ava-labs/libevm/event" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription + _ = abi.ConvertType +) + +// WarpBlockHash is an auto generated low-level Go binding around an user-defined struct. +type WarpBlockHash struct { + SourceChainID [32]byte + BlockHash [32]byte +} + +// WarpMessage is an auto generated low-level Go binding around an user-defined struct. +type WarpMessage struct { + SourceChainID [32]byte + OriginSenderAddress common.Address + Payload []byte +} + +// IWarpMessengerMetaData contains all meta data concerning the IWarpMessenger contract. +var IWarpMessengerMetaData = &bind.MetaData{ + ABI: "[{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"sender\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"bytes32\",\"name\":\"messageID\",\"type\":\"bytes32\"},{\"indexed\":false,\"internalType\":\"bytes\",\"name\":\"message\",\"type\":\"bytes\"}],\"name\":\"SendWarpMessage\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"getBlockchainID\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"blockchainID\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"index\",\"type\":\"uint32\"}],\"name\":\"getVerifiedWarpBlockHash\",\"outputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"sourceChainID\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"blockHash\",\"type\":\"bytes32\"}],\"internalType\":\"structWarpBlockHash\",\"name\":\"warpBlockHash\",\"type\":\"tuple\"},{\"internalType\":\"bool\",\"name\":\"valid\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"index\",\"type\":\"uint32\"}],\"name\":\"getVerifiedWarpMessage\",\"outputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"sourceChainID\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"originSenderAddress\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"payload\",\"type\":\"bytes\"}],\"internalType\":\"structWarpMessage\",\"name\":\"message\",\"type\":\"tuple\"},{\"internalType\":\"bool\",\"name\":\"valid\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"payload\",\"type\":\"bytes\"}],\"name\":\"sendWarpMessage\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"messageID\",\"type\":\"bytes32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", +} + +// IWarpMessengerABI is the input ABI used to generate the binding from. +// Deprecated: Use IWarpMessengerMetaData.ABI instead. +var IWarpMessengerABI = IWarpMessengerMetaData.ABI + +// IWarpMessenger is an auto generated Go binding around an Ethereum contract. +type IWarpMessenger struct { + IWarpMessengerCaller // Read-only binding to the contract + IWarpMessengerTransactor // Write-only binding to the contract + IWarpMessengerFilterer // Log filterer for contract events +} + +// IWarpMessengerCaller is an auto generated read-only Go binding around an Ethereum contract. +type IWarpMessengerCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IWarpMessengerTransactor is an auto generated write-only Go binding around an Ethereum contract. +type IWarpMessengerTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IWarpMessengerFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type IWarpMessengerFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// IWarpMessengerSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type IWarpMessengerSession struct { + Contract *IWarpMessenger // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// IWarpMessengerCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type IWarpMessengerCallerSession struct { + Contract *IWarpMessengerCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// IWarpMessengerTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type IWarpMessengerTransactorSession struct { + Contract *IWarpMessengerTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// IWarpMessengerRaw is an auto generated low-level Go binding around an Ethereum contract. +type IWarpMessengerRaw struct { + Contract *IWarpMessenger // Generic contract binding to access the raw methods on +} + +// IWarpMessengerCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type IWarpMessengerCallerRaw struct { + Contract *IWarpMessengerCaller // Generic read-only contract binding to access the raw methods on +} + +// IWarpMessengerTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type IWarpMessengerTransactorRaw struct { + Contract *IWarpMessengerTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewIWarpMessenger creates a new instance of IWarpMessenger, bound to a specific deployed contract. +func NewIWarpMessenger(address common.Address, backend bind.ContractBackend) (*IWarpMessenger, error) { + contract, err := bindIWarpMessenger(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &IWarpMessenger{IWarpMessengerCaller: IWarpMessengerCaller{contract: contract}, IWarpMessengerTransactor: IWarpMessengerTransactor{contract: contract}, IWarpMessengerFilterer: IWarpMessengerFilterer{contract: contract}}, nil +} + +// NewIWarpMessengerCaller creates a new read-only instance of IWarpMessenger, bound to a specific deployed contract. +func NewIWarpMessengerCaller(address common.Address, caller bind.ContractCaller) (*IWarpMessengerCaller, error) { + contract, err := bindIWarpMessenger(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &IWarpMessengerCaller{contract: contract}, nil +} + +// NewIWarpMessengerTransactor creates a new write-only instance of IWarpMessenger, bound to a specific deployed contract. +func NewIWarpMessengerTransactor(address common.Address, transactor bind.ContractTransactor) (*IWarpMessengerTransactor, error) { + contract, err := bindIWarpMessenger(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &IWarpMessengerTransactor{contract: contract}, nil +} + +// NewIWarpMessengerFilterer creates a new log filterer instance of IWarpMessenger, bound to a specific deployed contract. +func NewIWarpMessengerFilterer(address common.Address, filterer bind.ContractFilterer) (*IWarpMessengerFilterer, error) { + contract, err := bindIWarpMessenger(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &IWarpMessengerFilterer{contract: contract}, nil +} + +// bindIWarpMessenger binds a generic wrapper to an already deployed contract. +func bindIWarpMessenger(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := IWarpMessengerMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_IWarpMessenger *IWarpMessengerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _IWarpMessenger.Contract.IWarpMessengerCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_IWarpMessenger *IWarpMessengerRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IWarpMessenger.Contract.IWarpMessengerTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_IWarpMessenger *IWarpMessengerRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _IWarpMessenger.Contract.IWarpMessengerTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_IWarpMessenger *IWarpMessengerCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _IWarpMessenger.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_IWarpMessenger *IWarpMessengerTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _IWarpMessenger.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_IWarpMessenger *IWarpMessengerTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _IWarpMessenger.Contract.contract.Transact(opts, method, params...) +} + +// GetBlockchainID is a free data retrieval call binding the contract method 0x4213cf78. +// +// Solidity: function getBlockchainID() view returns(bytes32 blockchainID) +func (_IWarpMessenger *IWarpMessengerCaller) GetBlockchainID(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _IWarpMessenger.contract.Call(opts, &out, "getBlockchainID") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// GetBlockchainID is a free data retrieval call binding the contract method 0x4213cf78. +// +// Solidity: function getBlockchainID() view returns(bytes32 blockchainID) +func (_IWarpMessenger *IWarpMessengerSession) GetBlockchainID() ([32]byte, error) { + return _IWarpMessenger.Contract.GetBlockchainID(&_IWarpMessenger.CallOpts) +} + +// GetBlockchainID is a free data retrieval call binding the contract method 0x4213cf78. +// +// Solidity: function getBlockchainID() view returns(bytes32 blockchainID) +func (_IWarpMessenger *IWarpMessengerCallerSession) GetBlockchainID() ([32]byte, error) { + return _IWarpMessenger.Contract.GetBlockchainID(&_IWarpMessenger.CallOpts) +} + +// GetVerifiedWarpBlockHash is a free data retrieval call binding the contract method 0xce7f5929. +// +// Solidity: function getVerifiedWarpBlockHash(uint32 index) view returns((bytes32,bytes32) warpBlockHash, bool valid) +func (_IWarpMessenger *IWarpMessengerCaller) GetVerifiedWarpBlockHash(opts *bind.CallOpts, index uint32) (struct { + WarpBlockHash WarpBlockHash + Valid bool +}, error) { + var out []interface{} + err := _IWarpMessenger.contract.Call(opts, &out, "getVerifiedWarpBlockHash", index) + + outstruct := new(struct { + WarpBlockHash WarpBlockHash + Valid bool + }) + if err != nil { + return *outstruct, err + } + + outstruct.WarpBlockHash = *abi.ConvertType(out[0], new(WarpBlockHash)).(*WarpBlockHash) + outstruct.Valid = *abi.ConvertType(out[1], new(bool)).(*bool) + + return *outstruct, err + +} + +// GetVerifiedWarpBlockHash is a free data retrieval call binding the contract method 0xce7f5929. +// +// Solidity: function getVerifiedWarpBlockHash(uint32 index) view returns((bytes32,bytes32) warpBlockHash, bool valid) +func (_IWarpMessenger *IWarpMessengerSession) GetVerifiedWarpBlockHash(index uint32) (struct { + WarpBlockHash WarpBlockHash + Valid bool +}, error) { + return _IWarpMessenger.Contract.GetVerifiedWarpBlockHash(&_IWarpMessenger.CallOpts, index) +} + +// GetVerifiedWarpBlockHash is a free data retrieval call binding the contract method 0xce7f5929. +// +// Solidity: function getVerifiedWarpBlockHash(uint32 index) view returns((bytes32,bytes32) warpBlockHash, bool valid) +func (_IWarpMessenger *IWarpMessengerCallerSession) GetVerifiedWarpBlockHash(index uint32) (struct { + WarpBlockHash WarpBlockHash + Valid bool +}, error) { + return _IWarpMessenger.Contract.GetVerifiedWarpBlockHash(&_IWarpMessenger.CallOpts, index) +} + +// GetVerifiedWarpMessage is a free data retrieval call binding the contract method 0x6f825350. +// +// Solidity: function getVerifiedWarpMessage(uint32 index) view returns((bytes32,address,bytes) message, bool valid) +func (_IWarpMessenger *IWarpMessengerCaller) GetVerifiedWarpMessage(opts *bind.CallOpts, index uint32) (struct { + Message WarpMessage + Valid bool +}, error) { + var out []interface{} + err := _IWarpMessenger.contract.Call(opts, &out, "getVerifiedWarpMessage", index) + + outstruct := new(struct { + Message WarpMessage + Valid bool + }) + if err != nil { + return *outstruct, err + } + + outstruct.Message = *abi.ConvertType(out[0], new(WarpMessage)).(*WarpMessage) + outstruct.Valid = *abi.ConvertType(out[1], new(bool)).(*bool) + + return *outstruct, err + +} + +// GetVerifiedWarpMessage is a free data retrieval call binding the contract method 0x6f825350. +// +// Solidity: function getVerifiedWarpMessage(uint32 index) view returns((bytes32,address,bytes) message, bool valid) +func (_IWarpMessenger *IWarpMessengerSession) GetVerifiedWarpMessage(index uint32) (struct { + Message WarpMessage + Valid bool +}, error) { + return _IWarpMessenger.Contract.GetVerifiedWarpMessage(&_IWarpMessenger.CallOpts, index) +} + +// GetVerifiedWarpMessage is a free data retrieval call binding the contract method 0x6f825350. +// +// Solidity: function getVerifiedWarpMessage(uint32 index) view returns((bytes32,address,bytes) message, bool valid) +func (_IWarpMessenger *IWarpMessengerCallerSession) GetVerifiedWarpMessage(index uint32) (struct { + Message WarpMessage + Valid bool +}, error) { + return _IWarpMessenger.Contract.GetVerifiedWarpMessage(&_IWarpMessenger.CallOpts, index) +} + +// SendWarpMessage is a paid mutator transaction binding the contract method 0xee5b48eb. +// +// Solidity: function sendWarpMessage(bytes payload) returns(bytes32 messageID) +func (_IWarpMessenger *IWarpMessengerTransactor) SendWarpMessage(opts *bind.TransactOpts, payload []byte) (*types.Transaction, error) { + return _IWarpMessenger.contract.Transact(opts, "sendWarpMessage", payload) +} + +// SendWarpMessage is a paid mutator transaction binding the contract method 0xee5b48eb. +// +// Solidity: function sendWarpMessage(bytes payload) returns(bytes32 messageID) +func (_IWarpMessenger *IWarpMessengerSession) SendWarpMessage(payload []byte) (*types.Transaction, error) { + return _IWarpMessenger.Contract.SendWarpMessage(&_IWarpMessenger.TransactOpts, payload) +} + +// SendWarpMessage is a paid mutator transaction binding the contract method 0xee5b48eb. +// +// Solidity: function sendWarpMessage(bytes payload) returns(bytes32 messageID) +func (_IWarpMessenger *IWarpMessengerTransactorSession) SendWarpMessage(payload []byte) (*types.Transaction, error) { + return _IWarpMessenger.Contract.SendWarpMessage(&_IWarpMessenger.TransactOpts, payload) +} + +// IWarpMessengerSendWarpMessageIterator is returned from FilterSendWarpMessage and is used to iterate over the raw logs and unpacked data for SendWarpMessage events raised by the IWarpMessenger contract. +type IWarpMessengerSendWarpMessageIterator struct { + Event *IWarpMessengerSendWarpMessage // Event containing the contract specifics and raw log + + contract *bind.BoundContract // Generic contract to use for unpacking event data + event string // Event name to use for unpacking event data + + logs chan types.Log // Log channel receiving the found contract events + sub ethereum.Subscription // Subscription for errors, completion and termination + done bool // Whether the subscription completed delivering logs + fail error // Occurred error to stop iteration +} + +// Next advances the iterator to the subsequent event, returning whether there +// are any more events found. In case of a retrieval or parsing error, false is +// returned and Error() can be queried for the exact failure. +func (it *IWarpMessengerSendWarpMessageIterator) Next() bool { + // If the iterator failed, stop iterating + if it.fail != nil { + return false + } + // If the iterator completed, deliver directly whatever's available + if it.done { + select { + case log := <-it.logs: + it.Event = new(IWarpMessengerSendWarpMessage) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + default: + return false + } + } + // Iterator still in progress, wait for either a data or an error event + select { + case log := <-it.logs: + it.Event = new(IWarpMessengerSendWarpMessage) + if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil { + it.fail = err + return false + } + it.Event.Raw = log + return true + + case err := <-it.sub.Err(): + it.done = true + it.fail = err + return it.Next() + } +} + +// Error returns any retrieval or parsing error occurred during filtering. +func (it *IWarpMessengerSendWarpMessageIterator) Error() error { + return it.fail +} + +// Close terminates the iteration process, releasing any pending underlying +// resources. +func (it *IWarpMessengerSendWarpMessageIterator) Close() error { + it.sub.Unsubscribe() + return nil +} + +// IWarpMessengerSendWarpMessage represents a SendWarpMessage event raised by the IWarpMessenger contract. +type IWarpMessengerSendWarpMessage struct { + Sender common.Address + MessageID [32]byte + Message []byte + Raw types.Log // Blockchain specific contextual infos +} + +// FilterSendWarpMessage is a free log retrieval operation binding the contract event 0x56600c567728a800c0aa927500f831cb451df66a7af570eb4df4dfbf4674887d. +// +// Solidity: event SendWarpMessage(address indexed sender, bytes32 indexed messageID, bytes message) +func (_IWarpMessenger *IWarpMessengerFilterer) FilterSendWarpMessage(opts *bind.FilterOpts, sender []common.Address, messageID [][32]byte) (*IWarpMessengerSendWarpMessageIterator, error) { + + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + var messageIDRule []interface{} + for _, messageIDItem := range messageID { + messageIDRule = append(messageIDRule, messageIDItem) + } + + logs, sub, err := _IWarpMessenger.contract.FilterLogs(opts, "SendWarpMessage", senderRule, messageIDRule) + if err != nil { + return nil, err + } + return &IWarpMessengerSendWarpMessageIterator{contract: _IWarpMessenger.contract, event: "SendWarpMessage", logs: logs, sub: sub}, nil +} + +// WatchSendWarpMessage is a free log subscription operation binding the contract event 0x56600c567728a800c0aa927500f831cb451df66a7af570eb4df4dfbf4674887d. +// +// Solidity: event SendWarpMessage(address indexed sender, bytes32 indexed messageID, bytes message) +func (_IWarpMessenger *IWarpMessengerFilterer) WatchSendWarpMessage(opts *bind.WatchOpts, sink chan<- *IWarpMessengerSendWarpMessage, sender []common.Address, messageID [][32]byte) (event.Subscription, error) { + + var senderRule []interface{} + for _, senderItem := range sender { + senderRule = append(senderRule, senderItem) + } + var messageIDRule []interface{} + for _, messageIDItem := range messageID { + messageIDRule = append(messageIDRule, messageIDItem) + } + + logs, sub, err := _IWarpMessenger.contract.WatchLogs(opts, "SendWarpMessage", senderRule, messageIDRule) + if err != nil { + return nil, err + } + return event.NewSubscription(func(quit <-chan struct{}) error { + defer sub.Unsubscribe() + for { + select { + case log := <-logs: + // New log arrived, parse the event and forward to the user + event := new(IWarpMessengerSendWarpMessage) + if err := _IWarpMessenger.contract.UnpackLog(event, "SendWarpMessage", log); err != nil { + return err + } + event.Raw = log + + select { + case sink <- event: + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + case err := <-sub.Err(): + return err + case <-quit: + return nil + } + } + }), nil +} + +// ParseSendWarpMessage is a log parse operation binding the contract event 0x56600c567728a800c0aa927500f831cb451df66a7af570eb4df4dfbf4674887d. +// +// Solidity: event SendWarpMessage(address indexed sender, bytes32 indexed messageID, bytes message) +func (_IWarpMessenger *IWarpMessengerFilterer) ParseSendWarpMessage(log types.Log) (*IWarpMessengerSendWarpMessage, error) { + event := new(IWarpMessengerSendWarpMessage) + if err := _IWarpMessenger.contract.UnpackLog(event, "SendWarpMessage", log); err != nil { + return nil, err + } + event.Raw = log + return event, nil +} diff --git a/precompile/contracts/warp/warptest/bindings/WarpTest.sol b/precompile/contracts/warp/warptest/bindings/WarpTest.sol new file mode 100644 index 0000000000..bcc0667922 --- /dev/null +++ b/precompile/contracts/warp/warptest/bindings/WarpTest.sol @@ -0,0 +1,42 @@ +//SPDX-License-Identifier: MIT +pragma solidity ^0.8.24; + +import "precompile/contracts/warp/warpbindings/IWarpMessenger.sol"; + + +// This test contract exists to ensure that `IWarpPrecomile.sol` is properly covered by precompile tests. +// By invoking the precompile via a proxy contract that leverages the `IWarpPrecompile.sol` interface, +// we ensure the interface definition matches the precompile implementation regardless of how the proxy +// contract itself is invoked. +contract WarpTest { + IWarpMessenger private warp; + + constructor(address warpPrecompile) { + warp = IWarpMessenger(warpPrecompile); + } + + // Calls the getBlockchainID function on the precompile + function getBlockchainID() external view returns (bytes32) { + return warp.getBlockchainID(); + } + + // Calls the sendWarpMessage function on the precompile + function sendWarpMessage(bytes calldata payload) external returns (bytes32 messageID) { + return warp.sendWarpMessage(payload); + } + + // Calls the getVerifiedWarpMessage function on the precompile + function getVerifiedWarpMessage( + uint32 index + ) external view returns (WarpMessage memory message, bool valid) { + return warp.getVerifiedWarpMessage(index); + } + + // Calls the getVerifiedWarpBlockHash function on the precompile + function getVerifiedWarpBlockHash( + uint32 index + ) external view returns (WarpBlockHash memory warpBlockHash, bool valid) { + return warp.getVerifiedWarpBlockHash(index); + } +} + diff --git a/precompile/contracts/warp/warptest/bindings/compile.go b/precompile/contracts/warp/warptest/bindings/compile.go new file mode 100644 index 0000000000..a97b8c5a14 --- /dev/null +++ b/precompile/contracts/warp/warptest/bindings/compile.go @@ -0,0 +1,15 @@ +// Copyright (C) 2019-2025, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +package bindings + +// Step 1: Compile Solidity contract to generate ABI and bin files +// Uses base-path to resolve imports from the repo root +//go:generate solc-v0.8.30 -o artifacts --overwrite --abi --bin --base-path ../../../../.. precompile/=precompile/ --evm-version cancun WarpTest.sol +// Step 2: Generate Go bindings from the compiled artifacts +// WarpTest binding includes WarpMessage and WarpBlockHash struct definitions. +// For event filtering, use the IWarpMessenger binding from the warpbindings package. +//go:generate go run github.com/ava-labs/libevm/cmd/abigen --pkg bindings --type WarpTest --abi artifacts/WarpTest.abi --bin artifacts/WarpTest.bin --out gen_warptest_binding.go +// Step 3: Replace import paths in generated binding to use subnet-evm instead of libevm +// This is necessary because the libevm bindings package is not compatible with the subnet-evm simulated backend, which is used for testing. +//go:generate sh -c "sed -i.bak -e 's|github.com/ava-labs/libevm/accounts/abi|github.com/ava-labs/subnet-evm/accounts/abi|g' -e 's|github.com/ava-labs/libevm/accounts/abi/bind|github.com/ava-labs/subnet-evm/accounts/abi/bind|g' gen_warptest_binding.go && rm -f gen_warptest_binding.go.bak" diff --git a/precompile/contracts/warp/warptest/bindings/gen_warptest_binding.go b/precompile/contracts/warp/warptest/bindings/gen_warptest_binding.go new file mode 100644 index 0000000000..dc172fcc7f --- /dev/null +++ b/precompile/contracts/warp/warptest/bindings/gen_warptest_binding.go @@ -0,0 +1,358 @@ +// Code generated - DO NOT EDIT. +// This file is a generated binding and any manual changes will be lost. + +package bindings + +import ( + "errors" + "math/big" + "strings" + + ethereum "github.com/ava-labs/libevm" + "github.com/ava-labs/subnet-evm/accounts/abi" + "github.com/ava-labs/subnet-evm/accounts/abi/bind" + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/core/types" + "github.com/ava-labs/libevm/event" +) + +// Reference imports to suppress errors if they are not otherwise used. +var ( + _ = errors.New + _ = big.NewInt + _ = strings.NewReader + _ = ethereum.NotFound + _ = bind.Bind + _ = common.Big1 + _ = types.BloomLookup + _ = event.NewSubscription + _ = abi.ConvertType +) + +// WarpBlockHash is an auto generated low-level Go binding around an user-defined struct. +type WarpBlockHash struct { + SourceChainID [32]byte + BlockHash [32]byte +} + +// WarpMessage is an auto generated low-level Go binding around an user-defined struct. +type WarpMessage struct { + SourceChainID [32]byte + OriginSenderAddress common.Address + Payload []byte +} + +// WarpTestMetaData contains all meta data concerning the WarpTest contract. +var WarpTestMetaData = &bind.MetaData{ + ABI: "[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"warpPrecompile\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"getBlockchainID\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"index\",\"type\":\"uint32\"}],\"name\":\"getVerifiedWarpBlockHash\",\"outputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"sourceChainID\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"blockHash\",\"type\":\"bytes32\"}],\"internalType\":\"structWarpBlockHash\",\"name\":\"warpBlockHash\",\"type\":\"tuple\"},{\"internalType\":\"bool\",\"name\":\"valid\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint32\",\"name\":\"index\",\"type\":\"uint32\"}],\"name\":\"getVerifiedWarpMessage\",\"outputs\":[{\"components\":[{\"internalType\":\"bytes32\",\"name\":\"sourceChainID\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"originSenderAddress\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"payload\",\"type\":\"bytes\"}],\"internalType\":\"structWarpMessage\",\"name\":\"message\",\"type\":\"tuple\"},{\"internalType\":\"bool\",\"name\":\"valid\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"payload\",\"type\":\"bytes\"}],\"name\":\"sendWarpMessage\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"messageID\",\"type\":\"bytes32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", + Bin: "0x608060405234801561000f575f5ffd5b50604051610bd5380380610bd5833981810160405281019061003191906100d4565b805f5f6101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550506100ff565b5f5ffd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6100a38261007a565b9050919050565b6100b381610099565b81146100bd575f5ffd5b50565b5f815190506100ce816100aa565b92915050565b5f602082840312156100e9576100e8610076565b5b5f6100f6848285016100c0565b91505092915050565b610ac98061010c5f395ff3fe608060405234801561000f575f5ffd5b506004361061004a575f3560e01c80634213cf781461004e5780636f8253501461006c578063ce7f59291461009d578063ee5b48eb146100ce575b5f5ffd5b6100566100fe565b60405161006391906103f1565b60405180910390f35b61008660048036038101906100819190610454565b610191565b6040516100949291906105a4565b60405180910390f35b6100b760048036038101906100b29190610454565b61023e565b6040516100c59291906105ff565b60405180910390f35b6100e860048036038101906100e39190610687565b6102e8565b6040516100f591906103f1565b60405180910390f35b5f5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16634213cf786040518163ffffffff1660e01b8152600401602060405180830381865afa158015610168573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061018c91906106fc565b905090565b61019961038c565b5f5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16636f825350846040518263ffffffff1660e01b81526004016101f39190610736565b5f60405180830381865afa15801561020d573d5f5f3e3d5ffd5b505050506040513d5f823e3d601f19601f820116820180604052508101906102359190610942565b91509150915091565b6102466103c1565b5f5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663ce7f5929846040518263ffffffff1660e01b81526004016102a09190610736565b606060405180830381865afa1580156102bb573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906102df91906109e9565b91509150915091565b5f5f5f9054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663ee5b48eb84846040518363ffffffff1660e01b8152600401610344929190610a71565b6020604051808303815f875af1158015610360573d5f5f3e3d5ffd5b505050506040513d601f19601f8201168201806040525081019061038491906106fc565b905092915050565b60405180606001604052805f81526020015f73ffffffffffffffffffffffffffffffffffffffff168152602001606081525090565b60405180604001604052805f81526020015f81525090565b5f819050919050565b6103eb816103d9565b82525050565b5f6020820190506104045f8301846103e2565b92915050565b5f604051905090565b5f5ffd5b5f5ffd5b5f63ffffffff82169050919050565b6104338161041b565b811461043d575f5ffd5b50565b5f8135905061044e8161042a565b92915050565b5f6020828403121561046957610468610413565b5b5f61047684828501610440565b91505092915050565b610488816103d9565b82525050565b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6104b78261048e565b9050919050565b6104c7816104ad565b82525050565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f61050f826104cd565b61051981856104d7565b93506105298185602086016104e7565b610532816104f5565b840191505092915050565b5f606083015f8301516105525f86018261047f565b50602083015161056560208601826104be565b506040830151848203604086015261057d8282610505565b9150508091505092915050565b5f8115159050919050565b61059e8161058a565b82525050565b5f6040820190508181035f8301526105bc818561053d565b90506105cb6020830184610595565b9392505050565b604082015f8201516105e65f85018261047f565b5060208201516105f9602085018261047f565b50505050565b5f6060820190506106125f8301856105d2565b61061f6040830184610595565b9392505050565b5f5ffd5b5f5ffd5b5f5ffd5b5f5f83601f84011261064757610646610626565b5b8235905067ffffffffffffffff8111156106645761066361062a565b5b6020830191508360018202830111156106805761067f61062e565b5b9250929050565b5f5f6020838503121561069d5761069c610413565b5b5f83013567ffffffffffffffff8111156106ba576106b9610417565b5b6106c685828601610632565b92509250509250929050565b6106db816103d9565b81146106e5575f5ffd5b50565b5f815190506106f6816106d2565b92915050565b5f6020828403121561071157610710610413565b5b5f61071e848285016106e8565b91505092915050565b6107308161041b565b82525050565b5f6020820190506107495f830184610727565b92915050565b5f5ffd5b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffd5b610789826104f5565b810181811067ffffffffffffffff821117156107a8576107a7610753565b5b80604052505050565b5f6107ba61040a565b90506107c68282610780565b919050565b5f5ffd5b6107d8816104ad565b81146107e2575f5ffd5b50565b5f815190506107f3816107cf565b92915050565b5f5ffd5b5f67ffffffffffffffff82111561081757610816610753565b5b610820826104f5565b9050602081019050919050565b5f61083f61083a846107fd565b6107b1565b90508281526020810184848401111561085b5761085a6107f9565b5b6108668482856104e7565b509392505050565b5f82601f83011261088257610881610626565b5b815161089284826020860161082d565b91505092915050565b5f606082840312156108b0576108af61074f565b5b6108ba60606107b1565b90505f6108c9848285016106e8565b5f8301525060206108dc848285016107e5565b602083015250604082015167ffffffffffffffff811115610900576108ff6107cb565b5b61090c8482850161086e565b60408301525092915050565b6109218161058a565b811461092b575f5ffd5b50565b5f8151905061093c81610918565b92915050565b5f5f6040838503121561095857610957610413565b5b5f83015167ffffffffffffffff81111561097557610974610417565b5b6109818582860161089b565b92505060206109928582860161092e565b9150509250929050565b5f604082840312156109b1576109b061074f565b5b6109bb60406107b1565b90505f6109ca848285016106e8565b5f8301525060206109dd848285016106e8565b60208301525092915050565b5f5f606083850312156109ff576109fe610413565b5b5f610a0c8582860161099c565b9250506040610a1d8582860161092e565b9150509250929050565b5f82825260208201905092915050565b828183375f83830152505050565b5f610a508385610a27565b9350610a5d838584610a37565b610a66836104f5565b840190509392505050565b5f6020820190508181035f830152610a8a818486610a45565b9050939250505056fea26469706673582212208d14f752848aa9d15d2a4fdb9190892ea8e4d281777679d708d9c3996ea7358f64736f6c634300081e0033", +} + +// WarpTestABI is the input ABI used to generate the binding from. +// Deprecated: Use WarpTestMetaData.ABI instead. +var WarpTestABI = WarpTestMetaData.ABI + +// WarpTestBin is the compiled bytecode used for deploying new contracts. +// Deprecated: Use WarpTestMetaData.Bin instead. +var WarpTestBin = WarpTestMetaData.Bin + +// DeployWarpTest deploys a new Ethereum contract, binding an instance of WarpTest to it. +func DeployWarpTest(auth *bind.TransactOpts, backend bind.ContractBackend, warpPrecompile common.Address) (common.Address, *types.Transaction, *WarpTest, error) { + parsed, err := WarpTestMetaData.GetAbi() + if err != nil { + return common.Address{}, nil, nil, err + } + if parsed == nil { + return common.Address{}, nil, nil, errors.New("GetABI returned nil") + } + + address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex(WarpTestBin), backend, warpPrecompile) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, &WarpTest{WarpTestCaller: WarpTestCaller{contract: contract}, WarpTestTransactor: WarpTestTransactor{contract: contract}, WarpTestFilterer: WarpTestFilterer{contract: contract}}, nil +} + +// WarpTest is an auto generated Go binding around an Ethereum contract. +type WarpTest struct { + WarpTestCaller // Read-only binding to the contract + WarpTestTransactor // Write-only binding to the contract + WarpTestFilterer // Log filterer for contract events +} + +// WarpTestCaller is an auto generated read-only Go binding around an Ethereum contract. +type WarpTestCaller struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// WarpTestTransactor is an auto generated write-only Go binding around an Ethereum contract. +type WarpTestTransactor struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// WarpTestFilterer is an auto generated log filtering Go binding around an Ethereum contract events. +type WarpTestFilterer struct { + contract *bind.BoundContract // Generic contract wrapper for the low level calls +} + +// WarpTestSession is an auto generated Go binding around an Ethereum contract, +// with pre-set call and transact options. +type WarpTestSession struct { + Contract *WarpTest // Generic contract binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// WarpTestCallerSession is an auto generated read-only Go binding around an Ethereum contract, +// with pre-set call options. +type WarpTestCallerSession struct { + Contract *WarpTestCaller // Generic contract caller binding to set the session for + CallOpts bind.CallOpts // Call options to use throughout this session +} + +// WarpTestTransactorSession is an auto generated write-only Go binding around an Ethereum contract, +// with pre-set transact options. +type WarpTestTransactorSession struct { + Contract *WarpTestTransactor // Generic contract transactor binding to set the session for + TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session +} + +// WarpTestRaw is an auto generated low-level Go binding around an Ethereum contract. +type WarpTestRaw struct { + Contract *WarpTest // Generic contract binding to access the raw methods on +} + +// WarpTestCallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract. +type WarpTestCallerRaw struct { + Contract *WarpTestCaller // Generic read-only contract binding to access the raw methods on +} + +// WarpTestTransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract. +type WarpTestTransactorRaw struct { + Contract *WarpTestTransactor // Generic write-only contract binding to access the raw methods on +} + +// NewWarpTest creates a new instance of WarpTest, bound to a specific deployed contract. +func NewWarpTest(address common.Address, backend bind.ContractBackend) (*WarpTest, error) { + contract, err := bindWarpTest(address, backend, backend, backend) + if err != nil { + return nil, err + } + return &WarpTest{WarpTestCaller: WarpTestCaller{contract: contract}, WarpTestTransactor: WarpTestTransactor{contract: contract}, WarpTestFilterer: WarpTestFilterer{contract: contract}}, nil +} + +// NewWarpTestCaller creates a new read-only instance of WarpTest, bound to a specific deployed contract. +func NewWarpTestCaller(address common.Address, caller bind.ContractCaller) (*WarpTestCaller, error) { + contract, err := bindWarpTest(address, caller, nil, nil) + if err != nil { + return nil, err + } + return &WarpTestCaller{contract: contract}, nil +} + +// NewWarpTestTransactor creates a new write-only instance of WarpTest, bound to a specific deployed contract. +func NewWarpTestTransactor(address common.Address, transactor bind.ContractTransactor) (*WarpTestTransactor, error) { + contract, err := bindWarpTest(address, nil, transactor, nil) + if err != nil { + return nil, err + } + return &WarpTestTransactor{contract: contract}, nil +} + +// NewWarpTestFilterer creates a new log filterer instance of WarpTest, bound to a specific deployed contract. +func NewWarpTestFilterer(address common.Address, filterer bind.ContractFilterer) (*WarpTestFilterer, error) { + contract, err := bindWarpTest(address, nil, nil, filterer) + if err != nil { + return nil, err + } + return &WarpTestFilterer{contract: contract}, nil +} + +// bindWarpTest binds a generic wrapper to an already deployed contract. +func bindWarpTest(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) { + parsed, err := WarpTestMetaData.GetAbi() + if err != nil { + return nil, err + } + return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_WarpTest *WarpTestRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _WarpTest.Contract.WarpTestCaller.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_WarpTest *WarpTestRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _WarpTest.Contract.WarpTestTransactor.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_WarpTest *WarpTestRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _WarpTest.Contract.WarpTestTransactor.contract.Transact(opts, method, params...) +} + +// Call invokes the (constant) contract method with params as input values and +// sets the output to result. The result type might be a single field for simple +// returns, a slice of interfaces for anonymous returns and a struct for named +// returns. +func (_WarpTest *WarpTestCallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error { + return _WarpTest.Contract.contract.Call(opts, result, method, params...) +} + +// Transfer initiates a plain transaction to move funds to the contract, calling +// its default method if one is available. +func (_WarpTest *WarpTestTransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) { + return _WarpTest.Contract.contract.Transfer(opts) +} + +// Transact invokes the (paid) contract method with params as input values. +func (_WarpTest *WarpTestTransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) { + return _WarpTest.Contract.contract.Transact(opts, method, params...) +} + +// GetBlockchainID is a free data retrieval call binding the contract method 0x4213cf78. +// +// Solidity: function getBlockchainID() view returns(bytes32) +func (_WarpTest *WarpTestCaller) GetBlockchainID(opts *bind.CallOpts) ([32]byte, error) { + var out []interface{} + err := _WarpTest.contract.Call(opts, &out, "getBlockchainID") + + if err != nil { + return *new([32]byte), err + } + + out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte) + + return out0, err + +} + +// GetBlockchainID is a free data retrieval call binding the contract method 0x4213cf78. +// +// Solidity: function getBlockchainID() view returns(bytes32) +func (_WarpTest *WarpTestSession) GetBlockchainID() ([32]byte, error) { + return _WarpTest.Contract.GetBlockchainID(&_WarpTest.CallOpts) +} + +// GetBlockchainID is a free data retrieval call binding the contract method 0x4213cf78. +// +// Solidity: function getBlockchainID() view returns(bytes32) +func (_WarpTest *WarpTestCallerSession) GetBlockchainID() ([32]byte, error) { + return _WarpTest.Contract.GetBlockchainID(&_WarpTest.CallOpts) +} + +// GetVerifiedWarpBlockHash is a free data retrieval call binding the contract method 0xce7f5929. +// +// Solidity: function getVerifiedWarpBlockHash(uint32 index) view returns((bytes32,bytes32) warpBlockHash, bool valid) +func (_WarpTest *WarpTestCaller) GetVerifiedWarpBlockHash(opts *bind.CallOpts, index uint32) (struct { + WarpBlockHash WarpBlockHash + Valid bool +}, error) { + var out []interface{} + err := _WarpTest.contract.Call(opts, &out, "getVerifiedWarpBlockHash", index) + + outstruct := new(struct { + WarpBlockHash WarpBlockHash + Valid bool + }) + if err != nil { + return *outstruct, err + } + + outstruct.WarpBlockHash = *abi.ConvertType(out[0], new(WarpBlockHash)).(*WarpBlockHash) + outstruct.Valid = *abi.ConvertType(out[1], new(bool)).(*bool) + + return *outstruct, err + +} + +// GetVerifiedWarpBlockHash is a free data retrieval call binding the contract method 0xce7f5929. +// +// Solidity: function getVerifiedWarpBlockHash(uint32 index) view returns((bytes32,bytes32) warpBlockHash, bool valid) +func (_WarpTest *WarpTestSession) GetVerifiedWarpBlockHash(index uint32) (struct { + WarpBlockHash WarpBlockHash + Valid bool +}, error) { + return _WarpTest.Contract.GetVerifiedWarpBlockHash(&_WarpTest.CallOpts, index) +} + +// GetVerifiedWarpBlockHash is a free data retrieval call binding the contract method 0xce7f5929. +// +// Solidity: function getVerifiedWarpBlockHash(uint32 index) view returns((bytes32,bytes32) warpBlockHash, bool valid) +func (_WarpTest *WarpTestCallerSession) GetVerifiedWarpBlockHash(index uint32) (struct { + WarpBlockHash WarpBlockHash + Valid bool +}, error) { + return _WarpTest.Contract.GetVerifiedWarpBlockHash(&_WarpTest.CallOpts, index) +} + +// GetVerifiedWarpMessage is a free data retrieval call binding the contract method 0x6f825350. +// +// Solidity: function getVerifiedWarpMessage(uint32 index) view returns((bytes32,address,bytes) message, bool valid) +func (_WarpTest *WarpTestCaller) GetVerifiedWarpMessage(opts *bind.CallOpts, index uint32) (struct { + Message WarpMessage + Valid bool +}, error) { + var out []interface{} + err := _WarpTest.contract.Call(opts, &out, "getVerifiedWarpMessage", index) + + outstruct := new(struct { + Message WarpMessage + Valid bool + }) + if err != nil { + return *outstruct, err + } + + outstruct.Message = *abi.ConvertType(out[0], new(WarpMessage)).(*WarpMessage) + outstruct.Valid = *abi.ConvertType(out[1], new(bool)).(*bool) + + return *outstruct, err + +} + +// GetVerifiedWarpMessage is a free data retrieval call binding the contract method 0x6f825350. +// +// Solidity: function getVerifiedWarpMessage(uint32 index) view returns((bytes32,address,bytes) message, bool valid) +func (_WarpTest *WarpTestSession) GetVerifiedWarpMessage(index uint32) (struct { + Message WarpMessage + Valid bool +}, error) { + return _WarpTest.Contract.GetVerifiedWarpMessage(&_WarpTest.CallOpts, index) +} + +// GetVerifiedWarpMessage is a free data retrieval call binding the contract method 0x6f825350. +// +// Solidity: function getVerifiedWarpMessage(uint32 index) view returns((bytes32,address,bytes) message, bool valid) +func (_WarpTest *WarpTestCallerSession) GetVerifiedWarpMessage(index uint32) (struct { + Message WarpMessage + Valid bool +}, error) { + return _WarpTest.Contract.GetVerifiedWarpMessage(&_WarpTest.CallOpts, index) +} + +// SendWarpMessage is a paid mutator transaction binding the contract method 0xee5b48eb. +// +// Solidity: function sendWarpMessage(bytes payload) returns(bytes32 messageID) +func (_WarpTest *WarpTestTransactor) SendWarpMessage(opts *bind.TransactOpts, payload []byte) (*types.Transaction, error) { + return _WarpTest.contract.Transact(opts, "sendWarpMessage", payload) +} + +// SendWarpMessage is a paid mutator transaction binding the contract method 0xee5b48eb. +// +// Solidity: function sendWarpMessage(bytes payload) returns(bytes32 messageID) +func (_WarpTest *WarpTestSession) SendWarpMessage(payload []byte) (*types.Transaction, error) { + return _WarpTest.Contract.SendWarpMessage(&_WarpTest.TransactOpts, payload) +} + +// SendWarpMessage is a paid mutator transaction binding the contract method 0xee5b48eb. +// +// Solidity: function sendWarpMessage(bytes payload) returns(bytes32 messageID) +func (_WarpTest *WarpTestTransactorSession) SendWarpMessage(payload []byte) (*types.Transaction, error) { + return _WarpTest.Contract.SendWarpMessage(&_WarpTest.TransactOpts, payload) +} diff --git a/tests/warp/warp_test.go b/tests/warp/warp_test.go index e715a30907..e118087b39 100644 --- a/tests/warp/warp_test.go +++ b/tests/warp/warp_test.go @@ -7,12 +7,9 @@ package warp import ( "context" "crypto/ecdsa" - "encoding/hex" "fmt" "math/big" - "os" "path/filepath" - "strconv" "strings" "testing" "time" @@ -32,6 +29,7 @@ import ( "github.com/ava-labs/libevm/log" "github.com/stretchr/testify/require" + "github.com/ava-labs/subnet-evm/accounts/abi/bind" "github.com/ava-labs/subnet-evm/cmd/simulator/key" "github.com/ava-labs/subnet-evm/cmd/simulator/load" "github.com/ava-labs/subnet-evm/cmd/simulator/metrics" @@ -39,11 +37,14 @@ import ( "github.com/ava-labs/subnet-evm/ethclient" "github.com/ava-labs/subnet-evm/params" "github.com/ava-labs/subnet-evm/precompile/contracts/warp" + "github.com/ava-labs/subnet-evm/precompile/contracts/warp/warpbindings" "github.com/ava-labs/subnet-evm/tests" "github.com/ava-labs/subnet-evm/tests/utils" avalancheWarp "github.com/ava-labs/avalanchego/vms/platformvm/warp" + warpPayload "github.com/ava-labs/avalanchego/vms/platformvm/warp/payload" ethereum "github.com/ava-labs/libevm" + warptestbindings "github.com/ava-labs/subnet-evm/precompile/contracts/warp/warptest/bindings" warpBackend "github.com/ava-labs/subnet-evm/warp" ginkgo "github.com/onsi/ginkgo/v2" ) @@ -171,8 +172,8 @@ var _ = ginkgo.Describe("[Warp]", func() { log.Info("Delivering block hash payload to receiving subnet") w.deliverBlockHashPayload() - log.Info("Executing HardHat test") - w.executeHardHatTest() + log.Info("bindings test: verifying warp message and blockchain ID") + w.warpBindingsTest() log.Info("Executing warp load test") w.warpLoad() @@ -292,8 +293,37 @@ func (w *warpTest) sendMessageFromSendingSubnet() { tc := e2e.NewTestContext() ctx := tc.DefaultContext() require := require.New(ginkgo.GinkgoT()) - client := w.sendingSubnetClients[0] + + blockHash, blockNumber := w.sendWarpMessageTx(ctx, client) + w.blockID = ids.ID(blockHash) + + w.addressedCallUnsignedMessage = verifyAndExtractWarpMessage(ctx, client, blockNumber, w.sendingSubnetFundedAddress) + log.Info("Parsed unsignedWarpMsg", + "unsignedWarpMessageID", w.addressedCallUnsignedMessage.ID(), + "unsignedWarpMessage", w.addressedCallUnsignedMessage, + ) + + // Loop over each client on chain A to ensure they all have time to accept the block. + // Note: if we did not confirm this here, the next stage could be racy since it assumes every node + // has accepted the block. + for i, client := range w.sendingSubnetClients { + // Loop until each node has advanced to >= the height of the block that emitted the warp log + for { + block, err := client.BlockByNumber(ctx, nil) + require.NoError(err) + if block.NumberU64() >= blockNumber { + log.Info("client accepted the block containing SendWarpMessage", "client", i, "height", block.NumberU64()) + break + } + } + } +} + +// sendWarpMessageTx sends a warp message and returns the block hash and number +func (w *warpTest) sendWarpMessageTx(ctx context.Context, client ethclient.Client) (common.Hash, uint64) { + require := require.New(ginkgo.GinkgoT()) + log.Info("Subscribing to new heads") newHeads := make(chan *types.Header, 10) sub, err := client.SubscribeNewHead(ctx, newHeads) @@ -305,6 +335,7 @@ func (w *warpTest) sendMessageFromSendingSubnet() { packedInput, err := warp.PackSendWarpMessage(testPayload) require.NoError(err) + tx := types.NewTx(&types.DynamicFeeTx{ ChainID: w.sendingSubnetChainID, Nonce: startingNonce, @@ -315,54 +346,68 @@ func (w *warpTest) sendMessageFromSendingSubnet() { Value: common.Big0, Data: packedInput, }) + signedTx, err := types.SignTx(tx, w.sendingSubnetSigner, w.sendingSubnetFundedKey) require.NoError(err) + log.Info("Sending sendWarpMessage transaction", "txHash", signedTx.Hash()) require.NoError(client.SendTransaction(ctx, signedTx)) - log.Info("Waiting for new block confirmation") <-newHeads receiptCtx, cancel := context.WithTimeout(ctx, 10*time.Second) defer cancel() + blockHash, blockNumber := w.getBlockHashAndNumberFromTxReceipt(receiptCtx, client, signedTx) + log.Info("Warp message included in block", "blockHash", blockHash, "blockNumber", blockNumber) - log.Info("Constructing warp block hash unsigned message", "blockHash", blockHash) - w.blockID = ids.ID(blockHash) // Set blockID to construct a warp message containing a block hash payload later + return blockHash, blockNumber +} + +// verifyAndExtractWarpMessage queries the given block for SendWarpMessage events +// emitted by the specified sender using the IWarpMessengerFilterer binding. It +// asserts that exactly one such event exists and returns the parsed unsigned +// warp message. +func verifyAndExtractWarpMessage( + ctx context.Context, + client ethclient.Client, + blockNumber uint64, + sender common.Address, +) *avalancheWarp.UnsignedMessage { + require := require.New(ginkgo.GinkgoT()) + + log.Info("Filtering SendWarpMessage events using binding") + warpFilterer, err := warpbindings.NewIWarpMessengerFilterer(warp.Module.Address, client) require.NoError(err) - log.Info("Fetching relevant warp logs from the newly produced block") - logs, err := client.FilterLogs(ctx, ethereum.FilterQuery{ - BlockHash: &blockHash, - Addresses: []common.Address{warp.Module.Address}, - }) + iter, err := warpFilterer.FilterSendWarpMessage( + &bind.FilterOpts{ + Start: blockNumber, + End: &blockNumber, + Context: ctx, + }, + []common.Address{sender}, + nil, // messageID filter: any + ) require.NoError(err) - require.Len(logs, 1) + defer iter.Close() - // Check for relevant warp log from subscription and ensure that it matches - // the log extracted from the last block. - txLog := logs[0] - log.Info("Parsing logData as unsigned warp message") - unsignedMsg, err := warp.UnpackSendWarpEventDataToMessage(txLog.Data) + require.True(iter.Next(), "expected a SendWarpMessage event") + event := iter.Event + + log.Info("Found SendWarpMessage event", + "sender", event.Sender.Hex(), + "messageID", common.Bytes2Hex(event.MessageID[:]), + ) + + require.Equal(sender, event.Sender) + + unsignedMessage, err := avalancheWarp.ParseUnsignedMessage(event.Message) require.NoError(err) - // Set local variables for the duration of the test - w.addressedCallUnsignedMessage = unsignedMsg - log.Info("Parsed unsignedWarpMsg", "unsignedWarpMessageID", w.addressedCallUnsignedMessage.ID(), "unsignedWarpMessage", w.addressedCallUnsignedMessage) + require.False(iter.Next(), "expected exactly one SendWarpMessage event") + require.NoError(iter.Error()) - // Loop over each client on chain A to ensure they all have time to accept the block. - // Note: if we did not confirm this here, the next stage could be racy since it assumes every node - // has accepted the block. - for i, client := range w.sendingSubnetClients { - // Loop until each node has advanced to >= the height of the block that emitted the warp log - for { - block, err := client.BlockByNumber(ctx, nil) - require.NoError(err) - if block.NumberU64() >= blockNumber { - log.Info("client accepted the block containing SendWarpMessage", "client", i, "height", block.NumberU64()) - break - } - } - } + return unsignedMessage } func (w *warpTest) aggregateSignaturesViaAPI() { @@ -549,33 +594,54 @@ func (w *warpTest) deliverBlockHashPayload() { require.Equal(types.ReceiptStatusSuccessful, receipt.Status) } -func (w *warpTest) executeHardHatTest() { +func (w *warpTest) warpBindingsTest() { require := require.New(ginkgo.GinkgoT()) tc := e2e.NewTestContext() ctx := tc.DefaultContext() client := w.sendingSubnetClients[0] - log.Info("Subscribing to new heads") - newHeads := make(chan *types.Header, 10) - sub, err := client.SubscribeNewHead(ctx, newHeads) + + log.Info("Deploying WarpTest proxy contract") + auth, err := bind.NewKeyedTransactorWithChainID(w.sendingSubnetFundedKey, w.sendingSubnetChainID) require.NoError(err) - defer sub.Unsubscribe() + auth.Context = ctx + + proxyAddr, deployTx, warpTestContract, err := warptestbindings.DeployWarpTest(auth, client, warp.Module.Address) + require.NoError(err) + + log.Info("Waiting for WarpTest deployment", "txHash", deployTx.Hash(), "proxyAddr", proxyAddr) + deployReceipt, err := bind.WaitMined(ctx, client, deployTx) + require.NoError(err) + require.Equal(types.ReceiptStatusSuccessful, deployReceipt.Status) + + log.Info("Calling getBlockchainID via proxy contract") + returnedBlockchainID, err := warpTestContract.GetBlockchainID(&bind.CallOpts{Context: ctx}) + require.NoError(err) + require.Equal(w.sendingSubnet.BlockchainID, ids.ID(returnedBlockchainID)) + log.Info("getBlockchainID returned correct value", "blockchainID", ids.ID(returnedBlockchainID)) + + log.Info("Sending warp message via proxy contract", "payload", common.Bytes2Hex(testPayload)) - chainID, err := client.ChainID(ctx) + sendTx, err := warpTestContract.SendWarpMessage(auth, testPayload) require.NoError(err) - rpcURI := toRPCURI(w.sendingSubnetURIs[0], w.sendingSubnet.BlockchainID.String()) + log.Info("Waiting for sendWarpMessage transaction", "txHash", sendTx.Hash()) + sendReceipt, err := bind.WaitMined(ctx, client, sendTx) + require.NoError(err) + require.Equal(types.ReceiptStatusSuccessful, sendReceipt.Status) - os.Setenv("SENDER_ADDRESS", crypto.PubkeyToAddress(w.sendingSubnetFundedKey.PublicKey).Hex()) - os.Setenv("SOURCE_CHAIN_ID", "0x"+w.sendingSubnet.BlockchainID.Hex()) - os.Setenv("PAYLOAD", "0x"+common.Bytes2Hex(testPayload)) - os.Setenv("EXPECTED_UNSIGNED_MESSAGE", "0x"+hex.EncodeToString(w.addressedCallUnsignedMessage.Bytes())) - os.Setenv("CHAIN_ID", strconv.FormatUint(chainID.Uint64(), 10)) + unsignedMsg := verifyAndExtractWarpMessage(ctx, client, sendReceipt.BlockNumber.Uint64(), proxyAddr) + + addressedCall, err := warpPayload.ParseAddressedCall(unsignedMsg.Payload) + require.NoError(err) - cmdPath := filepath.Join(repoRootPath, "contracts") - // test path is relative to the cmd path - testPath := "./test/warp.ts" - utils.RunHardhatTestsCustomURI(ctx, rpcURI, cmdPath, testPath) + require.Equal(testPayload, addressedCall.Payload, "payload mismatch in warp message") + require.Equal(proxyAddr.Bytes(), addressedCall.SourceAddress, "source address should be proxy contract") + + log.Info("warp bindings test complete", + "proxyAddr", proxyAddr.Hex(), + "blockchainID", ids.ID(returnedBlockchainID), + ) } func (w *warpTest) warpLoad() { @@ -722,7 +788,3 @@ func generateKeys(preFundedKey *ecdsa.PrivateKey, numWorkers int) ([]*key.Key, [ func toWebsocketURI(uri string, blockchainID string) string { return fmt.Sprintf("ws://%s/ext/bc/%s/ws", strings.TrimPrefix(uri, "http://"), blockchainID) } - -func toRPCURI(uri string, blockchainID string) string { - return fmt.Sprintf("%s/ext/bc/%s/rpc", uri, blockchainID) -}