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