| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376 |
- // Copyright 2019 The go-ethereum Authors
- // This file is part of the go-ethereum library.
- //
- // The go-ethereum library is free software: you can redistribute it and/or modify
- // it under the terms of the GNU Lesser General Public License as published by
- // the Free Software Foundation, either version 3 of the License, or
- // (at your option) any later version.
- //
- // The go-ethereum library is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- // GNU Lesser General Public License for more details.
- //
- // You should have received a copy of the GNU Lesser General Public License
- // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
- package backends
- import (
- "bytes"
- "context"
- "errors"
- "math/big"
- "math/rand"
- "reflect"
- "strings"
- "testing"
- "time"
- "github.com/ethereum/go-ethereum"
- "github.com/ethereum/go-ethereum/accounts/abi"
- "github.com/ethereum/go-ethereum/accounts/abi/bind"
- "github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/core"
- "github.com/ethereum/go-ethereum/core/types"
- "github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/params"
- )
- func TestSimulatedBackend(t *testing.T) {
- var gasLimit uint64 = 8000029
- key, _ := crypto.GenerateKey() // nolint: gosec
- auth, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
- genAlloc := make(core.GenesisAlloc)
- genAlloc[auth.From] = core.GenesisAccount{Balance: big.NewInt(9223372036854775807)}
- sim := NewSimulatedBackend(genAlloc, gasLimit)
- defer sim.Close()
- // should return an error if the tx is not found
- txHash := common.HexToHash("2")
- _, isPending, err := sim.TransactionByHash(context.Background(), txHash)
- if isPending {
- t.Fatal("transaction should not be pending")
- }
- if err != ethereum.NotFound {
- t.Fatalf("err should be `ethereum.NotFound` but received %v", err)
- }
- // generate a transaction and confirm you can retrieve it
- head, _ := sim.HeaderByNumber(context.Background(), nil) // Should be child's, good enough
- gasPrice := new(big.Int).Add(head.BaseFee, big.NewInt(1))
- code := `6060604052600a8060106000396000f360606040526008565b00`
- var gas uint64 = 3000000
- tx := types.NewContractCreation(0, big.NewInt(0), gas, gasPrice, common.FromHex(code))
- tx, _ = types.SignTx(tx, types.HomesteadSigner{}, key)
- err = sim.SendTransaction(context.Background(), tx)
- if err != nil {
- t.Fatal("error sending transaction")
- }
- txHash = tx.Hash()
- _, isPending, err = sim.TransactionByHash(context.Background(), txHash)
- if err != nil {
- t.Fatalf("error getting transaction with hash: %v", txHash.String())
- }
- if !isPending {
- t.Fatal("transaction should have pending status")
- }
- sim.Commit()
- _, isPending, err = sim.TransactionByHash(context.Background(), txHash)
- if err != nil {
- t.Fatalf("error getting transaction with hash: %v", txHash.String())
- }
- if isPending {
- t.Fatal("transaction should not have pending status")
- }
- }
- var testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
- // the following is based on this contract:
- // contract T {
- // event received(address sender, uint amount, bytes memo);
- // event receivedAddr(address sender);
- //
- // function receive(bytes calldata memo) external payable returns (string memory res) {
- // emit received(msg.sender, msg.value, memo);
- // emit receivedAddr(msg.sender);
- // return "hello world";
- // }
- // }
- const abiJSON = `[ { "constant": false, "inputs": [ { "name": "memo", "type": "bytes" } ], "name": "receive", "outputs": [ { "name": "res", "type": "string" } ], "payable": true, "stateMutability": "payable", "type": "function" }, { "anonymous": false, "inputs": [ { "indexed": false, "name": "sender", "type": "address" }, { "indexed": false, "name": "amount", "type": "uint256" }, { "indexed": false, "name": "memo", "type": "bytes" } ], "name": "received", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": false, "name": "sender", "type": "address" } ], "name": "receivedAddr", "type": "event" } ]`
- const abiBin = `0x608060405234801561001057600080fd5b506102a0806100206000396000f3fe60806040526004361061003b576000357c010000000000000000000000000000000000000000000000000000000090048063a69b6ed014610040575b600080fd5b6100b76004803603602081101561005657600080fd5b810190808035906020019064010000000081111561007357600080fd5b82018360208201111561008557600080fd5b803590602001918460018302840111640100000000831117156100a757600080fd5b9091929391929390505050610132565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100f75780820151818401526020810190506100dc565b50505050905090810190601f1680156101245780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b60607f75fd880d39c1daf53b6547ab6cb59451fc6452d27caa90e5b6649dd8293b9eed33348585604051808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001848152602001806020018281038252848482818152602001925080828437600081840152601f19601f8201169050808301925050509550505050505060405180910390a17f46923992397eac56cf13058aced2a1871933622717e27b24eabc13bf9dd329c833604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a16040805190810160405280600b81526020017f68656c6c6f20776f726c6400000000000000000000000000000000000000000081525090509291505056fea165627a7a72305820ff0c57dad254cfeda48c9cfb47f1353a558bccb4d1bc31da1dae69315772d29e0029`
- const deployedCode = `60806040526004361061003b576000357c010000000000000000000000000000000000000000000000000000000090048063a69b6ed014610040575b600080fd5b6100b76004803603602081101561005657600080fd5b810190808035906020019064010000000081111561007357600080fd5b82018360208201111561008557600080fd5b803590602001918460018302840111640100000000831117156100a757600080fd5b9091929391929390505050610132565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100f75780820151818401526020810190506100dc565b50505050905090810190601f1680156101245780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b60607f75fd880d39c1daf53b6547ab6cb59451fc6452d27caa90e5b6649dd8293b9eed33348585604051808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001848152602001806020018281038252848482818152602001925080828437600081840152601f19601f8201169050808301925050509550505050505060405180910390a17f46923992397eac56cf13058aced2a1871933622717e27b24eabc13bf9dd329c833604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390a16040805190810160405280600b81526020017f68656c6c6f20776f726c6400000000000000000000000000000000000000000081525090509291505056fea165627a7a72305820ff0c57dad254cfeda48c9cfb47f1353a558bccb4d1bc31da1dae69315772d29e0029`
- // expected return value contains "hello world"
- var expectedReturn = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- func simTestBackend(testAddr common.Address) *SimulatedBackend {
- return NewSimulatedBackend(
- core.GenesisAlloc{
- testAddr: {Balance: big.NewInt(10000000000000000)},
- }, 10000000,
- )
- }
- func TestNewSimulatedBackend(t *testing.T) {
- testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
- expectedBal := big.NewInt(10000000000000000)
- sim := simTestBackend(testAddr)
- defer sim.Close()
- if sim.config != params.AllEthashProtocolChanges {
- t.Errorf("expected sim config to equal params.AllEthashProtocolChanges, got %v", sim.config)
- }
- if sim.blockchain.Config() != params.AllEthashProtocolChanges {
- t.Errorf("expected sim blockchain config to equal params.AllEthashProtocolChanges, got %v", sim.config)
- }
- stateDB, _ := sim.blockchain.State()
- bal := stateDB.GetBalance(testAddr)
- if bal.Cmp(expectedBal) != 0 {
- t.Errorf("expected balance for test address not received. expected: %v actual: %v", expectedBal, bal)
- }
- }
- func TestAdjustTime(t *testing.T) {
- sim := NewSimulatedBackend(
- core.GenesisAlloc{}, 10000000,
- )
- defer sim.Close()
- prevTime := sim.pendingBlock.Time()
- if err := sim.AdjustTime(time.Second); err != nil {
- t.Error(err)
- }
- newTime := sim.pendingBlock.Time()
- if newTime-prevTime != uint64(time.Second.Seconds()) {
- t.Errorf("adjusted time not equal to a second. prev: %v, new: %v", prevTime, newTime)
- }
- }
- func TestNewAdjustTimeFail(t *testing.T) {
- testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
- sim := simTestBackend(testAddr)
- // Create tx and send
- head, _ := sim.HeaderByNumber(context.Background(), nil) // Should be child's, good enough
- gasPrice := new(big.Int).Add(head.BaseFee, big.NewInt(1))
- tx := types.NewTransaction(0, testAddr, big.NewInt(1000), params.TxGas, gasPrice, nil)
- signedTx, err := types.SignTx(tx, types.HomesteadSigner{}, testKey)
- if err != nil {
- t.Errorf("could not sign tx: %v", err)
- }
- sim.SendTransaction(context.Background(), signedTx)
- // AdjustTime should fail on non-empty block
- if err := sim.AdjustTime(time.Second); err == nil {
- t.Error("Expected adjust time to error on non-empty block")
- }
- sim.Commit()
- prevTime := sim.pendingBlock.Time()
- if err := sim.AdjustTime(time.Minute); err != nil {
- t.Error(err)
- }
- newTime := sim.pendingBlock.Time()
- if newTime-prevTime != uint64(time.Minute.Seconds()) {
- t.Errorf("adjusted time not equal to a minute. prev: %v, new: %v", prevTime, newTime)
- }
- // Put a transaction after adjusting time
- tx2 := types.NewTransaction(1, testAddr, big.NewInt(1000), params.TxGas, gasPrice, nil)
- signedTx2, err := types.SignTx(tx2, types.HomesteadSigner{}, testKey)
- if err != nil {
- t.Errorf("could not sign tx: %v", err)
- }
- sim.SendTransaction(context.Background(), signedTx2)
- sim.Commit()
- newTime = sim.pendingBlock.Time()
- if newTime-prevTime >= uint64(time.Minute.Seconds()) {
- t.Errorf("time adjusted, but shouldn't be: prev: %v, new: %v", prevTime, newTime)
- }
- }
- func TestBalanceAt(t *testing.T) {
- testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
- expectedBal := big.NewInt(10000000000000000)
- sim := simTestBackend(testAddr)
- defer sim.Close()
- bgCtx := context.Background()
- bal, err := sim.BalanceAt(bgCtx, testAddr, nil)
- if err != nil {
- t.Error(err)
- }
- if bal.Cmp(expectedBal) != 0 {
- t.Errorf("expected balance for test address not received. expected: %v actual: %v", expectedBal, bal)
- }
- }
- func TestBlockByHash(t *testing.T) {
- sim := NewSimulatedBackend(
- core.GenesisAlloc{}, 10000000,
- )
- defer sim.Close()
- bgCtx := context.Background()
- block, err := sim.BlockByNumber(bgCtx, nil)
- if err != nil {
- t.Errorf("could not get recent block: %v", err)
- }
- blockByHash, err := sim.BlockByHash(bgCtx, block.Hash())
- if err != nil {
- t.Errorf("could not get recent block: %v", err)
- }
- if block.Hash() != blockByHash.Hash() {
- t.Errorf("did not get expected block")
- }
- }
- func TestBlockByNumber(t *testing.T) {
- sim := NewSimulatedBackend(
- core.GenesisAlloc{}, 10000000,
- )
- defer sim.Close()
- bgCtx := context.Background()
- block, err := sim.BlockByNumber(bgCtx, nil)
- if err != nil {
- t.Errorf("could not get recent block: %v", err)
- }
- if block.NumberU64() != 0 {
- t.Errorf("did not get most recent block, instead got block number %v", block.NumberU64())
- }
- // create one block
- sim.Commit()
- block, err = sim.BlockByNumber(bgCtx, nil)
- if err != nil {
- t.Errorf("could not get recent block: %v", err)
- }
- if block.NumberU64() != 1 {
- t.Errorf("did not get most recent block, instead got block number %v", block.NumberU64())
- }
- blockByNumber, err := sim.BlockByNumber(bgCtx, big.NewInt(1))
- if err != nil {
- t.Errorf("could not get block by number: %v", err)
- }
- if blockByNumber.Hash() != block.Hash() {
- t.Errorf("did not get the same block with height of 1 as before")
- }
- }
- func TestNonceAt(t *testing.T) {
- testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
- sim := simTestBackend(testAddr)
- defer sim.Close()
- bgCtx := context.Background()
- nonce, err := sim.NonceAt(bgCtx, testAddr, big.NewInt(0))
- if err != nil {
- t.Errorf("could not get nonce for test addr: %v", err)
- }
- if nonce != uint64(0) {
- t.Errorf("received incorrect nonce. expected 0, got %v", nonce)
- }
- // create a signed transaction to send
- head, _ := sim.HeaderByNumber(context.Background(), nil) // Should be child's, good enough
- gasPrice := new(big.Int).Add(head.BaseFee, big.NewInt(1))
- tx := types.NewTransaction(nonce, testAddr, big.NewInt(1000), params.TxGas, gasPrice, nil)
- signedTx, err := types.SignTx(tx, types.HomesteadSigner{}, testKey)
- if err != nil {
- t.Errorf("could not sign tx: %v", err)
- }
- // send tx to simulated backend
- err = sim.SendTransaction(bgCtx, signedTx)
- if err != nil {
- t.Errorf("could not add tx to pending block: %v", err)
- }
- sim.Commit()
- newNonce, err := sim.NonceAt(bgCtx, testAddr, big.NewInt(1))
- if err != nil {
- t.Errorf("could not get nonce for test addr: %v", err)
- }
- if newNonce != nonce+uint64(1) {
- t.Errorf("received incorrect nonce. expected 1, got %v", nonce)
- }
- // create some more blocks
- sim.Commit()
- // Check that we can get data for an older block/state
- newNonce, err = sim.NonceAt(bgCtx, testAddr, big.NewInt(1))
- if err != nil {
- t.Fatalf("could not get nonce for test addr: %v", err)
- }
- if newNonce != nonce+uint64(1) {
- t.Fatalf("received incorrect nonce. expected 1, got %v", nonce)
- }
- }
- func TestSendTransaction(t *testing.T) {
- testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
- sim := simTestBackend(testAddr)
- defer sim.Close()
- bgCtx := context.Background()
- // create a signed transaction to send
- head, _ := sim.HeaderByNumber(context.Background(), nil) // Should be child's, good enough
- gasPrice := new(big.Int).Add(head.BaseFee, big.NewInt(1))
- tx := types.NewTransaction(uint64(0), testAddr, big.NewInt(1000), params.TxGas, gasPrice, nil)
- signedTx, err := types.SignTx(tx, types.HomesteadSigner{}, testKey)
- if err != nil {
- t.Errorf("could not sign tx: %v", err)
- }
- // send tx to simulated backend
- err = sim.SendTransaction(bgCtx, signedTx)
- if err != nil {
- t.Errorf("could not add tx to pending block: %v", err)
- }
- sim.Commit()
- block, err := sim.BlockByNumber(bgCtx, big.NewInt(1))
- if err != nil {
- t.Errorf("could not get block at height 1: %v", err)
- }
- if signedTx.Hash() != block.Transactions()[0].Hash() {
- t.Errorf("did not commit sent transaction. expected hash %v got hash %v", block.Transactions()[0].Hash(), signedTx.Hash())
- }
- }
- func TestTransactionByHash(t *testing.T) {
- testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
- sim := NewSimulatedBackend(
- core.GenesisAlloc{
- testAddr: {Balance: big.NewInt(10000000000000000)},
- }, 10000000,
- )
- defer sim.Close()
- bgCtx := context.Background()
- // create a signed transaction to send
- head, _ := sim.HeaderByNumber(context.Background(), nil) // Should be child's, good enough
- gasPrice := new(big.Int).Add(head.BaseFee, big.NewInt(1))
- tx := types.NewTransaction(uint64(0), testAddr, big.NewInt(1000), params.TxGas, gasPrice, nil)
- signedTx, err := types.SignTx(tx, types.HomesteadSigner{}, testKey)
- if err != nil {
- t.Errorf("could not sign tx: %v", err)
- }
- // send tx to simulated backend
- err = sim.SendTransaction(bgCtx, signedTx)
- if err != nil {
- t.Errorf("could not add tx to pending block: %v", err)
- }
- // ensure tx is committed pending
- receivedTx, pending, err := sim.TransactionByHash(bgCtx, signedTx.Hash())
- if err != nil {
- t.Errorf("could not get transaction by hash %v: %v", signedTx.Hash(), err)
- }
- if !pending {
- t.Errorf("expected transaction to be in pending state")
- }
- if receivedTx.Hash() != signedTx.Hash() {
- t.Errorf("did not received committed transaction. expected hash %v got hash %v", signedTx.Hash(), receivedTx.Hash())
- }
- sim.Commit()
- // ensure tx is not and committed pending
- receivedTx, pending, err = sim.TransactionByHash(bgCtx, signedTx.Hash())
- if err != nil {
- t.Errorf("could not get transaction by hash %v: %v", signedTx.Hash(), err)
- }
- if pending {
- t.Errorf("expected transaction to not be in pending state")
- }
- if receivedTx.Hash() != signedTx.Hash() {
- t.Errorf("did not received committed transaction. expected hash %v got hash %v", signedTx.Hash(), receivedTx.Hash())
- }
- }
- func TestEstimateGas(t *testing.T) {
- /*
- pragma solidity ^0.6.4;
- contract GasEstimation {
- function PureRevert() public { revert(); }
- function Revert() public { revert("revert reason");}
- function OOG() public { for (uint i = 0; ; i++) {}}
- function Assert() public { assert(false);}
- function Valid() public {}
- }*/
- const contractAbi = "[{\"inputs\":[],\"name\":\"Assert\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"OOG\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"PureRevert\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"Revert\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"Valid\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]"
- const contractBin = "0x60806040523480156100115760006000fd5b50610017565b61016e806100266000396000f3fe60806040523480156100115760006000fd5b506004361061005c5760003560e01c806350f6fe3414610062578063aa8b1d301461006c578063b9b046f914610076578063d8b9839114610080578063e09fface1461008a5761005c565b60006000fd5b61006a610094565b005b6100746100ad565b005b61007e6100b5565b005b6100886100c2565b005b610092610135565b005b6000600090505b5b808060010191505061009b565b505b565b60006000fd5b565b600015156100bf57fe5b5b565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600d8152602001807f72657665727420726561736f6e0000000000000000000000000000000000000081526020015060200191505060405180910390fd5b565b5b56fea2646970667358221220345bbcbb1a5ecf22b53a78eaebf95f8ee0eceff6d10d4b9643495084d2ec934a64736f6c63430006040033"
- key, _ := crypto.GenerateKey()
- addr := crypto.PubkeyToAddress(key.PublicKey)
- opts, _ := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337))
- sim := NewSimulatedBackend(core.GenesisAlloc{addr: {Balance: big.NewInt(params.Ether)}}, 10000000)
- defer sim.Close()
- parsed, _ := abi.JSON(strings.NewReader(contractAbi))
- contractAddr, _, _, _ := bind.DeployContract(opts, parsed, common.FromHex(contractBin), sim)
- sim.Commit()
- var cases = []struct {
- name string
- message ethereum.CallMsg
- expect uint64
- expectError error
- expectData interface{}
- }{
- {"plain transfer(valid)", ethereum.CallMsg{
- From: addr,
- To: &addr,
- Gas: 0,
- GasPrice: big.NewInt(0),
- Value: big.NewInt(1),
- Data: nil,
- }, params.TxGas, nil, nil},
- {"plain transfer(invalid)", ethereum.CallMsg{
- From: addr,
- To: &contractAddr,
- Gas: 0,
- GasPrice: big.NewInt(0),
- Value: big.NewInt(1),
- Data: nil,
- }, 0, errors.New("execution reverted"), nil},
- {"Revert", ethereum.CallMsg{
- From: addr,
- To: &contractAddr,
- Gas: 0,
- GasPrice: big.NewInt(0),
- Value: nil,
- Data: common.Hex2Bytes("d8b98391"),
- }, 0, errors.New("execution reverted: revert reason"), "0x08c379a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000d72657665727420726561736f6e00000000000000000000000000000000000000"},
- {"PureRevert", ethereum.CallMsg{
- From: addr,
- To: &contractAddr,
- Gas: 0,
- GasPrice: big.NewInt(0),
- Value: nil,
- Data: common.Hex2Bytes("aa8b1d30"),
- }, 0, errors.New("execution reverted"), nil},
- {"OOG", ethereum.CallMsg{
- From: addr,
- To: &contractAddr,
- Gas: 100000,
- GasPrice: big.NewInt(0),
- Value: nil,
- Data: common.Hex2Bytes("50f6fe34"),
- }, 0, errors.New("gas required exceeds allowance (100000)"), nil},
- {"Assert", ethereum.CallMsg{
- From: addr,
- To: &contractAddr,
- Gas: 100000,
- GasPrice: big.NewInt(0),
- Value: nil,
- Data: common.Hex2Bytes("b9b046f9"),
- }, 0, errors.New("invalid opcode: INVALID"), nil},
- {"Valid", ethereum.CallMsg{
- From: addr,
- To: &contractAddr,
- Gas: 100000,
- GasPrice: big.NewInt(0),
- Value: nil,
- Data: common.Hex2Bytes("e09fface"),
- }, 21275, nil, nil},
- }
- for _, c := range cases {
- got, err := sim.EstimateGas(context.Background(), c.message)
- if c.expectError != nil {
- if err == nil {
- t.Fatalf("Expect error, got nil")
- }
- if c.expectError.Error() != err.Error() {
- t.Fatalf("Expect error, want %v, got %v", c.expectError, err)
- }
- if c.expectData != nil {
- if err, ok := err.(*revertError); !ok {
- t.Fatalf("Expect revert error, got %T", err)
- } else if !reflect.DeepEqual(err.ErrorData(), c.expectData) {
- t.Fatalf("Error data mismatch, want %v, got %v", c.expectData, err.ErrorData())
- }
- }
- continue
- }
- if got != c.expect {
- t.Fatalf("Gas estimation mismatch, want %d, got %d", c.expect, got)
- }
- }
- }
- func TestEstimateGasWithPrice(t *testing.T) {
- key, _ := crypto.GenerateKey()
- addr := crypto.PubkeyToAddress(key.PublicKey)
- sim := NewSimulatedBackend(core.GenesisAlloc{addr: {Balance: big.NewInt(params.Ether*2 + 2e17)}}, 10000000)
- defer sim.Close()
- recipient := common.HexToAddress("deadbeef")
- var cases = []struct {
- name string
- message ethereum.CallMsg
- expect uint64
- expectError error
- }{
- {"EstimateWithoutPrice", ethereum.CallMsg{
- From: addr,
- To: &recipient,
- Gas: 0,
- GasPrice: big.NewInt(0),
- Value: big.NewInt(100000000000),
- Data: nil,
- }, 21000, nil},
- {"EstimateWithPrice", ethereum.CallMsg{
- From: addr,
- To: &recipient,
- Gas: 0,
- GasPrice: big.NewInt(100000000000),
- Value: big.NewInt(100000000000),
- Data: nil,
- }, 21000, nil},
- {"EstimateWithVeryHighPrice", ethereum.CallMsg{
- From: addr,
- To: &recipient,
- Gas: 0,
- GasPrice: big.NewInt(1e14), // gascost = 2.1ether
- Value: big.NewInt(1e17), // the remaining balance for fee is 2.1ether
- Data: nil,
- }, 21000, nil},
- {"EstimateWithSuperhighPrice", ethereum.CallMsg{
- From: addr,
- To: &recipient,
- Gas: 0,
- GasPrice: big.NewInt(2e14), // gascost = 4.2ether
- Value: big.NewInt(100000000000),
- Data: nil,
- }, 21000, errors.New("gas required exceeds allowance (10999)")}, // 10999=(2.2ether-1000wei)/(2e14)
- {"EstimateEIP1559WithHighFees", ethereum.CallMsg{
- From: addr,
- To: &addr,
- Gas: 0,
- GasFeeCap: big.NewInt(1e14), // maxgascost = 2.1ether
- GasTipCap: big.NewInt(1),
- Value: big.NewInt(1e17), // the remaining balance for fee is 2.1ether
- Data: nil,
- }, params.TxGas, nil},
- {"EstimateEIP1559WithSuperHighFees", ethereum.CallMsg{
- From: addr,
- To: &addr,
- Gas: 0,
- GasFeeCap: big.NewInt(1e14), // maxgascost = 2.1ether
- GasTipCap: big.NewInt(1),
- Value: big.NewInt(1e17 + 1), // the remaining balance for fee is 2.1ether
- Data: nil,
- }, params.TxGas, errors.New("gas required exceeds allowance (20999)")}, // 20999=(2.2ether-0.1ether-1wei)/(1e14)
- }
- for i, c := range cases {
- got, err := sim.EstimateGas(context.Background(), c.message)
- if c.expectError != nil {
- if err == nil {
- t.Fatalf("test %d: expect error, got nil", i)
- }
- if c.expectError.Error() != err.Error() {
- t.Fatalf("test %d: expect error, want %v, got %v", i, c.expectError, err)
- }
- continue
- }
- if c.expectError == nil && err != nil {
- t.Fatalf("test %d: didn't expect error, got %v", i, err)
- }
- if got != c.expect {
- t.Fatalf("test %d: gas estimation mismatch, want %d, got %d", i, c.expect, got)
- }
- }
- }
- func TestHeaderByHash(t *testing.T) {
- testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
- sim := simTestBackend(testAddr)
- defer sim.Close()
- bgCtx := context.Background()
- header, err := sim.HeaderByNumber(bgCtx, nil)
- if err != nil {
- t.Errorf("could not get recent block: %v", err)
- }
- headerByHash, err := sim.HeaderByHash(bgCtx, header.Hash())
- if err != nil {
- t.Errorf("could not get recent block: %v", err)
- }
- if header.Hash() != headerByHash.Hash() {
- t.Errorf("did not get expected block")
- }
- }
- func TestHeaderByNumber(t *testing.T) {
- testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
- sim := simTestBackend(testAddr)
- defer sim.Close()
- bgCtx := context.Background()
- latestBlockHeader, err := sim.HeaderByNumber(bgCtx, nil)
- if err != nil {
- t.Errorf("could not get header for tip of chain: %v", err)
- }
- if latestBlockHeader == nil {
- t.Errorf("received a nil block header")
- } else if latestBlockHeader.Number.Uint64() != uint64(0) {
- t.Errorf("expected block header number 0, instead got %v", latestBlockHeader.Number.Uint64())
- }
- sim.Commit()
- latestBlockHeader, err = sim.HeaderByNumber(bgCtx, nil)
- if err != nil {
- t.Errorf("could not get header for blockheight of 1: %v", err)
- }
- blockHeader, err := sim.HeaderByNumber(bgCtx, big.NewInt(1))
- if err != nil {
- t.Errorf("could not get header for blockheight of 1: %v", err)
- }
- if blockHeader.Hash() != latestBlockHeader.Hash() {
- t.Errorf("block header and latest block header are not the same")
- }
- if blockHeader.Number.Int64() != int64(1) {
- t.Errorf("did not get blockheader for block 1. instead got block %v", blockHeader.Number.Int64())
- }
- block, err := sim.BlockByNumber(bgCtx, big.NewInt(1))
- if err != nil {
- t.Errorf("could not get block for blockheight of 1: %v", err)
- }
- if block.Hash() != blockHeader.Hash() {
- t.Errorf("block hash and block header hash do not match. expected %v, got %v", block.Hash(), blockHeader.Hash())
- }
- }
- func TestTransactionCount(t *testing.T) {
- testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
- sim := simTestBackend(testAddr)
- defer sim.Close()
- bgCtx := context.Background()
- currentBlock, err := sim.BlockByNumber(bgCtx, nil)
- if err != nil || currentBlock == nil {
- t.Error("could not get current block")
- }
- count, err := sim.TransactionCount(bgCtx, currentBlock.Hash())
- if err != nil {
- t.Error("could not get current block's transaction count")
- }
- if count != 0 {
- t.Errorf("expected transaction count of %v does not match actual count of %v", 0, count)
- }
- // create a signed transaction to send
- head, _ := sim.HeaderByNumber(context.Background(), nil) // Should be child's, good enough
- gasPrice := new(big.Int).Add(head.BaseFee, big.NewInt(1))
- tx := types.NewTransaction(uint64(0), testAddr, big.NewInt(1000), params.TxGas, gasPrice, nil)
- signedTx, err := types.SignTx(tx, types.HomesteadSigner{}, testKey)
- if err != nil {
- t.Errorf("could not sign tx: %v", err)
- }
- // send tx to simulated backend
- err = sim.SendTransaction(bgCtx, signedTx)
- if err != nil {
- t.Errorf("could not add tx to pending block: %v", err)
- }
- sim.Commit()
- lastBlock, err := sim.BlockByNumber(bgCtx, nil)
- if err != nil {
- t.Errorf("could not get header for tip of chain: %v", err)
- }
- count, err = sim.TransactionCount(bgCtx, lastBlock.Hash())
- if err != nil {
- t.Error("could not get current block's transaction count")
- }
- if count != 1 {
- t.Errorf("expected transaction count of %v does not match actual count of %v", 1, count)
- }
- }
- func TestTransactionInBlock(t *testing.T) {
- testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
- sim := simTestBackend(testAddr)
- defer sim.Close()
- bgCtx := context.Background()
- transaction, err := sim.TransactionInBlock(bgCtx, sim.pendingBlock.Hash(), uint(0))
- if err == nil && err != errTransactionDoesNotExist {
- t.Errorf("expected a transaction does not exist error to be received but received %v", err)
- }
- if transaction != nil {
- t.Errorf("expected transaction to be nil but received %v", transaction)
- }
- // expect pending nonce to be 0 since account has not been used
- pendingNonce, err := sim.PendingNonceAt(bgCtx, testAddr)
- if err != nil {
- t.Errorf("did not get the pending nonce: %v", err)
- }
- if pendingNonce != uint64(0) {
- t.Errorf("expected pending nonce of 0 got %v", pendingNonce)
- }
- // create a signed transaction to send
- head, _ := sim.HeaderByNumber(context.Background(), nil) // Should be child's, good enough
- gasPrice := new(big.Int).Add(head.BaseFee, big.NewInt(1))
- tx := types.NewTransaction(uint64(0), testAddr, big.NewInt(1000), params.TxGas, gasPrice, nil)
- signedTx, err := types.SignTx(tx, types.HomesteadSigner{}, testKey)
- if err != nil {
- t.Errorf("could not sign tx: %v", err)
- }
- // send tx to simulated backend
- err = sim.SendTransaction(bgCtx, signedTx)
- if err != nil {
- t.Errorf("could not add tx to pending block: %v", err)
- }
- sim.Commit()
- lastBlock, err := sim.BlockByNumber(bgCtx, nil)
- if err != nil {
- t.Errorf("could not get header for tip of chain: %v", err)
- }
- transaction, err = sim.TransactionInBlock(bgCtx, lastBlock.Hash(), uint(1))
- if err == nil && err != errTransactionDoesNotExist {
- t.Errorf("expected a transaction does not exist error to be received but received %v", err)
- }
- if transaction != nil {
- t.Errorf("expected transaction to be nil but received %v", transaction)
- }
- transaction, err = sim.TransactionInBlock(bgCtx, lastBlock.Hash(), uint(0))
- if err != nil {
- t.Errorf("could not get transaction in the lastest block with hash %v: %v", lastBlock.Hash().String(), err)
- }
- if signedTx.Hash().String() != transaction.Hash().String() {
- t.Errorf("received transaction that did not match the sent transaction. expected hash %v, got hash %v", signedTx.Hash().String(), transaction.Hash().String())
- }
- }
- func TestPendingNonceAt(t *testing.T) {
- testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
- sim := simTestBackend(testAddr)
- defer sim.Close()
- bgCtx := context.Background()
- // expect pending nonce to be 0 since account has not been used
- pendingNonce, err := sim.PendingNonceAt(bgCtx, testAddr)
- if err != nil {
- t.Errorf("did not get the pending nonce: %v", err)
- }
- if pendingNonce != uint64(0) {
- t.Errorf("expected pending nonce of 0 got %v", pendingNonce)
- }
- // create a signed transaction to send
- head, _ := sim.HeaderByNumber(context.Background(), nil) // Should be child's, good enough
- gasPrice := new(big.Int).Add(head.BaseFee, big.NewInt(1))
- tx := types.NewTransaction(uint64(0), testAddr, big.NewInt(1000), params.TxGas, gasPrice, nil)
- signedTx, err := types.SignTx(tx, types.HomesteadSigner{}, testKey)
- if err != nil {
- t.Errorf("could not sign tx: %v", err)
- }
- // send tx to simulated backend
- err = sim.SendTransaction(bgCtx, signedTx)
- if err != nil {
- t.Errorf("could not add tx to pending block: %v", err)
- }
- // expect pending nonce to be 1 since account has submitted one transaction
- pendingNonce, err = sim.PendingNonceAt(bgCtx, testAddr)
- if err != nil {
- t.Errorf("did not get the pending nonce: %v", err)
- }
- if pendingNonce != uint64(1) {
- t.Errorf("expected pending nonce of 1 got %v", pendingNonce)
- }
- // make a new transaction with a nonce of 1
- tx = types.NewTransaction(uint64(1), testAddr, big.NewInt(1000), params.TxGas, gasPrice, nil)
- signedTx, err = types.SignTx(tx, types.HomesteadSigner{}, testKey)
- if err != nil {
- t.Errorf("could not sign tx: %v", err)
- }
- err = sim.SendTransaction(bgCtx, signedTx)
- if err != nil {
- t.Errorf("could not send tx: %v", err)
- }
- // expect pending nonce to be 2 since account now has two transactions
- pendingNonce, err = sim.PendingNonceAt(bgCtx, testAddr)
- if err != nil {
- t.Errorf("did not get the pending nonce: %v", err)
- }
- if pendingNonce != uint64(2) {
- t.Errorf("expected pending nonce of 2 got %v", pendingNonce)
- }
- }
- func TestTransactionReceipt(t *testing.T) {
- testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
- sim := simTestBackend(testAddr)
- defer sim.Close()
- bgCtx := context.Background()
- // create a signed transaction to send
- head, _ := sim.HeaderByNumber(context.Background(), nil) // Should be child's, good enough
- gasPrice := new(big.Int).Add(head.BaseFee, big.NewInt(1))
- tx := types.NewTransaction(uint64(0), testAddr, big.NewInt(1000), params.TxGas, gasPrice, nil)
- signedTx, err := types.SignTx(tx, types.HomesteadSigner{}, testKey)
- if err != nil {
- t.Errorf("could not sign tx: %v", err)
- }
- // send tx to simulated backend
- err = sim.SendTransaction(bgCtx, signedTx)
- if err != nil {
- t.Errorf("could not add tx to pending block: %v", err)
- }
- sim.Commit()
- receipt, err := sim.TransactionReceipt(bgCtx, signedTx.Hash())
- if err != nil {
- t.Errorf("could not get transaction receipt: %v", err)
- }
- if receipt.ContractAddress != testAddr && receipt.TxHash != signedTx.Hash() {
- t.Errorf("received receipt is not correct: %v", receipt)
- }
- }
- func TestSuggestGasPrice(t *testing.T) {
- sim := NewSimulatedBackend(
- core.GenesisAlloc{},
- 10000000,
- )
- defer sim.Close()
- bgCtx := context.Background()
- gasPrice, err := sim.SuggestGasPrice(bgCtx)
- if err != nil {
- t.Errorf("could not get gas price: %v", err)
- }
- if gasPrice.Uint64() != sim.pendingBlock.Header().BaseFee.Uint64() {
- t.Errorf("gas price was not expected value of %v. actual: %v", sim.pendingBlock.Header().BaseFee.Uint64(), gasPrice.Uint64())
- }
- }
- func TestPendingCodeAt(t *testing.T) {
- testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
- sim := simTestBackend(testAddr)
- defer sim.Close()
- bgCtx := context.Background()
- code, err := sim.CodeAt(bgCtx, testAddr, nil)
- if err != nil {
- t.Errorf("could not get code at test addr: %v", err)
- }
- if len(code) != 0 {
- t.Errorf("got code for account that does not have contract code")
- }
- parsed, err := abi.JSON(strings.NewReader(abiJSON))
- if err != nil {
- t.Errorf("could not get code at test addr: %v", err)
- }
- auth, _ := bind.NewKeyedTransactorWithChainID(testKey, big.NewInt(1337))
- contractAddr, tx, contract, err := bind.DeployContract(auth, parsed, common.FromHex(abiBin), sim)
- if err != nil {
- t.Errorf("could not deploy contract: %v tx: %v contract: %v", err, tx, contract)
- }
- code, err = sim.PendingCodeAt(bgCtx, contractAddr)
- if err != nil {
- t.Errorf("could not get code at test addr: %v", err)
- }
- if len(code) == 0 {
- t.Errorf("did not get code for account that has contract code")
- }
- // ensure code received equals code deployed
- if !bytes.Equal(code, common.FromHex(deployedCode)) {
- t.Errorf("code received did not match expected deployed code:\n expected %v\n actual %v", common.FromHex(deployedCode), code)
- }
- }
- func TestCodeAt(t *testing.T) {
- testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
- sim := simTestBackend(testAddr)
- defer sim.Close()
- bgCtx := context.Background()
- code, err := sim.CodeAt(bgCtx, testAddr, nil)
- if err != nil {
- t.Errorf("could not get code at test addr: %v", err)
- }
- if len(code) != 0 {
- t.Errorf("got code for account that does not have contract code")
- }
- parsed, err := abi.JSON(strings.NewReader(abiJSON))
- if err != nil {
- t.Errorf("could not get code at test addr: %v", err)
- }
- auth, _ := bind.NewKeyedTransactorWithChainID(testKey, big.NewInt(1337))
- contractAddr, tx, contract, err := bind.DeployContract(auth, parsed, common.FromHex(abiBin), sim)
- if err != nil {
- t.Errorf("could not deploy contract: %v tx: %v contract: %v", err, tx, contract)
- }
- sim.Commit()
- code, err = sim.CodeAt(bgCtx, contractAddr, nil)
- if err != nil {
- t.Errorf("could not get code at test addr: %v", err)
- }
- if len(code) == 0 {
- t.Errorf("did not get code for account that has contract code")
- }
- // ensure code received equals code deployed
- if !bytes.Equal(code, common.FromHex(deployedCode)) {
- t.Errorf("code received did not match expected deployed code:\n expected %v\n actual %v", common.FromHex(deployedCode), code)
- }
- }
- // When receive("X") is called with sender 0x00... and value 1, it produces this tx receipt:
- // receipt{status=1 cgas=23949 bloom=00000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000040200000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 logs=[log: b6818c8064f645cd82d99b59a1a267d6d61117ef [75fd880d39c1daf53b6547ab6cb59451fc6452d27caa90e5b6649dd8293b9eed] 000000000000000000000000376c47978271565f56deb45495afa69e59c16ab200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000158 9ae378b6d4409eada347a5dc0c180f186cb62dc68fcc0f043425eb917335aa28 0 95d429d309bb9d753954195fe2d69bd140b4ae731b9b5b605c34323de162cf00 0]}
- func TestPendingAndCallContract(t *testing.T) {
- testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
- sim := simTestBackend(testAddr)
- defer sim.Close()
- bgCtx := context.Background()
- parsed, err := abi.JSON(strings.NewReader(abiJSON))
- if err != nil {
- t.Errorf("could not get code at test addr: %v", err)
- }
- contractAuth, _ := bind.NewKeyedTransactorWithChainID(testKey, big.NewInt(1337))
- addr, _, _, err := bind.DeployContract(contractAuth, parsed, common.FromHex(abiBin), sim)
- if err != nil {
- t.Errorf("could not deploy contract: %v", err)
- }
- input, err := parsed.Pack("receive", []byte("X"))
- if err != nil {
- t.Errorf("could not pack receive function on contract: %v", err)
- }
- // make sure you can call the contract in pending state
- res, err := sim.PendingCallContract(bgCtx, ethereum.CallMsg{
- From: testAddr,
- To: &addr,
- Data: input,
- })
- if err != nil {
- t.Errorf("could not call receive method on contract: %v", err)
- }
- if len(res) == 0 {
- t.Errorf("result of contract call was empty: %v", res)
- }
- // while comparing against the byte array is more exact, also compare against the human readable string for readability
- if !bytes.Equal(res, expectedReturn) || !strings.Contains(string(res), "hello world") {
- t.Errorf("response from calling contract was expected to be 'hello world' instead received %v", string(res))
- }
- sim.Commit()
- // make sure you can call the contract
- res, err = sim.CallContract(bgCtx, ethereum.CallMsg{
- From: testAddr,
- To: &addr,
- Data: input,
- }, nil)
- if err != nil {
- t.Errorf("could not call receive method on contract: %v", err)
- }
- if len(res) == 0 {
- t.Errorf("result of contract call was empty: %v", res)
- }
- if !bytes.Equal(res, expectedReturn) || !strings.Contains(string(res), "hello world") {
- t.Errorf("response from calling contract was expected to be 'hello world' instead received %v", string(res))
- }
- }
- // This test is based on the following contract:
- /*
- contract Reverter {
- function revertString() public pure{
- require(false, "some error");
- }
- function revertNoString() public pure {
- require(false, "");
- }
- function revertASM() public pure {
- assembly {
- revert(0x0, 0x0)
- }
- }
- function noRevert() public pure {
- assembly {
- // Assembles something that looks like require(false, "some error") but is not reverted
- mstore(0x0, 0x08c379a000000000000000000000000000000000000000000000000000000000)
- mstore(0x4, 0x0000000000000000000000000000000000000000000000000000000000000020)
- mstore(0x24, 0x000000000000000000000000000000000000000000000000000000000000000a)
- mstore(0x44, 0x736f6d65206572726f7200000000000000000000000000000000000000000000)
- return(0x0, 0x64)
- }
- }
- }*/
- func TestCallContractRevert(t *testing.T) {
- testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
- sim := simTestBackend(testAddr)
- defer sim.Close()
- bgCtx := context.Background()
- reverterABI := `[{"inputs": [],"name": "noRevert","outputs": [],"stateMutability": "pure","type": "function"},{"inputs": [],"name": "revertASM","outputs": [],"stateMutability": "pure","type": "function"},{"inputs": [],"name": "revertNoString","outputs": [],"stateMutability": "pure","type": "function"},{"inputs": [],"name": "revertString","outputs": [],"stateMutability": "pure","type": "function"}]`
- reverterBin := "608060405234801561001057600080fd5b506101d3806100206000396000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c80634b409e01146100515780639b340e361461005b5780639bd6103714610065578063b7246fc11461006f575b600080fd5b610059610079565b005b6100636100ca565b005b61006d6100cf565b005b610077610145565b005b60006100c8576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526000815260200160200191505060405180910390fd5b565b600080fd5b6000610143576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252600a8152602001807f736f6d65206572726f720000000000000000000000000000000000000000000081525060200191505060405180910390fd5b565b7f08c379a0000000000000000000000000000000000000000000000000000000006000526020600452600a6024527f736f6d65206572726f720000000000000000000000000000000000000000000060445260646000f3fea2646970667358221220cdd8af0609ec4996b7360c7c780bad5c735740c64b1fffc3445aa12d37f07cb164736f6c63430006070033"
- parsed, err := abi.JSON(strings.NewReader(reverterABI))
- if err != nil {
- t.Errorf("could not get code at test addr: %v", err)
- }
- contractAuth, _ := bind.NewKeyedTransactorWithChainID(testKey, big.NewInt(1337))
- addr, _, _, err := bind.DeployContract(contractAuth, parsed, common.FromHex(reverterBin), sim)
- if err != nil {
- t.Errorf("could not deploy contract: %v", err)
- }
- inputs := make(map[string]interface{}, 3)
- inputs["revertASM"] = nil
- inputs["revertNoString"] = ""
- inputs["revertString"] = "some error"
- call := make([]func([]byte) ([]byte, error), 2)
- call[0] = func(input []byte) ([]byte, error) {
- return sim.PendingCallContract(bgCtx, ethereum.CallMsg{
- From: testAddr,
- To: &addr,
- Data: input,
- })
- }
- call[1] = func(input []byte) ([]byte, error) {
- return sim.CallContract(bgCtx, ethereum.CallMsg{
- From: testAddr,
- To: &addr,
- Data: input,
- }, nil)
- }
- // Run pending calls then commit
- for _, cl := range call {
- for key, val := range inputs {
- input, err := parsed.Pack(key)
- if err != nil {
- t.Errorf("could not pack %v function on contract: %v", key, err)
- }
- res, err := cl(input)
- if err == nil {
- t.Errorf("call to %v was not reverted", key)
- }
- if res != nil {
- t.Errorf("result from %v was not nil: %v", key, res)
- }
- if val != nil {
- rerr, ok := err.(*revertError)
- if !ok {
- t.Errorf("expect revert error")
- }
- if rerr.Error() != "execution reverted: "+val.(string) {
- t.Errorf("error was malformed: got %v want %v", rerr.Error(), val)
- }
- } else {
- // revert(0x0,0x0)
- if err.Error() != "execution reverted" {
- t.Errorf("error was malformed: got %v want %v", err, "execution reverted")
- }
- }
- }
- input, err := parsed.Pack("noRevert")
- if err != nil {
- t.Errorf("could not pack noRevert function on contract: %v", err)
- }
- res, err := cl(input)
- if err != nil {
- t.Error("call to noRevert was reverted")
- }
- if res == nil {
- t.Errorf("result from noRevert was nil")
- }
- sim.Commit()
- }
- }
- // TestFork check that the chain length after a reorg is correct.
- // Steps:
- // 1. Save the current block which will serve as parent for the fork.
- // 2. Mine n blocks with n ∈ [0, 20].
- // 3. Assert that the chain length is n.
- // 4. Fork by using the parent block as ancestor.
- // 5. Mine n+1 blocks which should trigger a reorg.
- // 6. Assert that the chain length is n+1.
- // Since Commit() was called 2n+1 times in total,
- // having a chain length of just n+1 means that a reorg occurred.
- func TestFork(t *testing.T) {
- testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
- sim := simTestBackend(testAddr)
- defer sim.Close()
- // 1.
- parent := sim.blockchain.CurrentBlock()
- // 2.
- n := int(rand.Int31n(21))
- for i := 0; i < n; i++ {
- sim.Commit()
- }
- // 3.
- if sim.blockchain.CurrentBlock().NumberU64() != uint64(n) {
- t.Error("wrong chain length")
- }
- // 4.
- sim.Fork(context.Background(), parent.Hash())
- // 5.
- for i := 0; i < n+1; i++ {
- sim.Commit()
- }
- // 6.
- if sim.blockchain.CurrentBlock().NumberU64() != uint64(n+1) {
- t.Error("wrong chain length")
- }
- }
- /*
- Example contract to test event emission:
- pragma solidity >=0.7.0 <0.9.0;
- contract Callable {
- event Called();
- function Call() public { emit Called(); }
- }
- */
- const callableAbi = "[{\"anonymous\":false,\"inputs\":[],\"name\":\"Called\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"Call\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]"
- const callableBin = "6080604052348015600f57600080fd5b5060998061001e6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c806334e2292114602d575b600080fd5b60336035565b005b7f81fab7a4a0aa961db47eefc81f143a5220e8c8495260dd65b1356f1d19d3c7b860405160405180910390a156fea2646970667358221220029436d24f3ac598ceca41d4d712e13ced6d70727f4cdc580667de66d2f51d8b64736f6c63430008010033"
- // TestForkLogsReborn check that the simulated reorgs
- // correctly remove and reborn logs.
- // Steps:
- // 1. Deploy the Callable contract.
- // 2. Set up an event subscription.
- // 3. Save the current block which will serve as parent for the fork.
- // 4. Send a transaction.
- // 5. Check that the event was included.
- // 6. Fork by using the parent block as ancestor.
- // 7. Mine two blocks to trigger a reorg.
- // 8. Check that the event was removed.
- // 9. Re-send the transaction and mine a block.
- // 10. Check that the event was reborn.
- func TestForkLogsReborn(t *testing.T) {
- testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
- sim := simTestBackend(testAddr)
- defer sim.Close()
- // 1.
- parsed, _ := abi.JSON(strings.NewReader(callableAbi))
- auth, _ := bind.NewKeyedTransactorWithChainID(testKey, big.NewInt(1337))
- _, _, contract, err := bind.DeployContract(auth, parsed, common.FromHex(callableBin), sim)
- if err != nil {
- t.Errorf("deploying contract: %v", err)
- }
- sim.Commit()
- // 2.
- logs, sub, err := contract.WatchLogs(nil, "Called")
- if err != nil {
- t.Errorf("watching logs: %v", err)
- }
- defer sub.Unsubscribe()
- // 3.
- parent := sim.blockchain.CurrentBlock()
- // 4.
- tx, err := contract.Transact(auth, "Call")
- if err != nil {
- t.Errorf("transacting: %v", err)
- }
- sim.Commit()
- // 5.
- log := <-logs
- if log.TxHash != tx.Hash() {
- t.Error("wrong event tx hash")
- }
- if log.Removed {
- t.Error("Event should be included")
- }
- // 6.
- if err := sim.Fork(context.Background(), parent.Hash()); err != nil {
- t.Errorf("forking: %v", err)
- }
- // 7.
- sim.Commit()
- sim.Commit()
- // 8.
- log = <-logs
- if log.TxHash != tx.Hash() {
- t.Error("wrong event tx hash")
- }
- if !log.Removed {
- t.Error("Event should be removed")
- }
- // 9.
- if err := sim.SendTransaction(context.Background(), tx); err != nil {
- t.Errorf("sending transaction: %v", err)
- }
- sim.Commit()
- // 10.
- log = <-logs
- if log.TxHash != tx.Hash() {
- t.Error("wrong event tx hash")
- }
- if log.Removed {
- t.Error("Event should be included")
- }
- }
- // TestForkResendTx checks that re-sending a TX after a fork
- // is possible and does not cause a "nonce mismatch" panic.
- // Steps:
- // 1. Save the current block which will serve as parent for the fork.
- // 2. Send a transaction.
- // 3. Check that the TX is included in block 1.
- // 4. Fork by using the parent block as ancestor.
- // 5. Mine a block, Re-send the transaction and mine another one.
- // 6. Check that the TX is now included in block 2.
- func TestForkResendTx(t *testing.T) {
- testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
- sim := simTestBackend(testAddr)
- defer sim.Close()
- // 1.
- parent := sim.blockchain.CurrentBlock()
- // 2.
- head, _ := sim.HeaderByNumber(context.Background(), nil) // Should be child's, good enough
- gasPrice := new(big.Int).Add(head.BaseFee, big.NewInt(1))
- _tx := types.NewTransaction(0, testAddr, big.NewInt(1000), params.TxGas, gasPrice, nil)
- tx, _ := types.SignTx(_tx, types.HomesteadSigner{}, testKey)
- sim.SendTransaction(context.Background(), tx)
- sim.Commit()
- // 3.
- receipt, _ := sim.TransactionReceipt(context.Background(), tx.Hash())
- if h := receipt.BlockNumber.Uint64(); h != 1 {
- t.Errorf("TX included in wrong block: %d", h)
- }
- // 4.
- if err := sim.Fork(context.Background(), parent.Hash()); err != nil {
- t.Errorf("forking: %v", err)
- }
- // 5.
- sim.Commit()
- if err := sim.SendTransaction(context.Background(), tx); err != nil {
- t.Errorf("sending transaction: %v", err)
- }
- sim.Commit()
- // 6.
- receipt, _ = sim.TransactionReceipt(context.Background(), tx.Hash())
- if h := receipt.BlockNumber.Uint64(); h != 2 {
- t.Errorf("TX included in wrong block: %d", h)
- }
- }
- func TestCommitReturnValue(t *testing.T) {
- testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
- sim := simTestBackend(testAddr)
- defer sim.Close()
- startBlockHeight := sim.blockchain.CurrentBlock().NumberU64()
- // Test if Commit returns the correct block hash
- h1 := sim.Commit()
- if h1 != sim.blockchain.CurrentBlock().Hash() {
- t.Error("Commit did not return the hash of the last block.")
- }
- // Create a block in the original chain (containing a transaction to force different block hashes)
- head, _ := sim.HeaderByNumber(context.Background(), nil) // Should be child's, good enough
- gasPrice := new(big.Int).Add(head.BaseFee, big.NewInt(1))
- _tx := types.NewTransaction(0, testAddr, big.NewInt(1000), params.TxGas, gasPrice, nil)
- tx, _ := types.SignTx(_tx, types.HomesteadSigner{}, testKey)
- sim.SendTransaction(context.Background(), tx)
- h2 := sim.Commit()
- // Create another block in the original chain
- sim.Commit()
- // Fork at the first bock
- if err := sim.Fork(context.Background(), h1); err != nil {
- t.Errorf("forking: %v", err)
- }
- // Test if Commit returns the correct block hash after the reorg
- h2fork := sim.Commit()
- if h2 == h2fork {
- t.Error("The block in the fork and the original block are the same block!")
- }
- if sim.blockchain.GetHeader(h2fork, startBlockHeight+2) == nil {
- t.Error("Could not retrieve the just created block (side-chain)")
- }
- }
|