github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/accounts/abi/bind/backends/simulated.go (about) 1 2 //<developer> 3 // <name>linapex 曹一峰</name> 4 // <email>linapex@163.com</email> 5 // <wx>superexc</wx> 6 // <qqgroup>128148617</qqgroup> 7 // <url>https://jsq.ink</url> 8 // <role>pku engineer</role> 9 // <date>2019-03-16 12:09:26</date> 10 //</624342582608007168> 11 12 13 package backends 14 15 import ( 16 "context" 17 "errors" 18 "fmt" 19 "math/big" 20 "sync" 21 "time" 22 23 "github.com/ethereum/go-ethereum" 24 "github.com/ethereum/go-ethereum/accounts/abi/bind" 25 "github.com/ethereum/go-ethereum/common" 26 "github.com/ethereum/go-ethereum/common/math" 27 //“github.com/ethereum/go-ethereum/consultance/ethash” 28 "github.com/ethereum/go-ethereum/core" 29 "github.com/ethereum/go-ethereum/core/bloombits" 30 "github.com/ethereum/go-ethereum/core/rawdb" 31 "github.com/ethereum/go-ethereum/core/state" 32 "github.com/ethereum/go-ethereum/core/types" 33 "github.com/ethereum/go-ethereum/core/vm" 34 "github.com/ethereum/go-ethereum/eth/filters" 35 "github.com/ethereum/go-ethereum/ethdb" 36 "github.com/ethereum/go-ethereum/event" 37 "github.com/ethereum/go-ethereum/params" 38 "github.com/ethereum/go-ethereum/rpc" 39 "github.com/ethereum/go-ethereum/consensus/dpos" 40 ) 41 //这个nil分配确保了模拟后端实现bind.contractbackend的编译时间。 42 var _ bind.ContractBackend = (*SimulatedBackend)(nil) 43 44 var errBlockNumberUnsupported = errors.New("SimulatedBackend cannot access blocks other than the latest block") 45 var errGasEstimationFailed = errors.New("gas required exceeds allowance or always failing transaction") 46 47 //Simulatedbackend实现bind.contractbackend,在 48 //背景。其主要目的是允许轻松测试合同绑定。 49 type SimulatedBackend struct { 50 database ethdb.Database //存储测试数据的内存数据库 51 blockchain *core.BlockChain //以太坊区块链处理共识 52 53 mu sync.Mutex 54 pendingBlock *types.Block //将根据请求导入的当前挂起块 55 pendingState *state.StateDB //当前处于挂起状态,根据请求将处于活动状态 56 57 events *filters.EventSystem //用于实时筛选日志事件的事件系统 58 59 config *params.ChainConfig 60 } 61 62 //NewSimulatedBackend使用模拟区块链创建新的绑定后端 63 //用于测试。 64 func NewSimulatedBackend(alloc core.GenesisAlloc, gasLimit uint64) *SimulatedBackend { 65 database := ethdb.NewMemDatabase() 66 genesis := core.Genesis{Config: params.DposChainConfig, Alloc: alloc} 67 genesis.MustCommit(database) 68 dposcfg := ¶ms.DposConfig { 69 Validators: []common.Address{ 70 common.HexToAddress("0x3645b2bc6febc23d6634cc4114627c2b57b7dbb596c1bbb26af7ed9c4e57f370"), 71 common.HexToAddress("0x7bf279be14c6928b0ae372f82016138a49e80a146853bc5de45ba30069ef58a9"), 72 }, 73 } 74 blockchain, _ := core.NewBlockChain(database, nil, genesis.Config, dpos.New(dposcfg ,database), vm.Config{}) 75 76 backend := &SimulatedBackend{ 77 database: database, 78 blockchain: blockchain, 79 config: genesis.Config, 80 events: filters.NewEventSystem(new(event.TypeMux), &filterBackend{database, blockchain}, false), 81 } 82 backend.rollback() 83 return backend 84 } 85 86 //commit将所有挂起的事务作为单个块导入并启动 87 //新的状态。 88 func (b *SimulatedBackend) Commit() { 89 b.mu.Lock() 90 defer b.mu.Unlock() 91 92 if _, err := b.blockchain.InsertChain([]*types.Block{b.pendingBlock}); err != nil { 93 panic(err) //除非模拟器出错,否则不会发生这种情况,在这种情况下会失败。 94 } 95 b.rollback() 96 } 97 98 //回滚将中止所有挂起的事务,恢复到上一次提交的状态。 99 func (b *SimulatedBackend) Rollback() { 100 b.mu.Lock() 101 defer b.mu.Unlock() 102 103 b.rollback() 104 } 105 106 func (b *SimulatedBackend) rollback() { 107 blocks, _ := core.GenerateChain(b.config, b.blockchain.CurrentBlock(), ethash.NewFaker(), b.database, 1, func(int, *core.BlockGen) {}) 108 statedb, _ := b.blockchain.State() 109 110 b.pendingBlock = blocks[0] 111 b.pendingState, _ = state.New(b.pendingBlock.Root(), statedb.Database()) 112 } 113 114 //codeat返回与区块链中某个帐户关联的代码。 115 func (b *SimulatedBackend) CodeAt(ctx context.Context, contract common.Address, blockNumber *big.Int) ([]byte, error) { 116 b.mu.Lock() 117 defer b.mu.Unlock() 118 119 if blockNumber != nil && blockNumber.Cmp(b.blockchain.CurrentBlock().Number()) != 0 { 120 return nil, errBlockNumberUnsupported 121 } 122 statedb, _ := b.blockchain.State() 123 return statedb.GetCode(contract), nil 124 } 125 126 //balanceat返回区块链中某个账户的wei余额。 127 func (b *SimulatedBackend) BalanceAt(ctx context.Context, contract common.Address, blockNumber *big.Int) (*big.Int, error) { 128 b.mu.Lock() 129 defer b.mu.Unlock() 130 131 if blockNumber != nil && blockNumber.Cmp(b.blockchain.CurrentBlock().Number()) != 0 { 132 return nil, errBlockNumberUnsupported 133 } 134 statedb, _ := b.blockchain.State() 135 return statedb.GetBalance(contract), nil 136 } 137 138 //nonceat返回区块链中某个帐户的nonce。 139 func (b *SimulatedBackend) NonceAt(ctx context.Context, contract common.Address, blockNumber *big.Int) (uint64, error) { 140 b.mu.Lock() 141 defer b.mu.Unlock() 142 143 if blockNumber != nil && blockNumber.Cmp(b.blockchain.CurrentBlock().Number()) != 0 { 144 return 0, errBlockNumberUnsupported 145 } 146 statedb, _ := b.blockchain.State() 147 return statedb.GetNonce(contract), nil 148 } 149 150 //storageat返回在区块链中存储帐户的密钥的值。 151 func (b *SimulatedBackend) StorageAt(ctx context.Context, contract common.Address, key common.Hash, blockNumber *big.Int) ([]byte, error) { 152 b.mu.Lock() 153 defer b.mu.Unlock() 154 155 if blockNumber != nil && blockNumber.Cmp(b.blockchain.CurrentBlock().Number()) != 0 { 156 return nil, errBlockNumberUnsupported 157 } 158 statedb, _ := b.blockchain.State() 159 val := statedb.GetState(contract, key) 160 return val[:], nil 161 } 162 163 //TransactionReceipt返回交易的收据。 164 func (b *SimulatedBackend) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) { 165 receipt, _, _, _ := rawdb.ReadReceipt(b.database, txHash) 166 return receipt, nil 167 } 168 169 //PendingCodeAt返回与处于挂起状态的帐户关联的代码。 170 func (b *SimulatedBackend) PendingCodeAt(ctx context.Context, contract common.Address) ([]byte, error) { 171 b.mu.Lock() 172 defer b.mu.Unlock() 173 174 return b.pendingState.GetCode(contract), nil 175 } 176 177 //CallContract执行合同调用。 178 func (b *SimulatedBackend) CallContract(ctx context.Context, call ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) { 179 b.mu.Lock() 180 defer b.mu.Unlock() 181 182 if blockNumber != nil && blockNumber.Cmp(b.blockchain.CurrentBlock().Number()) != 0 { 183 return nil, errBlockNumberUnsupported 184 } 185 state, err := b.blockchain.State() 186 if err != nil { 187 return nil, err 188 } 189 rval, _, _, err := b.callContract(ctx, call, b.blockchain.CurrentBlock(), state) 190 return rval, err 191 } 192 193 //PendingCallContract对挂起状态执行合同调用。 194 func (b *SimulatedBackend) PendingCallContract(ctx context.Context, call ethereum.CallMsg) ([]byte, error) { 195 b.mu.Lock() 196 defer b.mu.Unlock() 197 defer b.pendingState.RevertToSnapshot(b.pendingState.Snapshot()) 198 199 rval, _, _, err := b.callContract(ctx, call, b.pendingBlock, b.pendingState) 200 return rval, err 201 } 202 203 //PendingOnCate实现PendingStateReader.PendingOnCate,检索 204 //当前为帐户挂起的非现金。 205 func (b *SimulatedBackend) PendingNonceAt(ctx context.Context, account common.Address) (uint64, error) { 206 b.mu.Lock() 207 defer b.mu.Unlock() 208 209 return b.pendingState.GetOrNewStateObject(account).Nonce(), nil 210 } 211 212 //Suggestgasprice执行ContractTransactor.Suggestgasprice。自从模拟 213 //这家连锁店没有矿工,我们只要回电1美元的汽油价格就行了。 214 func (b *SimulatedBackend) SuggestGasPrice(ctx context.Context) (*big.Int, error) { 215 return big.NewInt(1), nil 216 } 217 218 //EstimateGas针对当前挂起的块/状态执行请求的代码,并且 219 //返回使用的气体量。 220 func (b *SimulatedBackend) EstimateGas(ctx context.Context, call ethereum.CallMsg) (uint64, error) { 221 b.mu.Lock() 222 defer b.mu.Unlock() 223 224 //确定二元搜索的最低和最高气体限制 225 var ( 226 lo uint64 = params.TxGas - 1 227 hi uint64 228 cap uint64 229 ) 230 if call.Gas >= params.TxGas { 231 hi = call.Gas 232 } else { 233 hi = b.pendingBlock.GasLimit() 234 } 235 cap = hi 236 237 //创建一个助手以检查气体限额是否导致可执行事务 238 executable := func(gas uint64) bool { 239 call.Gas = gas 240 241 snapshot := b.pendingState.Snapshot() 242 _, _, failed, err := b.callContract(ctx, call, b.pendingBlock, b.pendingState) 243 b.pendingState.RevertToSnapshot(snapshot) 244 245 if err != nil || failed { 246 return false 247 } 248 return true 249 } 250 //执行二进制搜索并按可执行的气体限值接通。 251 for lo+1 < hi { 252 mid := (hi + lo) / 2 253 if !executable(mid) { 254 lo = mid 255 } else { 256 hi = mid 257 } 258 } 259 //如果交易仍以最高限额失败,则将其视为无效拒绝交易 260 if hi == cap { 261 if !executable(hi) { 262 return 0, errGasEstimationFailed 263 } 264 } 265 return hi, nil 266 } 267 268 //CallContract实现正常和挂起的合同调用之间的公共代码。 269 //状态在执行期间被修改,请确保在必要时复制它。 270 func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallMsg, block *types.Block, statedb *state.StateDB) ([]byte, uint64, bool, error) { 271 //确保消息已正确初始化。 272 if call.GasPrice == nil { 273 call.GasPrice = big.NewInt(1) 274 } 275 if call.Gas == 0 { 276 call.Gas = 50000000 277 } 278 if call.Value == nil { 279 call.Value = new(big.Int) 280 } 281 //将无限余额设置为假呼叫者帐户。 282 from := statedb.GetOrNewStateObject(call.From) 283 from.SetBalance(math.MaxBig256) 284 //执行呼叫。 285 msg := callmsg{call} 286 287 evmContext := core.NewEVMContext(msg, block.Header(), b.blockchain, nil) 288 //创建一个保存所有相关信息的新环境 289 //关于事务和调用机制。 290 vmenv := vm.NewEVM(evmContext, statedb, b.config, vm.Config{}) 291 gaspool := new(core.GasPool).AddGas(math.MaxUint64) 292 293 return core.NewStateTransition(vmenv, msg, gaspool).TransitionDb() 294 } 295 296 //sendTransaction更新挂起块以包括给定的事务。 297 //如果事务无效,它会恐慌。 298 func (b *SimulatedBackend) SendTransaction(ctx context.Context, tx *types.Transaction) error { 299 b.mu.Lock() 300 defer b.mu.Unlock() 301 302 sender, err := types.Sender(types.HomesteadSigner{}, tx) 303 if err != nil { 304 panic(fmt.Errorf("invalid transaction: %v", err)) 305 } 306 nonce := b.pendingState.GetNonce(sender) 307 if tx.Nonce() != nonce { 308 panic(fmt.Errorf("invalid transaction nonce: got %d, want %d", tx.Nonce(), nonce)) 309 } 310 311 blocks, _ := core.GenerateChain(b.config, b.blockchain.CurrentBlock(), ethash.NewFaker(), b.database, 1, func(number int, block *core.BlockGen) { 312 for _, tx := range b.pendingBlock.Transactions() { 313 block.AddTxWithChain(b.blockchain, tx) 314 } 315 block.AddTxWithChain(b.blockchain, tx) 316 }) 317 statedb, _ := b.blockchain.State() 318 319 b.pendingBlock = blocks[0] 320 b.pendingState, _ = state.New(b.pendingBlock.Root(), statedb.Database()) 321 return nil 322 } 323 324 //filterlogs执行日志筛选操作,在执行期间阻塞,以及 325 //一批返回所有结果。 326 // 327 //TODO(karalabe):当订阅可以返回过去的数据时,取消预测。 328 func (b *SimulatedBackend) FilterLogs(ctx context.Context, query ethereum.FilterQuery) ([]types.Log, error) { 329 var filter *filters.Filter 330 if query.BlockHash != nil { 331 //请求块筛选器,构造一个单镜头筛选器 332 filter = filters.NewBlockFilter(&filterBackend{b.database, b.blockchain}, *query.BlockHash, query.Addresses, query.Topics) 333 } else { 334 //初始化从Genesis运行到链头的未设置过滤器 335 from := int64(0) 336 if query.FromBlock != nil { 337 from = query.FromBlock.Int64() 338 } 339 to := int64(-1) 340 if query.ToBlock != nil { 341 to = query.ToBlock.Int64() 342 } 343 //构造范围过滤器 344 filter = filters.NewRangeFilter(&filterBackend{b.database, b.blockchain}, from, to, query.Addresses, query.Topics) 345 } 346 //运行过滤器并返回所有日志 347 logs, err := filter.Logs(ctx) 348 if err != nil { 349 return nil, err 350 } 351 res := make([]types.Log, len(logs)) 352 for i, log := range logs { 353 res[i] = *log 354 } 355 return res, nil 356 } 357 358 //subscribeBilterLogs创建后台日志筛选操作,返回 359 //立即订阅,可用于流式处理找到的事件。 360 func (b *SimulatedBackend) SubscribeFilterLogs(ctx context.Context, query ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error) { 361 //订阅合同事件 362 sink := make(chan []*types.Log) 363 364 sub, err := b.events.SubscribeLogs(query, sink) 365 if err != nil { 366 return nil, err 367 } 368 //因为我们要批量获取日志,所以我们需要将它们展平成一条普通的流。 369 return event.NewSubscription(func(quit <-chan struct{}) error { 370 defer sub.Unsubscribe() 371 for { 372 select { 373 case logs := <-sink: 374 for _, log := range logs { 375 select { 376 case ch <- *log: 377 case err := <-sub.Err(): 378 return err 379 case <-quit: 380 return nil 381 } 382 } 383 case err := <-sub.Err(): 384 return err 385 case <-quit: 386 return nil 387 } 388 } 389 }), nil 390 } 391 392 //AdjustTime为模拟时钟增加了一个时间偏移。 393 func (b *SimulatedBackend) AdjustTime(adjustment time.Duration) error { 394 b.mu.Lock() 395 defer b.mu.Unlock() 396 blocks, _ := core.GenerateChain(b.config, b.blockchain.CurrentBlock(), ethash.NewFaker(), b.database, 1, func(number int, block *core.BlockGen) { 397 for _, tx := range b.pendingBlock.Transactions() { 398 block.AddTx(tx) 399 } 400 block.OffsetTime(int64(adjustment.Seconds())) 401 }) 402 statedb, _ := b.blockchain.State() 403 404 b.pendingBlock = blocks[0] 405 b.pendingState, _ = state.New(b.pendingBlock.Root(), statedb.Database()) 406 407 return nil 408 } 409 410 //callmsg实现core.message以允许将其作为事务模拟器传递。 411 type callmsg struct { 412 ethereum.CallMsg 413 } 414 415 func (m callmsg) From() common.Address { return m.CallMsg.From } 416 func (m callmsg) Nonce() uint64 { return 0 } 417 func (m callmsg) CheckNonce() bool { return false } 418 func (m callmsg) To() *common.Address { return m.CallMsg.To } 419 func (m callmsg) GasPrice() *big.Int { return m.CallMsg.GasPrice } 420 func (m callmsg) Gas() uint64 { return m.CallMsg.Gas } 421 func (m callmsg) Value() *big.Int { return m.CallMsg.Value } 422 func (m callmsg) Data() []byte { return m.CallMsg.Data } 423 424 //filterbackend实现筛选器。backend支持筛选不包含 425 //考虑到布卢姆钻头的加速结构。 426 type filterBackend struct { 427 db ethdb.Database 428 bc *core.BlockChain 429 } 430 431 func (fb *filterBackend) ChainDb() ethdb.Database { return fb.db } 432 func (fb *filterBackend) EventMux() *event.TypeMux { panic("not supported") } 433 434 func (fb *filterBackend) HeaderByNumber(ctx context.Context, block rpc.BlockNumber) (*types.Header, error) { 435 if block == rpc.LatestBlockNumber { 436 return fb.bc.CurrentHeader(), nil 437 } 438 return fb.bc.GetHeaderByNumber(uint64(block.Int64())), nil 439 } 440 441 func (fb *filterBackend) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) { 442 return fb.bc.GetHeaderByHash(hash), nil 443 } 444 445 func (fb *filterBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) { 446 number := rawdb.ReadHeaderNumber(fb.db, hash) 447 if number == nil { 448 return nil, nil 449 } 450 return rawdb.ReadReceipts(fb.db, hash, *number), nil 451 } 452 453 func (fb *filterBackend) GetLogs(ctx context.Context, hash common.Hash) ([][]*types.Log, error) { 454 number := rawdb.ReadHeaderNumber(fb.db, hash) 455 if number == nil { 456 return nil, nil 457 } 458 receipts := rawdb.ReadReceipts(fb.db, hash, *number) 459 if receipts == nil { 460 return nil, nil 461 } 462 logs := make([][]*types.Log, len(receipts)) 463 for i, receipt := range receipts { 464 logs[i] = receipt.Logs 465 } 466 return logs, nil 467 } 468 469 func (fb *filterBackend) SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.Subscription { 470 return event.NewSubscription(func(quit <-chan struct{}) error { 471 <-quit 472 return nil 473 }) 474 } 475 func (fb *filterBackend) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription { 476 return fb.bc.SubscribeChainEvent(ch) 477 } 478 func (fb *filterBackend) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription { 479 return fb.bc.SubscribeRemovedLogsEvent(ch) 480 } 481 func (fb *filterBackend) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription { 482 return fb.bc.SubscribeLogsEvent(ch) 483 } 484 485 func (fb *filterBackend) BloomStatus() (uint64, uint64) { return 4096, 0 } 486 func (fb *filterBackend) ServiceFilter(ctx context.Context, ms *bloombits.MatcherSession) { 487 panic("not supported") 488 } 489