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