以太坊挖矿流程解析
字数 738 2025-08-22 12:23:12

以太坊挖矿流程与智能合约部署详解

一、以太坊挖矿核心概念

以太坊挖矿是通过工作量证明(PoW)机制来验证交易和创建新区块的过程,矿工通过解决复杂的数学难题来获得区块奖励和交易费用。

1.1 挖矿参数配置

挖矿配置参数定义在miner/miner.go中:

type Config struct {
    Etherbase  common.Address `toml:",omitempty"`  // 挖矿奖励接收地址
    Notify     []string       `toml:",omitempty"`  // 新工作包通知URL列表
    NotifyFull bool           `toml:",omitempty"`  // 是否使用完整区块头通知
    ExtraData  hexutil.Bytes  `toml:",omitempty"`  // 矿工添加的额外数据
    GasFloor   uint64         // 区块最低Gas限制
    GasCeil    uint64         // 区块最高Gas限制
    GasPrice   *big.Int       // 最低交易Gas价格
    Recommit   time.Duration  // 重新创建挖矿工作的时间间隔
    Noverify   bool           // 是否禁用远程挖矿验证
}

1.2 矿工核心数据结构

type Miner struct {
    mux        *event.TypeMux
    worker     *worker
    coinbase   common.Address
    eth        Backend
    engine     consensus.Engine
    exitCh     chan struct{}
    startCh    chan common.Address
    stopCh     chan struct{}
}

type worker struct {
    config       *Config
    chainConfig  *params.ChainConfig
    engine       consensus.Engine
    eth          Backend
    chain        *core.BlockChain
    // 其他字段...
}

二、挖矿流程详解

2.1 矿工实例创建

func New(eth Backend, config *Config, chainConfig *params.ChainConfig, 
       mux *event.TypeMux, engine consensus.Engine, 
       isLocalBlock func(block *types.Block) bool) *Miner {
    miner := &Miner{
        eth:      eth,
        mux:      mux,
        engine:   engine,
        exitCh:   make(chan struct{}),
        startCh:  make(chan common.Address),
        stopCh:   make(chan struct{}),
        worker:   newWorker(config, chainConfig, engine, eth, mux, isLocalBlock, true),
    }
    go miner.update()
    return miner
}

2.2 挖矿核心循环

2.2.1 newWorkLoop

负责在收到事件时提交新的挖矿工作:

func (w *worker) newWorkLoop(recommit time.Duration) {
    // 初始化定时器...
    
    commit := func(noempty bool, s int32) {
        // 中断当前任务并提交新工作
        if interrupt != nil {
            atomic.StoreInt32(interrupt, s)
        }
        interrupt = new(int32)
        w.newWorkCh <- &newWorkReq{
            interrupt: interrupt,
            noempty:   noempty,
            timestamp: timestamp,
        }
        timer.Reset(recommit)
        atomic.StoreInt32(&w.newTxs, 0)
    }
    
    // 清理过期的待处理任务
    clearPending := func(number uint64) {
        w.pendingMu.Lock()
        for h, t := range w.pendingTasks {
            if t.block.NumberU64()+staleThreshold <= number {
                delete(w.pendingTasks, h)
            }
        }
        w.pendingMu.Unlock()
    }
    
    // 主循环
    for {
        select {
        case <-w.startCh:
            clearPending(w.chain.CurrentBlock().NumberU64())
            timestamp = time.Now().Unix()
            commit(false, commitInterruptNewHead)
        case head := <-w.chainHeadCh:
            clearPending(head.Block.NumberU64())
            timestamp = time.Now().Unix()
            commit(false, commitInterruptNewHead)
        // 其他case处理...
        }
    }
}

2.2.2 mainLoop

处理新工作请求、分叉事件和交易池更新:

func (w *worker) mainLoop() {
    defer w.txsSub.Unsubscribe()
    defer w.chainHeadSub.Unsubscribe()
    defer w.chainSideSub.Unsubscribe()

    for {
        select {
        case req := <-w.newWorkCh:
            w.commitNewWork(req.interrupt, req.noempty, req.timestamp)
        case ev := <-w.chainSideCh:
            // 处理叔块
            if w.isLocalBlock != nil && w.isLocalBlock(ev.Block) {
                w.localUncles[ev.Block.Hash()] = ev.Block
            } else {
                w.remoteUncles[ev.Block.Hash()] = ev.Block
            }
            // 如果当前区块叔块少于2个,尝试添加
            if w.isRunning() && w.current != nil && w.current.uncles.Cardinality() < 2 {
                if err := w.commitUncle(w.current, ev.Block.Header()); err == nil {
                    // 提交新区块
                }
            }
        case ev := <-w.txsCh:
            // 处理交易池更新
            if !w.isRunning() && w.current != nil {
                // 执行交易并更新状态
            }
        // 其他case处理...
        }
    }
}

2.3 区块打包流程

2.3.1 commitNewWork

func (w *worker) commitNewWork(interrupt *int32, noempty bool, timestamp int64) {
    // 获取父区块
    parent := w.chain.CurrentBlock()
    
    // 创建新区块头
    header := &types.Header{
        ParentHash: parent.Hash(),
        Number:     num.Add(num, common.Big1),
        GasLimit:   core.CalcGasLimit(parent, w.config.GasFloor, w.config.GasCeil),
        Extra:      w.extra,
        Time:       uint64(timestamp),
    }
    
    // 设置矿工地址
    if w.isRunning() {
        header.Coinbase = w.coinbase
    }
    
    // 准备共识引擎
    if err := w.engine.Prepare(w.chain, header); err != nil {
        return
    }
    
    // 处理DAO分叉
    if daoBlock := w.chainConfig.DAOForkBlock; daoBlock != nil {
        // 处理分叉逻辑...
    }
    
    // 创建工作环境
    if err := w.makeCurrent(parent, header); err != nil {
        return
    }
    
    // 添加叔块
    uncles := make([]*types.Header, 0, 2)
    commitUncles := func(blocks map[common.Hash]*types.Block) {
        // 清理过期叔块并添加新叔块
    }
    commitUncles(w.localUncles)
    commitUncles(w.remoteUncles)
    
    // 创建空区块(如果需要)
    if !noempty && atomic.LoadUint32(&w.noempty) == 0 {
        w.commit(uncles, nil, false, tstart)
    }
    
    // 从交易池获取待处理交易
    pending, err := w.eth.TxPool().Pending()
    if err != nil {
        return
    }
    
    // 分离本地和远程交易
    localTxs, remoteTxs := make(map[common.Address]types.Transactions), pending
    for _, account := range w.eth.TxPool().Locals() {
        if txs := remoteTxs[account]; len(txs) > 0 {
            delete(remoteTxs, account)
            localTxs[account] = txs
        }
    }
    
    // 提交交易
    if len(localTxs) > 0 {
        txs := types.NewTransactionsByPriceAndNonce(w.current.signer, localTxs)
        if w.commitTransactions(txs, w.coinbase, interrupt) {
            return
        }
    }
    if len(remoteTxs) > 0 {
        txs := types.NewTransactionsByPriceAndNonce(w.current.signer, remoteTxs)
        if w.commitTransactions(txs, w.coinbase, interrupt) {
            return
        }
    }
    
    // 最终提交
    w.commit(uncles, w.fullTaskHook, true, tstart)
}

2.3.2 commitTransactions

func (w *worker) commitTransactions(txs *types.TransactionsByPriceAndNonce, coinbase common.Address, interrupt *int32) bool {
    for {
        // 检查中断信号
        if interrupt != nil && atomic.LoadInt32(interrupt) != commitInterruptNone {
            return true
        }
        
        // 获取下一个交易
        tx := txs.Peek()
        if tx == nil {
            break
        }
        
        // 执行交易
        w.current.state.Prepare(tx.Hash(), common.Hash{}, w.current.tcount)
        logs, err := w.commitTransaction(tx, coinbase)
        
        // 处理执行结果
        switch {
        case err == nil:
            // 交易成功,添加到收据
            w.current.tcount++
            w.current.receipts = append(w.current.receipts, receipt)
            w.current.logs = append(w.current.logs, logs...)
            
        // 其他错误处理...
        }
    }
    return false
}

2.4 挖矿任务处理

2.4.1 taskLoop

func (w *worker) taskLoop() {
    var (
        stopCh chan struct{}
        prev   common.Hash
    )
    
    interrupt := func() {
        if stopCh != nil {
            close(stopCh)
            stopCh = nil
        }
    }
    
    for {
        select {
        case task := <-w.taskCh:
            // 检查重复任务
            sealHash := w.engine.SealHash(task.block.Header())
            if sealHash == prev {
                continue
            }
            
            // 中断之前的挖矿操作
            interrupt()
            stopCh, prev = make(chan struct{}), sealHash
            
            // 添加到待处理任务
            w.pendingMu.Lock()
            w.pendingTasks[sealHash] = task
            w.pendingMu.Unlock()
            
            // 开始挖矿
            if err := w.engine.Seal(w.chain, task.block, w.resultCh, stopCh); err != nil {
                log.Warn("Block sealing failed", "err", err)
            }
        // 其他case处理...
        }
    }
}

2.4.2 resultLoop

func (w *worker) resultLoop() {
    for {
        select {
        case block := <-w.resultCh:
            // 获取相关任务
            var (
                sealhash = w.engine.SealHash(block.Header())
                hash     = block.Hash()
            )
            w.pendingMu.RLock()
            task, exist := w.pendingTasks[sealhash]
            w.pendingMu.RUnlock()
            
            if !exist {
                continue
            }
            
            // 更新收据和日志
            var (
                receipts = make([]*types.Receipt, len(task.receipts))
                logs     []*types.Log
            )
            for i, receipt := range task.receipts {
                receipt.BlockHash = hash
                receipt.BlockNumber = block.Number()
                receipt.TransactionIndex = uint(i)
                receipts[i] = new(types.Receipt)
                *receipts[i] = *receipt
                
                for _, log := range receipt.Logs {
                    log.BlockHash = hash
                }
                logs = append(logs, receipt.Logs...)
            }
            
            // 写入区块链
            _, err := w.chain.WriteBlockWithState(block, receipts, logs, task.state, true)
            if err != nil {
                log.Error("Failed writing block to chain", "err", err)
                continue
            }
            
            // 广播新区块
            w.mux.Post(core.NewMinedBlockEvent{Block: block})
            w.unconfirmed.Insert(block.NumberU64(), block.Hash())
        // 其他case处理...
        }
    }
}

三、智能合约部署实战

3.1 合约编写

pragma solidity ^0.8.4;

contract test {
    function multiply(uint a) public returns (uint d) {
        return a * 7;
    }
}

3.2 合约编译

编译后得到ABI接口定义:

[{
    "inputs": [{"internalType": "uint256", "name": "a", "type": "uint256"}],
    "name": "multiply",
    "outputs": [{"internalType": "uint256", "name": "d", "type": "uint256"}],
    "stateMutability": "nonpayable",
    "type": "function"
}]

3.3 合约部署步骤

  1. 启动Geth节点:
sudo geth --networkid 666 --datadir /home/ubuntu/Private_eth/eth1 \
--identity "node1" --rpc --rpcport "8545" --rpcaddr "192.168.174.212" \
--nodiscover --rpcapi "eth,net,web3,txpool,debug,miner" \
--allow-insecure-unlock console
  1. 创建合约对象:
var abi = JSON.parse('[{"constant":false,"inputs":[{"name":"a","type":"uint256"}],"name":"multiply","outputs":[{"name":"d","type":"uint256"}],"payable":false,"type":"function","stateMutability":"nonpayable"}]')
myContract = web3.eth.contract(abi)
  1. 检查账户余额:
eth.coinbase
// "0x8b52dc34762a2a951406d3189bdba1b920e7cde9"

web3.fromWei(eth.getBalance(eth.accounts[0]), "ether")
// 20.000021
  1. 解锁账户:
personal.unlockAccount(eth.accounts[0], "123456", 0)
  1. 预估部署手续费:
// 149143 wei
  1. 部署合约:
// 部署代码...
  1. 开始挖矿:
miner.start()
  1. 验证合约部署:
// 验证代码...

四、关键点总结

  1. 挖矿流程

    • 矿工实例创建 → 工作循环启动 → 区块打包 → 交易执行 → 工作量证明 → 区块提交
  2. 区块打包

    • 创建区块头 → 设置共识参数 → 添加叔块 → 执行交易 → 计算状态根 → 生成最终区块
  3. 智能合约部署

    • 编写合约 → 编译获取ABI → 预估Gas → 发送部署交易 → 挖矿确认 → 验证部署
  4. 性能优化

    • 合理设置GasFloor和GasCeil
    • 调整Recommit间隔平衡响应速度和资源消耗
    • 优先处理本地交易减少网络延迟
  5. 安全注意事项

    • 确保矿工地址安全
    • 谨慎处理DAO分叉等特殊情况
    • 验证远程叔块的有效性
以太坊挖矿流程与智能合约部署详解 一、以太坊挖矿核心概念 以太坊挖矿是通过工作量证明(PoW)机制来验证交易和创建新区块的过程,矿工通过解决复杂的数学难题来获得区块奖励和交易费用。 1.1 挖矿参数配置 挖矿配置参数定义在 miner/miner.go 中: 1.2 矿工核心数据结构 二、挖矿流程详解 2.1 矿工实例创建 2.2 挖矿核心循环 2.2.1 newWorkLoop 负责在收到事件时提交新的挖矿工作: 2.2.2 mainLoop 处理新工作请求、分叉事件和交易池更新: 2.3 区块打包流程 2.3.1 commitNewWork 2.3.2 commitTransactions 2.4 挖矿任务处理 2.4.1 taskLoop 2.4.2 resultLoop 三、智能合约部署实战 3.1 合约编写 3.2 合约编译 编译后得到ABI接口定义: 3.3 合约部署步骤 启动Geth节点: 创建合约对象: 检查账户余额: 解锁账户: 预估部署手续费: 部署合约: 开始挖矿: 验证合约部署: 四、关键点总结 挖矿流程 : 矿工实例创建 → 工作循环启动 → 区块打包 → 交易执行 → 工作量证明 → 区块提交 区块打包 : 创建区块头 → 设置共识参数 → 添加叔块 → 执行交易 → 计算状态根 → 生成最终区块 智能合约部署 : 编写合约 → 编译获取ABI → 预估Gas → 发送部署交易 → 挖矿确认 → 验证部署 性能优化 : 合理设置GasFloor和GasCeil 调整Recommit间隔平衡响应速度和资源消耗 优先处理本地交易减少网络延迟 安全注意事项 : 确保矿工地址安全 谨慎处理DAO分叉等特殊情况 验证远程叔块的有效性