Creating a Miner
The mining process begins with the initialization of a miner in miner/worker.go.
func newWorker(config *Config, chainConfig *params.ChainConfig, engine consensus.Engine, eth Backend, mux *event.TypeMux, isLocalBlock func(*types.Block) bool, init bool) *worker {
...
worker.wg.Add(4)
go worker.mainLoop()
go worker.newWorkLoop(recommit)
go worker.resultLoop()
go worker.taskLoop() This code snippet shows the worker starting four key goroutines:
mainLoop– Regenerates sealing tasks based on events.newWorkLoop– Submits new mining work upon receiving events.resultLoop– Handles completed block processing.taskLoop– Manages sealing tasks.
Receiving Tasks
The newWorkLoop function listens for new mining tasks and commits them:
func (w *worker) newWorkLoop(recommit time.Duration) {
...
commit := func(noempty bool, s int32) {
if interrupt != nil {
atomic.StoreInt32(interrupt, s)
}
interrupt = new(int32)
select {
case w.newWorkCh <- &newWorkReq{interrupt: interrupt, noempty: noempty, timestamp: timestamp}: Here, the miner receives a new task request and forwards it via newWorkCh.
Task Transmission
The mainLoop picks up the task and commits it:
func (w *worker) mainLoop() {
...
for {
select {
case req := <-w.newWorkCh:
w.commitNewWork(req.interrupt, req.noempty, req.timestamp) This ensures seamless transition from task reception to execution.
Initiating Submission
The commitNewWork function prepares and submits the task:
func (w *worker) commitNewWork(interrupt *int32, noempty bool, timestamp int64) {
...
w.commit(uncles, w.fullTaskHook, true, tstart) This step triggers the actual sealing and assembly process.
Assembling the Block
Next, FinalizeAndAssemble constructs the block:
func (w *worker) commit(uncles []*types.Header, interval func(), update bool, start time.Time) error {
...
block, receipts, err := w.engine.FinalizeAndAssemble(w.chain, w.current.header, s, txs, uncles, cpyReceipts)
if err != nil {
return err
}
if w.isRunning() {
select {
case w.taskCh <- &task{receipts: receipts, state: s, block: block, createdAt: time.Now()}: The assembled block is then passed to taskCh for sealing.
Miner Signing
The Seal function applies the miner's signature:
func (c *Congress) Seal(chain consensus.ChainHeaderReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error {
sighash, err := signFn(accounts.Account{Address: val}, accounts.MimetypeCongress, CongressRLP(header))
if err != nil {
return err
}
copy(header.Extra[len(header.Extra)-extraSeal:], sighash)
...
select {
case results <- block.WithSeal(header):
default:
log.Warn("Sealing result is not read by miner")
} The miner's signature is embedded in header.Extra, and the sealed block is returned.
Broadcasting the Block
Finally, resultLoop broadcasts the completed block:
func (w *worker) resultLoop() {
defer w.wg.Done()
for {
select {
case block := <-w.resultCh:
_, err := w.chain.WriteBlockWithState(block, receipts, logs, task.state, true)
...
w.mux.Post(core.NewMinedBlockEvent{Block: block}) The block is written to the local chain and broadcast to the network.
FAQs
How does Ethereum mining work?
Ethereum mining involves validating transactions, assembling them into blocks, and competing to solve cryptographic puzzles to add blocks to the blockchain.
What is the role of header.Extra in mining?
👉 Learn more about Ethereum mining
The header.Extra field stores the miner's signature, ensuring block authenticity.
How are blocks broadcast in Ethereum?
Completed blocks are propagated via the NewMinedBlockEvent, ensuring network-wide synchronization.
Why is task segmentation important?
Dividing tasks (mainLoop, newWorkLoop, etc.) optimizes efficiency and parallel processing in mining.
By following this structured approach, Ethereum miners efficiently validate and append transactions to the blockchain while maintaining network integrity.
👉 Explore advanced Ethereum mining techniques for deeper insights into consensus mechanisms.