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