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