github.com/insight-chain/inb-go@v1.1.3-0.20191221022159-da049980ae38/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 MiningReward, 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 "errors" 21 22 "fmt" 23 "github.com/insight-chain/inb-go/consensus/vdpos" 24 "math/big" 25 "sync" 26 "sync/atomic" 27 "time" 28 29 "github.com/deckarep/golang-set" 30 "github.com/insight-chain/inb-go/common" 31 "github.com/insight-chain/inb-go/common/hexutil" 32 "github.com/insight-chain/inb-go/consensus" 33 "github.com/insight-chain/inb-go/core" 34 "github.com/insight-chain/inb-go/core/state" 35 "github.com/insight-chain/inb-go/core/types" 36 "github.com/insight-chain/inb-go/event" 37 "github.com/insight-chain/inb-go/log" 38 "github.com/insight-chain/inb-go/params" 39 "github.com/insight-chain/inb-go/rlp" 40 ) 41 42 const ( 43 // resultQueueSize is the size of channel listening to sealing result. 44 resultQueueSize = 10 45 46 // txChanSize is the size of channel listening to NewTxsEvent. 47 // The number is referenced from the size of tx pool. 48 txChanSize = 4096 49 50 // chainHeadChanSize is the size of channel listening to ChainHeadEvent. 51 chainHeadChanSize = 10 52 53 // chainSideChanSize is the size of channel listening to ChainSideEvent. 54 chainSideChanSize = 10 55 56 // resubmitAdjustChanSize is the size of resubmitting interval adjustment channel. 57 resubmitAdjustChanSize = 10 58 59 // miningLogAtDepth is the number of confirmations before logging successful mining. 60 miningLogAtDepth = 7 61 62 // minRecommitInterval is the minimal time interval to recreate the mining block with 63 // any newly arrived transactions. 64 minRecommitInterval = 1 * time.Second 65 66 // maxRecommitInterval is the maximum time interval to recreate the mining block with 67 // any newly arrived transactions. 68 maxRecommitInterval = 15 * time.Second 69 70 // intervalAdjustRatio is the impact a single interval adjustment has on sealing work 71 // resubmitting interval. 72 intervalAdjustRatio = 0.1 73 74 // intervalAdjustBias is applied during the new resubmit interval calculation in favor of 75 // increasing upper limit or decreasing lower limit so that the limit can be reachable. 76 intervalAdjustBias = 200 * 1000.0 * 1000.0 77 78 // staleThreshold is the maximum depth of the acceptable stale block. 79 staleThreshold = 7 80 ) 81 82 type SendTxArgs struct { 83 From common.Address `json:"from"` 84 To common.Address `json:"to"` 85 Gas *hexutil.Uint64 `json:"gas"` 86 GasPrice *hexutil.Big `json:"gasPrice"` 87 Value *big.Int `json:"value"` 88 Nonce uint64 `json:"nonce"` 89 // We accept "data" and "input" for backwards-compatibility reasons. "input" is the 90 // newer name and should be preferred by clients. 91 Data *hexutil.Bytes `json:"data"` 92 Input *hexutil.Bytes `json:"input"` 93 Types types.TxType `json:"txType"` 94 ResourcePayer *common.Address `json:"resourcePayer"` 95 //Candidates []common.Address `json:"candidates"` 96 } 97 98 // environment is the worker's current environment and holds all of the current state information. 99 type environment struct { 100 signer types.Signer 101 102 state *state.StateDB // apply state changes here 103 vdposContext *types.VdposContext //add by ssh 190829 104 ancestors mapset.Set // ancestor set (used for checking uncle parent validity) 105 family mapset.Set // family set (used for checking uncle invalidity) 106 uncles mapset.Set // uncle set 107 tcount int // tx count in cycle 108 gasPool *core.GasPool // available gas used to pack transactions 109 110 header *types.Header 111 txs []*types.Transaction 112 receipts []*types.Receipt 113 } 114 115 // task contains all information for consensus engine sealing and result submitting. 116 type task struct { 117 receipts []*types.Receipt 118 state *state.StateDB 119 block *types.Block 120 createdAt time.Time 121 } 122 123 const ( 124 commitInterruptNone int32 = iota 125 commitInterruptNewHead 126 commitInterruptResubmit 127 ) 128 129 // newWorkReq represents a request for new sealing work submitting with relative interrupt notifier. 130 type newWorkReq struct { 131 interrupt *int32 132 noempty bool 133 timestamp int64 134 } 135 136 // intervalAdjust represents a resubmitting interval adjustment. 137 type intervalAdjust struct { 138 ratio float64 139 inc bool 140 } 141 142 // worker is the main object which takes care of submitting new work to consensus engine 143 // and gathering the sealing result. 144 type worker struct { 145 config *params.ChainConfig 146 engine consensus.Engine 147 eth Backend 148 chain *core.BlockChain 149 150 gasFloor uint64 151 gasCeil uint64 152 153 // Subscriptions 154 mux *event.TypeMux 155 txsCh chan core.NewTxsEvent 156 txsSub event.Subscription 157 chainHeadCh chan core.ChainHeadEvent 158 chainHeadSub event.Subscription 159 chainSideCh chan core.ChainSideEvent 160 chainSideSub event.Subscription 161 162 // Channels 163 newWorkCh chan *newWorkReq 164 taskCh chan *task 165 resultCh chan *types.Block 166 startCh chan struct{} 167 exitCh chan struct{} 168 resubmitIntervalCh chan time.Duration 169 resubmitAdjustCh chan *intervalAdjust 170 171 current *environment // An environment for current running cycle. 172 localUncles map[common.Hash]*types.Block // A set of side blocks generated locally as the possible uncle blocks. 173 remoteUncles map[common.Hash]*types.Block // A set of side blocks as the possible uncle blocks. 174 unconfirmed *unconfirmedBlocks // A set of locally mined blocks pending canonicalness confirmations. 175 176 mu sync.RWMutex // The lock used to protect the coinbase and extra fields 177 coinbase common.Address 178 extra []byte 179 180 pendingMu sync.RWMutex 181 pendingTasks map[common.Hash]*task 182 183 snapshotMu sync.RWMutex // The lock used to protect the block snapshot and state snapshot 184 snapshotBlock *types.Block 185 snapshotState *state.StateDB 186 187 // atomic status counters 188 running int32 // The indicator whether the consensus engine is running or not. 189 newTxs int32 // New arrival transaction count since last sealing work submitting. 190 191 // External functions 192 isLocalBlock func(block *types.Block) bool // Function used to determine whether the specified block is mined by local miner. 193 194 // Test hooks 195 newTaskHook func(*task) // Method to call upon receiving a new sealing task. 196 skipSealHook func(*task) bool // Method to decide whether skipping the sealing. 197 fullTaskHook func() // Method to call before pushing the full sealing task. 198 resubmitHook func(time.Duration, time.Duration) // Method to call upon updating resubmitting interval. 199 } 200 201 func newWorker(config *params.ChainConfig, engine consensus.Engine, eth Backend, mux *event.TypeMux, recommit time.Duration, gasFloor, gasCeil uint64, isLocalBlock func(*types.Block) bool) *worker { 202 worker := &worker{ 203 config: config, 204 engine: engine, 205 eth: eth, 206 mux: mux, 207 chain: eth.BlockChain(), 208 gasFloor: gasFloor, 209 gasCeil: gasCeil, 210 isLocalBlock: isLocalBlock, 211 localUncles: make(map[common.Hash]*types.Block), 212 remoteUncles: make(map[common.Hash]*types.Block), 213 unconfirmed: newUnconfirmedBlocks(eth.BlockChain(), miningLogAtDepth), 214 pendingTasks: make(map[common.Hash]*task), 215 txsCh: make(chan core.NewTxsEvent, txChanSize), 216 chainHeadCh: make(chan core.ChainHeadEvent, chainHeadChanSize), 217 chainSideCh: make(chan core.ChainSideEvent, chainSideChanSize), 218 newWorkCh: make(chan *newWorkReq), 219 taskCh: make(chan *task), 220 resultCh: make(chan *types.Block, resultQueueSize), 221 exitCh: make(chan struct{}), 222 startCh: make(chan struct{}, 1), 223 resubmitIntervalCh: make(chan time.Duration), 224 resubmitAdjustCh: make(chan *intervalAdjust, resubmitAdjustChanSize), 225 } 226 // Subscribe NewTxsEvent for tx pool 227 worker.txsSub = eth.TxPool().SubscribeNewTxsEvent(worker.txsCh) 228 // Subscribe events for blockchain 229 worker.chainHeadSub = eth.BlockChain().SubscribeChainHeadEvent(worker.chainHeadCh) 230 worker.chainSideSub = eth.BlockChain().SubscribeChainSideEvent(worker.chainSideCh) 231 232 // Sanitize recommit interval if the user-specified one is too short. 233 if recommit < minRecommitInterval { 234 log.Warn("Sanitizing miner recommit interval", "provided", recommit, "updated", minRecommitInterval) 235 recommit = minRecommitInterval 236 } 237 238 go worker.mainLoop() 239 go worker.newWorkLoop(recommit) 240 go worker.resultLoop() 241 go worker.taskLoop() 242 243 // Submit first work to initialize pending state. 244 worker.startCh <- struct{}{} 245 246 return worker 247 } 248 249 // setEtherbase sets the etherbase used to initialize the block coinbase field. 250 func (w *worker) setEtherbase(addr common.Address) { 251 w.mu.Lock() 252 defer w.mu.Unlock() 253 w.coinbase = addr 254 } 255 256 // setExtra sets the content used to initialize the block extra field. 257 func (w *worker) setExtra(extra []byte) { 258 w.mu.Lock() 259 defer w.mu.Unlock() 260 w.extra = extra 261 } 262 263 // setRecommitInterval updates the interval for miner sealing work recommitting. 264 func (w *worker) setRecommitInterval(interval time.Duration) { 265 w.resubmitIntervalCh <- interval 266 } 267 268 // pending returns the pending state and corresponding block. 269 func (w *worker) pending() (*types.Block, *state.StateDB) { 270 // return a snapshot to avoid contention on currentMu mutex 271 w.snapshotMu.RLock() 272 defer w.snapshotMu.RUnlock() 273 if w.snapshotState == nil { 274 return nil, nil 275 } 276 return w.snapshotBlock, w.snapshotState.Copy() 277 } 278 279 // pendingBlock returns pending block. 280 func (w *worker) pendingBlock() *types.Block { 281 // return a snapshot to avoid contention on currentMu mutex 282 w.snapshotMu.RLock() 283 defer w.snapshotMu.RUnlock() 284 return w.snapshotBlock 285 } 286 287 // start sets the running status as 1 and triggers new work submitting. 288 func (w *worker) start() { 289 atomic.StoreInt32(&w.running, 1) 290 w.startCh <- struct{}{} 291 } 292 293 // stop sets the running status as 0. 294 func (w *worker) stop() { 295 atomic.StoreInt32(&w.running, 0) 296 } 297 298 // isRunning returns an indicator whether worker is running or not. 299 func (w *worker) isRunning() bool { 300 return atomic.LoadInt32(&w.running) == 1 301 } 302 303 // close terminates all background threads maintained by the worker. 304 // Note the worker does not support being closed multiple times. 305 func (w *worker) close() { 306 close(w.exitCh) 307 } 308 309 // newWorkLoop is a standalone goroutine to submit new mining work upon received events. 310 func (w *worker) newWorkLoop(recommit time.Duration) { 311 var ( 312 interrupt *int32 313 minRecommit = recommit // minimal resubmit interval specified by user. 314 timestamp int64 // timestamp for each round of mining. 315 ) 316 317 timer := time.NewTimer(0) 318 <-timer.C // discard the initial tick 319 320 // commit aborts in-flight transaction execution with given signal and resubmits a new one. 321 commit := func(noempty bool, s int32) { 322 if interrupt != nil { 323 atomic.StoreInt32(interrupt, s) 324 } 325 interrupt = new(int32) 326 w.newWorkCh <- &newWorkReq{interrupt: interrupt, noempty: noempty, timestamp: timestamp} 327 timer.Reset(recommit) 328 atomic.StoreInt32(&w.newTxs, 0) 329 } 330 // recalcRecommit recalculates the resubmitting interval upon feedback. 331 recalcRecommit := func(target float64, inc bool) { 332 var ( 333 prev = float64(recommit.Nanoseconds()) 334 next float64 335 ) 336 if inc { 337 next = prev*(1-intervalAdjustRatio) + intervalAdjustRatio*(target+intervalAdjustBias) 338 // Recap if interval is larger than the maximum time interval 339 if next > float64(maxRecommitInterval.Nanoseconds()) { 340 next = float64(maxRecommitInterval.Nanoseconds()) 341 } 342 } else { 343 next = prev*(1-intervalAdjustRatio) + intervalAdjustRatio*(target-intervalAdjustBias) 344 // Recap if interval is less than the user specified minimum 345 if next < float64(minRecommit.Nanoseconds()) { 346 next = float64(minRecommit.Nanoseconds()) 347 } 348 } 349 recommit = time.Duration(int64(next)) 350 } 351 // clearPending cleans the stale pending tasks. 352 clearPending := func(number uint64) { 353 w.pendingMu.Lock() 354 for h, t := range w.pendingTasks { 355 if t.block.NumberU64()+staleThreshold <= number { 356 delete(w.pendingTasks, h) 357 } 358 } 359 w.pendingMu.Unlock() 360 } 361 362 for { 363 select { 364 case <-w.startCh: 365 clearPending(w.chain.CurrentBlock().NumberU64()) 366 timestamp = time.Now().Unix() 367 commit(false, commitInterruptNewHead) 368 369 case head := <-w.chainHeadCh: 370 clearPending(head.Block.NumberU64()) 371 timestamp = time.Now().Unix() 372 commit(false, commitInterruptNewHead) 373 374 case <-timer.C: 375 // If mining is running resubmit a new work cycle periodically to pull in 376 // higher priced transactions. Disable this overhead for pending blocks. 377 if w.isRunning() && (w.config.Clique == nil || w.config.Clique.Period > 0 || w.config.Vdpos.Period > 0) { 378 // Short circuit if no new transaction arrives. 379 if atomic.LoadInt32(&w.newTxs) == 0 { 380 timer.Reset(recommit) 381 continue 382 } 383 commit(true, commitInterruptResubmit) 384 } 385 386 case interval := <-w.resubmitIntervalCh: 387 // Adjust resubmit interval explicitly by user. 388 if interval < minRecommitInterval { 389 log.Warn("Sanitizing miner recommit interval", "provided", interval, "updated", minRecommitInterval) 390 interval = minRecommitInterval 391 } 392 log.Info("MiningReward recommit interval update", "from", minRecommit, "to", interval) 393 minRecommit, recommit = interval, interval 394 395 if w.resubmitHook != nil { 396 w.resubmitHook(minRecommit, recommit) 397 } 398 399 case adjust := <-w.resubmitAdjustCh: 400 // Adjust resubmit interval by feedback. 401 if adjust.inc { 402 before := recommit 403 recalcRecommit(float64(recommit.Nanoseconds())/adjust.ratio, true) 404 log.Trace("Increase miner recommit interval", "from", before, "to", recommit) 405 } else { 406 before := recommit 407 recalcRecommit(float64(minRecommit.Nanoseconds()), false) 408 log.Trace("Decrease miner recommit interval", "from", before, "to", recommit) 409 } 410 411 if w.resubmitHook != nil { 412 w.resubmitHook(minRecommit, recommit) 413 } 414 415 case <-w.exitCh: 416 return 417 } 418 } 419 } 420 421 // mainLoop is a standalone goroutine to regenerate the sealing task based on the received event. 422 func (w *worker) mainLoop() { 423 defer w.txsSub.Unsubscribe() 424 defer w.chainHeadSub.Unsubscribe() 425 defer w.chainSideSub.Unsubscribe() 426 427 //vdpos by ssh begin 428 vdposDelay := time.Duration(300) * time.Second 429 if w.config.Vdpos != nil && w.config.Vdpos.Period > 0 { 430 vdposDelay = time.Duration(w.config.Vdpos.Period) * time.Second 431 } 432 //vdpos by ssh end 433 434 for { 435 //w.commitNewWork(nil, false, time.Now().Unix()) 436 select { 437 case req := <-w.newWorkCh: 438 w.commitNewWork(req.interrupt, req.noempty, req.timestamp) 439 440 case ev := <-w.chainSideCh: 441 442 //vdpos by ssh begin 443 //uncle block useless in vdpos or clique 444 if w.config.Vdpos != nil || w.config.Clique != nil { 445 //do nothing 446 } else { 447 // Short circuit for duplicate side blocks 448 if _, exist := w.localUncles[ev.Block.Hash()]; exist { 449 continue 450 } 451 if _, exist := w.remoteUncles[ev.Block.Hash()]; exist { 452 continue 453 } 454 // Add side block to possible uncle block set depending on the author. 455 if w.isLocalBlock != nil && w.isLocalBlock(ev.Block) { 456 w.localUncles[ev.Block.Hash()] = ev.Block 457 } else { 458 w.remoteUncles[ev.Block.Hash()] = ev.Block 459 } 460 // If our mining block contains less than 2 uncle blocks, 461 // add the new uncle block if valid and regenerate a mining block. 462 if w.isRunning() && w.current != nil && w.current.uncles.Cardinality() < 2 { 463 start := time.Now() 464 if err := w.commitUncle(w.current, ev.Block.Header()); err == nil { 465 var uncles []*types.Header 466 w.current.uncles.Each(func(item interface{}) bool { 467 hash, ok := item.(common.Hash) 468 if !ok { 469 return false 470 } 471 uncle, exist := w.localUncles[hash] 472 if !exist { 473 uncle, exist = w.remoteUncles[hash] 474 } 475 if !exist { 476 return false 477 } 478 uncles = append(uncles, uncle.Header()) 479 return false 480 }) 481 w.commit(uncles, nil, true, start) 482 } 483 } 484 } 485 //vdpos by ssh end 486 487 case ev := <-w.txsCh: 488 // Apply transactions to the pending state if we're not mining. 489 // 490 // Note all transactions received may not be continuous with transactions 491 // already included in the current mining block. These transactions will 492 // be automatically eliminated. 493 if !w.isRunning() && w.current != nil { 494 w.mu.RLock() 495 coinbase := w.coinbase 496 w.mu.RUnlock() 497 498 txs := make(map[common.Address]types.Transactions) 499 for _, tx := range ev.Txs { 500 acc, _ := types.Sender(w.current.signer, tx) 501 txs[acc] = append(txs[acc], tx) 502 } 503 txset := types.NewTransactionsByPriceAndNonce(w.current.signer, txs) 504 w.commitTransactions(txset, coinbase, nil) 505 w.updateSnapshot() 506 } else { 507 // If we're mining, but nothing is being processed, wake on new transactions 508 if w.config.Clique != nil && w.config.Clique.Period == 0 { 509 w.commitNewWork(nil, false, time.Now().Unix()) 510 } 511 } 512 atomic.AddInt32(&w.newTxs, int32(len(ev.Txs))) 513 514 //vdpos by ssh begin 515 case <-time.After(vdposDelay): 516 // try to seal block in each period, even no new block received in dpos 517 if w.config.Vdpos != nil && w.config.Vdpos.Period > 0 { 518 w.commitNewWork(nil, false, time.Now().Unix()) 519 } 520 //vdpos by ssh end 521 522 // System stopped 523 case <-w.exitCh: 524 return 525 case <-w.txsSub.Err(): 526 return 527 case <-w.chainHeadSub.Err(): 528 return 529 case <-w.chainSideSub.Err(): 530 return 531 } 532 } 533 } 534 535 // taskLoop is a standalone goroutine to fetch sealing task from the generator and 536 // push them to consensus engine. 537 func (w *worker) taskLoop() { 538 var ( 539 stopCh chan struct{} 540 prev common.Hash 541 ) 542 543 // interrupt aborts the in-flight sealing task. 544 interrupt := func() { 545 if stopCh != nil { 546 close(stopCh) 547 stopCh = nil 548 } 549 } 550 for { 551 select { 552 case task := <-w.taskCh: 553 if w.newTaskHook != nil { 554 w.newTaskHook(task) 555 } 556 // Reject duplicate sealing work due to resubmitting. 557 sealHash := w.engine.SealHash(task.block.Header()) 558 if sealHash == prev { 559 continue 560 } 561 // Interrupt previous sealing operation 562 interrupt() 563 stopCh, prev = make(chan struct{}), sealHash 564 565 if w.skipSealHook != nil && w.skipSealHook(task) { 566 continue 567 } 568 w.pendingMu.Lock() 569 w.pendingTasks[w.engine.SealHash(task.block.Header())] = task 570 w.pendingMu.Unlock() 571 572 if err := w.engine.Seal(w.chain, task.block, w.resultCh, stopCh); err != nil { 573 //log.Warn("Block sealing failed", "err", err) 574 log.Info("Block sealing failed", "err", err) 575 } 576 case <-w.exitCh: 577 interrupt() 578 return 579 } 580 } 581 } 582 583 // resultLoop is a standalone goroutine to handle sealing result submitting 584 // and flush relative data to the database. 585 func (w *worker) resultLoop() { 586 for { 587 select { 588 case block := <-w.resultCh: 589 // Short circuit when receiving empty result. 590 if block == nil { 591 continue 592 } 593 // Short circuit when receiving duplicate result caused by resubmitting. 594 if w.chain.HasBlock(block.Hash(), block.NumberU64()) { 595 continue 596 } 597 var ( 598 sealhash = w.engine.SealHash(block.Header()) 599 hash = block.Hash() 600 ) 601 w.pendingMu.RLock() 602 task, exist := w.pendingTasks[sealhash] 603 w.pendingMu.RUnlock() 604 if !exist { 605 log.Error("Block found but no relative pending task", "number", block.Number(), "sealhash", sealhash, "hash", hash) 606 continue 607 } 608 // Different block could share same sealhash, deep copy here to prevent write-write conflict. 609 var ( 610 receipts = make([]*types.Receipt, len(task.receipts)) 611 logs []*types.Log 612 ) 613 for i, receipt := range task.receipts { 614 receipts[i] = new(types.Receipt) 615 *receipts[i] = *receipt 616 // Update the block hash in all logs since it is now available and not when the 617 // receipt/log of individual transactions were created. 618 for _, log := range receipt.Logs { 619 log.BlockHash = hash 620 } 621 logs = append(logs, receipt.Logs...) 622 } 623 // 2019.8.29 inb by ghy begin 624 if w.chain.CurrentHeader().Number.Cmp(big.NewInt(0)) == 1 { 625 parentBlock := w.chain.GetBlock(block.ParentHash(), block.NumberU64()-1) 626 if err := types.ValidateTx(w.chain.GetDb(), block.Transactions(), block.Header(), parentBlock.Header(), w.config.Vdpos.Period); err != nil { 627 fmt.Println(err) 628 return 629 } 630 } 631 // 2019.8.29 inb by ghy end 632 633 // Commit block and state to database. 634 stat, err := w.chain.WriteBlockWithState(block, receipts, task.state) 635 if err != nil { 636 log.Error("Failed writing block to chain", "err", err) 637 continue 638 } 639 log.Info("Successfully sealed new block", "number", block.Number(), "sealhash", sealhash, "hash", hash, 640 "elapsed", common.PrettyDuration(time.Since(task.createdAt))) 641 642 // Broadcast the block and announce chain insertion event 643 w.mux.Post(core.NewMinedBlockEvent{Block: block}) 644 645 var events []interface{} 646 switch stat { 647 case core.CanonStatTy: 648 events = append(events, core.ChainEvent{Block: block, Hash: block.Hash(), Logs: logs}) 649 events = append(events, core.ChainHeadEvent{Block: block}) 650 case core.SideStatTy: 651 events = append(events, core.ChainSideEvent{Block: block}) 652 } 653 w.chain.PostChainEvents(events, logs) 654 655 // Insert the block into the set of pending ones to resultLoop for confirmations 656 w.unconfirmed.Insert(block.NumberU64(), block.Hash()) 657 658 case <-w.exitCh: 659 return 660 } 661 } 662 } 663 664 // makeCurrent creates a new environment for the current cycle. 665 func (w *worker) makeCurrent(parent *types.Block, header *types.Header) error { 666 state, err := w.chain.StateAt(parent.Root()) 667 if err != nil { 668 return err 669 } 670 671 // add by ssh 190829 672 vdposContext, err := types.NewVdposContextFromProto(w.chain.GetDb(), parent.Header().VdposContext) 673 if err != nil { 674 return err 675 } 676 677 env := &environment{ 678 signer: types.NewEIP155Signer(w.config.ChainID), 679 state: state, 680 vdposContext: vdposContext, 681 ancestors: mapset.NewSet(), 682 family: mapset.NewSet(), 683 uncles: mapset.NewSet(), 684 header: header, 685 } 686 687 // when 08 is processed ancestors contain 07 (quick block) 688 for _, ancestor := range w.chain.GetBlocksFromHash(parent.Hash(), 7) { 689 for _, uncle := range ancestor.Uncles() { 690 env.family.Add(uncle.Hash()) 691 } 692 env.family.Add(ancestor.Hash()) 693 env.ancestors.Add(ancestor.Hash()) 694 } 695 696 // Keep track of transactions which return errors so they can be removed 697 env.tcount = 0 698 w.current = env 699 return nil 700 } 701 702 // commitUncle adds the given block to uncle block set, returns error if failed to add. 703 func (w *worker) commitUncle(env *environment, uncle *types.Header) error { 704 hash := uncle.Hash() 705 if env.uncles.Contains(hash) { 706 return errors.New("uncle not unique") 707 } 708 if env.header.ParentHash == uncle.ParentHash { 709 return errors.New("uncle is sibling") 710 } 711 if !env.ancestors.Contains(uncle.ParentHash) { 712 return errors.New("uncle's parent unknown") 713 } 714 if env.family.Contains(hash) { 715 return errors.New("uncle already included") 716 } 717 env.uncles.Add(uncle.Hash()) 718 return nil 719 } 720 721 // updateSnapshot updates pending snapshot block and state. 722 // Note this function assumes the current variable is thread safe. 723 func (w *worker) updateSnapshot() { 724 w.snapshotMu.Lock() 725 defer w.snapshotMu.Unlock() 726 727 var uncles []*types.Header 728 w.current.uncles.Each(func(item interface{}) bool { 729 hash, ok := item.(common.Hash) 730 if !ok { 731 return false 732 } 733 uncle, exist := w.localUncles[hash] 734 if !exist { 735 uncle, exist = w.remoteUncles[hash] 736 } 737 if !exist { 738 return false 739 } 740 uncles = append(uncles, uncle.Header()) 741 return false 742 }) 743 744 w.snapshotBlock = types.NewBlock( 745 w.current.header, 746 w.current.txs, 747 uncles, 748 w.current.receipts, 749 ) 750 751 w.snapshotState = w.current.state.Copy() 752 } 753 754 func (w *worker) commitTransaction(tx *types.Transaction, coinbase common.Address) ([]*types.Log, error) { 755 snap := w.current.state.Snapshot() 756 757 // add by ssh 190829 begin 758 vdposSnap := w.current.vdposContext.Snapshot() 759 receipt, _, err := core.ApplyTransaction(w.config, w.chain, &coinbase, w.current.gasPool, w.current.state, w.current.header, tx, &w.current.header.ResUsed, *w.chain.GetVMConfig()) 760 761 if err != nil { 762 w.current.state.RevertToSnapshot(snap) 763 w.current.vdposContext.RevertToSnapShot(vdposSnap) 764 return nil, err 765 } 766 // add by ssh 190829 end 767 w.current.txs = append(w.current.txs, tx) 768 w.current.receipts = append(w.current.receipts, receipt) 769 770 return receipt.Logs, nil 771 } 772 773 func (w *worker) commitTransactions(txs *types.TransactionsByPriceAndNonce, coinbase common.Address, interrupt *int32) bool { 774 // Short circuit if current is nil 775 if w.current == nil { 776 return true 777 } 778 779 if w.current.gasPool == nil { 780 w.current.gasPool = new(core.GasPool).AddGas(w.current.header.ResLimit) 781 } 782 783 var coalescedLogs []*types.Log 784 785 for { 786 // In the following three cases, we will interrupt the execution of the transaction. 787 // (1) new head block event arrival, the interrupt signal is 1 788 // (2) worker start or restart, the interrupt signal is 1 789 // (3) worker recreate the mining block with any newly arrived transactions, the interrupt signal is 2. 790 // For the first two cases, the semi-finished work will be discarded. 791 // For the third case, the semi-finished work will be submitted to the consensus engine. 792 if interrupt != nil && atomic.LoadInt32(interrupt) != commitInterruptNone { 793 // Notify resubmit loop to increase resubmitting interval due to too frequent commits. 794 if atomic.LoadInt32(interrupt) == commitInterruptResubmit { 795 ratio := float64(w.current.header.ResLimit-w.current.gasPool.Gas()) / float64(w.current.header.ResLimit) 796 if ratio < 0.1 { 797 ratio = 0.1 798 } 799 w.resubmitAdjustCh <- &intervalAdjust{ 800 ratio: ratio, 801 inc: true, 802 } 803 } 804 return atomic.LoadInt32(interrupt) == commitInterruptNewHead 805 } 806 // If we don't have enough gas for any further transactions then we're done 807 if w.current.gasPool.Gas() < params.TxGas { 808 log.Trace("Not enough gas for further transactions", "have", w.current.gasPool, "want", params.TxGas) 809 break 810 } 811 // Retrieve the next transaction and abort if all done 812 tx := txs.Peek() 813 if tx == nil { 814 break 815 } 816 // Error may be ignored here. The error has already been checked 817 // during transaction acceptance is the transaction pool. 818 // 819 // We use the eip155 signer regardless of the current hf. 820 from, _ := types.Sender(w.current.signer, tx) 821 // Check whether the tx is replay protected. If we're not in the EIP155 hf 822 // phase, start ignoring the sender until we do. 823 if tx.Protected() && !w.config.IsEIP155(w.current.header.Number) { 824 log.Trace("Ignoring reply protected transaction", "hash", tx.Hash(), "eip155", w.config.EIP155Block) 825 826 txs.Pop() 827 continue 828 } 829 // Start executing the transaction 830 w.current.state.Prepare(tx.Hash(), common.Hash{}, w.current.tcount) 831 logs, err := w.commitTransaction(tx, coinbase) 832 switch err { 833 case core.ErrGasLimitReached: 834 // Pop the current out-of-gas transaction without shifting in the next from the account 835 log.Trace("Gas limit exceeded for current block", "sender", from) 836 txs.Pop() 837 838 case core.ErrNonceTooLow: 839 // New head notification data race between the transaction pool and miner, shift 840 log.Trace("Skipping transaction with low nonce", "sender", from, "nonce", tx.Nonce()) 841 txs.Shift() 842 843 case core.ErrNonceTooHigh: 844 // Reorg notification data race between the transaction pool and miner, skip account = 845 log.Trace("Skipping account with hight nonce", "sender", from, "nonce", tx.Nonce()) 846 txs.Pop() 847 848 case nil: 849 // Everything ok, collect the logs and shift in the next transaction from the same account 850 coalescedLogs = append(coalescedLogs, logs...) 851 w.current.tcount++ 852 txs.Shift() 853 854 default: 855 // Strange error, discard the transaction and get the next in line (note, the 856 // nonce-too-high clause will prevent us from executing in vain). 857 log.Debug("Transaction failed, account skipped", "hash", tx.Hash(), "err", err) 858 txs.Shift() 859 } 860 } 861 862 if !w.isRunning() && len(coalescedLogs) > 0 { 863 // We don't push the pendingLogsEvent while we are mining. The reason is that 864 // when we are mining, the worker will regenerate a mining block every 3 seconds. 865 // In order to avoid pushing the repeated pendingLog, we disable the pending log pushing. 866 867 // make a copy, the state caches the logs and these logs get "upgraded" from pending to mined 868 // logs by filling in the block hash when the block was mined by the local miner. This can 869 // cause a race condition if a log was "upgraded" before the PendingLogsEvent is processed. 870 cpy := make([]*types.Log, len(coalescedLogs)) 871 for i, l := range coalescedLogs { 872 cpy[i] = new(types.Log) 873 *cpy[i] = *l 874 } 875 go w.mux.Post(core.PendingLogsEvent{Logs: cpy}) 876 } 877 // Notify resubmit loop to decrease resubmitting interval if current interval is larger 878 // than the user-specified one. 879 if interrupt != nil { 880 w.resubmitAdjustCh <- &intervalAdjust{inc: false} 881 } 882 883 return false 884 } 885 886 // commitNewWork generates several new sealing tasks based on the parent block. 887 func (w *worker) commitNewWork(interrupt *int32, noempty bool, timestamp int64) { 888 w.mu.RLock() 889 defer w.mu.RUnlock() 890 891 tstart := time.Now() 892 parent := w.chain.CurrentBlock() 893 894 if parent.Time().Cmp(new(big.Int).SetInt64(timestamp)) >= 0 { 895 timestamp = parent.Time().Int64() + 1 896 } 897 // this will ensure we're not going off too far in the future 898 if now := time.Now().Unix(); timestamp > now+1 { 899 wait := time.Duration(timestamp-now) * time.Second 900 log.Info("Mining too far in the future", "wait", common.PrettyDuration(wait)) 901 time.Sleep(wait) 902 } 903 904 num := parent.Number() 905 header := &types.Header{ 906 ParentHash: parent.Hash(), 907 Number: num.Add(num, common.Big1), 908 ResLimit: core.CalcGasLimit(parent, w.gasFloor, w.gasCeil), 909 Extra: w.extra, 910 Time: big.NewInt(timestamp), 911 } 912 // Only set the coinbase if our consensus engine is running (avoid spurious block rewards) 913 if w.isRunning() { 914 if w.coinbase == (common.Address{}) { 915 log.Error("Refusing to mine without etherbase") 916 return 917 } 918 header.Coinbase = w.coinbase 919 } 920 if err := w.engine.Prepare(w.chain, header); err != nil { 921 log.Error("Failed to prepare header for mining", "err", err) 922 return 923 } 924 // If we are care about TheDAO hard-fork check whether to override the extra-data or not 925 //if daoBlock := w.config.DAOForkBlock; daoBlock != nil { 926 // // Check whether the block is among the fork extra-override range 927 // limit := new(big.Int).Add(daoBlock, params.DAOForkExtraRange) 928 // if header.Number.Cmp(daoBlock) >= 0 && header.Number.Cmp(limit) < 0 { 929 // // Depending whether we support or oppose the fork, override differently 930 // if w.config.DAOForkSupport { 931 // header.Extra = common.CopyBytes(params.DAOForkBlockExtra) 932 // } else if bytes.Equal(header.Extra, params.DAOForkBlockExtra) { 933 // header.Extra = []byte{} // If miner opposes, don't let it use the reserved extra-data 934 // } 935 // } 936 //} 937 // Could potentially happen if starting to mine in an odd state. 938 err := w.makeCurrent(parent, header) 939 if err != nil { 940 log.Error("Failed to create mining context", "err", err) 941 return 942 } 943 // Create the current work task and check any fork transitions needed 944 env := w.current 945 946 // add by ssh 190906 begin 947 //if num.Uint64() > 1 && !w.inturn(w.coinbase, uint64(timestamp), parent.Header()) && !w.inturn(w.coinbase, uint64(timestamp)+w.config.Vdpos.Period, parent.Header()) { 948 // log.Debug("Cancel commitNewWork: unauthorized signer") 949 // return 950 //} 951 // add by ssh 190906 end 952 953 //if w.config.DAOForkSupport && w.config.DAOForkBlock != nil && w.config.DAOForkBlock.Cmp(header.Number) == 0 { 954 // misc.ApplyDAOHardFork(env.state) 955 //} 956 // Accumulate the uncles for the current block 957 uncles := make([]*types.Header, 0, 2) 958 commitUncles := func(blocks map[common.Hash]*types.Block) { 959 // Clean up stale uncle blocks first 960 for hash, uncle := range blocks { 961 if uncle.NumberU64()+staleThreshold <= header.Number.Uint64() { 962 delete(blocks, hash) 963 } 964 } 965 for hash, uncle := range blocks { 966 if len(uncles) == 2 { 967 break 968 } 969 if err := w.commitUncle(env, uncle.Header()); err != nil { 970 log.Trace("Possible uncle rejected", "hash", hash, "reason", err) 971 } else { 972 log.Debug("Committing new uncle to block", "hash", hash) 973 uncles = append(uncles, uncle.Header()) 974 } 975 } 976 } 977 // Prefer to locally generated uncle 978 commitUncles(w.localUncles) 979 commitUncles(w.remoteUncles) 980 981 if !noempty { 982 // Create an empty block based on temporary copied state for sealing in advance without waiting block 983 // execution finished. 984 w.commit(uncles, nil, false, tstart) 985 } 986 987 // Fill the block with all available pending transactions. 988 pending, err := w.eth.TxPool().Pending() 989 if err != nil { 990 log.Error("Failed to fetch pending transactions", "err", err) 991 return 992 } 993 //Short circuit if there is no available pending transactions 994 if len(pending) == 0 { 995 w.updateSnapshot() 996 //return 997 } 998 // Split the pending transactions into locals and remotes 999 localTxs, remoteTxs := make(map[common.Address]types.Transactions), pending 1000 for _, account := range w.eth.TxPool().Locals() { 1001 if txs := remoteTxs[account]; len(txs) > 0 { 1002 delete(remoteTxs, account) 1003 localTxs[account] = txs 1004 } 1005 } 1006 1007 //2019.8.29 inb by ghy begin 1008 //blockNumberOneYear := vdpos.OneYearBySec / int64(v.config.Period) 1009 blockNumberOneYear := vdpos.OneYearBySec / int64(w.config.Vdpos.Period) 1010 1011 minerReward := new(big.Int).Div(vdpos.DefaultMiningRewardOneYear, big.NewInt(blockNumberOneYear)) 1012 //allianceReward := new(big.Int).Div(vdpos.DefaultAllianceRewardOneYear, big.NewInt(blockNumberOneYear)) 1013 //marketingReward := new(big.Int).Div(vdpos.DefaultMarketingRewardOneYear, big.NewInt(blockNumberOneYear)) 1014 //sealReward := new(big.Int).Div(vdpos.DefaultSealRewardOneYear, big.NewInt(blockNumberOneYear)) 1015 //teamReward := new(big.Int).Div(vdpos.DefaultTeamRewardOneYear, big.NewInt(blockNumberOneYear)) 1016 1017 SpecialConsensus := header.GetSpecialConsensus() 1018 if len(SpecialConsensus.SpecialConsensusAddress) > 1 { 1019 for _, v := range SpecialConsensus.SpecialNumber { 1020 if header.Number.Cmp(v.Number) == 1 { 1021 minerMul := new(big.Int).Mul(minerReward, SpecialConsensus.Molecule) 1022 minerReward = new(big.Int).Div(minerMul, SpecialConsensus.Denominator) 1023 1024 //allianceMul := new(big.Int).Mul(allianceReward, SpecialConsensus.Molecule) 1025 //allianceReward = new(big.Int).Div(allianceMul, SpecialConsensus.Denominator) 1026 // 1027 //marketingMul := new(big.Int).Mul(marketingReward, SpecialConsensus.Molecule) 1028 //marketingReward = new(big.Int).Div(marketingMul, SpecialConsensus.Denominator) 1029 // 1030 //sealMul := new(big.Int).Mul(sealReward, SpecialConsensus.Molecule) 1031 //sealReward = new(big.Int).Div(sealMul, SpecialConsensus.Denominator) 1032 // 1033 //teamMul := new(big.Int).Mul(teamReward, SpecialConsensus.Molecule) 1034 //teamReward = new(big.Int).Div(teamMul, SpecialConsensus.Denominator) 1035 1036 } 1037 } 1038 } 1039 vdpos.DefaultMinerReward = minerReward 1040 header.Reward = minerReward.String() 1041 for _, v := range header.GetSpecialConsensus().SpecialConsensusAddress { 1042 switch v.SpecialType { 1043 case state.MiningReward: 1044 from := v.Address 1045 to := header.Coinbase 1046 superNodes, err := w.current.vdposContext.GetSuperNodesFromTrie() 1047 if err == nil { 1048 for _, v := range superNodes { 1049 if v.Address == header.Coinbase && v.RewardAccount != "" { 1050 address := common.HexToAddress(v.RewardAccount) 1051 to = address 1052 } 1053 } 1054 } 1055 value := minerReward 1056 newTx := w.CreateTx(from, to, value) 1057 localTxs[from] = append(localTxs[from], newTx, newTx) 1058 //case state.AllianceReward: 1059 // from := v.Address 1060 // to := v.ToAddress 1061 // value := allianceReward 1062 // newTx := w.CreateTx(from, to, value) 1063 // localTxs[from] = append(localTxs[from], newTx) 1064 //case state.MarketingReward: 1065 // from := v.Address 1066 // to := v.ToAddress 1067 // value := marketingReward 1068 // newTx := w.CreateTx(from, to, value) 1069 // localTxs[from] = append(localTxs[from], newTx) 1070 //case state.SealReward: 1071 // from := v.Address 1072 // to := v.ToAddress 1073 // value := sealReward 1074 // newTx := w.CreateTx(from, to, value) 1075 // localTxs[from] = append(localTxs[from], newTx) 1076 //case state.TeamReward: 1077 // from := v.Address 1078 // to := v.ToAddress 1079 // value := teamReward 1080 // newTx := w.CreateTx(from, to, value) 1081 // localTxs[from] = append(localTxs[from], newTx) 1082 1083 default: 1084 } 1085 } 1086 //2019.8.29 inb by ghy end 1087 if len(localTxs) > 0 { 1088 txs := types.NewTransactionsByPriceAndNonce(w.current.signer, localTxs) 1089 if w.commitTransactions(txs, w.coinbase, interrupt) { 1090 return 1091 } 1092 } 1093 if len(remoteTxs) > 0 { 1094 txs := types.NewTransactionsByPriceAndNonce(w.current.signer, remoteTxs) 1095 if w.commitTransactions(txs, w.coinbase, interrupt) { 1096 return 1097 } 1098 } 1099 w.commit(uncles, w.fullTaskHook, true, tstart) 1100 } 1101 func (w *worker) CreateTx(from, to common.Address, value *big.Int) *types.Transaction { 1102 args := SendTxArgs{ 1103 From: from, 1104 To: to, 1105 Value: new(big.Int), 1106 Types: types.SpecialTx, 1107 Nonce: 0, 1108 } 1109 if args.Gas == nil { 1110 args.Gas = new(hexutil.Uint64) 1111 *(*uint64)(args.Gas) = 0 1112 } 1113 1114 db, _ := w.chain.State() 1115 nonce := db.GetNonce(args.From) 1116 1117 args.Nonce = nonce 1118 args.Value = value 1119 1120 var input []byte 1121 1122 input = args.From.Bytes() 1123 1124 newTransaction := types.NewTransaction(args.Nonce, args.To, (*big.Int)(args.Value), uint64(*args.Gas), input, args.Types) 1125 1126 return newTransaction 1127 } 1128 1129 // commit runs any post-transaction state modifications, assembles the final block 1130 // and commits new work if consensus engine is running. 1131 func (w *worker) commit(uncles []*types.Header, interval func(), update bool, start time.Time) error { 1132 // Deep copy receipts here to avoid interaction between different tasks. 1133 receipts := make([]*types.Receipt, len(w.current.receipts)) 1134 for i, l := range w.current.receipts { 1135 receipts[i] = new(types.Receipt) 1136 *receipts[i] = *l 1137 } 1138 s := w.current.state.Copy() 1139 // add by ssh 190829 begin 1140 block, err := w.engine.Finalize(w.chain, w.current.header, s, w.current.txs, uncles, w.current.receipts, w.current.vdposContext) 1141 if err != nil { 1142 return err 1143 } 1144 block.VdposContext = w.current.vdposContext 1145 1146 // add by ssh 190829 end 1147 1148 if w.isRunning() { 1149 if interval != nil { 1150 interval() 1151 } 1152 select { 1153 case w.taskCh <- &task{receipts: receipts, state: s, block: block, createdAt: time.Now()}: 1154 w.unconfirmed.Shift(block.NumberU64() - 1) 1155 1156 feesWei := new(big.Int) 1157 1158 //for i, tx := range block.Transactions() { 1159 // feesWei.Add(feesWei, new(big.Int).Mul(new(big.Int).SetUint64(receipts[i].GasUsed), tx.GasPrice())) 1160 //} 1161 1162 feesEth := new(big.Float).Quo(new(big.Float).SetInt(feesWei), new(big.Float).SetInt(big.NewInt(params.Inber))) 1163 1164 log.Info("Commit new mining work", "number", block.Number(), "sealhash", w.engine.SealHash(block.Header()), 1165 "uncles", len(uncles), "txs", w.current.tcount, "net", block.GasUsed(), "fees", feesEth, "elapsed", common.PrettyDuration(time.Since(start))) 1166 1167 case <-w.exitCh: 1168 log.Info("Worker has exited") 1169 } 1170 } 1171 if update { 1172 w.updateSnapshot() 1173 } 1174 return nil 1175 } 1176 1177 // add by ssh 190906 begin 1178 // inturn returns if a signer is in-turn or not. 1179 func (w *worker) inturn(signer common.Address, headerTime uint64, parent *types.Header) bool { 1180 1181 parentExtra := vdpos.HeaderExtra{} 1182 err := rlp.DecodeBytes(parent.Extra[32:len(parent.Extra)-65], &parentExtra) 1183 if err != nil { 1184 log.Error("Fail to decode header", "err", err) 1185 return false 1186 } 1187 loopStartTime := parentExtra.LoopStartTime 1188 signers := parentExtra.SignersPool 1189 //signers, err := w.current.vdposContext.GetSignersFromTrie() 1190 //if err != nil { 1191 // return false 1192 //} 1193 //loopStartTime := parent.LoopStartTime 1194 if signersCount := len(signers); signersCount > 0 { 1195 if loopIndex := ((headerTime - loopStartTime) / (w.config.Vdpos.Period*(w.config.Vdpos.SignerBlocks-1) + w.config.Vdpos.SignerPeriod)) % uint64(signersCount); signers[loopIndex] == signer { 1196 return true 1197 } 1198 } 1199 return false 1200 } 1201 1202 // add by ssh 190906 end