github.com/waltonchain/waltonchain_gwtc_src@v1.1.4-0.20201225072101-8a298c95a819/accounts/abi/bind/backends/simulated.go (about) 1 // Copyright 2015 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-wtc 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-wtc 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 "context" 21 "errors" 22 "fmt" 23 "math/big" 24 "sync" 25 "time" 26 27 "github.com/wtc/go-wtc" 28 "github.com/wtc/go-wtc/accounts/abi/bind" 29 "github.com/wtc/go-wtc/common" 30 "github.com/wtc/go-wtc/common/math" 31 "github.com/wtc/go-wtc/consensus/ethash" 32 "github.com/wtc/go-wtc/core" 33 "github.com/wtc/go-wtc/core/state" 34 "github.com/wtc/go-wtc/core/types" 35 "github.com/wtc/go-wtc/core/vm" 36 "github.com/wtc/go-wtc/wtcdb" 37 "github.com/wtc/go-wtc/params" 38 ) 39 40 // This nil assignment ensures compile time that SimulatedBackend implements bind.ContractBackend. 41 var _ bind.ContractBackend = (*SimulatedBackend)(nil) 42 43 var errBlockNumberUnsupported = errors.New("SimulatedBackend cannot access blocks other than the latest block") 44 45 // SimulatedBackend implements bind.ContractBackend, simulating a blockchain in 46 // the background. Its main purpose is to allow easily testing contract bindings. 47 type SimulatedBackend struct { 48 database wtcdb.Database // In memory database to store our testing data 49 blockchain *core.BlockChain // Wtc blockchain to handle the consensus 50 51 mu sync.Mutex 52 pendingBlock *types.Block // Currently pending block that will be imported on request 53 pendingState *state.StateDB // Currently pending state that will be the active on on request 54 55 config *params.ChainConfig 56 } 57 58 // NewSimulatedBackend creates a new binding backend using a simulated blockchain 59 // for testing purposes. 60 func NewSimulatedBackend(alloc core.GenesisAlloc) *SimulatedBackend { 61 database, _ := wtcdb.NewMemDatabase() 62 genesis := core.Genesis{Config: params.AllProtocolChanges, Alloc: alloc} 63 genesis.MustCommit(database) 64 blockchain, _ := core.NewBlockChain(database, genesis.Config, ethash.NewFaker(), vm.Config{}) 65 backend := &SimulatedBackend{database: database, blockchain: blockchain, config: genesis.Config} 66 backend.rollback() 67 return backend 68 } 69 70 // Commit imports all the pending transactions as a single block and starts a 71 // fresh new state. 72 func (b *SimulatedBackend) Commit() { 73 b.mu.Lock() 74 defer b.mu.Unlock() 75 76 if _, err := b.blockchain.InsertChain([]*types.Block{b.pendingBlock}); err != nil { 77 panic(err) // This cannot happen unless the simulator is wrong, fail in that case 78 } 79 b.rollback() 80 } 81 82 // Rollback aborts all pending transactions, reverting to the last committed state. 83 func (b *SimulatedBackend) Rollback() { 84 b.mu.Lock() 85 defer b.mu.Unlock() 86 87 b.rollback() 88 } 89 90 func (b *SimulatedBackend) rollback() { 91 blocks, _ := core.GenerateChain(b.config, b.blockchain.CurrentBlock(), b.database, 1, func(int, *core.BlockGen) {}) 92 b.pendingBlock = blocks[0] 93 b.pendingState, _ = state.New(b.pendingBlock.Root(), state.NewDatabase(b.database)) 94 } 95 96 // CodeAt returns the code associated with a certain account in the blockchain. 97 func (b *SimulatedBackend) CodeAt(ctx context.Context, contract common.Address, blockNumber *big.Int) ([]byte, error) { 98 b.mu.Lock() 99 defer b.mu.Unlock() 100 101 if blockNumber != nil && blockNumber.Cmp(b.blockchain.CurrentBlock().Number()) != 0 { 102 return nil, errBlockNumberUnsupported 103 } 104 statedb, _, _, _ := b.blockchain.State() 105 return statedb.GetCode(contract), nil 106 } 107 108 // BalanceAt returns the wei balance of a certain account in the blockchain. 109 func (b *SimulatedBackend) BalanceAt(ctx context.Context, contract common.Address, blockNumber *big.Int) (*big.Int, error) { 110 b.mu.Lock() 111 defer b.mu.Unlock() 112 113 if blockNumber != nil && blockNumber.Cmp(b.blockchain.CurrentBlock().Number()) != 0 { 114 return nil, errBlockNumberUnsupported 115 } 116 statedb, _, _, _ := b.blockchain.State() 117 return statedb.GetBalance(contract), nil 118 } 119 120 // NonceAt returns the nonce of a certain account in the blockchain. 121 func (b *SimulatedBackend) NonceAt(ctx context.Context, contract common.Address, blockNumber *big.Int) (uint64, error) { 122 b.mu.Lock() 123 defer b.mu.Unlock() 124 125 if blockNumber != nil && blockNumber.Cmp(b.blockchain.CurrentBlock().Number()) != 0 { 126 return 0, errBlockNumberUnsupported 127 } 128 statedb, _, _, _ := b.blockchain.State() 129 return statedb.GetNonce(contract), nil 130 } 131 132 // StorageAt returns the value of key in the storage of an account in the blockchain. 133 func (b *SimulatedBackend) StorageAt(ctx context.Context, contract common.Address, key common.Hash, blockNumber *big.Int) ([]byte, error) { 134 b.mu.Lock() 135 defer b.mu.Unlock() 136 137 if blockNumber != nil && blockNumber.Cmp(b.blockchain.CurrentBlock().Number()) != 0 { 138 return nil, errBlockNumberUnsupported 139 } 140 statedb, _, _, _ := b.blockchain.State() 141 val := statedb.GetState(contract, key) 142 return val[:], nil 143 } 144 145 // TransactionReceipt returns the receipt of a transaction. 146 func (b *SimulatedBackend) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) { 147 receipt, _, _, _ := core.GetReceipt(b.database, txHash) 148 return receipt, nil 149 } 150 151 // PendingCodeAt returns the code associated with an account in the pending state. 152 func (b *SimulatedBackend) PendingCodeAt(ctx context.Context, contract common.Address) ([]byte, error) { 153 b.mu.Lock() 154 defer b.mu.Unlock() 155 156 return b.pendingState.GetCode(contract), nil 157 } 158 159 // CallContract executes a contract call. 160 func (b *SimulatedBackend) CallContract(ctx context.Context, call wtc.CallMsg, blockNumber *big.Int) ([]byte, error) { 161 b.mu.Lock() 162 defer b.mu.Unlock() 163 164 if blockNumber != nil && blockNumber.Cmp(b.blockchain.CurrentBlock().Number()) != 0 { 165 return nil, errBlockNumberUnsupported 166 } 167 state, err, _, _ := b.blockchain.State() 168 if err != nil { 169 return nil, err 170 } 171 rval, _, _, err := b.callContract(ctx, call, b.blockchain.CurrentBlock(), state) 172 return rval, err 173 } 174 175 // PendingCallContract executes a contract call on the pending state. 176 func (b *SimulatedBackend) PendingCallContract(ctx context.Context, call wtc.CallMsg) ([]byte, error) { 177 b.mu.Lock() 178 defer b.mu.Unlock() 179 defer b.pendingState.RevertToSnapshot(b.pendingState.Snapshot()) 180 181 rval, _, _, err := b.callContract(ctx, call, b.pendingBlock, b.pendingState) 182 return rval, err 183 } 184 185 // PendingNonceAt implements PendingStateReader.PendingNonceAt, retrieving 186 // the nonce currently pending for the account. 187 func (b *SimulatedBackend) PendingNonceAt(ctx context.Context, account common.Address) (uint64, error) { 188 b.mu.Lock() 189 defer b.mu.Unlock() 190 191 return b.pendingState.GetOrNewStateObject(account).Nonce(), nil 192 } 193 194 // SuggestGasPrice implements ContractTransactor.SuggestGasPrice. Since the simulated 195 // chain doens't have miners, we just return a gas price of 1 for any call. 196 func (b *SimulatedBackend) SuggestGasPrice(ctx context.Context) (*big.Int, error) { 197 return big.NewInt(1), nil 198 } 199 200 // EstimateGas executes the requested code against the currently pending block/state and 201 // returns the used amount of gas. 202 func (b *SimulatedBackend) EstimateGas(ctx context.Context, call wtc.CallMsg) (*big.Int, error) { 203 b.mu.Lock() 204 defer b.mu.Unlock() 205 206 // Binary search the gas requirement, as it may be higher than the amount used 207 var ( 208 lo uint64 = params.TxGas - 1 209 hi uint64 210 ) 211 if call.Gas != nil && call.Gas.Uint64() >= params.TxGas { 212 hi = call.Gas.Uint64() 213 } else { 214 hi = b.pendingBlock.GasLimit().Uint64() 215 } 216 for lo+1 < hi { 217 // Take a guess at the gas, and check transaction validity 218 mid := (hi + lo) / 2 219 call.Gas = new(big.Int).SetUint64(mid) 220 221 snapshot := b.pendingState.Snapshot() 222 _, _, failed, err := b.callContract(ctx, call, b.pendingBlock, b.pendingState) 223 b.pendingState.RevertToSnapshot(snapshot) 224 225 // If the transaction became invalid or execution failed, raise the gas limit 226 if err != nil || failed { 227 lo = mid 228 continue 229 } 230 // Otherwise assume the transaction succeeded, lower the gas limit 231 hi = mid 232 } 233 return new(big.Int).SetUint64(hi), nil 234 } 235 236 // callContract implemens common code between normal and pending contract calls. 237 // state is modified during execution, make sure to copy it if necessary. 238 func (b *SimulatedBackend) callContract(ctx context.Context, call wtc.CallMsg, block *types.Block, statedb *state.StateDB) ([]byte, *big.Int, bool, error) { 239 // Ensure message is initialized properly. 240 if call.GasPrice == nil { 241 call.GasPrice = big.NewInt(1) 242 } 243 if call.Gas == nil || call.Gas.Sign() == 0 { 244 call.Gas = big.NewInt(50000000) 245 } 246 if call.Value == nil { 247 call.Value = new(big.Int) 248 } 249 // Set infinite balance to the fake caller account. 250 from := statedb.GetOrNewStateObject(call.From) 251 from.SetBalance(math.MaxBig256,new(big.Int),new(big.Int)) 252 // Execute the call. 253 msg := callmsg{call} 254 255 evmContext := core.NewEVMContext(msg, block.Header(), b.blockchain, nil) 256 // Create a new environment which holds all relevant information 257 // about the transaction and calling mechanisms. 258 vmenv := vm.NewEVM(evmContext, statedb, b.config, vm.Config{}) 259 gaspool := new(core.GasPool).AddGas(math.MaxBig256) 260 ret, gasUsed, _, failed, err := core.NewStateTransition(vmenv, msg, gaspool).TransitionDb() 261 return ret, gasUsed, failed, err 262 } 263 264 // SendTransaction updates the pending block to include the given transaction. 265 // It panics if the transaction is invalid. 266 func (b *SimulatedBackend) SendTransaction(ctx context.Context, tx *types.Transaction) error { 267 b.mu.Lock() 268 defer b.mu.Unlock() 269 270 sender, err := types.Sender(types.HomesteadSigner{}, tx) 271 if err != nil { 272 panic(fmt.Errorf("invalid transaction: %v", err)) 273 } 274 nonce := b.pendingState.GetNonce(sender) 275 if tx.Nonce() != nonce { 276 panic(fmt.Errorf("invalid transaction nonce: got %d, want %d", tx.Nonce(), nonce)) 277 } 278 279 blocks, _ := core.GenerateChain(b.config, b.blockchain.CurrentBlock(), b.database, 1, func(number int, block *core.BlockGen) { 280 for _, tx := range b.pendingBlock.Transactions() { 281 block.AddTx(tx) 282 } 283 block.AddTx(tx) 284 }) 285 b.pendingBlock = blocks[0] 286 b.pendingState, _ = state.New(b.pendingBlock.Root(), state.NewDatabase(b.database)) 287 return nil 288 } 289 290 // JumpTimeInSeconds adds skip seconds to the clock 291 func (b *SimulatedBackend) AdjustTime(adjustment time.Duration) error { 292 b.mu.Lock() 293 defer b.mu.Unlock() 294 blocks, _ := core.GenerateChain(b.config, b.blockchain.CurrentBlock(), b.database, 1, func(number int, block *core.BlockGen) { 295 for _, tx := range b.pendingBlock.Transactions() { 296 block.AddTx(tx) 297 } 298 block.OffsetTime(int64(adjustment.Seconds())) 299 }) 300 b.pendingBlock = blocks[0] 301 b.pendingState, _ = state.New(b.pendingBlock.Root(), state.NewDatabase(b.database)) 302 303 return nil 304 } 305 306 // callmsg implements core.Message to allow passing it as a transaction simulator. 307 type callmsg struct { 308 wtc.CallMsg 309 } 310 311 func (m callmsg) From() common.Address { return m.CallMsg.From } 312 func (m callmsg) Nonce() uint64 { return 0 } 313 func (m callmsg) CheckNonce() bool { return false } 314 func (m callmsg) To() *common.Address { return m.CallMsg.To } 315 func (m callmsg) GasPrice() *big.Int { return m.CallMsg.GasPrice } 316 func (m callmsg) Gas() *big.Int { return m.CallMsg.Gas } 317 func (m callmsg) Value() *big.Int { return m.CallMsg.Value } 318 func (m callmsg) Data() []byte { return m.CallMsg.Data }