diff --git a/packages/solo/chain.go b/packages/solo/chain.go index 82ad14e20c..44966443ba 100644 --- a/packages/solo/chain.go +++ b/packages/solo/chain.go @@ -5,18 +5,27 @@ package solo import ( "context" + "crypto/ecdsa" "errors" "fmt" "io" "math" + "math/big" "os" + "strings" "time" + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" "github.com/stretchr/testify/require" iotago "github.com/iotaledger/iota.go/v3" "github.com/iotaledger/wasp/packages/chain" "github.com/iotaledger/wasp/packages/cryptolib" + "github.com/iotaledger/wasp/packages/evm/evmutil" "github.com/iotaledger/wasp/packages/hashing" "github.com/iotaledger/wasp/packages/isc" "github.com/iotaledger/wasp/packages/kv" @@ -275,6 +284,42 @@ func (ch *Chain) DeployWasmContract(keyPair *cryptolib.KeyPair, name, fname stri return ch.DeployContract(keyPair, name, hprog, params...) } +// DeployEVMContract deploys an evm contract on the chain +func (ch *Chain) DeployEVMContract(creator *ecdsa.PrivateKey, abiJSON string, bytecode []byte, args ...interface{}) (common.Address, abi.ABI) { + creatorAddress := crypto.PubkeyToAddress(creator.PublicKey) + + nonce := ch.Nonce(isc.NewEthereumAddressAgentID(ch.ChainID, creatorAddress)) + + contractABI, err := abi.JSON(strings.NewReader(abiJSON)) + require.NoError(ch.Env.T, err) + constructorArguments, err := contractABI.Pack("", args...) + require.NoError(ch.Env.T, err) + + data := []byte{} + data = append(data, bytecode...) + data = append(data, constructorArguments...) + + value := big.NewInt(0) + + gasLimit, err := ch.EVM().EstimateGas(ethereum.CallMsg{ + From: creatorAddress, + Value: value, + Data: data, + }, nil) + require.NoError(ch.Env.T, err) + + tx, err := types.SignTx( + types.NewContractCreation(nonce, value, gasLimit, ch.EVM().GasPrice(), data), + evmutil.Signer(big.NewInt(int64(ch.EVM().ChainID()))), + creator, + ) + require.NoError(ch.Env.T, err) + + err = ch.EVM().SendTransaction(tx) + require.NoError(ch.Env.T, err) + return crypto.CreateAddress(creatorAddress, nonce), contractABI +} + // GetInfo return main parameters of the chain: // - chainID // - agentID of the chain owner diff --git a/packages/vm/core/evm/evmtest/contractInstance.go b/packages/vm/core/evm/evmtest/contractInstance.go index dc189273ba..d9452b21dc 100644 --- a/packages/vm/core/evm/evmtest/contractInstance.go +++ b/packages/vm/core/evm/evmtest/contractInstance.go @@ -13,6 +13,7 @@ import ( "github.com/ethereum/go-ethereum/rpc" "github.com/stretchr/testify/require" + "github.com/iotaledger/wasp/packages/evm/evmutil" "github.com/iotaledger/wasp/packages/isc" ) @@ -103,7 +104,7 @@ func (e *EVMContractInstance) buildEthTx(opts []ethCallOptions, fnName string, a unsignedTx := types.NewTransaction(nonce, e.address, opt.value, opt.gasLimit, opt.gasPrice, callData) - return types.SignTx(unsignedTx, e.chain.getSigner(), opt.sender) + return types.SignTx(unsignedTx, evmutil.Signer(big.NewInt(int64(e.chain.evmChain.ChainID()))), opt.sender) } func (e *EVMContractInstance) estimateGas(opts []ethCallOptions, fnName string, args ...interface{}) (uint64, error) { diff --git a/packages/vm/core/evm/evmtest/evm_test.go b/packages/vm/core/evm/evmtest/evm_test.go index 87e04671b3..fb84893ee8 100644 --- a/packages/vm/core/evm/evmtest/evm_test.go +++ b/packages/vm/core/evm/evmtest/evm_test.go @@ -1598,7 +1598,7 @@ func TestEVMGasPriceMismatch(t *testing.T) { nonce := storage.chain.getNonce(senderAddress) unsignedTx := types.NewTransaction(nonce, storage.address, util.Big0, env.maxGasLimit(), gasPrice, callArguments) - tx, err := types.SignTx(unsignedTx, storage.chain.getSigner(), ethKey) + tx, err := types.SignTx(unsignedTx, evmutil.Signer(big.NewInt(int64(storage.chain.evmChain.ChainID()))), ethKey) require.NoError(t, err) err = storage.chain.evmChain.SendTransaction(tx) @@ -2201,9 +2201,16 @@ func TestPreEIP155Transaction(t *testing.T) { env := InitEVM(t) ethKey, _ := env.Chain.EthereumAccountByIndexWithL2Funds(0) - // set a signer without replay protection - env.setSigner(types.HomesteadSigner{}) + // use a signer without replay protection + signer := types.HomesteadSigner{} - // deploy solidity `storage` contract, it should suceeed - env.deployStorageContract(ethKey) + tx, err := types.SignTx( + types.NewContractCreation(0, big.NewInt(1_000_000_000), 1_000_000_000, env.evmChain.GasPrice(), nil), + signer, + ethKey, + ) + require.NoError(t, err) + + err = env.evmChain.SendTransaction(tx) + require.NoError(t, err) } diff --git a/packages/vm/core/evm/evmtest/setup.go b/packages/vm/core/evm/evmtest/setup.go index 060ce4125d..71e3fcdae2 100644 --- a/packages/vm/core/evm/evmtest/setup.go +++ b/packages/vm/core/evm/evmtest/setup.go @@ -6,11 +6,9 @@ import ( "strings" "testing" - "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/crypto" "github.com/stretchr/testify/require" iotago "github.com/iotaledger/iota.go/v3" @@ -258,14 +256,6 @@ func (e *SoloChainEnv) deployERC20ExampleContract(creator *ecdsa.PrivateKey) *er return &erc20ContractInstance{e.DeployContract(creator, evmtest.ERC20ExampleContractABI, evmtest.ERC20ExampleContractBytecode)} } -func (e *SoloChainEnv) setSigner(s types.Signer) { - e.signer = s -} - -func (e *SoloChainEnv) getSigner() types.Signer { - return e.signer -} - func (e *SoloChainEnv) maxGasLimit() uint64 { fp := e.Chain.GetGasFeePolicy() gl := e.Chain.GetGasLimits() @@ -273,42 +263,12 @@ func (e *SoloChainEnv) maxGasLimit() uint64 { } func (e *SoloChainEnv) DeployContract(creator *ecdsa.PrivateKey, abiJSON string, bytecode []byte, args ...interface{}) *EVMContractInstance { - creatorAddress := crypto.PubkeyToAddress(creator.PublicKey) - - nonce := e.getNonce(creatorAddress) - - contractABI, err := abi.JSON(strings.NewReader(abiJSON)) - require.NoError(e.t, err) - constructorArguments, err := contractABI.Pack("", args...) - require.NoError(e.t, err) - - data := []byte{} - data = append(data, bytecode...) - data = append(data, constructorArguments...) - - value := big.NewInt(0) - - gasLimit, err := e.evmChain.EstimateGas(ethereum.CallMsg{ - From: creatorAddress, - Value: value, - Data: data, - }, nil) - require.NoError(e.t, err) - - tx, err := types.SignTx( - types.NewContractCreation(nonce, value, gasLimit, e.evmChain.GasPrice(), data), - e.getSigner(), - creator, - ) - require.NoError(e.t, err) - - err = e.evmChain.SendTransaction(tx) - require.NoError(e.t, err) + contractAddr, contractABI := e.Chain.DeployEVMContract(creator, abiJSON, bytecode, args...) return &EVMContractInstance{ chain: e, defaultSender: creator, - address: crypto.CreateAddress(creatorAddress, nonce), + address: contractAddr, abi: contractABI, } }