<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>Nerbonic</title>
        <link>https://paragraph.com/@nerbonic</link>
        <description>undefined</description>
        <lastBuildDate>Thu, 20 Aug 2026 02:57:38 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <copyright>All rights reserved</copyright>
        <item>
            <title><![CDATA[以太坊节点同步]]></title>
            <link>https://paragraph.com/@nerbonic/Gwpga87MWULVA7Gzvr2b</link>
            <guid>Gwpga87MWULVA7Gzvr2b</guid>
            <pubDate>Tue, 03 May 2022 20:49:25 GMT</pubDate>
            <description><![CDATA[Go-ethereum同步轻节点0.前置知识节点：客户端的软件。全节点、轻节点 客户端：一种以太坊的实现，提供RPC API端点方便用户控制客户端，标准的JSON RPC每个客户端都可以使用。geth、OpenEthereum(停止维护) 轻量同步：下载所有区块头、区块数据并对其进行随机验证 通过客户端与以太坊网络进行交互： -使用合适的协议(eg.curl)手动调用 -附加一个控制台(geth attach) -应用程序中执行1.安装所需基础工具yum update -y && yum install git wget bzip2 vim gcc-c++ ntp epel-release nodejs cmake -y2.安装golang并配置yum install golang // 不需要翻墙，yum search xxx可以查找需要安装的文件路径 golang配置 echo &apos;export GOROOT=/usr/lib/go&apos; >> /etc/profile //golang的安装路径 echo &apos;export PATH=$PATH:$GO...]]></description>
            <content:encoded><![CDATA[<h2 id="h-go-ethereum" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">Go-ethereum同步轻节点</h2><h3 id="h-0" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">0.前置知识</h3><p>节点：客户端的软件。全节点、轻节点</p><p>客户端：一种以太坊的实现，提供RPC API端点方便用户控制客户端，标准的JSON RPC每个客户端都可以使用。geth、OpenEthereum(停止维护)</p><p>轻量同步：下载所有区块头、区块数据并对其进行随机验证</p><p>通过客户端与以太坊网络进行交互：</p><p>-使用合适的协议(eg.curl)手动调用</p><p>-附加一个控制台(geth attach)</p><p>-应用程序中执行</p><h3 id="h-1" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">1.安装所需基础工具</h3><p><code>yum update -y &amp;&amp; yum install git wget bzip2 vim gcc-c++ ntp epel-release nodejs cmake -y</code></p><h3 id="h-2golang" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">2.安装golang并配置</h3><p><code>yum install golang // 不需要翻墙，yum search xxx可以查找需要安装的文件路径</code></p><p>golang配置</p><p><code>echo &apos;export GOROOT=/usr/lib/go&apos; &gt;&gt; /etc/profile //golang的安装路径</code></p><p><code>echo &apos;export PATH=$PATH:$GOROOT/bin&apos; &gt;&gt; /etc/profile</code></p><p><code>echo &apos;export GOPATH=/ssd/go&apos; &gt;&gt; /etc/profile // go文件执行时存放的路径</code></p><p><code>echo &apos;export PATH=$PATH:$GOPATH/bin&apos; &gt;&gt; /etc/profile</code></p><p><code>source /etc/profile</code></p><p><code>go env -w GOPROXY=https://goproxy.cn,direct // 修改代理，国内编译go文件</code></p><h3 id="h-3go-ethereum" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">3.下载并编译go-ethereum</h3><p>下载：下载到本地然后拖到ssd文件里</p><p><code>cd go-ethereum</code></p><p><code>make all // 编译</code></p><p><code>echo &apos;export PATH=$PATH:/ssd/go-ethereum/build/bin&apos; &gt;&gt; /etc/profile // 在path中加入geth路径</code></p><p><code>source /etc/profile</code></p><p><code>geth version // 验证是否安装成功</code></p><h3 id="h-4" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">4.同步以太坊区块</h3><p><code>nohup /ssd/go-ethereum/build/bin/geth --syncmode &quot;snap&quot; --port &quot;30303&quot; --cache=4096 --datadir /ssd/data/geth --http --http.api db,eth,net,web3,personal,admin,miner,debug --http.port 8545 --http.addr 0.0.0.0 --http.corsdomain &quot;*&quot; --maxpendpeers 999 &gt; /ssd/data/output.log 2&gt;&amp;1 &amp;</code></p><p>&quot;snap&quot;：替代传统的&quot;fast&quot;，当指定同步模式为 “fast” 时，以太坊节点会从网络同步所有的区块头，区块体以及状态数据，但不对区块中的交易进行重放，只会对区块中的数据进行校验。</p><p>当指定同步模式为&quot;full&quot;时，以太坊节点会从网络同步所有的区块头，区块体并重放区块中的交易以生成状态数据。</p><p>当指定同步模式为“light”时，以太坊节点仅从网络中同步所有区块头，不去同步区块体，也不去同步状态数据，仅在需要相应区块和状态数据时从网络上获取。</p><p>当不指定任何模式时，默认为 “fast” 模式。</p><p>最新的命令参考：<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://geth.ethereum.org/docs/interface/command-line-options">https://geth.ethereum.org/docs/interface/command-line-options</a></p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.cnblogs.com/kaifayuan/p/14970409.html(%E4%B8%AD%E6%96%87%E7%89%88)">https://www.cnblogs.com/kaifayuan/p/14970409.html(中文版)</a></p><h3 id="h-5geth-console-attach" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">5.geth console命令 / attach 命令</h3><p><code>/ssd/go-ethereum/build/bin/geth attach /ssd/data/geth/geth.ipc // 使用ipc方式连接geth客户端(http/ws/ipc)</code></p><p>打开JS控制台，可以使用web3.js与节点进行交互(初始化账户、向网络中写入和广播交易请求、查找账户余额和元数据等)</p><h3 id="h-6json-rpc-web3" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">6.节点交互：JSON RPC / web3模块</h3><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.quicknode.com/docs/ethereum/">https://www.quicknode.com/docs/ethereum/</a> (可以查询不同的命令的使用方法)</p><p>JSON形式、RPC方法调用API对象</p><p>RPC方式：</p><pre data-type="codeBlock" text="curl 
  -X POST \ (\符号表示换行，真正使用的时候要去掉\)
  -H &quot;Content-Type: application/json&quot; \
  --data &apos;{&quot;method&quot;:&quot;debug_traceTransaction&quot;,&quot;params&quot;:[&quot;0x9e63085271890a141297039b3b711913699f1ee4db1acb667ad7ce304772036b&quot;],&quot;id&quot;:1,&quot;jsonrpc&quot;:&quot;2.0&quot;}&apos; 127.0.0.1:8545
  //jsonrpc-指定JSON-RPC版本号，method字段指定要调用的api方法名
"><code>curl 
  -X POST \ (\符号表示换行，真正使用的时候要去掉\)
  -H <span class="hljs-string">"Content-Type: application/json"</span> \
  --data '<span class="hljs-punctuation">{</span><span class="hljs-attr">"method"</span><span class="hljs-punctuation">:</span><span class="hljs-string">"debug_traceTransaction"</span><span class="hljs-punctuation">,</span><span class="hljs-attr">"params"</span><span class="hljs-punctuation">:</span><span class="hljs-punctuation">[</span><span class="hljs-string">"0x9e63085271890a141297039b3b711913699f1ee4db1acb667ad7ce304772036b"</span><span class="hljs-punctuation">]</span><span class="hljs-punctuation">,</span><span class="hljs-attr">"id"</span><span class="hljs-punctuation">:</span><span class="hljs-number">1</span><span class="hljs-punctuation">,</span><span class="hljs-attr">"jsonrpc"</span><span class="hljs-punctuation">:</span><span class="hljs-string">"2.0"</span><span class="hljs-punctuation">}</span>' <span class="hljs-number">127.0</span><span class="hljs-number">.0</span><span class="hljs-number">.1</span><span class="hljs-punctuation">:</span><span class="hljs-number">8545</span>
  <span class="hljs-comment">//jsonrpc-指定JSON-RPC版本号，method字段指定要调用的api方法名</span>
</code></pre><p>eth：包含一些跟操作区块链相关的方法</p><p>net：包含一些查看p2p网络状态的方法</p><p>admin：包含一些与管理节点相关的方法</p><p>miner：包含启动&amp;停止挖矿的一些方法</p><p>personal：主要包含一些管理账户的方法</p><p>txpool：包含一些查看交易内存池的方法</p><p><code>net.peerCount</code> : 返回连接到的对等点的数量</p><p><code>admin.peers</code> : 列出节点连接到的所有对等点</p><p><code>eth.blockNumber</code>查看区块号，<code>eth.synacing</code>查看更多信息exit</p><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0"></h3><p>搜索关键词：json-rpc eth</p><p>debug.traceTransaction(&quot;Transaction_hash&quot;)</p><p>!1648982534926</p><p>例：通过debug_traceTransaction获得指定交易hash的trace</p><p>debug.stacks / debug.storageRangeAt / debug.</p><p>eth.syncing --- false：表示已经同步到最新的区块了</p><p>attach状态下</p><p>eth命令</p><p>eth.getTransactionCount(&quot;BlockNumber&quot;) -- 可以获得该区块中发生的交易数</p><p><strong>eth.getBlock(&quot;BlockNumber&quot;)</strong> --- 可以获得发生在这个区块中的所有交易hash</p><p>eth.getRawTransactionFromBlock(&quot;BlockNumber&quot;)</p><p>eth.getCode(&quot;Contract_address&quot;) -- 可以获得合约的字节码</p><p>eth.getBlockByHash(&quot;Block_Hash&quot;) -- 能获得区块内容，获得的一部分信息是hash形式的</p><p>eth.getBlockByNumber(&quot;0x(BlockNumber)&quot;) -- &quot;0xddbe98&quot;区块信息中出现的number，是区块号的十六进制形式</p><p>eth.getRawTransaction(&quot;Transaction_hash&quot;) / eth.getRawTransactionFromBlock(&quot;BlockNumber&quot;) -- 根据交易hash获得了一串十六进制数，不知道是啥意思</p><p>eth.getTransaction(&quot;Transaction_hash&quot;) -- 获得交易的blockHash、blockNumber、input、from、to等等的信息</p><p>eth.getTransactionCount(&quot;Contract_addr&quot;) -- 获得合约发生过的交易数，但是在什么范围内(某一区块内还是所有区块内)未知</p><p>eth.getTransactionFromBlock(&quot;BlockNumber&quot;) -- 或者区块号发生的第一个交易及信息</p><p>eth.getStorageAt 、eth.getTransaction不会用</p><p><strong>eth.blockNumber</strong> -- 获得当前区块号</p><p><strong>debug.traceTransaction(&quot;Transaction_hash&quot;)</strong> -- 获得该交易中具体的操作码信息</p><pre data-type="codeBlock" text="// 将给定事务转出给定块
debug.standardTraceBlockToFile(&quot;0x0bbe9f1484668a2bf159c63f0cf556ed8c8282f99e3ffdb03ad2175a863bca63&quot;, {txHash:&quot;0x4049f61ffbb0747bb88dc1c85dd6686ebf225a3c10c282c45a8e0c644739f7e9&quot;, disableMemory:true})
[&quot;/tmp/block_0x0bbe9f14-14-0x4049f61f-099048234&quot;]
"><code><span class="hljs-comment">// 将给定事务转出给定块</span>
debug.<span class="hljs-title function_ invoke__">standardTraceBlockToFile</span>(<span class="hljs-string">"0x0bbe9f1484668a2bf159c63f0cf556ed8c8282f99e3ffdb03ad2175a863bca63"</span>, {<span class="hljs-attr">txHash</span>:<span class="hljs-string">"0x4049f61ffbb0747bb88dc1c85dd6686ebf225a3c10c282c45a8e0c644739f7e9"</span>, <span class="hljs-attr">disableMemory</span>:<span class="hljs-literal">true</span>})
[<span class="hljs-string">"/tmp/block_0x0bbe9f14-14-0x4049f61f-099048234"</span>]
</code></pre><pre data-type="codeBlock" text="// 转出某个区块中的所有TX
debug.standardTraceBlockToFile(&quot;0x0bbe9f1484668a2bf159c63f0cf556ed8c8282f99e3ffdb03ad2175a863bca63&quot;, {disableMemory:true})
[&quot;文件路径&quot;]
"><code><span class="hljs-comment">// 转出某个区块中的所有TX</span>
debug.standardTraceBlockToFile(<span class="hljs-string">"0x0bbe9f1484668a2bf159c63f0cf556ed8c8282f99e3ffdb03ad2175a863bca63"</span>, {disableMemory:<span class="hljs-literal">true</span>})
[<span class="hljs-string">"文件路径"</span>]
</code></pre><p>使用命名标准在临时位置创建文件<code>block_---</code>。每个操作码都会立即流到文件，除了os正常进行的缓冲外，没有缓冲缓冲</p><ul><li><p>使用跨客户端标准化输出，即所谓的“标准json”</p><ul><li><p>用途<code>op</code>为操作码的字符串表示，而不是<code>op</code>/ <code>opName</code>对数字/串，和其他小simlar差异。</p></li><li><p>有 <code>refund</code></p></li><li><p>将内存表示为连续的数据块，而不是<code>32</code>像-byte段这样的列表<code>debug_traceTransaction</code></p></li></ul></li></ul><pre data-type="codeBlock" text="debug.traceTransaction(
&quot;0x0903c3f6b08ff8729598de40932355410c3cac5e2a48e9f383629eeb6b23c972&quot;)
"><code>debug.traceTransaction(
<span class="hljs-string">"0x0903c3f6b08ff8729598de40932355410c3cac5e2a48e9f383629eeb6b23c972"</span>)
</code></pre><h2 id="h-" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">节点服务</h2><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ethereum.org/zh/developers/docs/nodes-and-clients/nodes-as-a-service/">https://ethereum.org/zh/developers/docs/nodes-and-clients/nodes-as-a-service/</a></p>]]></content:encoded>
            <author>nerbonic@newsletter.paragraph.com (Nerbonic)</author>
        </item>
        <item>
            <title><![CDATA[以太坊源码解析之一——出块与同步]]></title>
            <link>https://paragraph.com/@nerbonic/A4UOZ4kLJ04HWonaXg42</link>
            <guid>A4UOZ4kLJ04HWonaXg42</guid>
            <pubDate>Thu, 03 Mar 2022 04:22:30 GMT</pubDate>
            <description><![CDATA[以太坊解析之一——POW共识出块和同步过程前言一、一图展示以太坊出块过程在这里插入图片描述二、具体过程1.geth启动一切开始于geth启动指令：1.1 启动geth同步节点main.go:313：geth(ctx *cli.Context) main.go:319：makeFullNode(ctx)1.2 注册以太坊服务config.go:147：RegisterEthService(stack, &cfg.Eth) flags.go:1718：RegisterEthService(stack, &cfg.Eth)1.3 实例化以太坊项目flags.go:1727：eth.New(stack, cfg) backend.go:102:New(stack *node.Node, config *ethconfig.Config)1.4 实例化过程，创建miner, workerbackend.go:102:New(stack *node.Node, config *ethconfig.Config) backend.go:230:eth.miner = miner.New() m...]]></description>
            <content:encoded><![CDATA[<h1 id="h-pow" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">以太坊解析之一——POW共识出块和同步过程</h1><h1 id="h-" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">前言</h1><h1 id="h-" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">一、一图展示以太坊出块过程</h1><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/34c1e5cfed76588d39206be12ad1e33c994cc60428559ad0f56af57f09c01e84.png" alt="在这里插入图片描述" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">在这里插入图片描述</figcaption></figure><h1 id="h-" class="text-4xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">二、具体过程</h1><h2 id="h-1geth" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">1.geth启动</h2><p>一切开始于geth启动指令：</p><h3 id="h-11-geth" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">1.1 启动geth同步节点</h3><blockquote><p>main.go:313：geth(ctx *cli.Context) main.go:319：makeFullNode(ctx)</p></blockquote><h3 id="h-12" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">1.2 注册以太坊服务</h3><blockquote><p>config.go:147：RegisterEthService(stack, &amp;cfg.Eth) flags.go:1718：RegisterEthService(stack, &amp;cfg.Eth)</p></blockquote><h3 id="h-13" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">1.3 实例化以太坊项目</h3><blockquote><p>flags.go:1727：eth.New(stack, cfg) backend.go:102:New(stack *node.Node, config *ethconfig.Config)</p></blockquote><h3 id="h-14-miner-worker" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">1.4 实例化过程，创建miner, worker</h3><blockquote><p>backend.go:102:New(stack *node.Node, config *ethconfig.Config) backend.go:230:eth.miner = miner.New() miner.go:68:New() miner.go:76:worker:newWorker()//实例化出块工作流，以作准备 worker.go:190:newWorker()</p></blockquote><h3 id="h-15" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">1.5 开启四个协程</h3><blockquote><p>worker.go:227-230: go worker.mainLoop() go worker.newWorkLoop(recommit) go worker.resultLoop() go worker.taskLoop() miner.go:78:go miner.update()//启动update协程监测以决定是出块还是收块 miner.go:97:dlEventCh := events.Chan()//看看可能有没有新块，有就收，没有就监听下startCh miner.go:131-134: case addr := &lt;-miner.startCh://监听startCh，有就开始出块:miner.worker.start()</p></blockquote><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">小结</h3><p>经过启动后，geth开启了5个协程： 即：</p><blockquote><p>mainloop:用来进行计算、状态改变 taskloop：用来封装区块 resultloop：用来收区块，校验，上链，广播 newworkloop：用来接收任务</p></blockquote><p>以及：</p><blockquote><p>update：监测以决定是否主动出块</p></blockquote><h2 id="h-2minerstart" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">2.miner.start()启动</h2><h3 id="h-minerstart" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">miner.start():</h3><blockquote><p>api.go:101:Start(threads *int)//threads:选择用几个线程出</p></blockquote><pre data-type="codeBlock" text="func (api *PrivateminerAPI) Start(threads *int) error {
    if threads == nil {
        return api.e.StartMining(runtime.NumCPU())
    }
    return api.e.StartMining(*threads)
}
"><code>func (api <span class="hljs-operator">*</span>PrivateminerAPI) Start(threads <span class="hljs-operator">*</span><span class="hljs-keyword">int</span>) <span class="hljs-function"><span class="hljs-keyword">error</span> </span>{
    <span class="hljs-keyword">if</span> threads <span class="hljs-operator">=</span><span class="hljs-operator">=</span> nil {
        <span class="hljs-keyword">return</span> api.e.StartMining(runtime.NumCPU())
    }
    <span class="hljs-keyword">return</span> api.e.StartMining(<span class="hljs-operator">*</span>threads)
}
</code></pre><blockquote><p>backend.go:444:StartMining(threads int) backend.go:482:go s.miner.Start(eb) //eb:etherbase(收益地址) miner.go:147:Start(coinbase common.Address) miner.go:147:Start(coinbase common.Address) miner.go:148:miner.startCh &lt;- coinbase</p></blockquote><p>startCh放入Ch，由newworkloop接收</p><blockquote><p>worker.go:374：case &lt;-w.startCh://监听到开始的Ch信号，clear清除Pending worker.go:377:commit(false, commitInterruptNewHead) worker.go:348-354:newWorkCh信号</p></blockquote><p>至此，miner.start()作用完成，总结就是 发newWorkCh与startCh信号供监听用</p><blockquote><p>worker.go:227-230: （这里是同时开启四个协程来并发，下面依照流程挨个解释） go worker.mainLoop() go worker.newWorkLoop(recommit) go worker.resultLoop() go worker.taskLoop()</p></blockquote><h2 id="h-3mainloop" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">3.mainLoop</h2><p>worker.go:433：mainLoop（）</p><blockquote><p>worker.go:其中分为三种情况： 还记的第二张的newWorkCh吗，在这里接收 并进行【1、出新块操作】 441：1、出新块:（只考虑它）:commitNewWork（） 478：2、考虑分叉（与叔块相关） 504：3、如果没有在出，但是收到txs，那就自动清除</p></blockquote><p>worker.go:869：commitNewWork（）：</p><pre data-type="codeBlock" text="...
  //检查系统时间和当前区块时间差异
  //新建一个区块头，填入父区块号，区块高度，gasLimit，时间戳等
  //检查coinbase是否存在
  
  //Prepare方法是consenus包下面定义的Engine的接口，由consenus/ethash和clique包分别实现其所有方法，包含Prepare方法
  //ethash实现的是pos算法，clique实现的是poa算法，poa算法主要运行在测试网上，之所以不在测试网也使用pos是因为测试网算力不足，pos会遭到攻击
  //本文主要分析ethash算法过程，除了特别说明，下文所有介绍的Engine接口的实现算法都是ethash算法
  //Prepare方法是计算当前区块所需要的难度值，即header.Difficulty，方便后续计算hash的时候做比较(pos算法精髓)
      if err := w.engine.Prepare(w.chain, header); err != nil {
        log.Error(&quot;Failed to prepare header for mining&quot;, &quot;err&quot;, err)
        return
    }
   //检查是否有DAO硬分叉
   //945，946：组装叔块，叔块不能距离当前块的高度超过7
   //948-952：装个空块，不等tx执行完毕，后面954再去填充这个块
//组装交易池中的交易
   
   //954组装成区块并987提交新交易
   w.commit(uncles, w.fullTaskHook, true, tstart)
"><code>...
  <span class="hljs-comment">//检查系统时间和当前区块时间差异</span>
  <span class="hljs-comment">//新建一个区块头，填入父区块号，区块高度，gasLimit，时间戳等</span>
  <span class="hljs-comment">//检查coinbase是否存在</span>
  
  <span class="hljs-comment">//Prepare方法是consenus包下面定义的Engine的接口，由consenus/ethash和clique包分别实现其所有方法，包含Prepare方法</span>
  <span class="hljs-comment">//ethash实现的是pos算法，clique实现的是poa算法，poa算法主要运行在测试网上，之所以不在测试网也使用pos是因为测试网算力不足，pos会遭到攻击</span>
  <span class="hljs-comment">//本文主要分析ethash算法过程，除了特别说明，下文所有介绍的Engine接口的实现算法都是ethash算法</span>
  <span class="hljs-comment">//Prepare方法是计算当前区块所需要的难度值，即header.Difficulty，方便后续计算hash的时候做比较(pos算法精髓)</span>
      <span class="hljs-keyword">if</span> err :<span class="hljs-operator">=</span> w.engine.Prepare(w.chain, header); err <span class="hljs-operator">!</span><span class="hljs-operator">=</span> nil {
        log.Error(<span class="hljs-string">"Failed to prepare header for mining"</span>, <span class="hljs-string">"err"</span>, err)
        <span class="hljs-keyword">return</span>
    }
   <span class="hljs-comment">//检查是否有DAO硬分叉</span>
   <span class="hljs-comment">//945，946：组装叔块，叔块不能距离当前块的高度超过7</span>
   <span class="hljs-comment">//948-952：装个空块，不等tx执行完毕，后面954再去填充这个块</span>
<span class="hljs-comment">//组装交易池中的交易</span>
   
   <span class="hljs-comment">//954组装成区块并987提交新交易</span>
   w.commit(uncles, w.fullTaskHook, <span class="hljs-literal">true</span>, tstart)
</code></pre><p>worker.go:992：commit()：</p><p>代码如下（示例）： func (w *worker) commit(uncles []*types.Header, interval func(), update bool, start time.Time) error {
   ...
   //FinalizeAndAssemble也是ethash包中的方法，根据传入参数组装成区块
   block, err := w.engine.FinalizeAndAssemble(w.chain, w.current.header, s, w.current.txs, uncles, receipts)
   ...
   //将组装好的区块和数据发送给taskCh这个channel，该channel是在taskLoop中监听的channel，详见下文
    case w.taskCh &lt;- &amp;task{receipts: receipts, state: s, block: block, createdAt: time.Now()}:
    //*******！！！！！重点关注此1005行
    w.unconfirmed.Shift(block.NumberU64() - 1)
    log.Info(&quot;Commit new mining work&quot;, &quot;number&quot;, block.Number(), &quot;sealhash&quot;, w.engine.SealHash(block.Header()),
       &quot;uncles&quot;, len(uncles), &quot;txs&quot;, w.current.tcount,
       &quot;gas&quot;, block.GasUsed(), &quot;fees&quot;, totalFees(block, receipts),
       &quot;elapsed&quot;, common.PrettyDuration(time.Since(start)))
 //上面这个loginfo就是我们在geth命令行中看见的
    ...
}
commit信息进入taskCh中，被taskloop监听到，后面的任务就是封装块并出块 附：具体打包（即ethash计算过程）区块过程参见FinalizeAndAssemble（这里面包含了奖励），consensus/clique/clique.go中的Finalize consensus/ethash/consensus.go: 597：FinalizeAndAssemble()：并调用 589：Finalize：并调用 641：accumulateRewards 最后在667： state.AddBalance(header.Coinbase, reward) 看名字就能知道了 4.taskloop worker.go:535：taskloop()： worker.go:552：newTaskHook()：钩子监听 worker.go:555：sealHash=SealHash(task.block.Header()): Seal封装区块 worker.go:567,570(关注resultCh）： 567：pendingTasks[sealHash] = task 570：engine.Seal(链，块, resultCh, ..):封装好了 出块过程完成，出块成功，注意还没完，还得广播，来看resultLoop() 5.resultLoop 来看worker.go:582:resultLoop() worker.go:585：block := &lt;-w.resultCh监听到块 worker.go:610-624：块的信息保存到全局receipt worker.go:625：块写到链中， 626：进行写入链，验证，最后输出我们见到的信息 在这里插入图片描述 worker.go:635：提交广播区块mux.Post() event.go:83：进行提交广播区块mux.Post() event.go:97：区块广播（递送）sub.deliver(event) event.go:204：区块广播（递送）sub.deliver(event) event.go:204：区块广播到Ch：postC &lt;- event: 6.如何收新块 接下来看看怎么接收传过来的块，我们回到update中 miner.go:78:go miner.update()//启动update协程监测以决定是出块还是收块 miner.go:97:dlEventCh := events.Chan()//看看可能有没有新块，有就收，没有就监听下startCh 假设有了dlEventCh新块 case downloader.StartEvent:
    wasMining := miner.Mining()//你是不是在出
    miner.worker.stop()//不管怎么样不要出了
    canStart = false//用户，你也不许自己开始出
    if wasMining
     {//如果你真的之前在出
    // Resume mining after sync was finished
    shouldStart = true//你应该开始同步了
    log.Info(&quot;Mining aborted due to sync&quot;)//告诉用户因为同步所以不出了
    }
后面的也是miner.worker.start（），只不过因为没有newWorkCh，就不会主动出了，接下来需要参见sync.go 总结 现在可以用比喻的方式来看一下各个部分是干什么的： miner：总包工头，也就是用户 worker：总包工头助理（代替总包统管所有事务） Work: 代表了要干的事情 ethash/Clique: 干活的工具 其中，ethash代表了POW共识，Clique代表了POA共识 接下来 我们是如何使用共识工具的，即commit函数当中的 block, err := w.engine.FinalizeAndAssemble(w.chain, w.current.header, s, w.current.txs, uncles, receipts)
以此为入口，可以继续深入了解共识如何工作，这是FinalizeAndAssemble的函数定义： FinalizeAndAssemble(
chain ChainHeaderReader, //当前链，用来代表整条链
header *types.Header, //当前区块头指针
state *state.StateDB, //用来保存账户等等等数据的本地节点数据库
txs []*types.Transaction,//要被打包的所有交易
uncles []*types.Header, //叔块的区块头，用来给那些本来计算出来叔块的人奖励
receipts []*types.Receipt，//用来保存交易执行后的结果
)</p>]]></content:encoded>
            <author>nerbonic@newsletter.paragraph.com (Nerbonic)</author>
        </item>
        <item>
            <title><![CDATA[TestBlog]]></title>
            <link>https://paragraph.com/@nerbonic/testblog</link>
            <guid>NQIAR5YlGLEGo5AJEmIO</guid>
            <pubDate>Thu, 23 Dec 2021 15:23:59 GMT</pubDate>
            <description><![CDATA[nothing]]></description>
            <content:encoded><![CDATA[<p>nothing</p>]]></content:encoded>
            <author>nerbonic@newsletter.paragraph.com (Nerbonic)</author>
        </item>
    </channel>
</rss>