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