github.com/ethereumproject/go-ethereum@v5.5.2+incompatible/accounts/abi/bind/backends/simulated.go (about) 1 // Copyright 2016 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package backends 18 19 import ( 20 "math/big" 21 22 "github.com/ethereumproject/go-ethereum/accounts/abi/bind" 23 "github.com/ethereumproject/go-ethereum/common" 24 "github.com/ethereumproject/go-ethereum/core" 25 "github.com/ethereumproject/go-ethereum/core/state" 26 "github.com/ethereumproject/go-ethereum/core/types" 27 "github.com/ethereumproject/go-ethereum/ethdb" 28 "github.com/ethereumproject/go-ethereum/event" 29 ) 30 31 // This nil assignment ensures compile time that SimulatedBackend implements bind.ContractBackend. 32 var _ bind.ContractBackend = (*SimulatedBackend)(nil) 33 34 // SimulatedBackend implements bind.ContractBackend, simulating a blockchain in 35 // the background. Its main purpose is to allow easily testing contract bindings. 36 type SimulatedBackend struct { 37 database ethdb.Database // In memory database to store our testing data 38 blockchain *core.BlockChain // Ethereum blockchain to handle the consensus 39 40 pendingBlock *types.Block // Currently pending block that will be imported on request 41 pendingState *state.StateDB // Currently pending state that will be the active on on request 42 } 43 44 // NewSimulatedBackend creates a new binding backend using a simulated blockchain 45 // for testing purposes. 46 func NewSimulatedBackend(accounts ...core.GenesisAccount) *SimulatedBackend { 47 database, _ := ethdb.NewMemDatabase() 48 core.WriteGenesisBlockForTesting(database, accounts...) 49 blockchain, _ := core.NewBlockChain(database, core.DefaultConfigMorden.ChainConfig, new(core.FakePow), new(event.TypeMux)) 50 51 backend := &SimulatedBackend{ 52 database: database, 53 blockchain: blockchain, 54 } 55 backend.Rollback() 56 57 return backend 58 } 59 60 // Commit imports all the pending transactions as a single block and starts a 61 // fresh new state. 62 func (b *SimulatedBackend) Commit() { 63 if res := b.blockchain.InsertChain([]*types.Block{b.pendingBlock}); res.Error != nil { 64 panic(res.Error) // This cannot happen unless the simulator is wrong, fail in that case 65 } 66 b.Rollback() 67 } 68 69 // Rollback aborts all pending transactions, reverting to the last committed state. 70 func (b *SimulatedBackend) Rollback() { 71 blocks, _ := core.GenerateChain(core.DefaultConfigMorden.ChainConfig, b.blockchain.CurrentBlock(), b.database, 1, func(int, *core.BlockGen) {}) 72 73 b.pendingBlock = blocks[0] 74 b.pendingState, _ = state.New(b.pendingBlock.Root(), state.NewDatabase(b.database)) 75 } 76 77 // HasCode implements ContractVerifier.HasCode, checking whether there is any 78 // code associated with a certain account in the blockchain. 79 func (b *SimulatedBackend) HasCode(contract common.Address, pending bool) (bool, error) { 80 if pending { 81 return len(b.pendingState.GetCode(contract)) > 0, nil 82 } 83 statedb, _ := b.blockchain.State() 84 return len(statedb.GetCode(contract)) > 0, nil 85 } 86 87 // ContractCall implements ContractCaller.ContractCall, executing the specified 88 // contract with the given input data. 89 func (b *SimulatedBackend) ContractCall(contract common.Address, data []byte, pending bool) ([]byte, error) { 90 // Create a copy of the current state db to screw around with 91 var ( 92 block *types.Block 93 statedb *state.StateDB 94 ) 95 if pending { 96 block, statedb = b.pendingBlock, b.pendingState 97 defer statedb.RevertToSnapshot(statedb.Snapshot()) 98 } else { 99 block = b.blockchain.CurrentBlock() 100 statedb, _ = b.blockchain.State() 101 } 102 // If there's no code to interact with, respond with an appropriate error 103 if code := statedb.GetCode(contract); len(code) == 0 { 104 return nil, bind.ErrNoCode 105 } 106 // Set infinite balance to the a fake caller account 107 from := statedb.GetOrNewStateObject(common.Address{}) 108 from.SetBalance(common.MaxBig) 109 110 // Assemble the call invocation to measure the gas usage 111 msg := callmsg{ 112 from: from, 113 to: &contract, 114 gasPrice: new(big.Int), 115 gasLimit: common.MaxBig, 116 value: new(big.Int), 117 data: data, 118 } 119 // Execute the call and return 120 vmenv := core.NewEnv(statedb, core.DefaultConfigMorden.ChainConfig, b.blockchain, msg, block.Header()) 121 gaspool := new(core.GasPool).AddGas(common.MaxBig) 122 123 out, _, _, err := core.ApplyMessage(vmenv, msg, gaspool) 124 return out, err 125 } 126 127 // PendingAccountNonce implements ContractTransactor.PendingAccountNonce, retrieving 128 // the nonce currently pending for the account. 129 func (b *SimulatedBackend) PendingAccountNonce(account common.Address) (uint64, error) { 130 return b.pendingState.GetOrNewStateObject(account).Nonce(), nil 131 } 132 133 // SuggestGasPrice implements ContractTransactor.SuggestGasPrice. Since the simulated 134 // chain doens't have miners, we just return a gas price of 1 for any call. 135 func (b *SimulatedBackend) SuggestGasPrice() (*big.Int, error) { 136 return big.NewInt(1), nil 137 } 138 139 // EstimateGasLimit implements ContractTransactor.EstimateGasLimit, executing the 140 // requested code against the currently pending block/state and returning the used 141 // gas. 142 func (b *SimulatedBackend) EstimateGasLimit(sender common.Address, contract *common.Address, value *big.Int, data []byte) (*big.Int, error) { 143 // Create a copy of the currently pending state db to screw around with 144 var ( 145 block = b.pendingBlock 146 statedb = b.pendingState 147 ) 148 defer statedb.RevertToSnapshot(statedb.Snapshot()) 149 150 // If there's no code to interact with, respond with an appropriate error 151 if contract != nil { 152 if code := statedb.GetCode(*contract); len(code) == 0 { 153 return nil, bind.ErrNoCode 154 } 155 } 156 // Set infinite balance to the a fake caller account 157 from := statedb.GetOrNewStateObject(sender) 158 from.SetBalance(common.MaxBig) 159 160 // Assemble the call invocation to measure the gas usage 161 msg := callmsg{ 162 from: from, 163 to: contract, 164 gasPrice: new(big.Int), 165 gasLimit: common.MaxBig, 166 value: value, 167 data: data, 168 } 169 // Execute the call and return 170 vmenv := core.NewEnv(statedb, core.DefaultConfigMorden.ChainConfig, b.blockchain, msg, block.Header()) 171 gaspool := new(core.GasPool).AddGas(common.MaxBig) 172 173 _, gas, _, err := core.NewStateTransition(vmenv, msg, gaspool).TransitionDb() 174 return gas, err 175 } 176 177 // SendTransaction implements ContractTransactor.SendTransaction, delegating the raw 178 // transaction injection to the remote node. 179 func (b *SimulatedBackend) SendTransaction(tx *types.Transaction) error { 180 blocks, _ := core.GenerateChain(core.DefaultConfigMorden.ChainConfig, b.blockchain.CurrentBlock(), b.database, 1, func(number int, block *core.BlockGen) { 181 for _, tx := range b.pendingBlock.Transactions() { 182 block.AddTx(tx) 183 } 184 block.AddTx(tx) 185 }) 186 b.pendingBlock = blocks[0] 187 b.pendingState, _ = state.New(b.pendingBlock.Root(), state.NewDatabase(b.database)) 188 189 return nil 190 } 191 192 // callmsg implements core.Message to allow passing it as a transaction simulator. 193 type callmsg struct { 194 from *state.StateObject 195 to *common.Address 196 gasLimit *big.Int 197 gasPrice *big.Int 198 value *big.Int 199 data []byte 200 } 201 202 func (m callmsg) From() (common.Address, error) { return m.from.Address(), nil } 203 func (m callmsg) FromFrontier() (common.Address, error) { return m.from.Address(), nil } 204 func (m callmsg) Nonce() uint64 { return m.from.Nonce() } 205 func (m callmsg) To() *common.Address { return m.to } 206 func (m callmsg) GasPrice() *big.Int { return m.gasPrice } 207 func (m callmsg) Gas() *big.Int { return m.gasLimit } 208 func (m callmsg) Value() *big.Int { return m.value } 209 func (m callmsg) Data() []byte { return m.data }