github.com/SmartMeshFoundation/Spectrum@v0.0.0-20220621030607-452a266fee1e/miner/worker.go (about) 1 // Copyright 2015 The Spectrum Authors 2 // This file is part of the Spectrum library. 3 // 4 // The Spectrum 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 Spectrum 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 Spectrum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package miner 18 19 import ( 20 "fmt" 21 "github.com/SmartMeshFoundation/Spectrum/common" 22 "github.com/SmartMeshFoundation/Spectrum/consensus" 23 "github.com/SmartMeshFoundation/Spectrum/consensus/tribe" 24 "github.com/SmartMeshFoundation/Spectrum/core" 25 "github.com/SmartMeshFoundation/Spectrum/core/state" 26 "github.com/SmartMeshFoundation/Spectrum/core/types" 27 "github.com/SmartMeshFoundation/Spectrum/core/vm" 28 "github.com/SmartMeshFoundation/Spectrum/ethdb" 29 "github.com/SmartMeshFoundation/Spectrum/event" 30 "github.com/SmartMeshFoundation/Spectrum/log" 31 "github.com/SmartMeshFoundation/Spectrum/params" 32 mapset "github.com/deckarep/golang-set" 33 "math/big" 34 "sync" 35 "sync/atomic" 36 "time" 37 ) 38 39 const ( 40 resultQueueSize = 10 41 miningLogAtDepth = 5 42 43 // txChanSize is the size of channel listening to TxPreEvent. 44 // The number is referenced from the size of tx pool. 45 txChanSize = 4096 46 // chainHeadChanSize is the size of channel listening to ChainHeadEvent. 47 chainHeadChanSize = 10 48 // chainSideChanSize is the size of channel listening to ChainSideEvent. 49 chainSideChanSize = 10 50 ) 51 52 func appendToFailTx(txHash common.Hash) { 53 //failTxCh <- txHash 54 } 55 56 // Agent can register themself with the worker 57 type Agent interface { 58 Work() chan<- *Work 59 SetReturnCh(chan<- *Result) 60 Stop() 61 Start() 62 GetHashRate() int64 63 } 64 65 // Work is the workers current environment and holds 66 // all of the current state information 67 type Work struct { 68 config *params.ChainConfig 69 signer types.Signer 70 71 state *state.StateDB // apply state changes here 72 ancestors mapset.Set // ancestor set (used for checking uncle parent validity) 73 family mapset.Set // family set (used for checking uncle invalidity) 74 uncles mapset.Set // uncle set 75 tcount int // tx count in cycle 76 77 Block *types.Block // the new block 78 79 header *types.Header 80 txs []*types.Transaction 81 receipts []*types.Receipt 82 83 createdAt time.Time 84 } 85 86 type Result struct { 87 Work *Work 88 Block *types.Block 89 } 90 91 // worker is the main object which takes care of applying messages to the new state 92 type worker struct { 93 config *params.ChainConfig 94 engine consensus.Engine 95 96 mu sync.Mutex 97 98 // update loop 99 mux *event.TypeMux 100 txCh chan core.TxPreEvent 101 txSub event.Subscription 102 chainHeadCh chan core.ChainHeadEvent 103 chainHeadSub event.Subscription 104 chainSideCh chan core.ChainSideEvent 105 chainSideSub event.Subscription 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 uncleMu sync.Mutex 122 possibleUncles map[common.Hash]*types.Block 123 124 unconfirmed *unconfirmedBlocks // set of locally mined blocks pending canonicalness confirmations 125 126 // atomic status counters 127 mining int32 128 atWork int32 129 } 130 131 func newWorker(config *params.ChainConfig, engine consensus.Engine, coinbase common.Address, eth Backend, mux *event.TypeMux) *worker { 132 worker := &worker{ 133 config: config, 134 engine: engine, 135 eth: eth, 136 mux: mux, 137 txCh: make(chan core.TxPreEvent, txChanSize), 138 chainHeadCh: make(chan core.ChainHeadEvent, chainHeadChanSize), 139 chainSideCh: make(chan core.ChainSideEvent, chainSideChanSize), 140 chainDb: eth.ChainDb(), 141 recv: make(chan *Result, resultQueueSize), 142 chain: eth.BlockChain(), 143 proc: eth.BlockChain().Validator(), 144 possibleUncles: make(map[common.Hash]*types.Block), 145 coinbase: coinbase, 146 agents: make(map[Agent]struct{}), 147 unconfirmed: newUnconfirmedBlocks(eth.BlockChain(), miningLogAtDepth), 148 } 149 // Subscribe TxPreEvent for tx pool 150 worker.txSub = eth.TxPool().SubscribeTxPreEvent(worker.txCh) 151 // Subscribe events for blockchain 152 worker.chainHeadSub = eth.BlockChain().SubscribeChainHeadEvent(worker.chainHeadCh) 153 worker.chainSideSub = eth.BlockChain().SubscribeChainSideEvent(worker.chainSideCh) 154 155 go worker.update() 156 go worker.wait() 157 if _, ok := engine.(*tribe.Tribe); ok { 158 go func() { 159 <-params.InitTribe 160 worker.commitNewWork() 161 }() 162 } else { 163 worker.commitNewWork() 164 } 165 return worker 166 } 167 168 func (self *worker) setEtherbase(addr common.Address) { 169 self.mu.Lock() 170 defer self.mu.Unlock() 171 self.coinbase = addr 172 } 173 174 func (self *worker) setExtra(extra []byte) { 175 self.mu.Lock() 176 defer self.mu.Unlock() 177 self.extra = extra 178 } 179 180 func (self *worker) pending() (*types.Block, *state.StateDB) { 181 self.currentMu.Lock() 182 defer self.currentMu.Unlock() 183 184 if atomic.LoadInt32(&self.mining) == 0 { 185 return types.NewBlock( 186 self.current.header, 187 self.current.txs, 188 nil, 189 self.current.receipts, 190 ), self.current.state.Copy() 191 } 192 return self.current.Block, self.current.state.Copy() 193 } 194 195 func (self *worker) pendingBlock() *types.Block { 196 self.currentMu.Lock() 197 defer self.currentMu.Unlock() 198 199 if atomic.LoadInt32(&self.mining) == 0 { 200 return types.NewBlock( 201 self.current.header, 202 self.current.txs, 203 nil, 204 self.current.receipts, 205 ) 206 } 207 return self.current.Block 208 } 209 210 func (self *worker) start(s chan int) { 211 self.mu.Lock() 212 defer self.mu.Unlock() 213 214 go func() { 215 defer func() { close(s) }() 216 atomic.StoreInt32(&self.mining, 1) 217 // spin up agents 218 for agent := range self.agents { 219 agent.Start() 220 } 221 }() 222 } 223 224 func (self *worker) stop() { 225 226 self.mu.Lock() 227 defer self.mu.Unlock() 228 if atomic.LoadInt32(&self.mining) == 1 { 229 for agent := range self.agents { 230 agent.Stop() 231 } 232 } 233 atomic.StoreInt32(&self.mining, 0) 234 atomic.StoreInt32(&self.atWork, 0) 235 } 236 237 func (self *worker) register(agent Agent) { 238 self.mu.Lock() 239 defer self.mu.Unlock() 240 self.agents[agent] = struct{}{} 241 agent.SetReturnCh(self.recv) 242 } 243 244 func (self *worker) unregister(agent Agent) { 245 self.mu.Lock() 246 defer self.mu.Unlock() 247 delete(self.agents, agent) 248 agent.Stop() 249 } 250 251 func (self *worker) update() { 252 defer self.txSub.Unsubscribe() 253 defer self.chainHeadSub.Unsubscribe() 254 defer self.chainSideSub.Unsubscribe() 255 256 for { 257 // A real event arrived, process interesting content 258 select { 259 // Handle ChainHeadEvent 260 case <-self.chainHeadCh: 261 log.Debug("worker commitNewWork because of chainHeadCh") 262 self.commitNewWork() 263 264 // Handle ChainSideEvent 265 case ev := <-self.chainSideCh: 266 self.uncleMu.Lock() 267 self.possibleUncles[ev.Block.Hash()] = ev.Block 268 self.uncleMu.Unlock() 269 270 // Handle TxPreEvent 271 case ev := <-self.txCh: 272 // Apply transaction to the pending state if we're not mining 273 if self.current != nil && atomic.LoadInt32(&self.mining) == 0 { 274 self.currentMu.Lock() 275 acc, _ := types.Sender(self.current.signer, ev.Tx) 276 txs := map[common.Address]types.Transactions{acc: {ev.Tx}} 277 txset := types.NewTransactionsByPriceAndNonce(self.current.signer, txs) 278 //fmt.Println("1111111",ev.Tx.Hash().Hex()) 279 self.current.commitTransactions(self.mux, txset, self.chain, self.coinbase, nil) 280 self.currentMu.Unlock() 281 } else { 282 // If we're mining, but nothing is being processed, wake on new transactions 283 if self.config.Clique != nil && self.config.Clique.Period == 0 { 284 log.Debug("worker commitNewWork because of TxPreEvent") 285 self.commitNewWork() 286 } 287 } 288 // System stopped 289 case <-self.txSub.Err(): 290 return 291 case <-self.chainHeadSub.Err(): 292 return 293 case <-self.chainSideSub.Err(): 294 return 295 } 296 } 297 } 298 299 func (self *worker) wait() { 300 for { 301 mustCommitNewWork := true 302 for result := range self.recv { 303 atomic.AddInt32(&self.atWork, -1) 304 if result == nil { //如果自己打包的块通不过验证,panic? 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.WriteBlockAndState(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: mapset.NewSet(), 376 family: mapset.NewSet(), 377 uncles: mapset.NewSet(), 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 399 self.mu.Lock() 400 defer self.mu.Unlock() 401 self.uncleMu.Lock() 402 defer self.uncleMu.Unlock() 403 self.currentMu.Lock() 404 defer self.currentMu.Unlock() 405 406 tstart := time.Now() 407 parent := self.chain.CurrentBlock() 408 409 tstamp := tstart.Unix() 410 if parent.Time().Cmp(new(big.Int).SetInt64(tstamp)) >= 0 { 411 tstamp = parent.Time().Int64() + 1 412 } 413 // this will ensure we're not going off too far in the future 414 if now := time.Now().Unix(); tstamp > now+1 { 415 wait := time.Duration(tstamp-now) * time.Second 416 log.Info("Mining too far in the future", "wait", common.PrettyDuration(wait)) 417 time.Sleep(wait) 418 } 419 log.Debug(fmt.Sprintf("worker commitNewWork ming=%v", self.mining)) 420 num := parent.Number() 421 header := &types.Header{ 422 ParentHash: parent.Hash(), 423 Number: num.Add(num, common.Big1), 424 GasLimit: core.CalcGasLimit(parent), 425 GasUsed: new(big.Int), 426 Extra: self.extra, 427 Time: big.NewInt(tstamp), 428 } 429 430 // Only set the coinbase if we are mining (avoid spurious block rewards) 431 if atomic.LoadInt32(&self.mining) == 1 { 432 header.Coinbase = self.coinbase 433 } 434 435 if err := self.engine.Prepare(self.chain, header); err != nil { 436 log.Error("Failed to prepare header for mining", "err", err, "number", header.Number) 437 return 438 } 439 440 err := self.makeCurrent(parent, header) 441 if err != nil { 442 log.Error("Failed to create mining context", "err", err) 443 return 444 } 445 // Create the current work task and check any fork transitions needed 446 work := self.current 447 448 /* 449 if self.config.DAOForkSupport && self.config.DAOForkBlock != nil && self.config.DAOForkBlock.Cmp(header.Number) == 0 { 450 misc.ApplyDAOHardFork(work.state) 451 }*/ 452 // SIP004 --> SIP100 453 pending, err := self.eth.TxPool().Pending() 454 //fmt.Println(header.Number.Int64(),err, "====== commitNewWork =======> pending.len:", len(pending)) 455 if err != nil { 456 log.Error("Failed to fetch pending transactions", "err", err) 457 return 458 } 459 if tribe, ok := self.engine.(*tribe.Tribe); ok { 460 chiefTx := tribe.GetChiefUpdateTx(self.chain, header, work.state) 461 if chiefTx != nil { 462 pending[tribe.Status.GetMinerAddress()] = types.Transactions{chiefTx} 463 } 464 } 465 log.Debug("pending_len", "cn", parent.Number().Int64(), "len", len(pending)) 466 txs := types.NewTransactionsByPriceAndNonce(self.current.signer, pending) 467 work.commitTransactions(self.mux, txs, self.chain, self.coinbase, header) 468 469 // compute uncles for the new block. 470 var ( 471 uncles []*types.Header 472 badUncles []common.Hash 473 ) 474 for hash, uncle := range self.possibleUncles { 475 if len(uncles) == 2 { 476 break 477 } 478 if err := self.commitUncle(work, uncle.Header()); err != nil { 479 log.Trace("Bad uncle found and will be removed", "hash", hash) 480 log.Trace(fmt.Sprint(uncle)) 481 482 badUncles = append(badUncles, hash) 483 } else { 484 log.Debug("Committing new uncle to block", "hash", hash) 485 uncles = append(uncles, uncle.Header()) 486 } 487 } 488 for _, hash := range badUncles { 489 delete(self.possibleUncles, hash) 490 } 491 // Create the new block to seal with the consensus engine 492 if work.Block, err = self.engine.Finalize(self.chain, header, work.state, work.txs, uncles, work.receipts); err != nil { 493 log.Error("Failed to finalize block for sealing", "err", err) 494 return 495 } 496 // We only care about logging if we're actually mining. 497 if atomic.LoadInt32(&self.mining) == 1 { 498 log.Debug("Commit new mining work", "number", work.Block.Number(), "txs", work.tcount, "uncles", len(uncles), "elapsed", common.PrettyDuration(time.Since(tstart))) 499 self.unconfirmed.Shift(work.Block.NumberU64() - 1) 500 } 501 //log.Info(fmt.Sprintf("xxxxxxxx work=%#v", work)) 502 self.push(work) 503 } 504 505 func (self *worker) commitUncle(work *Work, uncle *types.Header) error { 506 hash := uncle.Hash() 507 if work.uncles.Contains(hash) { 508 return fmt.Errorf("uncle not unique") 509 } 510 if !work.ancestors.Contains(uncle.ParentHash) { 511 return fmt.Errorf("uncle's parent unknown (%x)", uncle.ParentHash[0:4]) 512 } 513 if work.family.Contains(hash) { 514 return fmt.Errorf("uncle already in family (%x)", hash) 515 } 516 work.uncles.Add(uncle.Hash()) 517 return nil 518 } 519 520 func (env *Work) commitTransactions(mux *event.TypeMux, txs *types.TransactionsByPriceAndNonce, bc *core.BlockChain, coinbase common.Address, currentHeader *types.Header) { 521 //gp := new(core.GasPool).AddGas(env.header.GasLimit) 522 // modified by cai.zhihong 523 gp := new(core.GasPool).AddGas(env.header.GasLimit) 524 525 var coalescedLogs []*types.Log 526 var timeout time.Time 527 if currentHeader != nil { 528 timeout = time.Unix(currentHeader.Time.Int64(), 0) 529 } 530 for { 531 // Retrieve the next transaction and abort if all done 532 tx := txs.Peek() 533 if tx == nil { 534 break 535 } 536 log.Debug(fmt.Sprintf("timeout=%s", timeout)) 537 //there may be too many transactions, thus missing the block time 538 if currentHeader != nil && timeout.Before(time.Now()) && len(env.txs) > 0 { 539 break 540 } 541 /* 542 if tx.To()!= nil { 543 fmt.Println(bc.CurrentBlock().Number().Int64(),"---- work.commitTransactions ---->",1,tx.To().Hex()) 544 } 545 */ 546 // Error may be ignored here. The error has already been checked 547 // during transaction acceptance is the transaction pool. 548 // 549 // We use the eip155 signer regardless of the current hf. 550 from, _ := types.Sender(env.signer, tx) 551 // Check whether the tx is replay protected. If we're not in the EIP155 hf 552 // phase, start ignoring the sender until we do. 553 if tx.Protected() && !env.config.IsEIP155(env.header.Number) { 554 log.Trace("Ignoring reply protected transaction", "hash", tx.Hash(), "eip155", env.config.EIP155Block) 555 txs.Pop() 556 continue 557 } 558 //fmt.Println(bc.CurrentBlock().Number().Int64(),"---- work.commitTransactions ---->",2) 559 // Start executing the transaction 560 // TODO : add by liangc 561 env.state.Prepare(tx.Hash(), common.Hash{}, env.tcount) 562 err, logs := env.commitTransaction(tx, bc, coinbase, gp) 563 if err != nil { 564 if tx.To() != nil { 565 log.Debug("cc14514_TODO_004", "cn", bc.CurrentHeader().Number.Int64(), "tx", tx.Hash().Hex(), "to", *tx.To(), "err", err) 566 } else { 567 log.Debug("cc14514_TODO_004", "cn", bc.CurrentHeader().Number.Int64(), "tx", tx.Hash().Hex(), "err", err) 568 } 569 appendToFailTx(tx.Hash()) 570 } 571 switch err { 572 case core.ErrGasLimitReached: 573 // Pop the current out-of-gas transaction without shifting in the next from the account 574 log.Trace("Gas limit exceeded for current block", "sender", from) 575 txs.Pop() 576 577 case core.ErrNonceTooLow: 578 // New head notification data race between the transaction pool and miner, shift 579 log.Trace("Skipping transaction with low nonce", "sender", from, "nonce", tx.Nonce()) 580 txs.Shift() 581 582 case core.ErrNonceTooHigh: 583 // Reorg notification data race between the transaction pool and miner, skip account = 584 log.Trace("Skipping account with hight nonce", "sender", from, "nonce", tx.Nonce()) 585 txs.Pop() 586 587 case nil: 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 default: 593 // Strange error, discard the transaction and get the next in line (note, the 594 // nonce-too-high clause will prevent us from executing in vain). 595 log.Debug("Transaction failed, account skipped", "hash", tx.Hash(), "err", err) 596 txs.Shift() 597 } 598 } 599 600 if len(coalescedLogs) > 0 || env.tcount > 0 { 601 // make a copy, the state caches the logs and these logs get "upgraded" from pending to mined 602 // logs by filling in the block hash when the block was mined by the local miner. This can 603 // cause a race condition if a log was "upgraded" before the PendingLogsEvent is processed. 604 cpy := make([]*types.Log, len(coalescedLogs)) 605 for i, l := range coalescedLogs { 606 cpy[i] = new(types.Log) 607 *cpy[i] = *l 608 } 609 go func(logs []*types.Log, tcount int) { 610 if len(logs) > 0 { 611 mux.Post(core.PendingLogsEvent{Logs: logs}) 612 } 613 if tcount > 0 { 614 mux.Post(core.PendingStateEvent{}) 615 } 616 }(cpy, env.tcount) 617 } 618 } 619 620 func (env *Work) commitTransaction(tx *types.Transaction, bc *core.BlockChain, coinbase common.Address, gp *core.GasPool) (error, []*types.Log) { 621 snap := env.state.Snapshot() 622 receipt, _, err := core.ApplyTransaction(env.config, bc, &coinbase, gp, env.state, env.header, tx, env.header.GasUsed, vm.Config{}) 623 if err != nil { 624 env.state.RevertToSnapshot(snap) 625 return err, nil 626 } 627 env.txs = append(env.txs, tx) 628 env.receipts = append(env.receipts, receipt) 629 630 return nil, receipt.Logs 631 }