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