github.com/insight-chain/inb-go@v1.1.3-0.20191221022159-da049980ae38/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-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 MiningReward, 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 "context" 21 "errors" 22 "fmt" 23 "math/big" 24 "sync" 25 "time" 26 27 "github.com/insight-chain/inb-go" 28 "github.com/insight-chain/inb-go/accounts/abi/bind" 29 "github.com/insight-chain/inb-go/common" 30 "github.com/insight-chain/inb-go/common/math" 31 "github.com/insight-chain/inb-go/consensus/ethash" 32 "github.com/insight-chain/inb-go/core" 33 "github.com/insight-chain/inb-go/core/bloombits" 34 "github.com/insight-chain/inb-go/core/rawdb" 35 "github.com/insight-chain/inb-go/core/state" 36 "github.com/insight-chain/inb-go/core/types" 37 "github.com/insight-chain/inb-go/core/vm" 38 "github.com/insight-chain/inb-go/eth/filters" 39 "github.com/insight-chain/inb-go/ethdb" 40 "github.com/insight-chain/inb-go/event" 41 "github.com/insight-chain/inb-go/params" 42 "github.com/insight-chain/inb-go/rpc" 43 ) 44 45 // This nil assignment ensures compile time that SimulatedBackend implements bind.ContractBackend. 46 var _ bind.ContractBackend = (*SimulatedBackend)(nil) 47 48 var errBlockNumberUnsupported = errors.New("SimulatedBackend cannot access blocks other than the latest block") 49 var errGasEstimationFailed = errors.New("gas required exceeds allowance or always failing transaction") 50 51 // SimulatedBackend implements bind.ContractBackend, simulating a blockchain in 52 // the background. Its main purpose is to allow easily testing contract bindings. 53 type SimulatedBackend struct { 54 database ethdb.Database // In memory database to store our testing data 55 blockchain *core.BlockChain // Ethereum blockchain to handle the consensus 56 57 mu sync.Mutex 58 pendingBlock *types.Block // Currently pending block that will be imported on request 59 pendingState *state.StateDB // Currently pending state that will be the active on on request 60 61 events *filters.EventSystem // Event system for filtering log events live 62 63 config *params.ChainConfig 64 } 65 66 // NewSimulatedBackend creates a new binding backend using a simulated blockchain 67 // for testing purposes. 68 func NewSimulatedBackend(alloc core.GenesisAlloc, gasLimit uint64) *SimulatedBackend { 69 database := ethdb.NewMemDatabase() 70 genesis := core.Genesis{Config: params.AllEthashProtocolChanges, ResLimit: gasLimit, Alloc: alloc} 71 genesis.MustCommit(database) 72 blockchain, _ := core.NewBlockChain(database, nil, genesis.Config, ethash.NewFaker(), vm.Config{}, nil) 73 74 backend := &SimulatedBackend{ 75 database: database, 76 blockchain: blockchain, 77 config: genesis.Config, 78 events: filters.NewEventSystem(new(event.TypeMux), &filterBackend{database, blockchain}, false), 79 } 80 backend.rollback() 81 return backend 82 } 83 84 // Commit imports all the pending transactions as a single block and starts a 85 // fresh new state. 86 func (b *SimulatedBackend) Commit() { 87 b.mu.Lock() 88 defer b.mu.Unlock() 89 90 if _, err := b.blockchain.InsertChain([]*types.Block{b.pendingBlock}); err != nil { 91 panic(err) // This cannot happen unless the simulator is wrong, fail in that case 92 } 93 b.rollback() 94 } 95 96 // Rollback aborts all pending transactions, reverting to the last committed state. 97 func (b *SimulatedBackend) Rollback() { 98 b.mu.Lock() 99 defer b.mu.Unlock() 100 101 b.rollback() 102 } 103 104 func (b *SimulatedBackend) rollback() { 105 blocks, _ := core.GenerateChain(b.config, b.blockchain.CurrentBlock(), ethash.NewFaker(), b.database, 1, func(int, *core.BlockGen) {}) 106 statedb, _ := b.blockchain.State() 107 108 b.pendingBlock = blocks[0] 109 b.pendingState, _ = state.New(b.pendingBlock.Root(), statedb.Database()) 110 } 111 112 // CodeAt returns the code associated with a certain account in the blockchain. 113 func (b *SimulatedBackend) CodeAt(ctx context.Context, contract common.Address, blockNumber *big.Int) ([]byte, error) { 114 b.mu.Lock() 115 defer b.mu.Unlock() 116 117 if blockNumber != nil && blockNumber.Cmp(b.blockchain.CurrentBlock().Number()) != 0 { 118 return nil, errBlockNumberUnsupported 119 } 120 statedb, _ := b.blockchain.State() 121 return statedb.GetCode(contract), nil 122 } 123 124 // BalanceAt returns the wei balance of a certain account in the blockchain. 125 func (b *SimulatedBackend) BalanceAt(ctx context.Context, contract common.Address, blockNumber *big.Int) (*big.Int, error) { 126 b.mu.Lock() 127 defer b.mu.Unlock() 128 129 if blockNumber != nil && blockNumber.Cmp(b.blockchain.CurrentBlock().Number()) != 0 { 130 return nil, errBlockNumberUnsupported 131 } 132 statedb, _ := b.blockchain.State() 133 return statedb.GetBalance(contract), nil 134 } 135 136 //Resource by zc 137 //func (b *SimulatedBackend) CpuAt(ctx context.Context, contract common.Address, blockNumber *big.Int) (*big.Int, error) { 138 // b.mu.Lock() 139 // defer b.mu.Unlock() 140 // 141 // if blockNumber != nil && blockNumber.Cmp(b.blockchain.CurrentBlock().Number()) != 0 { 142 // return nil, errBlockNumberUnsupported 143 // } 144 // statedb, _ := b.blockchain.State() 145 // return statedb.GetCpu(contract), nil 146 //} 147 func (b *SimulatedBackend) NetAt(ctx context.Context, contract common.Address, blockNumber *big.Int) (*big.Int, error) { 148 b.mu.Lock() 149 defer b.mu.Unlock() 150 151 if blockNumber != nil && blockNumber.Cmp(b.blockchain.CurrentBlock().Number()) != 0 { 152 return nil, errBlockNumberUnsupported 153 } 154 statedb, _ := b.blockchain.State() 155 return statedb.GetNet(contract), nil 156 } 157 158 //Resource by zc 159 // NonceAt returns the nonce of a certain account in the blockchain. 160 func (b *SimulatedBackend) NonceAt(ctx context.Context, contract common.Address, blockNumber *big.Int) (uint64, error) { 161 b.mu.Lock() 162 defer b.mu.Unlock() 163 164 if blockNumber != nil && blockNumber.Cmp(b.blockchain.CurrentBlock().Number()) != 0 { 165 return 0, errBlockNumberUnsupported 166 } 167 statedb, _ := b.blockchain.State() 168 return statedb.GetNonce(contract), nil 169 } 170 171 // StorageAt returns the value of key in the storage of an account in the blockchain. 172 func (b *SimulatedBackend) StorageAt(ctx context.Context, contract common.Address, key common.Hash, blockNumber *big.Int) ([]byte, error) { 173 b.mu.Lock() 174 defer b.mu.Unlock() 175 176 if blockNumber != nil && blockNumber.Cmp(b.blockchain.CurrentBlock().Number()) != 0 { 177 return nil, errBlockNumberUnsupported 178 } 179 statedb, _ := b.blockchain.State() 180 val := statedb.GetState(contract, key) 181 return val[:], nil 182 } 183 184 // TransactionReceipt returns the receipt of a transaction. 185 func (b *SimulatedBackend) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) { 186 receipt, _, _, _ := rawdb.ReadReceipt(b.database, txHash) 187 return receipt, nil 188 } 189 190 // PendingCodeAt returns the code associated with an account in the pending state. 191 func (b *SimulatedBackend) PendingCodeAt(ctx context.Context, contract common.Address) ([]byte, error) { 192 b.mu.Lock() 193 defer b.mu.Unlock() 194 195 return b.pendingState.GetCode(contract), nil 196 } 197 198 // CallContract executes a contract call. 199 func (b *SimulatedBackend) CallContract(ctx context.Context, call ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) { 200 b.mu.Lock() 201 defer b.mu.Unlock() 202 203 if blockNumber != nil && blockNumber.Cmp(b.blockchain.CurrentBlock().Number()) != 0 { 204 return nil, errBlockNumberUnsupported 205 } 206 state, err := b.blockchain.State() 207 if err != nil { 208 return nil, err 209 } 210 rval, _, _, err := b.callContract(ctx, call, b.blockchain.CurrentBlock(), state) 211 return rval, err 212 } 213 214 // PendingCallContract executes a contract call on the pending state. 215 func (b *SimulatedBackend) PendingCallContract(ctx context.Context, call ethereum.CallMsg) ([]byte, error) { 216 b.mu.Lock() 217 defer b.mu.Unlock() 218 defer b.pendingState.RevertToSnapshot(b.pendingState.Snapshot()) 219 220 rval, _, _, err := b.callContract(ctx, call, b.pendingBlock, b.pendingState) 221 return rval, err 222 } 223 224 // PendingNonceAt implements PendingStateReader.PendingNonceAt, retrieving 225 // the nonce currently pending for the account. 226 func (b *SimulatedBackend) PendingNonceAt(ctx context.Context, account common.Address) (uint64, error) { 227 b.mu.Lock() 228 defer b.mu.Unlock() 229 230 return b.pendingState.GetOrNewStateObject(account).Nonce(), nil 231 } 232 233 // SuggestGasPrice implements ContractTransactor.SuggestGasPrice. Since the simulated 234 // chain doesn't have miners, we just return a gas price of 1 for any call. 235 func (b *SimulatedBackend) SuggestGasPrice(ctx context.Context) (*big.Int, error) { 236 return big.NewInt(1), nil 237 } 238 239 // EstimateGas executes the requested code against the currently pending block/state and 240 // returns the used amount of gas. 241 func (b *SimulatedBackend) EstimateGas(ctx context.Context, call ethereum.CallMsg) (uint64, error) { 242 b.mu.Lock() 243 defer b.mu.Unlock() 244 245 // Determine the lowest and highest possible gas limits to binary search in between 246 var ( 247 lo uint64 = params.TxGas - 1 248 hi uint64 249 cap uint64 250 ) 251 //achilles0817 replace column 'gas' with 'net' 252 if call.Net >= params.TxGas { 253 hi = call.Net 254 } else { 255 hi = b.pendingBlock.GasLimit() 256 } 257 cap = hi 258 259 // Create a helper to check if a gas allowance results in an executable transaction 260 executable := func(gas uint64) bool { 261 call.Net = gas 262 263 snapshot := b.pendingState.Snapshot() 264 _, _, failed, err := b.callContract(ctx, call, b.pendingBlock, b.pendingState) 265 b.pendingState.RevertToSnapshot(snapshot) 266 267 if err != nil || failed { 268 return false 269 } 270 return true 271 } 272 // Execute the binary search and hone in on an executable gas limit 273 for lo+1 < hi { 274 mid := (hi + lo) / 2 275 if !executable(mid) { 276 lo = mid 277 } else { 278 hi = mid 279 } 280 } 281 // Reject the transaction as invalid if it still fails at the highest allowance 282 if hi == cap { 283 if !executable(hi) { 284 return 0, errGasEstimationFailed 285 } 286 } 287 return hi, nil 288 } 289 290 // callContract implements common code between normal and pending contract calls. 291 // state is modified during execution, make sure to copy it if necessary. 292 func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallMsg, block *types.Block, statedb *state.StateDB) ([]byte, uint64, bool, error) { 293 // Ensure message is initialized properly. 294 //if call.GasPrice == nil { 295 // call.GasPrice = big.NewInt(1) 296 //} 297 if call.Net == 0 { 298 call.Net = 50000000 299 } 300 if call.Value == nil { 301 call.Value = new(big.Int) 302 } 303 // Set infinite balance to the fake caller account. 304 from := statedb.GetOrNewStateObject(call.From) 305 from.SetBalance(math.MaxBig256) 306 // Execute the call. 307 msg := callmsg{call} 308 309 evmContext := core.NewEVMContext(msg, block.Header(), b.blockchain, nil) 310 // Create a new environment which holds all relevant information 311 // about the transaction and calling mechanisms. 312 vmenv := vm.NewEVM(evmContext, statedb, b.config, vm.Config{}) 313 gaspool := new(core.GasPool).AddGas(math.MaxUint64) 314 315 //2019.8.1 mod inb by ghy 316 ret, usedGas, failed, err, _ := core.NewStateTransition(vmenv, msg, gaspool).TransitionDb() 317 318 return ret, usedGas, failed, err 319 //2019.8.1 mod inb by end 320 } 321 322 // SendTransaction updates the pending block to include the given transaction. 323 // It panics if the transaction is invalid. 324 func (b *SimulatedBackend) SendTransaction(ctx context.Context, tx *types.Transaction) error { 325 b.mu.Lock() 326 defer b.mu.Unlock() 327 328 sender, err := types.Sender(types.HomesteadSigner{}, tx) 329 if err != nil { 330 panic(fmt.Errorf("invalid transaction: %v", err)) 331 } 332 nonce := b.pendingState.GetNonce(sender) 333 if tx.Nonce() != nonce { 334 panic(fmt.Errorf("invalid transaction nonce: got %d, want %d", tx.Nonce(), nonce)) 335 } 336 337 blocks, _ := core.GenerateChain(b.config, b.blockchain.CurrentBlock(), ethash.NewFaker(), b.database, 1, func(number int, block *core.BlockGen) { 338 for _, tx := range b.pendingBlock.Transactions() { 339 block.AddTxWithChain(b.blockchain, tx) 340 } 341 block.AddTxWithChain(b.blockchain, tx) 342 }) 343 statedb, _ := b.blockchain.State() 344 345 b.pendingBlock = blocks[0] 346 b.pendingState, _ = state.New(b.pendingBlock.Root(), statedb.Database()) 347 return nil 348 } 349 350 // FilterLogs executes a log filter operation, blocking during execution and 351 // returning all the results in one batch. 352 // 353 // TODO(karalabe): Deprecate when the subscription one can return past data too. 354 func (b *SimulatedBackend) FilterLogs(ctx context.Context, query ethereum.FilterQuery) ([]types.Log, error) { 355 var filter *filters.Filter 356 if query.BlockHash != nil { 357 // Block filter requested, construct a single-shot filter 358 filter = filters.NewBlockFilter(&filterBackend{b.database, b.blockchain}, *query.BlockHash, query.Addresses, query.Topics) 359 } else { 360 // Initialize unset filter boundaried to run from genesis to chain head 361 from := int64(0) 362 if query.FromBlock != nil { 363 from = query.FromBlock.Int64() 364 } 365 to := int64(-1) 366 if query.ToBlock != nil { 367 to = query.ToBlock.Int64() 368 } 369 // Construct the range filter 370 filter = filters.NewRangeFilter(&filterBackend{b.database, b.blockchain}, from, to, query.Addresses, query.Topics) 371 } 372 // Run the filter and return all the logs 373 logs, err := filter.Logs(ctx) 374 if err != nil { 375 return nil, err 376 } 377 res := make([]types.Log, len(logs)) 378 for i, log := range logs { 379 res[i] = *log 380 } 381 return res, nil 382 } 383 384 // SubscribeFilterLogs creates a background log filtering operation, returning a 385 // subscription immediately, which can be used to stream the found events. 386 func (b *SimulatedBackend) SubscribeFilterLogs(ctx context.Context, query ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error) { 387 // Subscribe to contract events 388 sink := make(chan []*types.Log) 389 390 sub, err := b.events.SubscribeLogs(query, sink) 391 if err != nil { 392 return nil, err 393 } 394 // Since we're getting logs in batches, we need to flatten them into a plain stream 395 return event.NewSubscription(func(quit <-chan struct{}) error { 396 defer sub.Unsubscribe() 397 for { 398 select { 399 case logs := <-sink: 400 for _, log := range logs { 401 select { 402 case ch <- *log: 403 case err := <-sub.Err(): 404 return err 405 case <-quit: 406 return nil 407 } 408 } 409 case err := <-sub.Err(): 410 return err 411 case <-quit: 412 return nil 413 } 414 } 415 }), nil 416 } 417 418 // AdjustTime adds a time shift to the simulated clock. 419 func (b *SimulatedBackend) AdjustTime(adjustment time.Duration) error { 420 b.mu.Lock() 421 defer b.mu.Unlock() 422 blocks, _ := core.GenerateChain(b.config, b.blockchain.CurrentBlock(), ethash.NewFaker(), b.database, 1, func(number int, block *core.BlockGen) { 423 for _, tx := range b.pendingBlock.Transactions() { 424 block.AddTx(tx) 425 } 426 block.OffsetTime(int64(adjustment.Seconds())) 427 }) 428 statedb, _ := b.blockchain.State() 429 430 b.pendingBlock = blocks[0] 431 b.pendingState, _ = state.New(b.pendingBlock.Root(), statedb.Database()) 432 433 return nil 434 } 435 436 // callmsg implements core.Message to allow passing it as a transaction simulator. 437 type callmsg struct { 438 ethereum.CallMsg 439 } 440 441 func (m callmsg) From() common.Address { return m.CallMsg.From } 442 func (m callmsg) Nonce() uint64 { return 0 } 443 func (m callmsg) CheckNonce() bool { return false } 444 func (m callmsg) To() *common.Address { return m.CallMsg.To } 445 func (m callmsg) Receive() *big.Int { return m.CallMsg.Receive } 446 447 //func (m callmsg) GasPrice() *big.Int { return m.CallMsg.GasPrice } 448 func (m callmsg) GasPrice() *big.Int { return big.NewInt(1) } 449 func (m callmsg) Gas() uint64 { return m.CallMsg.Net } 450 func (m callmsg) Value() *big.Int { return m.CallMsg.Value } 451 func (m callmsg) Data() []byte { return m.CallMsg.Data } 452 453 //achilles repayment add apis 454 func (m callmsg) ResourcePayer() common.Address { return [20]byte{} } 455 func (m callmsg) IsRePayment() bool { return false } 456 func (m callmsg) Types() types.TxType { return 0 } 457 func (m callmsg) Hash() common.Hash { return [32]byte{} } 458 459 // filterBackend implements filters.Backend to support filtering for logs without 460 // taking bloom-bits acceleration structures into account. 461 type filterBackend struct { 462 db ethdb.Database 463 bc *core.BlockChain 464 } 465 466 func (fb *filterBackend) ChainDb() ethdb.Database { return fb.db } 467 func (fb *filterBackend) EventMux() *event.TypeMux { panic("not supported") } 468 469 func (fb *filterBackend) HeaderByNumber(ctx context.Context, block rpc.BlockNumber) (*types.Header, error) { 470 if block == rpc.LatestBlockNumber { 471 return fb.bc.CurrentHeader(), nil 472 } 473 return fb.bc.GetHeaderByNumber(uint64(block.Int64())), nil 474 } 475 476 func (fb *filterBackend) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) { 477 return fb.bc.GetHeaderByHash(hash), nil 478 } 479 480 func (fb *filterBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) { 481 number := rawdb.ReadHeaderNumber(fb.db, hash) 482 if number == nil { 483 return nil, nil 484 } 485 return rawdb.ReadReceipts(fb.db, hash, *number), nil 486 } 487 488 func (fb *filterBackend) GetLogs(ctx context.Context, hash common.Hash) ([][]*types.Log, error) { 489 number := rawdb.ReadHeaderNumber(fb.db, hash) 490 if number == nil { 491 return nil, nil 492 } 493 receipts := rawdb.ReadReceipts(fb.db, hash, *number) 494 if receipts == nil { 495 return nil, nil 496 } 497 logs := make([][]*types.Log, len(receipts)) 498 for i, receipt := range receipts { 499 logs[i] = receipt.Logs 500 } 501 return logs, nil 502 } 503 504 func (fb *filterBackend) SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.Subscription { 505 return event.NewSubscription(func(quit <-chan struct{}) error { 506 <-quit 507 return nil 508 }) 509 } 510 func (fb *filterBackend) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription { 511 return fb.bc.SubscribeChainEvent(ch) 512 } 513 func (fb *filterBackend) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription { 514 return fb.bc.SubscribeRemovedLogsEvent(ch) 515 } 516 func (fb *filterBackend) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription { 517 return fb.bc.SubscribeLogsEvent(ch) 518 } 519 520 func (fb *filterBackend) BloomStatus() (uint64, uint64) { return 4096, 0 } 521 func (fb *filterBackend) ServiceFilter(ctx context.Context, ms *bloombits.MatcherSession) { 522 panic("not supported") 523 }