github.com/daragao/go-ethereum@v1.8.14-0.20180809141559-45eaef243198/miner/worker.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 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 miner 18 19 import ( 20 "bytes" 21 "fmt" 22 "math/big" 23 "sync" 24 "sync/atomic" 25 "time" 26 27 mapset "github.com/deckarep/golang-set" 28 "github.com/ethereum/go-ethereum/common" 29 "github.com/ethereum/go-ethereum/consensus" 30 "github.com/ethereum/go-ethereum/consensus/misc" 31 "github.com/ethereum/go-ethereum/core" 32 "github.com/ethereum/go-ethereum/core/state" 33 "github.com/ethereum/go-ethereum/core/types" 34 "github.com/ethereum/go-ethereum/core/vm" 35 "github.com/ethereum/go-ethereum/ethdb" 36 "github.com/ethereum/go-ethereum/event" 37 "github.com/ethereum/go-ethereum/log" 38 "github.com/ethereum/go-ethereum/params" 39 ) 40 41 const ( 42 resultQueueSize = 10 43 miningLogAtDepth = 5 44 45 // txChanSize is the size of channel listening to NewTxsEvent. 46 // The number is referenced from the size of tx pool. 47 txChanSize = 4096 48 // chainHeadChanSize is the size of channel listening to ChainHeadEvent. 49 chainHeadChanSize = 10 50 // chainSideChanSize is the size of channel listening to ChainSideEvent. 51 chainSideChanSize = 10 52 ) 53 54 // Agent can register themselves with the worker 55 type Agent interface { 56 AssignTask(*Package) 57 DeliverTo(chan<- *Package) 58 Start() 59 Stop() 60 } 61 62 // Env is the workers current environment and holds all of the current state information. 63 type Env struct { 64 config *params.ChainConfig 65 signer types.Signer 66 67 state *state.StateDB // apply state changes here 68 ancestors mapset.Set // ancestor set (used for checking uncle parent validity) 69 family mapset.Set // family set (used for checking uncle invalidity) 70 uncles mapset.Set // uncle set 71 tcount int // tx count in cycle 72 gasPool *core.GasPool // available gas used to pack transactions 73 74 header *types.Header 75 txs []*types.Transaction 76 receipts []*types.Receipt 77 78 createdAt time.Time 79 } 80 81 // Package contains all information for consensus engine sealing and result submitting. 82 type Package struct { 83 Receipts []*types.Receipt 84 State *state.StateDB 85 Block *types.Block 86 } 87 88 // worker is the main object which takes care of applying messages to the new state 89 type worker struct { 90 config *params.ChainConfig 91 engine consensus.Engine 92 93 mu sync.Mutex 94 95 // update loop 96 mux *event.TypeMux 97 txsCh chan core.NewTxsEvent 98 txsSub event.Subscription 99 chainHeadCh chan core.ChainHeadEvent 100 chainHeadSub event.Subscription 101 chainSideCh chan core.ChainSideEvent 102 chainSideSub event.Subscription 103 104 agents map[Agent]struct{} 105 recv chan *Package 106 107 eth Backend 108 chain *core.BlockChain 109 proc core.Validator 110 chainDb ethdb.Database 111 112 coinbase common.Address 113 extra []byte 114 115 currentMu sync.Mutex 116 current *Env 117 118 snapshotMu sync.RWMutex 119 snapshotBlock *types.Block 120 snapshotState *state.StateDB 121 122 uncleMu sync.Mutex 123 possibleUncles map[common.Hash]*types.Block 124 125 unconfirmed *unconfirmedBlocks // set of locally mined blocks pending canonicalness confirmations 126 127 // atomic status counters 128 running int32 // The indicator whether the consensus engine is running or not. 129 } 130 131 func newWorker(config *params.ChainConfig, engine consensus.Engine, eth Backend, mux *event.TypeMux) *worker { 132 worker := &worker{ 133 config: config, 134 engine: engine, 135 eth: eth, 136 mux: mux, 137 txsCh: make(chan core.NewTxsEvent, txChanSize), 138 chainHeadCh: make(chan core.ChainHeadEvent, chainHeadChanSize), 139 chainSideCh: make(chan core.ChainSideEvent, chainSideChanSize), 140 chainDb: eth.ChainDb(), 141 recv: make(chan *Package, resultQueueSize), 142 chain: eth.BlockChain(), 143 proc: eth.BlockChain().Validator(), 144 possibleUncles: make(map[common.Hash]*types.Block), 145 agents: make(map[Agent]struct{}), 146 unconfirmed: newUnconfirmedBlocks(eth.BlockChain(), miningLogAtDepth), 147 } 148 // Subscribe NewTxsEvent for tx pool 149 worker.txsSub = eth.TxPool().SubscribeNewTxsEvent(worker.txsCh) 150 // Subscribe events for blockchain 151 worker.chainHeadSub = eth.BlockChain().SubscribeChainHeadEvent(worker.chainHeadCh) 152 worker.chainSideSub = eth.BlockChain().SubscribeChainSideEvent(worker.chainSideCh) 153 go worker.update() 154 155 go worker.wait() 156 worker.commitNewWork() 157 158 return worker 159 } 160 161 func (self *worker) setEtherbase(addr common.Address) { 162 self.mu.Lock() 163 defer self.mu.Unlock() 164 self.coinbase = addr 165 } 166 167 func (self *worker) setExtra(extra []byte) { 168 self.mu.Lock() 169 defer self.mu.Unlock() 170 self.extra = extra 171 } 172 173 func (self *worker) pending() (*types.Block, *state.StateDB) { 174 // return a snapshot to avoid contention on currentMu mutex 175 self.snapshotMu.RLock() 176 defer self.snapshotMu.RUnlock() 177 return self.snapshotBlock, self.snapshotState.Copy() 178 } 179 180 func (self *worker) pendingBlock() *types.Block { 181 // return a snapshot to avoid contention on currentMu mutex 182 self.snapshotMu.RLock() 183 defer self.snapshotMu.RUnlock() 184 return self.snapshotBlock 185 } 186 187 func (self *worker) start() { 188 self.mu.Lock() 189 defer self.mu.Unlock() 190 atomic.StoreInt32(&self.running, 1) 191 for agent := range self.agents { 192 agent.Start() 193 } 194 } 195 196 func (self *worker) stop() { 197 self.mu.Lock() 198 defer self.mu.Unlock() 199 200 atomic.StoreInt32(&self.running, 0) 201 for agent := range self.agents { 202 agent.Stop() 203 } 204 } 205 206 func (self *worker) isRunning() bool { 207 return atomic.LoadInt32(&self.running) == 1 208 } 209 210 func (self *worker) register(agent Agent) { 211 self.mu.Lock() 212 defer self.mu.Unlock() 213 self.agents[agent] = struct{}{} 214 agent.DeliverTo(self.recv) 215 if self.isRunning() { 216 agent.Start() 217 } 218 } 219 220 func (self *worker) unregister(agent Agent) { 221 self.mu.Lock() 222 defer self.mu.Unlock() 223 delete(self.agents, agent) 224 agent.Stop() 225 } 226 227 func (self *worker) update() { 228 defer self.txsSub.Unsubscribe() 229 defer self.chainHeadSub.Unsubscribe() 230 defer self.chainSideSub.Unsubscribe() 231 232 for { 233 // A real event arrived, process interesting content 234 select { 235 // Handle ChainHeadEvent 236 case <-self.chainHeadCh: 237 self.commitNewWork() 238 239 // Handle ChainSideEvent 240 case ev := <-self.chainSideCh: 241 self.uncleMu.Lock() 242 self.possibleUncles[ev.Block.Hash()] = ev.Block 243 self.uncleMu.Unlock() 244 245 // Handle NewTxsEvent 246 case ev := <-self.txsCh: 247 // Apply transactions to the pending state if we're not mining. 248 // 249 // Note all transactions received may not be continuous with transactions 250 // already included in the current mining block. These transactions will 251 // be automatically eliminated. 252 if !self.isRunning() { 253 self.currentMu.Lock() 254 txs := make(map[common.Address]types.Transactions) 255 for _, tx := range ev.Txs { 256 acc, _ := types.Sender(self.current.signer, tx) 257 txs[acc] = append(txs[acc], tx) 258 } 259 txset := types.NewTransactionsByPriceAndNonce(self.current.signer, txs) 260 self.current.commitTransactions(self.mux, txset, self.chain, self.coinbase) 261 self.updateSnapshot() 262 self.currentMu.Unlock() 263 } else { 264 // If we're mining, but nothing is being processed, wake on new transactions 265 if self.config.Clique != nil && self.config.Clique.Period == 0 { 266 self.commitNewWork() 267 } 268 } 269 270 // System stopped 271 case <-self.txsSub.Err(): 272 return 273 case <-self.chainHeadSub.Err(): 274 return 275 case <-self.chainSideSub.Err(): 276 return 277 } 278 } 279 } 280 281 func (self *worker) wait() { 282 for { 283 for result := range self.recv { 284 285 if result == nil { 286 continue 287 } 288 block := result.Block 289 290 // Update the block hash in all logs since it is now available and not when the 291 // receipt/log of individual transactions were created. 292 for _, r := range result.Receipts { 293 for _, l := range r.Logs { 294 l.BlockHash = block.Hash() 295 } 296 } 297 for _, log := range result.State.Logs() { 298 log.BlockHash = block.Hash() 299 } 300 self.currentMu.Lock() 301 stat, err := self.chain.WriteBlockWithState(block, result.Receipts, result.State) 302 self.currentMu.Unlock() 303 if err != nil { 304 log.Error("Failed writing block to chain", "err", err) 305 continue 306 } 307 // Broadcast the block and announce chain insertion event 308 self.mux.Post(core.NewMinedBlockEvent{Block: block}) 309 var ( 310 events []interface{} 311 logs = result.State.Logs() 312 ) 313 events = append(events, core.ChainEvent{Block: block, Hash: block.Hash(), Logs: logs}) 314 if stat == core.CanonStatTy { 315 events = append(events, core.ChainHeadEvent{Block: block}) 316 } 317 self.chain.PostChainEvents(events, logs) 318 319 // Insert the block into the set of pending ones to wait for confirmations 320 self.unconfirmed.Insert(block.NumberU64(), block.Hash()) 321 } 322 } 323 } 324 325 // push sends a new work task to currently live miner agents. 326 func (self *worker) push(p *Package) { 327 for agent := range self.agents { 328 agent.AssignTask(p) 329 } 330 } 331 332 // makeCurrent creates a new environment for the current cycle. 333 func (self *worker) makeCurrent(parent *types.Block, header *types.Header) error { 334 state, err := self.chain.StateAt(parent.Root()) 335 if err != nil { 336 return err 337 } 338 env := &Env{ 339 config: self.config, 340 signer: types.NewEIP155Signer(self.config.ChainID), 341 state: state, 342 ancestors: mapset.NewSet(), 343 family: mapset.NewSet(), 344 uncles: mapset.NewSet(), 345 header: header, 346 createdAt: time.Now(), 347 } 348 349 // when 08 is processed ancestors contain 07 (quick block) 350 for _, ancestor := range self.chain.GetBlocksFromHash(parent.Hash(), 7) { 351 for _, uncle := range ancestor.Uncles() { 352 env.family.Add(uncle.Hash()) 353 } 354 env.family.Add(ancestor.Hash()) 355 env.ancestors.Add(ancestor.Hash()) 356 } 357 358 // Keep track of transactions which return errors so they can be removed 359 env.tcount = 0 360 self.current = env 361 return nil 362 } 363 364 func (self *worker) commitNewWork() { 365 self.mu.Lock() 366 defer self.mu.Unlock() 367 self.uncleMu.Lock() 368 defer self.uncleMu.Unlock() 369 self.currentMu.Lock() 370 defer self.currentMu.Unlock() 371 372 tstart := time.Now() 373 parent := self.chain.CurrentBlock() 374 375 tstamp := tstart.Unix() 376 if parent.Time().Cmp(new(big.Int).SetInt64(tstamp)) >= 0 { 377 tstamp = parent.Time().Int64() + 1 378 } 379 // this will ensure we're not going off too far in the future 380 if now := time.Now().Unix(); tstamp > now+1 { 381 wait := time.Duration(tstamp-now) * time.Second 382 log.Info("Mining too far in the future", "wait", common.PrettyDuration(wait)) 383 time.Sleep(wait) 384 } 385 386 num := parent.Number() 387 header := &types.Header{ 388 ParentHash: parent.Hash(), 389 Number: num.Add(num, common.Big1), 390 GasLimit: core.CalcGasLimit(parent), 391 Extra: self.extra, 392 Time: big.NewInt(tstamp), 393 } 394 // Only set the coinbase if our consensus engine is running (avoid spurious block rewards) 395 if self.isRunning() { 396 if self.coinbase == (common.Address{}) { 397 log.Error("Refusing to mine without etherbase") 398 return 399 } 400 header.Coinbase = self.coinbase 401 } 402 if err := self.engine.Prepare(self.chain, header); err != nil { 403 log.Error("Failed to prepare header for mining", "err", err) 404 return 405 } 406 // If we are care about TheDAO hard-fork check whether to override the extra-data or not 407 if daoBlock := self.config.DAOForkBlock; daoBlock != nil { 408 // Check whether the block is among the fork extra-override range 409 limit := new(big.Int).Add(daoBlock, params.DAOForkExtraRange) 410 if header.Number.Cmp(daoBlock) >= 0 && header.Number.Cmp(limit) < 0 { 411 // Depending whether we support or oppose the fork, override differently 412 if self.config.DAOForkSupport { 413 header.Extra = common.CopyBytes(params.DAOForkBlockExtra) 414 } else if bytes.Equal(header.Extra, params.DAOForkBlockExtra) { 415 header.Extra = []byte{} // If miner opposes, don't let it use the reserved extra-data 416 } 417 } 418 } 419 // Could potentially happen if starting to mine in an odd state. 420 err := self.makeCurrent(parent, header) 421 if err != nil { 422 log.Error("Failed to create mining context", "err", err) 423 return 424 } 425 // Create the current work task and check any fork transitions needed 426 env := self.current 427 if self.config.DAOForkSupport && self.config.DAOForkBlock != nil && self.config.DAOForkBlock.Cmp(header.Number) == 0 { 428 misc.ApplyDAOHardFork(env.state) 429 } 430 431 // compute uncles for the new block. 432 var ( 433 uncles []*types.Header 434 badUncles []common.Hash 435 ) 436 for hash, uncle := range self.possibleUncles { 437 if len(uncles) == 2 { 438 break 439 } 440 if err := self.commitUncle(env, uncle.Header()); err != nil { 441 log.Trace("Bad uncle found and will be removed", "hash", hash) 442 log.Trace(fmt.Sprint(uncle)) 443 444 badUncles = append(badUncles, hash) 445 } else { 446 log.Debug("Committing new uncle to block", "hash", hash) 447 uncles = append(uncles, uncle.Header()) 448 } 449 } 450 for _, hash := range badUncles { 451 delete(self.possibleUncles, hash) 452 } 453 454 var ( 455 emptyBlock *types.Block 456 fullBlock *types.Block 457 ) 458 459 // Create an empty block based on temporary copied state for sealing in advance without waiting block 460 // execution finished. 461 emptyState := env.state.Copy() 462 if emptyBlock, err = self.engine.Finalize(self.chain, header, emptyState, nil, uncles, nil); err != nil { 463 log.Error("Failed to finalize block for temporary sealing", "err", err) 464 } else { 465 // Push empty work in advance without applying pending transaction. 466 // The reason is transactions execution can cost a lot and sealer need to 467 // take advantage of this part time. 468 if self.isRunning() { 469 log.Info("Commit new empty mining work", "number", emptyBlock.Number(), "uncles", len(uncles)) 470 self.push(&Package{nil, emptyState, emptyBlock}) 471 } 472 } 473 474 // Fill the block with all available pending transactions. 475 pending, err := self.eth.TxPool().Pending() 476 if err != nil { 477 log.Error("Failed to fetch pending transactions", "err", err) 478 return 479 } 480 txs := types.NewTransactionsByPriceAndNonce(self.current.signer, pending) 481 env.commitTransactions(self.mux, txs, self.chain, self.coinbase) 482 483 // Create the full block to seal with the consensus engine 484 if fullBlock, err = self.engine.Finalize(self.chain, header, env.state, env.txs, uncles, env.receipts); err != nil { 485 log.Error("Failed to finalize block for sealing", "err", err) 486 return 487 } 488 // We only care about logging if we're actually mining. 489 if self.isRunning() { 490 log.Info("Commit new full mining work", "number", fullBlock.Number(), "txs", env.tcount, "uncles", len(uncles), "elapsed", common.PrettyDuration(time.Since(tstart))) 491 self.unconfirmed.Shift(fullBlock.NumberU64() - 1) 492 self.push(&Package{env.receipts, env.state, fullBlock}) 493 } 494 self.updateSnapshot() 495 } 496 497 func (self *worker) commitUncle(env *Env, uncle *types.Header) error { 498 hash := uncle.Hash() 499 if env.uncles.Contains(hash) { 500 return fmt.Errorf("uncle not unique") 501 } 502 if !env.ancestors.Contains(uncle.ParentHash) { 503 return fmt.Errorf("uncle's parent unknown (%x)", uncle.ParentHash[0:4]) 504 } 505 if env.family.Contains(hash) { 506 return fmt.Errorf("uncle already in family (%x)", hash) 507 } 508 env.uncles.Add(uncle.Hash()) 509 return nil 510 } 511 512 func (self *worker) updateSnapshot() { 513 self.snapshotMu.Lock() 514 defer self.snapshotMu.Unlock() 515 516 var uncles []*types.Header 517 self.current.uncles.Each(func(item interface{}) bool { 518 if header, ok := item.(*types.Header); ok { 519 uncles = append(uncles, header) 520 return true 521 } 522 return false 523 }) 524 525 self.snapshotBlock = types.NewBlock( 526 self.current.header, 527 self.current.txs, 528 uncles, 529 self.current.receipts, 530 ) 531 self.snapshotState = self.current.state.Copy() 532 } 533 534 func (env *Env) commitTransactions(mux *event.TypeMux, txs *types.TransactionsByPriceAndNonce, bc *core.BlockChain, coinbase common.Address) { 535 if env.gasPool == nil { 536 env.gasPool = new(core.GasPool).AddGas(env.header.GasLimit) 537 } 538 539 var coalescedLogs []*types.Log 540 541 for { 542 // If we don't have enough gas for any further transactions then we're done 543 if env.gasPool.Gas() < params.TxGas { 544 log.Trace("Not enough gas for further transactions", "have", env.gasPool, "want", params.TxGas) 545 break 546 } 547 // Retrieve the next transaction and abort if all done 548 tx := txs.Peek() 549 if tx == nil { 550 break 551 } 552 // Error may be ignored here. The error has already been checked 553 // during transaction acceptance is the transaction pool. 554 // 555 // We use the eip155 signer regardless of the current hf. 556 from, _ := types.Sender(env.signer, tx) 557 // Check whether the tx is replay protected. If we're not in the EIP155 hf 558 // phase, start ignoring the sender until we do. 559 if tx.Protected() && !env.config.IsEIP155(env.header.Number) { 560 log.Trace("Ignoring reply protected transaction", "hash", tx.Hash(), "eip155", env.config.EIP155Block) 561 562 txs.Pop() 563 continue 564 } 565 // Start executing the transaction 566 env.state.Prepare(tx.Hash(), common.Hash{}, env.tcount) 567 568 err, logs := env.commitTransaction(tx, bc, coinbase, env.gasPool) 569 switch err { 570 case core.ErrGasLimitReached: 571 // Pop the current out-of-gas transaction without shifting in the next from the account 572 log.Trace("Gas limit exceeded for current block", "sender", from) 573 txs.Pop() 574 575 case core.ErrNonceTooLow: 576 // New head notification data race between the transaction pool and miner, shift 577 log.Trace("Skipping transaction with low nonce", "sender", from, "nonce", tx.Nonce()) 578 txs.Shift() 579 580 case core.ErrNonceTooHigh: 581 // Reorg notification data race between the transaction pool and miner, skip account = 582 log.Trace("Skipping account with hight nonce", "sender", from, "nonce", tx.Nonce()) 583 txs.Pop() 584 585 case nil: 586 // Everything ok, collect the logs and shift in the next transaction from the same account 587 coalescedLogs = append(coalescedLogs, logs...) 588 env.tcount++ 589 txs.Shift() 590 591 default: 592 // Strange error, discard the transaction and get the next in line (note, the 593 // nonce-too-high clause will prevent us from executing in vain). 594 log.Debug("Transaction failed, account skipped", "hash", tx.Hash(), "err", err) 595 txs.Shift() 596 } 597 } 598 599 if len(coalescedLogs) > 0 || env.tcount > 0 { 600 // make a copy, the state caches the logs and these logs get "upgraded" from pending to mined 601 // logs by filling in the block hash when the block was mined by the local miner. This can 602 // cause a race condition if a log was "upgraded" before the PendingLogsEvent is processed. 603 cpy := make([]*types.Log, len(coalescedLogs)) 604 for i, l := range coalescedLogs { 605 cpy[i] = new(types.Log) 606 *cpy[i] = *l 607 } 608 go func(logs []*types.Log, tcount int) { 609 if len(logs) > 0 { 610 mux.Post(core.PendingLogsEvent{Logs: logs}) 611 } 612 if tcount > 0 { 613 mux.Post(core.PendingStateEvent{}) 614 } 615 }(cpy, env.tcount) 616 } 617 } 618 619 func (env *Env) commitTransaction(tx *types.Transaction, bc *core.BlockChain, coinbase common.Address, gp *core.GasPool) (error, []*types.Log) { 620 snap := env.state.Snapshot() 621 622 receipt, _, err := core.ApplyTransaction(env.config, bc, &coinbase, gp, env.state, env.header, tx, &env.header.GasUsed, vm.Config{}) 623 if err != nil { 624 env.state.RevertToSnapshot(snap) 625 return err, nil 626 } 627 env.txs = append(env.txs, tx) 628 env.receipts = append(env.receipts, receipt) 629 630 return nil, receipt.Logs 631 }