<?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>OutOfToken</title>
        <link>https://paragraph.com/@lua</link>
        <description>事情没你想象的那么复杂，当然也没有你想象的那么简单。</description>
        <lastBuildDate>Wed, 06 May 2026 00:15:30 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <image>
            <title>OutOfToken</title>
            <url>https://storage.googleapis.com/papyrus_images/70cdd6cd946bf4dcd3f2f30b1604facfe1c1d31a70b16fe95026fee8b5cbef65.jpg</url>
            <link>https://paragraph.com/@lua</link>
        </image>
        <copyright>All rights reserved</copyright>
        <item>
            <title><![CDATA[深入学习 Go-Ethereum : 014. CMD 模块 - Geth -usage.go&version_check.go]]></title>
            <link>https://paragraph.com/@lua/go-ethereum-014-cmd-geth-usage-go-version-check-go</link>
            <guid>9VS21fN5VJi5fURtKQtj</guid>
            <pubDate>Fri, 29 Jul 2022 03:07:21 GMT</pubDate>
            <description><![CDATA[⬇️以下是 cmd/geth 包中其他代码的介绍：├── accountcmd.go ├── chaincmd.go ├── config.go ├── consolecmd.go ├── dbcmd.go ├── misccmd.go ├── snapshot.go ├── usage.go 🔫 └── version_check.go 🔫 《深入学习 Go-Ethereum : 013. CMD 模块 - Geth - snapshot.go》中罗列了 snapshot 子命令集主要源码，接下来描述下关于 usage.go&version_check.go 中的代码功能。⬇️ usage.gousage 主要定义了众多flag相关信息,并对帮助信息进行打印。其中使用helper.go中相关方法和结构体完成主要功能。 👇定义了命令的名称和使用说明⬇️ version_check.go主要功能是进行 geth 对应版本的漏洞检查，使用命令 geth version_check （命令定义在 misccmd.go ）,如果不传入参数，默认请求的校验地址是version_che...]]></description>
            <content:encoded><![CDATA[<p>⬇️以下是 cmd/geth 包中其他代码的介绍：</p><pre data-type="codeBlock" text="├── accountcmd.go 
├── chaincmd.go 
├── config.go 
├── consolecmd.go 
├── dbcmd.go 
├── misccmd.go 
├── snapshot.go 
├── usage.go 🔫
└── version_check.go 🔫
"><code>├── accountcmd.go 
├── chaincmd.go 
├── config.go 
├── consolecmd.go 
├── dbcmd.go 
├── misccmd.go 
├── snapshot.go 
├── usage.go 🔫
└── version_check.go 🔫
</code></pre><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://mirror.xyz/laosan.eth/qwUu-PvNRs_zVfHsonhpAkI03Zdfo2zn0Us6CxsElX4">《深入学习 Go-Ethereum : 013. CMD 模块 - Geth - snapshot.go》</a>中罗列了 <code>snapshot</code> 子命令集主要源码，接下来描述下关于 <code>usage.go&amp;version_check.go</code> 中的代码功能。</p><h2 id="h-usagego" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">⬇️ usage.go</h2><p>usage 主要定义了众多flag相关信息,并对帮助信息进行打印。其中使用helper.go中相关方法和结构体完成主要功能。</p><p>👇定义了命令的名称和使用说明</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/7c2189fccd777fa5aa77226d971667e95033df1f57a6c2335f94912054942409.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/dd63698a97b61a2e06aae04c79414be35829e8a3045528cd476a1729ccaa2f1f.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><h2 id="h-versioncheckgo" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">⬇️ version_check.go</h2><p>主要功能是进行 geth 对应版本的漏洞检查，使用命令 <code>geth version_check</code> （命令定义在 <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/HugePages/go-ethereum/blob/84bd692dbe540eebad03758e9e714ba2cf8cca12/cmd/geth/misccmd.go#L81">misccmd.go</a> ）,如果不传入参数，默认请求的校验地址是<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://geth.ethereum.org/docs/vulnerabilities/vulnerabilities.json">version_check_url</a>。</p><p>👇JSON数据如图，包含了name、uid、CVE编号等等信息。</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/bc1be9395798c44f73afdae1cb4fdbd6b55b0c3cd34e5d7b2161fb9ddf878bfb.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>👇核心代码结构</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/f29241ab2a66517d47f6bf624d9f2854502a04e13db38360916fbdb7a8b40c67.png" alt="version_check.go" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">version_check.go</figcaption></figure><p>使用效果如图：</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/4ff513d9ce67003d046940e03be9b3b8f92201e460da2e09af69e2d6ce981b15.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>截止到此， <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/HugePages/go-ethereum/tree/master/cmd/geth">geth</a> 中相关的主要代码已经了解大概，后续穿插了解记录关于 <code>cmd</code> 模块中其他命令的主要代码。后续规划了解 <code>geth</code> 的业务核心代码 (列表如下👇）：</p><ol><li><p>基础组件（密码学、数据序列化/反序列化、数据存储）：</p><ol><li><p>🔖 rlp - 以太坊序列化-递归线性前缀(Recursive Linear Prefix)模块</p></li><li><p>🔖 trie - 改进的默克尔+前缀树 MPT(Merkle Patricia Tries)</p></li><li><p>❇️ ethdb - 以太坊堆数据库的操作代码,包含了levelDB和内存数据库</p></li><li><p>❇️ common - 公用工具,如:debug、数学相关、bit工具等</p></li><li><p>❇️ internal - 项目内部使用工具代码,如构建、debug、调用服务API、测试指南、测试日志、web3js扩展等</p></li></ol></li><li><p>网络层（p2p、rpc）：</p><ol><li><p>🔖 p2p - 点对点网络协议相关实现</p></li><li><p>🔖 rpc - 以太坊RPC服务</p></li></ol></li><li><p>业务层（账户体系、交易、共识机制、gas、evm等）：</p><ol><li><p>🔖 accounts - 以太坊的钱包、地址、账号系统,不同于 Bitcoin 的 UTXO 模式</p></li><li><p>🔖consensus - 共识机制,实现不同的以太坊共识机制引擎</p></li><li><p>❇️ core - 系统核心的数据结构和基础模块,如 虚拟机 、状态模块、批量数据的布隆过滤器 、RawDB、汇编模块</p></li><li><p>❇️ eth - 以太坊协议的核心模块,包含了节点发现、全节点数据下载、eth配置、数据获取(base header、交易、区块)、协议(广播、点对点等)、gas模块</p></li><li><p>🔖miner - 提供以太坊的区块创建和挖矿</p></li></ol></li></ol><p>❇️ : 穿插在其他模块了解、分析代码。</p><p>🔖 ：主入口，顺序为 <code>rlp</code> → <code>trie</code> → <code>accounts</code> → <code>consensus</code> → <code>miner</code> → <code>p2p</code> → <code>rpc</code></p>]]></content:encoded>
            <author>lua@newsletter.paragraph.com (OutOfToken)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/37497f30113dbcdce63e4f913a2525270857a06d3f9c3631a53c3742ce9969bf.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[深入学习 Go-Ethereum : 013. CMD 模块 - Geth -snapshot.go]]></title>
            <link>https://paragraph.com/@lua/go-ethereum-013-cmd-geth-snapshot-go</link>
            <guid>2okXBfPoeK5A2U9u0MGu</guid>
            <pubDate>Thu, 28 Jul 2022 12:58:06 GMT</pubDate>
            <description><![CDATA[⬇️以下是 cmd/geth 包中其他代码的介绍：├── accountcmd.go ├── chaincmd.go ├── config.go ├── consolecmd.go ├── dbcmd.go ├── misccmd.go ├── snapshot.go 🔫 ├── usage.go └── version_check.go 《深入学习 Go-Ethereum : 012. CMD 模块 - Geth - misccmd.go》中罗列了 misccmd 主要源码，接下来描述下关于 snapshot.go 中的代码功能（基于2022-07-25的认知稀里糊涂的记录）。⬇️ snapshot.gosnapshot 是一系列子命令的集合。其中包含了：等同于 geth dump 功能的 geth snapshot dump 方法基于快照的历史状态数据清理 prune-state基于快照数据重新进行hash计算，用于验证 verify-state检查是否存在 “dangling” 数据 check-dangling-storage用给定的root hash进行遍历校验 tr...]]></description>
            <content:encoded><![CDATA[<p>⬇️以下是 cmd/geth 包中其他代码的介绍：</p><pre data-type="codeBlock" text="├── accountcmd.go 
├── chaincmd.go 
├── config.go 
├── consolecmd.go 
├── dbcmd.go 
├── misccmd.go 
├── snapshot.go 🔫
├── usage.go
└── version_check.go
"><code>├── accountcmd.go 
├── chaincmd.go 
├── config.go 
├── consolecmd.go 
├── dbcmd.go 
├── misccmd.go 
├── snapshot.go 🔫
├── usage.go
└── version_check.go
</code></pre><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://mirror.xyz/laosan.eth/B9-a2rKBo33nQSB-hlrqxIbuLnmj0pbwdYjYNsB3f4s">《深入学习 Go-Ethereum : 012. CMD 模块 - Geth - misccmd.go》</a>中罗列了 <code>misccmd</code> 主要源码，接下来描述下关于 <code>snapshot.go</code> 中的代码功能（基于2022-07-25的认知稀里糊涂的记录）。</p><h2 id="h-snapshotgo" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">⬇️ snapshot.go</h2><p>snapshot 是一系列子命令的集合。其中包含了：</p><ol><li><p>等同于 <code>geth dump</code> 功能的 <code>geth snapshot dump </code>方法</p></li><li><p>基于快照的历史状态数据清理 <code>prune-state</code></p></li><li><p>基于快照数据重新进行hash计算，用于验证 <code>verify-state</code></p></li><li><p>检查是否存在 “dangling” 数据 <code>check-dangling-storage</code></p></li><li><p>用给定的root hash进行遍历校验 <code>traverse-state</code> (快速遍历)</p></li><li><p>用给定的root hash进行遍历校验 <code>traverse-rawstate</code> （遍历每一个节点）</p></li></ol><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/5877360c5bd618e790f229dada6f7b350d877844cf3a094f748d405aacb9dac1.png" alt="snapshot.go 代码结构概览" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">snapshot.go 代码结构概览</figcaption></figure><h3 id="h-prunestate" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">⬇️ pruneState方法：</h3><p>描述：<code>geth snapshot prune-state &lt;state-root&gt;</code> will prune historical state data with the help of the state snapshot. <strong><s>All trie nodes and contract codes that do not belong to the specified version state will be deleted from the database</s></strong>. After pruning, only two version states are available: genesis and the specific one.</p><p>(对历史状态数据进行清理，不满足指定版本状态所有trie结构节点数据和合约代码将会被清除，只有两个版本数据有效：创世区块和唯一指定的数据)。</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/34b87b556971f28a00f3c5d774bf1cbcd8472d872a7201117b5fb421064efc4f.png" alt="pruneState方法代码" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">pruneState方法代码</figcaption></figure><p>关键方法调用 <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/HugePages/go-ethereum/blob/master/core/state/pruner/pruner.go">core.state.prune.pruner.go</a> 中的 <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/HugePages/go-ethereum/blob/21a09da78fd3e032f36ebd4bf7c3d7944faa92e3/core/state/pruner/pruner.go#L234">Prune()</a> 方法。后续对其中代码详细分析。（数据检索使用到了 <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://zh.wikipedia.org/wiki/%E5%B8%83%E9%9A%86%E8%BF%87%E6%BB%A4%E5%99%A8">Bloom Filter</a> ）</p><h3 id="h-verifystate" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">⬇️ verifyState方法：</h3><p>描述：<code>geth snapshot verify-state &lt;state-root&gt;</code> will traverse the whole accounts and storages set based on the specified snapshot and recalculate the root hash of state for verification. In other words, this command does the snapshot to trie conversion.</p><p>（此方法对指定的快照中账户和存储集合进行遍历，然后重新计算状态数据根哈希值，以用于校验。换句话说，这个命令将快照转换成 <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://zh.wikipedia.org/zh-cn/Trie">Trie</a> 「字典树」格式）。</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/c21b8d09497687dccc6cafb7341ec01904c26d7df116ca312763ca13e6338bfa.png" alt="verifyState方法代码" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">verifyState方法代码</figcaption></figure><h3 id="h-checkdanglingstorage" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">⬇️ checkDanglingStorage方法：</h3><p>描述：<code>geth snapshot check-dangling-storage &lt;state-root&gt;</code> traverses the snap storage data, and verifies that all snapshot storage data has a corresponding account.</p><p>（此方法遍历快照中的存储数据，并校验所有存储数据都有与之对应的账户）</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/6596a9f75e5a5ae67241f8fa61852f86809d6945235363d71d81a166a58bb57b.png" alt="checkDanglingStorage方法代码" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">checkDanglingStorage方法代码</figcaption></figure><h3 id="h-traversestate" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">⬇️ traverseState方法：</h3><p>描述：<code>geth snapshot traverse-state &lt;state-root&gt;</code> will traverse the whole state from the given state root and will abort if any referenced trie node or contract code is missing. This command can be used for state integrity verification. The default checking target is the HEAD state. It&apos;s also usable without snapshot enabled.</p><p>(此防范会遍历整个状态数据，当出现Trie节点或者合约代码丢失。此命令可以用于状态数据的完整验证。默认的检查是 「区块头」 状态数据)</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/7b7425e69a223ebbd4a5859e91886b633e35882c002683011ab2b9965bbc914c.png" alt="traverseState方法代码" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">traverseState方法代码</figcaption></figure><h3 id="h-traverserawstate" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">⬇️ traverseRawState方法：</h3><p>和traverseState方法的主要区别，1.方法获取数据的二进制原始数据，差别如下图⬇️</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/d46fdb6a7429d565092266e8cb4562451c346965bf5f5aa59a2f824b136c540c.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p><code>LeafBlob returns the content of the leaf，返回类型 []byte</code> 。2.会检查所有Tire节点。</p><h3 id="h-dump" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">⬇️ dump方法：</h3><p>描述：This command is semantically equivalent to &apos;geth dump&apos;, but uses the snapshots as the backend data source, making this command a lot faster. The argument is interpreted as block number or hash. If none is provided, the latest block is used.</p><p>（此方法基于快照进行数据dump，速度会比 <code>geth dump</code> 快）。</p>]]></content:encoded>
            <author>lua@newsletter.paragraph.com (OutOfToken)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/7e8037ab083a5ac4984445307f29647ad3b369b25d56fa298284001947062a0f.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[深入学习 Go-Ethereum : 012. CMD 模块 - Geth -misccmd.go]]></title>
            <link>https://paragraph.com/@lua/go-ethereum-012-cmd-geth-misccmd-go</link>
            <guid>kBya2TsBle1cs3XPAxnW</guid>
            <pubDate>Mon, 25 Jul 2022 05:00:12 GMT</pubDate>
            <description><![CDATA[⬇️以下是 cmd/geth 包中其他代码的介绍：├── accountcmd.go ├── chaincmd.go ├── config.go ├── consolecmd.go ├── dbcmd.go ├── misccmd.go 🔫 ├── snapshot.go ├── usage.go └── version_check.go 《深入学习 Go-Ethereum : 011. CMD 模块 - Geth - dbcmd.go》中罗列了 dbcmd 主要源码，接下来描述下关于 misccmd.go 中的代码功能。⬇️ misccmd.gomisccmd 是多种功能的混合代码。 其中包括查看版本、版本检查、授权查看、生成缓存(测试使用)、生成DAG（有向环形图）。⬇️ makecache 方法：用来创建ethash共识校验使用的缓存数据。⬇️ makedag 方法：// makedag generates an ethash mining DAG into the provided folder. Ethash 是 PoW 系统，它需要一个大约 1GB 的数据集，它就是...]]></description>
            <content:encoded><![CDATA[<p>⬇️以下是 cmd/geth 包中其他代码的介绍：</p><pre data-type="codeBlock" text="├── accountcmd.go 
├── chaincmd.go 
├── config.go 
├── consolecmd.go 
├── dbcmd.go 
├── misccmd.go 🔫
├── snapshot.go
├── usage.go
└── version_check.go
"><code>├── accountcmd.go 
├── chaincmd.go 
├── config.go 
├── consolecmd.go 
├── dbcmd.go 
├── misccmd.go 🔫
├── snapshot.go
├── usage.go
└── version_check.go
</code></pre><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://mirror.xyz/laosan.eth/f_QZO4ZlTZkvQeAblB1IBdNgtWZjAegNzNMiBaHllp8">《深入学习 Go-Ethereum : 011. CMD 模块 - Geth - dbcmd.go》</a>中罗列了 <code>dbcmd</code> 主要源码，接下来描述下关于 <code>misccmd.go</code> 中的代码功能。</p><h2 id="h-misccmdgo" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">⬇️ misccmd.go</h2><p>misccmd 是多种功能的混合代码。 其中包括查看版本、版本检查、授权查看、生成缓存(测试使用)、生成DAG（有向环形图）。</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/f0e9b28dda74b0369187d225fea360977ca78564cf478f489491d7a54918ef89.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><h3 id="h-makecache" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">⬇️ makecache 方法：</h3><p>用来创建ethash共识校验使用的缓存数据。</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/2ba29dfb6c6b0b7d9fb88adc658a0eac292708eb09d71e2832dd8811b0cda5c8.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><h3 id="h-makedag" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">⬇️ makedag 方法：</h3><pre data-type="codeBlock" text="// makedag generates an ethash mining DAG into the provided folder.
"><code><span class="hljs-comment">// makedag generates an ethash mining DAG into the provided folder.</span>
</code></pre><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/c80e7c9b3be4696a90f1c73f9cc9d809f47f7792e643116c1791a213ad18aca1.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>Ethash 是 PoW 系统，它需要一个大约 1GB 的数据集，它就是 <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://zh.wikipedia.org/wiki/%E6%9C%89%E5%90%91%E6%97%A0%E7%8E%AF%E5%9B%BE">DAG</a>，在硬盘中存储它。</p><h3 id="h-versionlicense" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">⬇️ version/license 方法：</h3><p>获取 geth 的版本信息和授权信息。</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/1b1a2276bf6c42ab581bc7e9dd6a62af9825f472792939cb9dcf1e813e559c7b.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>使用效果如下:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/d621ffd12a3d17bd4367058e66db8025bbcd6141b1c7ea61f7f886ffbccd6aee.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure>]]></content:encoded>
            <author>lua@newsletter.paragraph.com (OutOfToken)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/37497f30113dbcdce63e4f913a2525270857a06d3f9c3631a53c3742ce9969bf.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[深入学习 Go-Ethereum : 011. CMD 模块 - Geth -dbcmd.go]]></title>
            <link>https://paragraph.com/@lua/go-ethereum-011-cmd-geth-dbcmd-go</link>
            <guid>0gSAICvhoYCACwbKrReC</guid>
            <pubDate>Thu, 21 Jul 2022 10:05:37 GMT</pubDate>
            <description><![CDATA[⬇️以下是 cmd/geth 包中其他代码的介绍：├── accountcmd.go ├── chaincmd.go ├── config.go ├── consolecmd.go ├── dbcmd.go 🔫 ├── misccmd.go ├── snapshot.go ├── usage.go └── version_check.go 《深入学习 Go-Ethereum : 010. CMD 模块 - Geth - consolecmd.go》中罗列了 consolecmd 主要源码，接下来描述下关于 dbcmd.go 中的代码功能。 dbcmd 会依赖 go-ethereum 项目源码中 "github.com/ethereum/go-ethereum/cmd/utils"、 "github.com/ethereum/go-ethereum/common"、 "github.com/ethereum/go-ethereum/common/hexutil"、 "github.com/ethereum/go-ethereum/console/prompt"、 "github....]]></description>
            <content:encoded><![CDATA[<p>⬇️以下是 cmd/geth 包中其他代码的介绍：</p><pre data-type="codeBlock" text="├── accountcmd.go 
├── chaincmd.go 
├── config.go 
├── consolecmd.go 
├── dbcmd.go 🔫
├── misccmd.go
├── snapshot.go
├── usage.go
└── version_check.go
"><code>├── accountcmd.go 
├── chaincmd.go 
├── config.go 
├── consolecmd.go 
├── dbcmd.go 🔫
├── misccmd.go
├── snapshot.go
├── usage.go
└── version_check.go
</code></pre><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://mirror.xyz/laosan.eth/Tb3ppjEJqUBbbYjuBiGFhoSCm5_OTM1Oe2oIa-Wj-5M">《深入学习 Go-Ethereum : 010. CMD 模块 - Geth - consolecmd.go》</a>中罗列了 <code>consolecmd</code> 主要源码，接下来描述下关于 <code>dbcmd.go</code> 中的代码功能。</p><p>dbcmd 会依赖 <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ethereum/go-ethereum">go-ethereum</a> 项目源码中</p><p><code>&quot;github.com/ethereum/go-ethereum/cmd/utils&quot;</code>、 <code>&quot;github.com/ethereum/go-ethereum/common&quot;</code>、 <code>&quot;github.com/ethereum/go-ethereum/common/hexutil&quot;</code>、 <code>&quot;github.com/ethereum/go-ethereum/console/prompt&quot;</code>、 <code>&quot;github.com/ethereum/go-ethereum/core/rawdb&quot;</code>、 <code>&quot;github.com/ethereum/go-ethereum/core/state/snapshot&quot;</code>、 <code>&quot;github.com/ethereum/go-ethereum/core/types&quot;</code>、 <code>&quot;github.com/ethereum/go-ethereum/ethdb&quot;</code>、 <code>&quot;github.com/ethereum/go-ethereum/log&quot;</code>、 <code>&quot;github.com/ethereum/go-ethereum/trie&quot;</code> 相关组件。</p><h2 id="h-dbcmdgo" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">⬇️ dbcmd.go</h2><p>dbcmd 主要功能是操作<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/google/leveldb">levelDB</a>(一个本地的 Key-Value 数据库)，代码主要包含了 <code>db</code> 命令和 <code>13 个子命令</code>及实现相应功能的函数。</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/56dc6fd32b8609d0f848fbb4148c700e3d5a2be513a84e512697f7f0a9e30b85.png" alt="dbcmd.go 代码结构" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">dbcmd.go 代码结构</figcaption></figure><p><code>geth db --help</code> 查看子命令列表及简介</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/4ce756629408822c7d4140db1d142fee3fb91b4adac7d3b77f1756697e055447.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><h3 id="h-removedb" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">⬇️ removeDB 方法：</h3><p>查看 db 统计信息</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/322dc66a001b2ee64532b0648dbeb7c2876f12dd5bceeaa7b1cc81340d21af65.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>删除数据库中数据 <code>geth removedb</code></p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/1e68f57d60a39aa4a26fbbd2a45b4bc1a4c6ad4a1c9f1a989c24aedc9abfc1bc.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>再次查看数据库，不存在数据库文件</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/0df94971598fb3914c992500754702cddc8ae5bb8a45359cc86e9068b1632a9a.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>代码主逻辑⬇️：</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/cbe4c4a9d7bba2abfeca859e7953dc245274fee339dd12eb96e501b9dfbf4430.png" alt="removedb 命令对应的方法" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">removedb 命令对应的方法</figcaption></figure><p>提醒用户确认并删除数据文件⬇️</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/80589ddb4f0852a2ea134cf2389bf04dc4641b00e15ebc59a06bbd0ad2413089.png" alt="内部方法，提醒用户确认并删除文件" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">内部方法，提醒用户确认并删除文件</figcaption></figure><h3 id="h-inspect" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">⬇️ inspect 方法：</h3><p>主要作用是检查当前数据库中的数据分布，代码如下图⬇️，主要逻辑处理 <code>rawdb.InspectDatabase()</code> 。</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/5014bf72f1d3cab0b198a81228402dc6318516ac0f553d04d3dd63722d3fa090.png" alt="inspect 命令对应的方法" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">inspect 命令对应的方法</figcaption></figure><p>对比参数查询结果：<code>左侧是有前缀参数</code>、<code>右侧无参数（全数据库）</code> 。</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/b1ad66cea8273f0dca7b0e6c1abec7df0ecab9f3c71216feafb0cbccd7fd33cc.png" alt="使用效果对比" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">使用效果对比</figcaption></figure><h3 id="h-dbstats" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">⬇️ dbStats 方法：</h3><p>主要作用查询数据库存储状态,其中最重要的代码逻辑是</p><ol><li><p><code>db.Stat()</code> →</p></li><li><p>ethdb/leveldb/leveldb.go 代码中的 <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/HugePages/go-ethereum/blob/21a09da78fd3e032f36ebd4bf7c3d7944faa92e3/ethdb/leveldb/leveldb.go#L246">db.db.GetProperty()</a> →</p></li><li><p>leveldb/db.go 代码中的 <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/syndtr/goleveldb/blob/64ee5596c38af10edb6d93e1327b3ed1739747c7/leveldb/db.go#L954">GetProperty()</a>，获取levelDB的统计数据</p></li></ol><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/02324b86d4cc3c56c39f4e8c7f7a41cee21dd6088f03ec1c42d93ed6e5f66782.png" alt="dbStates方法代码截图" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">dbStates方法代码截图</figcaption></figure><h3 id="h-dbcompact" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">⬇️ dbCompact 方法：</h3><p><code>Compact</code> 主要作用「压缩」数据，对指定范围 start ，limit 两个参数范围内的数据进行处理，本质上是对 <code>删除的</code> 数据和<code>不再使用的版本</code>数据 进行重排序。（⚠️：此方法会花费较长时间。同时对数据进行加锁）</p><ol><li><p><code>db.Compact()</code> →</p></li><li><p>ethdb/leveldb/leveldb.go 代码中的 <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/HugePages/go-ethereum/blob/21a09da78fd3e032f36ebd4bf7c3d7944faa92e3/ethdb/leveldb/leveldb.go#L257">db.db.CompactRange()</a> →</p></li><li><p>leveldb/db_write.go 代码中的 <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/syndtr/goleveldb/blob/64ee5596c38af10edb6d93e1327b3ed1739747c7/leveldb/db_write.go#L403">CompactRange()</a>，进行数据压缩处理</p></li></ol><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/272f74b7011f2dd15fbf618834e7da797ee96bb8a074060bc4ed13bd89d9a7e3.png" alt="dbCompact方法代码截图" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">dbCompact方法代码截图</figcaption></figure><h3 id="h-dbgetdbdeletedbput" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">⬇️ dbGet、dbDelete、dbPut 方法：</h3><p>主要是使用 levelDB 的 db.go 进行操作。</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/0eea09dd9b313d4a968ad3220e383e70d21fbb096c260102f51595fbc6a5e14f.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><h3 id="h-dbdumptrie" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">⬇️ dbDumpTrie 方法：</h3><p>指定根节点进行数据导出操作。</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/f5570bee457e777c026262948746a41764c8389bdb525fb132f7adeef33ccc6b.png" alt="dbDumpTrie方法代码截图" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">dbDumpTrie方法代码截图</figcaption></figure><h3 id="h-freezerinspect" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">⬇️ freezerInspect 方法：</h3><p>导出”冷数据“，指定导出的数据类型，开始数据 index，和结束数据 index。</p><p>数据类型参数范围是[bodies diffs hashes headers receipts]</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/036ca0315008acc3424709dd7ac9cffa6609ae58fdc3f886801178d2108ad1b5.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>通过下面命令进行 “凉凉“ 数据进行 dump 操作。</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/6f8552d58aa44ac47d74524f19134959d7c7438837a82b2f5b86bcb0f0458635.png" alt="操作示例" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">操作示例</figcaption></figure><h3 id="h-importldbdata" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">⬇️ importLDBdata 方法：</h3><p>导入指定文件(以RLP格式进行快照)数据到 <code>eth.Database</code> ,如果是 <code>gz</code> 文件会通过 <code>gzip</code> 进行文件操作。</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/HugePages/go-ethereum/blob/21a09da78fd3e032f36ebd4bf7c3d7944faa92e3/cmd/utils/cmd.go#L387">// ImportLDBData imports a batch of snapshot data into the database</a> 可以查看 <code>utils.ImportLDBData()</code> 具体实现</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/fb9c80c8d84b83eb449805fbaa9ffac583981b1e6508d57076516bc2613f60b2.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><h3 id="h-exportchaindata" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">⬇️ exportChaindata 方法：</h3><p>与 import 对应的方法就是数据的导出。导出需要指定数据是preimage还是snapshot，此外需要指定导出文件名及文件后缀名，如果是gz格式，程序会使用gzip进行文件压缩。</p><p>调用<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/HugePages/go-ethereum/blob/21a09da78fd3e032f36ebd4bf7c3d7944faa92e3/cmd/utils/cmd.go#L505">ExportChaindata()</a>进行数据文件生成</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/5db84ceb467769fded95469626bdbc7e04c8004114b0a16c04acfee2860f8fcc.png" alt="exportChaindata方法" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">exportChaindata方法</figcaption></figure><h3 id="h-showmetadata" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">⬇️ showMetaData 方法：</h3><p>显示levelDB相关元数据信息，比如数据库版本、头信息、快照信息等</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/40ebe6cb5c0379b640970b2ac62b80b6c8d626d4f6bc145c464058ff0eb5a18e.png" alt="showMetaData方法" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">showMetaData方法</figcaption></figure><h3 id="h-freezermigrate" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">⬇️ freezerMigrate 方法：</h3><p>迁移”冷数据“，到指定表中<code>「receipts」</code></p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/7140c50d2f16fc030854a5dc941819b1ab77e2513c39a22237f833c232136acd.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>以上是dbcmd中代码的主要功能。底层依赖ethdb进行操作KV数据库leveldb。</p>]]></content:encoded>
            <author>lua@newsletter.paragraph.com (OutOfToken)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/7e8037ab083a5ac4984445307f29647ad3b369b25d56fa298284001947062a0f.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[深入学习 Go-Ethereum : 010. CMD 模块 - Geth -consolecmd.go]]></title>
            <link>https://paragraph.com/@lua/go-ethereum-010-cmd-geth-consolecmd-go</link>
            <guid>67cMY26lZKoMgZ85NPGf</guid>
            <pubDate>Mon, 04 Jul 2022 11:42:06 GMT</pubDate>
            <description><![CDATA[《深入学习 Go-Ethereum : 009. CMD 模块 - Geth - config.go》中罗列了 config 主要源码，接下来描述下关于 consolecmd.go 中的代码功能 ⬇️以下是 cmd/geth 包中其他代码的介绍：├── accountcmd.go ├── chaincmd.go ├── config.go ├── consolecmd.go 🔫 ├── dbcmd.go ├── misccmd.go ├── snapshot.go ├── usage.go └── version_check.go ⬇️ consolecmd.goconsolecmd 主要功能是创建一个可以交互的Javascript环境（本地节点、远程节点、临时执行js文件的节点），代码主要包含了 3 个子命令 js 、 attach、console 及实现相应功能的4个函数。consolecmd.go代码结构⬇️ localConsole 方法：1.创建环境，准备全节点。 2.通过stack.Attach 创建rpc客户端（通过ipc通信。 3.根据参数获取配置信息后，创建c...]]></description>
            <content:encoded><![CDATA[<p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://mirror.xyz/dashboard/edit/S75i2h5oUwqgkrF4oKPaV8LZ4dBmatw6GEYlpASPHNU">《深入学习 Go-Ethereum : 009. CMD 模块 - Geth - config.go》</a>中罗列了 <code>config</code> 主要源码，接下来描述下关于 <code>consolecmd.go</code> 中的代码功能</p><p>⬇️以下是 cmd/geth 包中其他代码的介绍：</p><pre data-type="codeBlock" text="├── accountcmd.go 
├── chaincmd.go 
├── config.go 
├── consolecmd.go 🔫
├── dbcmd.go
├── misccmd.go
├── snapshot.go
├── usage.go
└── version_check.go
"><code>├── accountcmd.go 
├── chaincmd.go 
├── config.go 
├── consolecmd.go 🔫
├── dbcmd.go
├── misccmd.go
├── snapshot.go
├── usage.go
└── version_check.go
</code></pre><h2 id="h-consolecmdgo" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">⬇️ consolecmd.go</h2><p>consolecmd 主要功能是创建一个可以交互的Javascript环境（本地节点、远程节点、临时执行js文件的节点），代码主要包含了 3 个子命令 <code>js</code> 、 <code>attach</code>、<code>console </code>及实现相应功能的4个函数。</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/1c40056643707c6ded9527c6469d6ada966480993a858ff4f3285187a1b20918.png" alt="consolecmd.go代码结构" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">consolecmd.go代码结构</figcaption></figure><h3 id="h-localconsole" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">⬇️ localConsole 方法：</h3><p><code>1.创建环境，准备全节点</code>。</p><p><code>2.通过stack.Attach 创建rpc客户端（通过ipc通信。</code></p><p><code>3.根据参数获取配置信息后，创建console对象，生成js交互环境。并开启goroutine等待statck信息。</code></p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/d5835a74a5b8027cf8d6430fbd127e4df55ea78aec889134a180ec5651f21f8b.png" alt="localCache 对应 console 命令" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">localCache 对应 console 命令</figcaption></figure><h3 id="h-remoteconsole" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">⬇️ remoteConsole 方法：</h3><p><code>1.解析参数,判断是 RPC 还是 IPC</code>，如果是IPC ，判断是什么网络（主网、Ropsten、Rinkeby等）。</p><p><code>2.调用 dialRPC 方法，创建 endpoint 的 RPC 客户端。</code></p><p><code>3.根据参数获取配置信息后，创建console对象，生成js交互环境。并开启goroutine等待statck信息。</code></p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/aa5d5f4c2c8e61b73b37e2bb5d6ec8d09ef99886fba593412982d6d5189289aa.png" alt="remoteConsole 对应 attach 命令" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">remoteConsole 对应 attach 命令</figcaption></figure><h3 id="h-dialrpc" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">⬇️ dialRPC 方法：</h3><p>如果参数为空，默认开启 IPC 连接，否则创建 RPC 客户端</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/39ba8526200ef8c5866107ef6ec473190444546eb69addfc6bffbd314baefa30.png" alt="内部方法，创建RPC endpoint" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">内部方法，创建RPC endpoint</figcaption></figure><h3 id="h-ephemeralconsole" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">⬇️ ephemeralConsole 方法：</h3><p><code>1.创建一个全节点服务。</code></p><p><code>2.goroutine 异步等待。</code></p><p><code>3.遍历参数中的js文件，执行完毕后，关闭console。</code></p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/acedf9d568f1c25fa7f94f0a06fcc39024c0dfffc8b6ed8c1662ba3abcd1486b.png" alt="ephemeralConsole  对应 js 命令" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">ephemeralConsole 对应 js 命令</figcaption></figure>]]></content:encoded>
            <author>lua@newsletter.paragraph.com (OutOfToken)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/37497f30113dbcdce63e4f913a2525270857a06d3f9c3631a53c3742ce9969bf.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[深入学习 Go-Ethereum : 009. CMD 模块 - Geth -config.go]]></title>
            <link>https://paragraph.com/@lua/go-ethereum-009-cmd-geth-config-go</link>
            <guid>lratjt2qiU2zW0gLfqZR</guid>
            <pubDate>Fri, 01 Jul 2022 08:43:44 GMT</pubDate>
            <description><![CDATA[《深入学习 Go-Ethereum : 008. CMD 模块 - Geth - chaincmd.go》中罗列了 chaincmd 主要源码，接下来描述下关于 config.go 中的代码功能 ⬇️以下是 cmd/geth 包中其他代码的介绍：├── accountcmd.go ├── chaincmd.go ├── config.go 🔫 ├── consolecmd.go ├── dbcmd.go ├── misccmd.go ├── snapshot.go ├── usage.go └── version_check.go ⬇️ config.goconfig 代码主要包含了 1 个子命令（dumpconfig） 及configFileFlag相关描述。代码结构其中比较重要的代码为dumpconfig及configFileFlag声明，此外定义了两个结构体：gethConfig（主要包含了eth、node、ethstat、metrics）和ethstatsConfig（toml文件路径）。 其他的方法介绍如下：⬇️ dumpConfig 方法：dumpConfig 方法...]]></description>
            <content:encoded><![CDATA[<p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://mirror.xyz/laosan.eth/0PqOMEyugWMpez6s4LXYEGCi9folF7mRd5orfI2xBX4">《深入学习 Go-Ethereum : 008. CMD 模块 - Geth - chaincmd.go》</a>中罗列了 <code>chaincmd</code> 主要源码，接下来描述下关于 <code>config.go</code> 中的代码功能</p><p>⬇️以下是 cmd/geth 包中其他代码的介绍：</p><pre data-type="codeBlock" text="├── accountcmd.go 
├── chaincmd.go 
├── config.go 🔫
├── consolecmd.go
├── dbcmd.go
├── misccmd.go
├── snapshot.go
├── usage.go
└── version_check.go
"><code>├── accountcmd.go 
├── chaincmd.go 
├── config.go 🔫
├── consolecmd.go
├── dbcmd.go
├── misccmd.go
├── snapshot.go
├── usage.go
└── version_check.go
</code></pre><h2 id="h-configgo" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">⬇️ config.go</h2><p>config 代码主要包含了 1 个子命令<code>（dumpconfig）</code> 及configFileFlag相关描述。</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/f5774d3cecf62ef2ef10eb7be7f9c78d180c1c31cc78a49191d5c4ac67b55d7e.png" alt="代码结构" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">代码结构</figcaption></figure><p>其中比较重要的代码为dumpconfig及configFileFlag声明，此外定义了两个结构体：gethConfig（主要包含了eth、node、ethstat、metrics）和ethstatsConfig（toml文件路径）。</p><p>其他的方法介绍如下：</p><h3 id="h-dumpconfig" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">⬇️ dumpConfig 方法：</h3><p>dumpConfig 方法的主要作用是对节点配置信息的导出。（导出文件格式 <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://zh.m.wikipedia.org/wiki/TOML">TOML</a>）</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/0373d009a1474c374fc78e0873e079163997212f6ac19eb5b491c16d7aed198d.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>使用方法 <code>geth dumpconfig filename</code> 。</p><h3 id="h-loadconfig" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">⬇️ loadConfig 方法：</h3><p>根据指定文件路径（一般都是从别的环境中dump出相应的配置信息），进行配置信息的导入。文件格式内容使用<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://zh.m.wikipedia.org/wiki/TOML">TOML</a>进行配置。</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/6e9c6f22ba1a68982551a4dbdb7a0949d90c5204609d53284df4928528ef0e41.png" alt="loadConfig" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">loadConfig</figcaption></figure><p>查看调用关系，此方法被 <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/HugePages/go-ethereum/blob/21a09da78fd3e032f36ebd4bf7c3d7944faa92e3/cmd/geth/config.go#L121">config.go</a> 和 <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/HugePages/go-ethereum/blob/21a09da78fd3e032f36ebd4bf7c3d7944faa92e3/cmd/geth/accountcmd.go#L267">accountcmd.go</a> 使用。</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/8aeeb124579dc987a8523d2a7bb8737f5ac4f3bc71c807a45757b6a0e4c974a7.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>配置文件部分信息示例：</p><pre data-type="codeBlock" text="[Eth]
NetworkId = 1
SyncMode = &quot;snap&quot;
EthDiscoveryURLs = [&quot;enrtree://AKA3AM6LPBYEUDMVNU3BSVQJ5AD45Y7YPOHJLEF6W26QOE4VTUDPE@all.mainnet.ethdisco.net&quot;]
SnapDiscoveryURLs = [&quot;enrtree://AKA3AM6LPBYEUDMVNU3BSVQJ5AD45Y7YPOHJLEF6W26QOE4VTUDPE@all.mainnet.ethdisco.net&quot;]
......
"><code><span class="hljs-section">[Eth]</span>
<span class="hljs-attr">NetworkId</span> = <span class="hljs-number">1</span>
<span class="hljs-attr">SyncMode</span> = <span class="hljs-string">"snap"</span>
<span class="hljs-attr">EthDiscoveryURLs</span> = [<span class="hljs-string">"enrtree://AKA3AM6LPBYEUDMVNU3BSVQJ5AD45Y7YPOHJLEF6W26QOE4VTUDPE@all.mainnet.ethdisco.net"</span>]
<span class="hljs-attr">SnapDiscoveryURLs</span> = [<span class="hljs-string">"enrtree://AKA3AM6LPBYEUDMVNU3BSVQJ5AD45Y7YPOHJLEF6W26QOE4VTUDPE@all.mainnet.ethdisco.net"</span>]
......
</code></pre><h3 id="h-makeconfignode" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">⬇️ makeConfigNode 方法：</h3><p>此方法的主要功能是<code>加载geth配置</code>信息并<code>创建一个区块节点实例</code> 。</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/56bce14c7170cf0de2e32bea5e1e921fb1f8944908ee2fbe65df85f560e1607f.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><h3 id="h-makefullnode" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">⬇️ makeFullNode 方法📍：</h3><p>在geth启动时被调用，根据上下文参数，创建相应的配置信息，并启动eth后端服务。</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/8bf47f86a9c1b317c20173970f71edd9c58fa094d70a5b669600795e7cc52c6f.png" alt="makeFullNode" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">makeFullNode</figcaption></figure><p>以上是 <code>config.go</code> 代码中比较重要的方法及功能介绍。</p>]]></content:encoded>
            <author>lua@newsletter.paragraph.com (OutOfToken)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/7e8037ab083a5ac4984445307f29647ad3b369b25d56fa298284001947062a0f.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[深入学习 Go-Ethereum : 008. CMD 模块 - Geth - chaincmd.go]]></title>
            <link>https://paragraph.com/@lua/go-ethereum-008-cmd-geth-chaincmd-go</link>
            <guid>MzXUNmj7WmFvRM5BWale</guid>
            <pubDate>Sat, 18 Jun 2022 13:50:00 GMT</pubDate>
            <description><![CDATA[《深入学习 Go-Ethereum : 007. CMD 模块 - Geth - accountcmd.go》中罗列了 accountcmd 中关于 account 和 wallet 两个字命令的相关主要源码，接下来描述下关于 chaincmd.go 中的代码功能 ⬇️以下是 cmd/geth 包中其他代码的介绍：├── accountcmd.go ├── chaincmd.go 🔫 ├── config.go ├── consolecmd.go ├── dbcmd.go ├── misccmd.go ├── snapshot.go ├── usage.go └── version_check.go ⬇️ chaincmd.gochaincmd 代码主要包含了7个子命令（init、dump、dumpgenesis、export-preimages、import-preimages、export、import） 及对应的实现方法chaincmd.go 代码结构⬇️ 子命令声明⬇️ initGenesis 方法：initGenesis在使用 geth init 命令时需要提供 ge...]]></description>
            <content:encoded><![CDATA[<p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://mirror.xyz/dashboard/edit/UimLyxEqgwRU0udjAhXPAZwVkEmsI1ZGclGiU70zWwY">《深入学习 Go-Ethereum : 007. CMD 模块 - Geth - accountcmd.go》</a>中罗列了 <code>accountcmd</code> 中关于 <code>account</code> 和 <code>wallet</code> 两个字命令的相关主要源码，接下来描述下关于 <code>chaincmd.go</code> 中的代码功能</p><p>⬇️以下是 cmd/geth 包中其他代码的介绍：</p><pre data-type="codeBlock" text="├── accountcmd.go 
├── chaincmd.go 🔫
├── config.go
├── consolecmd.go
├── dbcmd.go
├── misccmd.go
├── snapshot.go
├── usage.go
└── version_check.go
"><code>├── accountcmd.go 
├── chaincmd.go 🔫
├── config.go
├── consolecmd.go
├── dbcmd.go
├── misccmd.go
├── snapshot.go
├── usage.go
└── version_check.go
</code></pre><blockquote><h2 id="h-chaincmdgo" class="text-3xl font-header !mt-8 !mb-4 first:!mt-0 first:!mb-0">⬇️ chaincmd.go</h2></blockquote><p>chaincmd 代码主要包含了7个子命令<code>（init、dump、dumpgenesis、export-preimages、import-preimages、export、import）</code> 及对应的实现方法</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/1c2d006da0785248f3f193f6247a81bfadc57508c2e799c0a0b3df68c6f11941.png" alt="chaincmd.go 代码结构" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">chaincmd.go 代码结构</figcaption></figure><p><strong>⬇️ 子命令声明</strong></p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/acd5d43c65983a6a020daf2c380f5be67db3ec310fc788a7b2ff821e9019bf92.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><h3 id="h-initgenesis" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">⬇️ initGenesis 方法：</h3><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/8bd873781e9fee242f3425be32e34cf52ccb33f29dd7bd505b806efca4a47d7c.png" alt="initGenesis" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">initGenesis</figcaption></figure><p>在使用 <code>geth init</code> 命令时需要提供 <code>genesis.json</code> 文件（也可以不使用init命令，各种配置项以参数方式进行启动），作为创世区块的基本配置。配置信息可以查看 <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://geth.ethereum.org/docs/interface/private-network">私有网络</a> 相关介绍。</p><p>⚠️ 备注：只有当 <strong><em>network</em></strong>*、<strong>chainID</strong>、<strong>创世区块配置</strong> * 都相同时，才是同一条链。</p><blockquote><p>Every blockchain starts with the genesis block. When you run Geth with default settings for the first time, it commits the main net genesis to the database. For a private network, you usually want a different genesis block.</p><p>在一个节点启动的时候，做为默认数据，会使用主网的创世块。如果是一个私有网络，通常需要一个不同的创世块信息。</p></blockquote><p><strong>关于配置项 ，</strong><code>json </code>中配置项对应了 <code>core/genesis.go</code> 代码中的 <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/HugePages/go-ethereum/blob/cd454edf55ac1939857b88cf89ae36b1a217784d/core/genesis.go#L49">Genesis</a> 结构体。</p><p>*示例1： Genesis.json（*with an empty chain configuration <em>）:</em></p><pre data-type="codeBlock" text="{
  &quot;alloc&quot;      : {},
  &quot;coinbase&quot;   : &quot;0x0000000000000000000000000000000000000000&quot;,
  &quot;difficulty&quot; : &quot;0x20000&quot;,
  &quot;extraData&quot;  : &quot;&quot;,
  &quot;gasLimit&quot;   : &quot;0x2fefd8&quot;,
  &quot;nonce&quot;      : &quot;0x0000000000001338&quot;,
  &quot;mixhash&quot;    : &quot;0x0000000000000000000000000000000000000000000000000000000000000000&quot;,
  &quot;parentHash&quot; : &quot;0x0000000000000000000000000000000000000000000000000000000000000000&quot;,
  &quot;timestamp&quot;  : &quot;0x00&quot;,
   &quot;config&quot;     : {}
}
"><code><span class="hljs-punctuation">{</span>
  <span class="hljs-attr">"alloc"</span>      <span class="hljs-punctuation">:</span> <span class="hljs-punctuation">{</span><span class="hljs-punctuation">}</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">"coinbase"</span>   <span class="hljs-punctuation">:</span> <span class="hljs-string">"0x0000000000000000000000000000000000000000"</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">"difficulty"</span> <span class="hljs-punctuation">:</span> <span class="hljs-string">"0x20000"</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">"extraData"</span>  <span class="hljs-punctuation">:</span> <span class="hljs-string">""</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">"gasLimit"</span>   <span class="hljs-punctuation">:</span> <span class="hljs-string">"0x2fefd8"</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">"nonce"</span>      <span class="hljs-punctuation">:</span> <span class="hljs-string">"0x0000000000001338"</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">"mixhash"</span>    <span class="hljs-punctuation">:</span> <span class="hljs-string">"0x0000000000000000000000000000000000000000000000000000000000000000"</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">"parentHash"</span> <span class="hljs-punctuation">:</span> <span class="hljs-string">"0x0000000000000000000000000000000000000000000000000000000000000000"</span><span class="hljs-punctuation">,</span>
  <span class="hljs-attr">"timestamp"</span>  <span class="hljs-punctuation">:</span> <span class="hljs-string">"0x00"</span><span class="hljs-punctuation">,</span>
   <span class="hljs-attr">"config"</span>     <span class="hljs-punctuation">:</span> <span class="hljs-punctuation">{</span><span class="hljs-punctuation">}</span>
<span class="hljs-punctuation">}</span>
</code></pre><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/78142cc729328cc9eb21e2393de421a5d0a7e7dfb2d4d9f85fa511301509f8ac.png" alt="json内容可视化" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">json内容可视化</figcaption></figure><p>配置项解释如下：</p><p><code>alloc</code> 初始化区块链，给预定用户进行资产分配（单位时 WEI ）。</p><p><code>difficulty</code> 挖矿的难度，能决定酸楚nonce的难度。</p><p><code>nonce</code> 挖矿的一次性数字随机数。</p><p><code>coinbase</code> 出块的奖励，一般在启动服务作为挖矿节点的时候，会设置当前节点挖矿奖励的目标地址是自己。</p><p><code>timestamp</code> 时间戳，规定创世区块开始的时间。</p><p><code>parentHash</code> 父区块的 hash 。</p><p><code>gasLimit</code> 当前区块的 gas 上限。</p><p><code>mixhash</code> pow机制中， 出块权获取后，给别的矿工进行验证的摘要信息。</p><p><code>extraData</code> 额外的信息。</p><p><em>示例2： Genesis.json（</em> with specific chain configurations <em>）:</em></p><pre data-type="codeBlock" text="{
  &quot;config&quot;: {
    &quot;chainId&quot;: 15,
    &quot;homesteadBlock&quot;: 0,
    &quot;eip150Block&quot;: 0,
    &quot;eip155Block&quot;: 0,
    &quot;eip158Block&quot;: 0,
    &quot;byzantiumBlock&quot;: 0,
    &quot;constantinopleBlock&quot;: 0,
    &quot;petersburgBlock&quot;: 0,
    ...
    ...指定区块的高度
    &quot;ethash&quot;: {}
  },
  &quot;difficulty&quot;: &quot;1&quot;,
  &quot;gasLimit&quot;: &quot;8000000&quot;,
  &quot;alloc&quot;: {
    &quot;7df9a875a174b3bc565e6424a0050ebc1b2d1d82&quot;: {
      &quot;balance&quot;: &quot;300000&quot;
    },
    &quot;f41c74c9ae680c1aa78f42e5647a62f353b7bdde&quot;: {
      &quot;balance&quot;: &quot;400000&quot;
    }
  }
}
"><code>{
  <span class="hljs-string">"config"</span>: {
    <span class="hljs-string">"chainId"</span>: <span class="hljs-number">15</span>,
    <span class="hljs-string">"homesteadBlock"</span>: <span class="hljs-number">0</span>,
    <span class="hljs-string">"eip150Block"</span>: <span class="hljs-number">0</span>,
    <span class="hljs-string">"eip155Block"</span>: <span class="hljs-number">0</span>,
    <span class="hljs-string">"eip158Block"</span>: <span class="hljs-number">0</span>,
    <span class="hljs-string">"byzantiumBlock"</span>: <span class="hljs-number">0</span>,
    <span class="hljs-string">"constantinopleBlock"</span>: <span class="hljs-number">0</span>,
    <span class="hljs-string">"petersburgBlock"</span>: <span class="hljs-number">0</span>,
    ...
    ...指定区块的高度
    <span class="hljs-string">"ethash"</span>: {}
  },
  <span class="hljs-string">"difficulty"</span>: <span class="hljs-string">"1"</span>,
  <span class="hljs-string">"gasLimit"</span>: <span class="hljs-string">"8000000"</span>,
  <span class="hljs-string">"alloc"</span>: {
    <span class="hljs-string">"7df9a875a174b3bc565e6424a0050ebc1b2d1d82"</span>: {
      <span class="hljs-string">"balance"</span>: <span class="hljs-string">"300000"</span>
    },
    <span class="hljs-string">"f41c74c9ae680c1aa78f42e5647a62f353b7bdde"</span>: {
      <span class="hljs-string">"balance"</span>: <span class="hljs-string">"400000"</span>
    }
  }
}
</code></pre><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/b015114c7be3b1fcb6a4e56fdb32d3e1e462ac2b4ceb7a275d43f357a136b497.png" alt="json内容可视化" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">json内容可视化</figcaption></figure><p>配置项解释如下：</p><p><code>chainId</code> 区块链的Id，默主网Id是 1 。</p><p><code>***Block</code> 区块高度，根据硬分叉等升级需求，指定区块高度（相关信息可以<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/HugePages/go-ethereum/blob/cd454edf55ac1939857b88cf89ae36b1a217784d/params/config.go#L59">点击查看源码</a>）。</p><hr><p>⬇️ <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://etherscan.io/block/0">主网创世块区块信息</a>如图</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/ac861712c14c69748e85495efc5c77c3975bc132b128273bfde820bceb6bc95a.png" alt="Block/0" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">Block/0</figcaption></figure><blockquote><h3 id="h-dumpgenesis" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">⬇️ dumpgenesis 方法：</h3></blockquote><p>此方法主要功能是导出创世块的数据信息，默认打印在控制台。执行 <code>geth dumpgenesis</code> 效果⬇️</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/82a9bd1503c729036ec2a2b82b4dba8c3aed7246db9c2c6926ec7217fedee8f0.png" alt="geth dumpgenesis" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">geth dumpgenesis</figcaption></figure><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/6a1fc93cc16ec798d01b7f5886b24a23c3bf7d904114ddea147c9b52a7e76826.png" alt="json数据可视化" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">json数据可视化</figcaption></figure><p>⬇️ 代码截图</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/29c788a61ae9bed695c67b6761627e7dea7716a1766b85dd53d16688356f7359.png" alt="dumpGenesis" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">dumpGenesis</figcaption></figure><p>调用 <code>utils.MakeGenesis()</code> 方法， 最终执行 <code>core.Genesis</code> 的 <code>DefaultGenesisBlock()</code> 方法</p><blockquote><h3 id="h-exportchain" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">⬇️ exportChain 方法：</h3></blockquote><p>此方法功能是将当前区块链数据导出成文件（使用 gzip 进行文件输出），执行 <code>append</code> 模式。具体导出代码可查看 <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/HugePages/go-ethereum/blob/cd454edf55ac1939857b88cf89ae36b1a217784d/cmd/utils/cmd.go#L241">ExportChain</a> 和 <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/HugePages/go-ethereum/blob/cd454edf55ac1939857b88cf89ae36b1a217784d/cmd/utils/cmd.go#L267">ExportAppendChain</a></p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/92503d72febd463d5fbc813d3369bc99a23d16b86d74115320d83122c26f188c.png" alt="exportChain" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">exportChain</figcaption></figure><blockquote><h3 id="h-importchain" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">⬇️ importChain 方法：</h3></blockquote><p>导入指定文，创建 Blockchain对象。其中主要的方法逻辑是 创建 <code>node</code> 对象、创建 <code>chain</code> 对象、判断参数数量执行 <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/HugePages/go-ethereum/blob/cd454edf55ac1939857b88cf89ae36b1a217784d/cmd/utils/cmd.go#L138">ImportChain</a></p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/008974344c1574961ac8d22748eee2628c8c117be5ce10ffc4a7df21a548bedb.png" alt="ImportChain" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">ImportChain</figcaption></figure><blockquote><h3 id="h-exportpreimages" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">⬇️ exportPreimages 方法：</h3></blockquote><p>以RLP方式编码，导出preimage数据。</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/34a5e70a5a3e67de5e593575831d35aa85c8a38f691646b247f7ffcc34046bd1.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><blockquote><h3 id="h-importpreimages" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">⬇️ importPreimages 方法：</h3></blockquote><p>导入指定文件的 <code>preimage</code> 数据，使用 <code>rawdb</code> 的<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/HugePages/go-ethereum/blob/cd454edf55ac1939857b88cf89ae36b1a217784d/core/rawdb/accessors_state.go#L84">WritePreimages</a>方法进行数据库数据操作。</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/d1e31b93e749c535d68720ed6fc484bba790b1461e54fe383b57ad5d9e132f90.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure>]]></content:encoded>
            <author>lua@newsletter.paragraph.com (OutOfToken)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/37497f30113dbcdce63e4f913a2525270857a06d3f9c3631a53c3742ce9969bf.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[深入学习 Go-Ethereum : 007. CMD 模块 - Geth - accountcmd.go]]></title>
            <link>https://paragraph.com/@lua/go-ethereum-007-cmd-geth-accountcmd-go</link>
            <guid>KinyGzYZOX6QJoBq7RQk</guid>
            <pubDate>Tue, 14 Jun 2022 05:03:55 GMT</pubDate>
            <description><![CDATA[《深入学习 Go-Ethereum : 006. CMD模块-Geth》 中梳理了启动流程，下面开始梳理同目录下其他子命令。 ⬇️以下是 cmd/geth包中其他代码的介绍：├── accountcmd.go 🔫 ├── chaincmd.go ├── config.go ├── consolecmd.go ├── dbcmd.go ├── misccmd.go ├── snapshot.go ├── usage.go └── version_check.go ⬇️accountcmd.goaccountcmd.go 源码概览accountcmd.go 包含了 account 和 wallet 两个子命令。geth 子命令 account 和 wallet两个命令分别是 wallet（预售钱包） 和 account 的管理功能。 例如：列出当前节点中创建或者导入的账号 ⬇️ geth account listgeth account list⬇️ geth account newgeth account newgeth wallet import ：用来导入 presale（预...]]></description>
            <content:encoded><![CDATA[<p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://mirror.xyz/laosan.eth/SGjKlIIb6NHYVlLjPhD-TFE1iuQmUptBJ8Dcx89YK0c">《深入学习 Go-Ethereum : 006. CMD模块-Geth》</a> 中梳理了启动流程，下面开始梳理同目录下其他子命令。</p><p>⬇️以下是 cmd/geth包中其他代码的介绍：</p><pre data-type="codeBlock" text="├── accountcmd.go 🔫
├── chaincmd.go
├── config.go
├── consolecmd.go
├── dbcmd.go
├── misccmd.go
├── snapshot.go
├── usage.go
└── version_check.go
"><code>├── accountcmd.go 🔫
├── chaincmd.go
├── config.go
├── consolecmd.go
├── dbcmd.go
├── misccmd.go
├── snapshot.go
├── usage.go
└── version_check.go
</code></pre><blockquote><h3 id="h-accountcmdgo" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">⬇️accountcmd.go</h3></blockquote><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/b6a4415492daee9f4a0309e90a440abf9d6e0d61c7fc5e1c0b46ff32f31c3416.png" alt="accountcmd.go 源码概览" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">accountcmd.go 源码概览</figcaption></figure><p><code>accountcmd.go</code> 包含了 <code>account</code> 和 <code>wallet</code> 两个子命令。</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/2cf0a8e79422604e68e4773adab1e3afed6b69f72886a0496c9c0533a3f008bc.png" alt="geth 子命令 account 和 wallet" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">geth 子命令 account 和 wallet</figcaption></figure><p><strong>两个命令分别是 wallet（预售钱包） 和 account 的管理功能。</strong></p><p>例如：列出当前节点中创建或者导入的账号</p><p><code>⬇️ geth account list</code></p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/7757884bcae03a5668a95e3c799122d15e32a5a03b9717cfefd31d649b30c092.png" alt="geth account list" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">geth account list</figcaption></figure><p><code>⬇️ geth account new</code></p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/46c82e364954522f750ccb914fa988e9696a58b89d0914288d254358f4411053.png" alt="geth account new" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">geth account new</figcaption></figure><p><code>geth wallet import</code> ：用来导入 <code>presale（预售）</code> 账户钱包</p><hr><p><code>account</code> 相关源码</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/f5b1604db2e1d81672f9092ee0c66148dba2208154016786d2254795b8c8f14e.png" alt="accountList" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">accountList</figcaption></figure><p>⬆️ <strong>accountList</strong> 方法，主要是获取当前节点可管理账号信息列表（包含了本地创建、导入的账号）。</p><p>代码逻辑是通过 ctx 上下文获取 <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/HugePages/go-ethereum/blob/26ff2c1e0ed8eae9e83ddec6c777bfec9afef906/node/node.go#L647">Node</a> 对象的stack实例，然后获取账户管理器，查询节点的所有钱包信息。然后进行遍历，打印 Account 的地址和 keystore 存储 url 地址。</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/7399d427017534ff11ffc2f92b56f86593779fd4eb9cd0aab385362d901f9162.png" alt="accountCreate" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">accountCreate</figcaption></figure><p>⬆️ <strong>accountCreate</strong> 方法，根据用户输入的密码，创建一个账号，控制台打印创建用户对应的<code>公开地址</code> 和 keystore 文件存储路径。具体代码可查看 <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/HugePages/go-ethereum/blob/26ff2c1e0ed8eae9e83ddec6c777bfec9afef906/accounts/keystore/passphrase.go#L101">StoreKey</a> 函数。</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/68bed7c47975f8bbb3236beb7d27f2aaa12abcb93e9dbd3d767ec6308967d2c8.png" alt="accountUpdate" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">accountUpdate</figcaption></figure><p>⬆️ <strong>accountUpdate</strong> 方法，输入参数是账号地址，可以对账号的格式进行更新，也可以对账号进行解锁（修改账号的密码，使用 unlockAccount 方法）。</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/8d45fe1fb0e834e4d31a607f81e3ed9be6f5ff8e657f1a6ccbd983f77b3e3962.png" alt="unlockAccount" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">unlockAccount</figcaption></figure><p>⬆️ <strong>unlockAccount</strong> 方法， 对指定账号进行解锁。调用 keystore 的 unlock 方法。如果解锁失败，则进行模糊地址（可能存在一个地址对应了多个 keystore 文件）恢复。</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/664ae949e33e33f4b8d844c5176fd816e7001babd7c860e1b5c35b08a5146655.png" alt="ambiguousAddrRecovery" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">ambiguousAddrRecovery</figcaption></figure><p>⬆️ ambiguousAddrRecovery 方法，修复单一账户对应多个keystore 文件问题。🤔️ 什么情况会出现此现象❓</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/7b936d66ea09659abd6c274b4323324673ab3a23c19d71e5dc621863a83e1234.png" alt="accountImport" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">accountImport</figcaption></figure><p>⬆️ accountImport 方法， <code>keystore.go</code> 使用 <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/HugePages/go-ethereum/blob/26ff2c1e0ed8eae9e83ddec6c777bfec9afef906/accounts/keystore/keystore.go#L457">ImportECDSA</a> 导入账号信息，这里操作导入的参数是<code>私钥数据所在的文件路径</code></p><p>例如 <code>7b2905d895b6a0e5ba976cff63bb80ac1600c8811f59f74e29919c46e6053dbe</code> 存储在 <code>/Users/zhangyu/z.txt（MacOS）</code> 文件中，使用 <code>geth account import /Users/zhangyu/z.txt</code> 即可。输入密码后，账号导入成功 🎉</p>]]></content:encoded>
            <author>lua@newsletter.paragraph.com (OutOfToken)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/7e8037ab083a5ac4984445307f29647ad3b369b25d56fa298284001947062a0f.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[深入学习 Go-Ethereum : 006. CMD模块-Geth]]></title>
            <link>https://paragraph.com/@lua/go-ethereum-006-cmd-geth</link>
            <guid>ulzXlzbBnstZsIfJogBe</guid>
            <pubDate>Mon, 13 Jun 2022 05:32:47 GMT</pubDate>
            <description><![CDATA[在 Go-Ethereum 源码中，cmd 包中包含了例如 geth、evm、clf等等客户端命令工具。如下图所示⬇️go-ethereum 源码中 cmd 包结构其中最为重要的就是 geth 命令。它是使用以太坊客户端的主要命令。它还包含了很多子命令。在命令行中，可以使用 geth --help ⬇️查看相关帮助手册。geth --help 执行结果，截取部分结果信息geth 子命令清单及简介⬆️如上图是 geth 的子命令信息，使用频次比较高的例如 account、console、db、dump、init、wallet 等代码调用链程序入口 cmd/geth/main.go⬇️geth 的命令行使用 "gopkg.in/urfave/cli.v1" 库做为基础， 代码中执行 app.Run 启动geth。初始化方法在初始化函数中，指定了 geth 函数。程序的核心入口 ⬇️ // geth is the main entry point into the system if no special subcommand is ran. // It creates a defau...]]></description>
            <content:encoded><![CDATA[<p>在 Go-Ethereum 源码中，cmd 包中包含了例如 geth、evm、clf等等客户端命令工具。如下图所示⬇️</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/a7c0273bfeedbd0353c513b70533ff4a72677aa55a419f66bc0fe5085e7ccab0.png" alt="go-ethereum 源码中 cmd 包结构" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">go-ethereum 源码中 cmd 包结构</figcaption></figure><p>其中最为重要的就是 <code>geth</code> 命令。它是使用以太坊客户端的主要命令。它还包含了很多子命令。在命令行中，可以使用 <code>geth --help</code> ⬇️查看相关帮助手册。</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/ec9acf84b5c749c629d8f8ccba21e55a9a7e7b8d5dfa544539cf769281e6aa3f.png" alt="geth --help 执行结果，截取部分结果信息" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">geth --help 执行结果，截取部分结果信息</figcaption></figure><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/848612ced2f353f8af59b3436eebd6bc5f18acba082531bae94d4c114e14ccf9.png" alt=" geth 子命令清单及简介" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">geth 子命令清单及简介</figcaption></figure><p>⬆️如上图是 geth 的子命令信息，使用频次比较高的例如 <code>account、console、db、dump、init、wallet</code> 等</p><hr><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/bc0d1bdea19d752f61a14735eb300702dca51c5e1f6b193cace2957eaed96917.png" alt="代码调用链" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">代码调用链</figcaption></figure><p>程序入口 <code>cmd/geth/main.go⬇️</code></p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/823c459eaa275f6a39be3439f3cbb40ebb4675e31f8037943040a73a0bc26ff1.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>geth 的命令行使用 <code>&quot;gopkg.in/urfave/cli.v1&quot;</code> 库做为基础， 代码中执行 <code>app.Run</code> 启动geth。</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/4fb8fbb9322b93fc679510d91f450ff477206ea01f38363ea01c18d3de243218.png" alt="初始化方法" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">初始化方法</figcaption></figure><p>在初始化函数中，指定了 <code>geth</code> 函数。程序的核心入口 ⬇️</p><pre data-type="codeBlock" text="
// geth is the main entry point into the system if no special subcommand is ran.
// It creates a default node based on the command line arguments and runs it in
// blocking mode, waiting for it to be shut down.
func geth(ctx *cli.Context) error {
    if args := ctx.Args(); len(args) &gt; 0 {
        return fmt.Errorf(&quot;invalid command: %q&quot;, args[0])
    }
    prepare(ctx)
    stack, backend := makeFullNode(ctx)
    defer stack.Close()
    startNode(ctx, stack, backend, false)
    stack.Wait()
    return nil
}
"><code>
<span class="hljs-comment">// geth is the main entry point into the system if no special subcommand is ran.</span>
<span class="hljs-comment">// It creates a default node based on the command line arguments and runs it in</span>
<span class="hljs-comment">// blocking mode, waiting for it to be shut down.</span>
func geth(ctx <span class="hljs-operator">*</span>cli.Context) <span class="hljs-function"><span class="hljs-keyword">error</span> </span>{
    <span class="hljs-keyword">if</span> args :<span class="hljs-operator">=</span> ctx.Args(); len(args) <span class="hljs-operator">></span> <span class="hljs-number">0</span> {
        <span class="hljs-keyword">return</span> fmt.Errorf(<span class="hljs-string">"invalid command: %q"</span>, args[<span class="hljs-number">0</span>])
    }
    prepare(ctx)
    stack, backend :<span class="hljs-operator">=</span> makeFullNode(ctx)
    defer stack.Close()
    startNode(ctx, stack, backend, <span class="hljs-literal">false</span>)
    stack.Wait()
    <span class="hljs-keyword">return</span> nil
}
</code></pre><ol><li><p>程序先判断上下文参数是否存在异常参数，如果存在异常参数，直接打印错误信息，并终止程序。</p></li><li><p>预处理 prepare 方法，主要内容是 <code>创建缓存</code> 和 <code>启动度量服务（启动 InfluxDB 时序数据库进行记录）。</code></p></li><li><p>创建全节点。<code>// makeFullNode loads geth configuration and creates the Ethereum backend.</code></p></li><li><p>启动节点。</p></li><li><p>阻塞方式运行程序，等待关闭或者异常错误终止程序。</p></li></ol><blockquote><p><strong>makeFullNode</strong> ⬇️</p></blockquote><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/HugePages/go-ethereum/blob/26ff2c1e0ed8eae9e83ddec6c777bfec9afef906/cmd/geth/config.go#L121">https://github.com/HugePages/go-ethereum/blob/26ff2c1e0ed8eae9e83ddec6c777bfec9afef906/cmd/geth/config.go#L121</a></p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/3c58713aea9c88f6f77b13e35f5ed35395e0b2e59a04b6005d2a2d743c906874.png" alt="makeFullNode" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">makeFullNode</figcaption></figure><p>⬆️此方法的主要功能是 设置系统级别参数 和 启动 ethereum network 后台服务，方法内部关注makeConfigNode() 和 utils.RegisterEthService()</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/55cd75f600be5925982ccb0042b0009fa519abf912ca1a7ffca6955112edaaf2.png" alt="makeConfigNode" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">makeConfigNode</figcaption></figure><p>⬆️创建配置节点主要是获取 eth 的配置信息、节点的默认配置信息、度量服务的默认配置星系。然后将这些配置信息进行处理，创建 node 对象 <code>stack, err := node.New(&amp;cfg.Node)</code></p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/37aaed10212f8b0b176dc71150833b7be7a73ae1ba8b871c22a28a3fc81b6c60.png" alt="RegisterEthService" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">RegisterEthService</figcaption></figure><p>⬆️RegisterEthService 是将一个 Ethereum 客户端添加到 stack 中， 如果启动时轻节点服务，此方法两个返回值中第二个是 <code>les.Ethereum</code>。如果同步模式是轻客户端模式，则启动轻量级客户端，否则启动全节点客户端，核心方法是 <code>eth.New</code></p><blockquote><p>startNode ⬇️</p></blockquote><pre data-type="codeBlock" text="// startNode boots up the system node and all registered protocols, after which it unlocks any requested accounts, and starts the RPC/IPC interfaces and the miner.
"><code><span class="hljs-comment">// startNode boots up the system node and all registered protocols, after which it unlocks any requested accounts, and starts the RPC/IPC interfaces and the miner.</span>
</code></pre><p>此方法主要功能包含 <code>启动系统节点和所有注册的协议、解锁用户、启动 RPC/IPC 接口服务、启动矿工挖矿服务</code><strong>。</strong></p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/acac659dde221c203bbcd32d890a27200988132af7da21ed8243020942fd0748.png" alt="startNode" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">startNode</figcaption></figure><ol><li><p>添加对象内存大小计算功能，使用 <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/fjl/memsize">memsize</a> 类库进行处理</p></li><li><p>utils启动节点</p></li><li><p>解锁请求账户（意图还不了解，//TODO</p></li><li><p>订阅钱包事件</p></li><li><p>绑定本地客户端和geth节点的交互</p></li><li><p>创建客户端</p></li><li><p>开启协程进行「事件」处理</p></li></ol><p>以上就是默认 geth 启动的代码流程了。</p><p>参考链接：</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.cnblogs.com/wanghui-garcia/p/10252260.html">https://www.cnblogs.com/wanghui-garcia/p/10252260.html</a></p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://knarfeh.com/2018/03/10/go-ethereum%20%E6%BA%90%E7%A0%81%E7%AC%94%E8%AE%B0%EF%BC%88cmd%20%E6%A8%A1%E5%9D%97-geth%20%E5%91%BD%E4%BB%A4%EF%BC%89/">https://knarfeh.com/2018/03/10/go-ethereum%20%E6%BA%90%E7%A0%81%E7%AC%94%E8%AE%B0%EF%BC%88cmd%20%E6%A8%A1%E5%9D%97-geth%20%E5%91%BD%E4%BB%A4%EF%BC%89/</a></p>]]></content:encoded>
            <author>lua@newsletter.paragraph.com (OutOfToken)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/37497f30113dbcdce63e4f913a2525270857a06d3f9c3631a53c3742ce9969bf.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[深入学习 Go-Ethereum : 005. 数据结构]]></title>
            <link>https://paragraph.com/@lua/go-ethereum-005</link>
            <guid>qkAGeBEDcf0RFSERRZnm</guid>
            <pubDate>Mon, 16 May 2022 03:48:41 GMT</pubDate>
            <description><![CDATA[代码文件 core.types.block.go结构图:区块 ( Block )BlockBlock区块头 ( Header )Header区块体 ( Body )Body拓展区块信息 ( ExtBlock )extBlock]]></description>
            <content:encoded><![CDATA[<h3 id="h-coretypesblockgo" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">代码文件 core.types.block.go</h3><p><strong>结构图:</strong></p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/884a2689d7f2297932f1aedc22752e17c67adf82adef3fdd06db4aaffc0e9a27.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p><strong>区块 ( Block )</strong></p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/dda79d9568c6f6dbbc7f37ff6e4e5a7cc8dbd80650af0409843278160e511bb6.jpg" alt="Block" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">Block</figcaption></figure><p><strong>Block区块头 ( Header )</strong></p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/5e99188b60a36dfae0b089819af330a7f71c45d8fb04089b35918d19e02f4975.jpg" alt="Header" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">Header</figcaption></figure><p><strong>区块体 ( Body )</strong></p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/3125a2eef72f49d25f4f1ae3798cebfd95677a3403db46c7b69f21ad44261654.jpg" alt="Body" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">Body</figcaption></figure><p><strong>拓展区块信息 ( ExtBlock )</strong></p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/33419729ba96ad7d49f8c4701a394fb817c0323207bcfebbfe0d24301159071e.jpg" alt="extBlock" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">extBlock</figcaption></figure>]]></content:encoded>
            <author>lua@newsletter.paragraph.com (OutOfToken)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/7e8037ab083a5ac4984445307f29647ad3b369b25d56fa298284001947062a0f.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[深入学习 Go-Ethereum : 004. 项目架构]]></title>
            <link>https://paragraph.com/@lua/go-ethereum-004</link>
            <guid>c0x3x0mCHUKo7xMxm8kf</guid>
            <pubDate>Tue, 15 Mar 2022 02:01:26 GMT</pubDate>
            <description><![CDATA[现阶段(2022-03-11)认知底层基础:P2P 网络密码学中间件 : KV 、时序数据库核心功能组件:账号体系、钱包、地址区块、交易、状态、事件经济机制 : Miner、GasEVM生态:智能合约 : Solidity、Rust开发工具 : Remix基础设施 : 去中心化存储、预言机等Further reading …https://ethereum.stackexchange.com/questions/268/ethereum-block-architecture/757 https://eth.wiki/en/fundamentals/design-rationale https://book.douban.com/subject/30199891/ https://preethikasireddy.medium.com/how-does-ethereum-work-anyway-22d1df506369 https://bit.ly/3N6ALsD]]></description>
            <content:encoded><![CDATA[<figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/84e54101f6f61a6a00ed8e899df1e57dfdc05830e2f31566ace131a0a2be9e7b.png" alt="现阶段(2022-03-11)认知" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">现阶段(2022-03-11)认知</figcaption></figure><p>底层基础:</p><ul><li><p>P2P 网络</p></li><li><p>密码学</p></li><li><p>中间件 : KV 、时序数据库</p></li></ul><p>核心功能组件:</p><ul><li><p>账号体系、钱包、地址</p></li><li><p>区块、交易、状态、事件</p></li><li><p>经济机制 : Miner、Gas</p></li><li><p>EVM</p></li></ul><p>生态:</p><ul><li><p>智能合约 : Solidity、Rust</p></li><li><p>开发工具 : Remix</p></li><li><p>基础设施 : 去中心化存储、预言机等</p></li></ul><h3 id="h-further-reading" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Further reading …</h3><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ethereum.stackexchange.com/questions/268/ethereum-block-architecture/757">https://ethereum.stackexchange.com/questions/268/ethereum-block-architecture/757</a></p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://eth.wiki/en/fundamentals/design-rationale">https://eth.wiki/en/fundamentals/design-rationale</a></p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://book.douban.com/subject/30199891/">https://book.douban.com/subject/30199891/</a></p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://preethikasireddy.medium.com/how-does-ethereum-work-anyway-22d1df506369">https://preethikasireddy.medium.com/how-does-ethereum-work-anyway-22d1df506369</a></p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://bit.ly/3N6ALsD">https://bit.ly/3N6ALsD</a></p>]]></content:encoded>
            <author>lua@newsletter.paragraph.com (OutOfToken)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/37497f30113dbcdce63e4f913a2525270857a06d3f9c3631a53c3742ce9969bf.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[深入学习 Go-Ethereum : 003.源码包介绍]]></title>
            <link>https://paragraph.com/@lua/go-ethereum-003</link>
            <guid>eDUfGsNeU0l6926zqAAB</guid>
            <pubDate>Thu, 10 Mar 2022 15:21:30 GMT</pubDate>
            <description><![CDATA[Github commit ID : 5079e3c6 对应的目录/文件结构具体文本文件可以访问 包说明.txt 其中（个人此时认为，后续跟进补充）比较重要的几个包,清单如下:]]></description>
            <content:encoded><![CDATA[<figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/b9c6191bb832ee6ae593c41dc14ac64795e4685dc3be7c5dc84a6896005eac5f.png" alt="Github commit ID : 5079e3c6 对应的目录/文件结构" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">Github commit ID : 5079e3c6 对应的目录/文件结构</figcaption></figure><p>具体文本文件可以访问 <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/HugePages/go-ethereum/blob/master/%E5%8C%85%E8%AF%B4%E6%98%8E.txt">包说明.txt</a></p><p>其中（个人此时认为，后续跟进补充）比较重要的几个包,清单如下:</p><pre data-type="codeBlock" text="accounts
consensus
core
eth
miner
node
p2p
rpl
rpc
trie
cmd
"><code></code></pre>]]></content:encoded>
            <author>lua@newsletter.paragraph.com (OutOfToken)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/7e8037ab083a5ac4984445307f29647ad3b369b25d56fa298284001947062a0f.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[深入学习 Go-Ethereum : 002.环境搭建]]></title>
            <link>https://paragraph.com/@lua/go-ethereum-002</link>
            <guid>2z3UsYcoDjXVfhdsKcnd</guid>
            <pubDate>Tue, 08 Mar 2022 09:58:25 GMT</pubDate>
            <description><![CDATA[基本介绍Ethereum 的主流版本 Geth ,代码托管在 Github 中. 具体的访问地址如下: https://github.com/ethereum/go-ethereum 此项目也是ethereum账号下star最多的开源项目.截止2022-03-08,star数量 35909安装Golang因为此项目的开发语言是 Golang,所以电脑需要安装 Golang 环境.我的电脑系统是 MacOS,使用常用的软件包管理工具 brew 进行安装. (如果不了解可以访问 https://brew.sh 进行相关工具的了解,其他操作系统可自行 Google )安装完成后,可以使用 go version 进行测试,会显示对应的版本号,效果如下:以上完成了第一步, Golang 环境的安装.下载源码和编译接下来我们进行代码的下载和编译.访问官方代码库,点击代码按钮,即可看到三种 clone 代码方式. 推荐使用 ssh 进行代码 clone.在命令行中切换工作路径(存放代码的路径),输入 git clone https://github.com/ethereum/go-ethere...]]></description>
            <content:encoded><![CDATA[<h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">基本介绍</h3><p>Ethereum 的主流版本 Geth ,代码托管在 Github 中. 具体的访问地址如下:</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ethereum/go-ethereum">https://github.com/ethereum/go-ethereum</a></p><p>此项目也是ethereum账号下star最多的开源项目.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/ac9d23f3b5e74b13314a9c3255c32ec71790e5e0b86c13a4aaa760a8a05b0f5c.png" alt="截止2022-03-08,star数量 35909" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">截止2022-03-08,star数量 35909</figcaption></figure><h3 id="h-golang" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">安装Golang</h3><p>因为此项目的开发语言是 <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://go.dev">Golang</a>,所以电脑需要安装 Golang 环境.我的电脑系统是 MacOS,使用常用的软件包管理工具 brew 进行安装.</p><p>(如果不了解可以访问 <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://brew.sh">https://brew.sh</a> 进行相关工具的了解,其他操作系统可自行 <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://google.com">Google</a> )</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/f781bbe788f60f60418770636258b796215f4b64f7ebb5bac537be01a7c8f6b0.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>安装完成后,可以使用 <code>go version</code> 进行测试,会显示对应的版本号,效果如下:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/712d00cb160651497df98a6b9ceeeab513d64ddd5f76392972e450b32417656f.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>以上完成了第一步, Golang 环境的安装.</p><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">下载源码和编译</h3><p>接下来我们进行代码的下载和编译.访问官方代码库,点击代码按钮,即可看到三种 clone 代码方式. 推荐使用 ssh 进行代码 clone.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/e470c9c88b046c3a871f98bceae93d26c4c4c85e7056353cf83a7338a3bf71f6.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>在命令行中切换工作路径(存放代码的路径),输入 <code>git clone https://github.com/ethereum/go-ethereum.git</code> 回车,等待代码检出到本地.效果如下:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/ec9328d3bcf305ded8edcd0fc8b906eb7771eb29607df7897f972ef872f40335.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>下载完成后,执行 <code>make</code> 命令进行代码编译,效果如下图</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/8763a3ca4baabfd64b15e0bbfda1819208b937a5f4eed32c816e913ed9371d06.png" alt="make 执行构建" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">make 执行构建</figcaption></figure><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/3c6809433d98db1dce3d7efc0e6cfae033592476f7d52149133e15db774597dc.png" alt="构建结束,按照提示启动 geth" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">构建结束,按照提示启动 geth</figcaption></figure><p><code>./build/bin/geth</code> 启动程序</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/cdadd7251c6f7f8030a7e9dcd66426ae3c99c36eb2413eaf9d1b58740bdfc7e1.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>以上,是安装Geth的步骤及编译运行程序的记录.</p><ol><li><p>下载Golang</p></li><li><p>Checkout Geth 源码</p></li><li><p>make</p></li><li><p>./geth</p></li></ol><h3 id="h-further-reading" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">Further reading …</h3><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://geth.ethereum.org/docs/install-and-build/installing-geth#install-on-macos-via-homebrew">https://geth.ethereum.org/docs/install-and-build/installing-geth#install-on-macos-via-homebrew</a></p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ethereum.org/zh/developers/tutorials/run-light-node-geth/">https://ethereum.org/zh/developers/tutorials/run-light-node-geth/</a></p>]]></content:encoded>
            <author>lua@newsletter.paragraph.com (OutOfToken)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/37497f30113dbcdce63e4f913a2525270857a06d3f9c3631a53c3742ce9969bf.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[深入学习Go-Ethereum : 001.什么是Geth]]></title>
            <link>https://paragraph.com/@lua/go-ethereum-001-geth</link>
            <guid>k1YwglZHTMogLdm2i1wy</guid>
            <pubDate>Fri, 04 Mar 2022 01:57:30 GMT</pubDate>
            <description><![CDATA[基本介绍在 Ethereum (以太坊网络)中,存在很多的客户端,其中 Geth 是运行节点数最多的客户端版本. 官方介绍: Geth is the Golang implementation of the Ethereum protocol. It is fast, open-source software that is actively maintained. Geth是基于Golang实现的以太坊网络协议.它是运行快速、代码开源(下载地址)的软件,并由以太坊基金会积极维护地以太坊客户端类型、开发语言版本、操作系统统计从图中可以看出Geth是以太坊网络协议中,占比最高的客户端,高达90%. (此外也推荐学习了解基于Rust语言开发的openethereum)阅读参考查询地址: https://etherscan.io/nodetracker 代码下载地址: https://github.com/ethereum/go-ethereum 官方面向开发者的学习文档: https://ethereum.org/zh/developers/]]></description>
            <content:encoded><![CDATA[<h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">基本介绍</h3><p>在 Ethereum (以太坊网络)中,存在很多的客户端,其中 <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://geth.ethereum.org/">Geth</a> 是运行节点数最多的客户端版本.</p><p>官方介绍:</p><p>Geth is the Golang implementation of the Ethereum protocol. It is fast, open-source software that is actively maintained.</p><p>Geth是基于Golang实现的以太坊网络协议.它是运行快速、代码开源(<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ethereum/go-ethereum">下载地址</a>)的软件,并由以太坊基金会积极维护地</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/d9eb49888886a2484394b4532909703b47b1188a88a66b3bb08d120b3a5a683c.png" alt="以太坊客户端类型、开发语言版本、操作系统统计" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">以太坊客户端类型、开发语言版本、操作系统统计</figcaption></figure><p>从图中可以看出Geth是以太坊网络协议中,占比最高的客户端,高达90%.</p><p>(此外也推荐学习了解基于Rust语言开发的<a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/openethereum/openethereum">openethereum</a>)</p><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">阅读参考</h3><p>查询地址:</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://etherscan.io/nodetracker">https://etherscan.io/nodetracker</a></p><p>代码下载地址:</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/ethereum/go-ethereum">https://github.com/ethereum/go-ethereum</a></p><p>官方面向开发者的学习文档:</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://ethereum.org/zh/developers/">https://ethereum.org/zh/developers/</a></p>]]></content:encoded>
            <author>lua@newsletter.paragraph.com (OutOfToken)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/7e8037ab083a5ac4984445307f29647ad3b369b25d56fa298284001947062a0f.png" length="0" type="image/png"/>
        </item>
        <item>
            <title><![CDATA[JDK 版本差异，导致系统启动失败]]></title>
            <link>https://paragraph.com/@lua/jdk</link>
            <guid>RZ79COWE499Nx35vlg6H</guid>
            <pubDate>Tue, 25 Jan 2022 10:39:04 GMT</pubDate>
            <description><![CDATA[涉及技术【ClassLoader、mybatis 框架 mapper 文件解析】问题背景描述之前的研发平台在后期维护中主要是支持 MySQL 数据库，对 Oracle 兼容性慢慢缺失。近期一个项目使用的是 Oracle 数据库，两位开发小哥就开始针对 Oracle 数据库，做兼容开发有问题修复。 在其中一个服务系统系统管理做兼容改造开始时，系统切换到oracle数据库方言后，系统启动失败。异常信息如下:[ERROR] 2019-07-18 11:01:17.246 [main] SpringApplication - Application startup failed org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): dao.IDataTypeDao.selectDataTypeList at org.apache.ibatis.binding.MapperMethod$SqlCommand.&#x3C;init>(MapperMethod.java:225) ~[m...]]></description>
            <content:encoded><![CDATA[<p><em>涉及技术【ClassLoader、mybatis 框架 mapper 文件解析】</em></p><h4 id="h-" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">问题背景描述</h4><p>之前的研发平台在后期维护中主要是支持 MySQL 数据库，对 Oracle 兼容性慢慢缺失。近期一个项目使用的是 Oracle 数据库，两位开发小哥就开始针对 Oracle 数据库，做兼容开发有问题修复。</p><p>在其中一个服务系统<code>系统管理</code>做兼容改造开始时，系统切换到oracle数据库方言后，系统启动失败。异常信息如下:</p><pre data-type="codeBlock" text="[ERROR] 2019-07-18 11:01:17.246 [main] SpringApplication - Application startup failed
org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): dao.IDataTypeDao.selectDataTypeList
    at org.apache.ibatis.binding.MapperMethod$SqlCommand.&lt;init&gt;(MapperMethod.java:225) ~[mybatis-3.4.4.jar:3.4.4]
    at org.apache.ibatis.binding.MapperMethod.&lt;init&gt;(MapperMethod.java:48) ~[mybatis-3.4.4.jar:3.4.4]
    at org.apache.ibatis.binding.MapperProxy.cachedMapperMethod(MapperProxy.java:65) ~[mybatis-3.4.4.jar:3.4.4]
    at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:58) ~[mybatis-3.4.4.jar:3.4.4]
    at com.sun.proxy.$Proxy161.selectDataTypeList(Unknown Source) ~[?:?]
......
org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:167) ~[spring-context-4.3.9.RELEASE.jar:4.3.9.RELEASE]
    at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139) ~[spring-context-4.3.9.RELEASE.jar:4.3.9.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:393) ~[spring-context-4.3.9.RELEASE.jar:4.3.9.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:347) ~[spring-context-4.3.9.RELEASE.jar:4.3.9.RELEASE]
    at org.springframework.boot.context.event.EventPublishingRunListener.finished(EventPublishingRunListener.java:101) ~[spring-boot-1.5.4.RELEASE.jar:1.5.4.RELEASE]
    at org.springframework.boot.SpringApplicationRunListeners.callFinishedListener(SpringApplicationRunListeners.java:79) ~[spring-boot-1.5.4.RELEASE.jar:1.5.4.RELEASE]
    at org.springframework.boot.SpringApplicationRunListeners.finished(SpringApplicationRunListeners.java:72) ~[spring-boot-1.5.4.RELEASE.jar:1.5.4.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:305) ~[spring-boot-1.5.4.RELEASE.jar:1.5.4.RELEASE]
    at sys.SysApplication.main(SysApplication.java:66) ~[classes/:?]
"><code>[ERROR] <span class="hljs-number">2019</span><span class="hljs-operator">-</span>07<span class="hljs-number">-18</span> <span class="hljs-number">11</span>:01:<span class="hljs-number">17.246</span> [main] SpringApplication <span class="hljs-operator">-</span> Application startup failed
org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): dao.IDataTypeDao.selectDataTypeList
    at org.apache.ibatis.binding.MapperMethod$SqlCommand.&#x3C;init<span class="hljs-operator">></span>(MapperMethod.java:<span class="hljs-number">225</span>) <span class="hljs-operator">~</span>[mybatis<span class="hljs-number">-3.4</span><span class="hljs-number">.4</span>.jar:<span class="hljs-number">3.4</span><span class="hljs-number">.4</span>]
    at org.apache.ibatis.binding.MapperMethod.&#x3C;init<span class="hljs-operator">></span>(MapperMethod.java:<span class="hljs-number">48</span>) <span class="hljs-operator">~</span>[mybatis<span class="hljs-number">-3.4</span><span class="hljs-number">.4</span>.jar:<span class="hljs-number">3.4</span><span class="hljs-number">.4</span>]
    at org.apache.ibatis.binding.MapperProxy.cachedMapperMethod(MapperProxy.java:<span class="hljs-number">65</span>) <span class="hljs-operator">~</span>[mybatis<span class="hljs-number">-3.4</span><span class="hljs-number">.4</span>.jar:<span class="hljs-number">3.4</span><span class="hljs-number">.4</span>]
    at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:<span class="hljs-number">58</span>) <span class="hljs-operator">~</span>[mybatis<span class="hljs-number">-3.4</span><span class="hljs-number">.4</span>.jar:<span class="hljs-number">3.4</span><span class="hljs-number">.4</span>]
    at com.sun.proxy.$Proxy161.selectDataTypeList(Unknown Source) <span class="hljs-operator">~</span>[?:?]
......
org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:<span class="hljs-number">167</span>) <span class="hljs-operator">~</span>[spring<span class="hljs-operator">-</span>context<span class="hljs-number">-4.3</span><span class="hljs-number">.9</span>.RELEASE.jar:<span class="hljs-number">4.3</span><span class="hljs-number">.9</span>.RELEASE]
    at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:<span class="hljs-number">139</span>) <span class="hljs-operator">~</span>[spring<span class="hljs-operator">-</span>context<span class="hljs-number">-4.3</span><span class="hljs-number">.9</span>.RELEASE.jar:<span class="hljs-number">4.3</span><span class="hljs-number">.9</span>.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:<span class="hljs-number">393</span>) <span class="hljs-operator">~</span>[spring<span class="hljs-operator">-</span>context<span class="hljs-number">-4.3</span><span class="hljs-number">.9</span>.RELEASE.jar:<span class="hljs-number">4.3</span><span class="hljs-number">.9</span>.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:<span class="hljs-number">347</span>) <span class="hljs-operator">~</span>[spring<span class="hljs-operator">-</span>context<span class="hljs-number">-4.3</span><span class="hljs-number">.9</span>.RELEASE.jar:<span class="hljs-number">4.3</span><span class="hljs-number">.9</span>.RELEASE]
    at org.springframework.boot.context.event.EventPublishingRunListener.finished(EventPublishingRunListener.java:<span class="hljs-number">101</span>) <span class="hljs-operator">~</span>[spring<span class="hljs-operator">-</span>boot<span class="hljs-number">-1.5</span><span class="hljs-number">.4</span>.RELEASE.jar:<span class="hljs-number">1.5</span><span class="hljs-number">.4</span>.RELEASE]
    at org.springframework.boot.SpringApplicationRunListeners.callFinishedListener(SpringApplicationRunListeners.java:<span class="hljs-number">79</span>) <span class="hljs-operator">~</span>[spring<span class="hljs-operator">-</span>boot<span class="hljs-number">-1.5</span><span class="hljs-number">.4</span>.RELEASE.jar:<span class="hljs-number">1.5</span><span class="hljs-number">.4</span>.RELEASE]
    at org.springframework.boot.SpringApplicationRunListeners.finished(SpringApplicationRunListeners.java:<span class="hljs-number">72</span>) <span class="hljs-operator">~</span>[spring<span class="hljs-operator">-</span>boot<span class="hljs-number">-1.5</span><span class="hljs-number">.4</span>.RELEASE.jar:<span class="hljs-number">1.5</span><span class="hljs-number">.4</span>.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:<span class="hljs-number">305</span>) <span class="hljs-operator">~</span>[spring<span class="hljs-operator">-</span>boot<span class="hljs-number">-1.5</span><span class="hljs-number">.4</span>.RELEASE.jar:<span class="hljs-number">1.5</span><span class="hljs-number">.4</span>.RELEASE]
    at sys.SysApplication.main(SysApplication.java:<span class="hljs-number">66</span>) <span class="hljs-operator">~</span>[classes<span class="hljs-operator">/</span>:?]
</code></pre><p>如上错误信息中 <code>org.apache.ibatis.binding.BindingException: Invalid bound statement (not found)</code>，但是在代码中结构如下 :</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/f904f6c2f43d06c02b04659ac278e8f802c5c086e0081564df275d3e22ced83e.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/e2a8c3c833cc12dba2fd191e0d04dabe0b2872e1f953318c9fc716ca3978d79f.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>在 IDEA 中代码导航，是可以找到相应的代码关联关系，难道是因为编译构建出来的 class 文件和 mapper 文件路径出现问题，导致 mapper 文件解析不到出现<code>方法</code>和 <code>mapper中的配置</code>没有关联。</p><p>接下来查看相应配置文件读取的 <code>mybatis mapper</code> 文件路径和 <code>build out</code> 文件，如下图：</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/25dd9956ebecab567fa8c25d85be1e2a816da7f6fc76d78deca8a620f881dfc7.png" alt="bootstrap.yml 配置信息" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">bootstrap.yml 配置信息</figcaption></figure><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/3b74b81f68a89f6d67bb8e9790240645b43945c4c3db18173d349e3382f62ad1.png" alt="具体 mapper 文件内容（路径查看蓝色背景文字）" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">具体 mapper 文件内容（路径查看蓝色背景文字）</figcaption></figure><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/fa49a8f26abfa0ccfffa57f82ff2b2d05badb03649a185eb75f1ee879828af88.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>根据上面逻辑梳理和图片证明，文件配置路径和编译后的环境信息是吻合的，但是项目运行时是没有解析到 mapper 文件。以上，确定了配置没有问题，只能 debug 代码排查原因。</p><h3 id="h-1debug" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">1.正向debug方法查询逻辑，寻找缺失信息</h3><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/8388fda583faa077e05f41a9aa9591a7b5bd2f4f0435c8abcc7e8eba6c9fe00b.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/e76242b4587ac55a9d06d2eea3425680d31cb947927c6d41d9ec09d08b66eae8.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/1a925e90bb8530655fba0972eccbc66559e2707c2833e2bb7f364dc08f88d017.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><h3 id="h-2-debug-configuration-mapperregistry-debug-mapper-configuration" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">2. 根据正向 debug，发现 Configuration 中并没有 mapperRegistry。反向推断，准备 debug 解析 mapper 文件相关代码，创建 Configuration的代码过程</h3><p>通过代码搜索，查找到，获取配置文件代码如下图：</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/15daaeccf09bb463204255402d8c4e3efbdc3e6a41dfa34ae76cf205ebe766ef.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><h3 id="h-3-path-oracle" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">3.添加条件断点，当 path 中包含 oracle 中，断点生效</h3><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/5243c1dbebaaf837edc2e25606b080e427b0c371b84155a3067db99ddbbad1e2.jpg" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><h3 id="h-4-debug" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">4.如下动图是具体 debug 记录</h3><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/96563ddc47033d09be0cf1f07c4c0f31b2fe80da5df15db1f0e8151c54e520d7.gif" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><h3 id="h-5-url-jdk-jar" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">5.最终获取的 URL 路径如下图，是一个 JDK 自带 jar 包</h3><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/2356bd2a1925640f71f4d80a6608225cb0e6fb774aa61603dcee9cbb220c6e0f.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><h3 id="h-6-jar-oracle-classloader-jar" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">6. 查看路径 jar 包中文件，其中确实包含了 oracle 文件夹，导致ClassLoader 加载到了这个 jar 对应的路径</h3><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/d120ac60fe19216d75f3325b59cbdc7de7bb6346b52bc9dc9fcae92eacca5252.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>为了快速解决项目问题，统一将 <code>mapper 文件路径添加 mybatis</code> 前缀，这样 ClassLoader 搜索最终会使用 <code>APPClassLoader</code> 定位到 class/resource 路径下的 <code>mybatis/oracle/*.xml</code></p><p>以上方式是解决了项目问题，仍然遗留一个问题：在 macOS jdk1.8.0_162 版本下 ExtClassLoader 加载到了 jar 文件路径。</p><p>测试：</p><blockquote><ul><li><p>1.7版本下会获取到 resource 路径（原因是因为 sa-jdi.jar 中不包含 oracle 路径）</p></li><li><p>1.9版本下会获取到 resource 路径，但是 sa-jdi.jar 中包含 oracle！（疑惑！！！）</p></li><li><p>TODO : 了解相应源码查看原因</p></li></ul></blockquote><p>1.9 之前JDK自带 ClassLoader 分为三种</p><blockquote><ul><li><p>Bootstrap ClassLoader 加载 rt.jar</p></li></ul></blockquote><blockquote><ul><li><p>ExtClassloader 加载 lib/ext 下的 class</p></li></ul></blockquote><blockquote><ul><li><p>APPClassLoader 加载 <code>-cp</code> 指定的类</p></li></ul></blockquote><p>1.9 引入了 module 概念。 ClassLoader 也发生了改变</p><blockquote><ul><li><p>Bootstrap ClassLoader</p></li></ul></blockquote><blockquote><ul><li><p>Platform ClassLoader</p></li></ul></blockquote><blockquote><ul><li><p>AppClassLoader</p></li></ul></blockquote><p>[参考资料]  <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://www.ibm.com/developerworks/cn/java/j-lo-classloader/index.html">深入探讨 Java 类加载器</a></p>]]></content:encoded>
            <author>lua@newsletter.paragraph.com (OutOfToken)</author>
        </item>
        <item>
            <title><![CDATA[数据源不懂的配置请使用默认值]]></title>
            <link>https://paragraph.com/@lua/ZMT4YBuerCeWl8PAoV6Z</link>
            <guid>ZMT4YBuerCeWl8PAoV6Z</guid>
            <pubDate>Mon, 10 Jan 2022 10:33:47 GMT</pubDate>
            <description><![CDATA[TL;NR:请按照HikariCP官方推荐进行配置数据库连接池dataSource.cachePrepStmts=true dataSource.prepStmtCacheSize=250 dataSource.prepStmtCacheSqlLimit=2048 dataSource.useServerPrepStmts=true dataSource.useLocalSessionState=true dataSource.rewriteBatchedStatements=true dataSource.cacheResultSetMetadata=true dataSource.cacheServerConfiguration=true dataSource.elideSetAutoCommits=true dataSource.maintainTimeStats=false 背景信息介绍:公司的项目部门使用我们研发中心的框架进行产品开发,再使用动态数据源进行数据库操作的时候出现两种奇怪的现象:相同的 sql 语句「一种写法是 navicat 格式化后的语句(字符较多), ...]]></description>
            <content:encoded><![CDATA[<h3 id="h-tlnr" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">TL;NR:</h3><p><code>请按照HikariCP官方推荐进行配置数据库连接池</code></p><pre data-type="codeBlock" text="dataSource.cachePrepStmts=true
dataSource.prepStmtCacheSize=250
dataSource.prepStmtCacheSqlLimit=2048
dataSource.useServerPrepStmts=true
dataSource.useLocalSessionState=true
dataSource.rewriteBatchedStatements=true
dataSource.cacheResultSetMetadata=true
dataSource.cacheServerConfiguration=true
dataSource.elideSetAutoCommits=true
dataSource.maintainTimeStats=false
"><code><span class="hljs-attr">dataSource.cachePrepStmts</span>=<span class="hljs-literal">true</span>
<span class="hljs-attr">dataSource.prepStmtCacheSize</span>=<span class="hljs-number">250</span>
<span class="hljs-attr">dataSource.prepStmtCacheSqlLimit</span>=<span class="hljs-number">2048</span>
<span class="hljs-attr">dataSource.useServerPrepStmts</span>=<span class="hljs-literal">true</span>
<span class="hljs-attr">dataSource.useLocalSessionState</span>=<span class="hljs-literal">true</span>
<span class="hljs-attr">dataSource.rewriteBatchedStatements</span>=<span class="hljs-literal">true</span>
<span class="hljs-attr">dataSource.cacheResultSetMetadata</span>=<span class="hljs-literal">true</span>
<span class="hljs-attr">dataSource.cacheServerConfiguration</span>=<span class="hljs-literal">true</span>
<span class="hljs-attr">dataSource.elideSetAutoCommits</span>=<span class="hljs-literal">true</span>
<span class="hljs-attr">dataSource.maintainTimeStats</span>=<span class="hljs-literal">false</span>
</code></pre><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">背景信息介绍:</h3><p>公司的项目部门使用我们研发中心的框架进行产品开发,再使用动态数据源进行数据库操作的时候出现两种奇怪的现象:</p><ul><li><p>相同的 sql 语句「一种写法是 navicat 格式化后的语句(字符较多), 一种写法是单行压缩的语句(字符较短)」,两种语句在<code>正确执行SQL语句</code> <code>+ java逻辑代码进行处理的时候出现异常</code> 两个条件下,执行结果是不同的.</p><ul><li><p>正确期望 : 出现异常,两种写法语句对应的整个事务回滚,数据库无新增数据.</p></li><li><p>错误现象 :</p><ul><li><p>长语句事务不回滚,不符合预期</p></li><li><p>短语句事务回滚,符合预期</p></li></ul></li></ul></li><li><p>一个mybatis的语句包含多个insert(比如执行三个 insert into tablename values)操作,如果中途的语句出现表名错误、字段名称不存在等原因导致sql执行失败</p><ul><li><p>正确期望 : 出现异常,整个事务回滚,数据库无新增数据.</p></li><li><p>错误现象 : 事务是不回滚,数据部分插入成功</p></li></ul></li></ul><p>最小化测试代码请参考:</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/HugePages/troubles">https://github.com/HugePages/troubles</a></p><p>代码时序图:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/7b35542d1650b37fcf73038699da8b033e3cfdbb6b3aa4a6e0cc680164a36df8.png" alt="主体代码时序图" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">主体代码时序图</figcaption></figure><hr><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">现象复现 :</h3><h4 id="h-sql-sql-2048" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">📍 执行不同长度的 sql 语句,当 sql 长度小于2048,事务正常回滚</h4><h4 id="h-http1270018080demoinsert-rollbacktype1andexception1" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">发起请求 <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="http://127.0.0.1:8080/demo/insert-rollback?type=1&amp;exception=1">http://127.0.0.1:8080/demo/insert-rollback?type=1&amp;exception=1</a></h4><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/290fd0c3717e1b6b61cef10329a17b624635179c6f855ee2928d35745e51f340.png" alt="type 为 1" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">type 为 1</figcaption></figure><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="http://127.0.0.1:8080/demo/insert-rollback?type=1&amp;exception=1">http://127.0.0.1:8080/demo/insert-rollback?type=1&amp;exception=1</a></p><p>查看 Wireshark 对应 mysql 协议的监控如图:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/dc48c5569772c235e061ae2d442d50f57ba793fd0e2404a1f8e34b21b7a4fef5.png" alt="sql 语句执行 insert1 语句(不超过配置项2048长度)" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">sql 语句执行 insert1 语句(不超过配置项2048长度)</figcaption></figure><p>此时,代码执行符合预期 : 出现异常, spring 的事务管理正常,执行 rollback 操作,数据库没有新数据插入:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/6340915e460d3ec82bdf227c08770efcda5c808334c3357bbf33b1bc2ceecca0.png" alt="查询数据库结果,数量为0" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">查询数据库结果,数量为0</figcaption></figure><hr><h4 id="h-sql-sql" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">📍 执行不同长度的 sql 语句,当 sql 太长,导致事务不回滚</h4><h4 id="h-http1270018080demoinsert-rollbacktype0andexception1" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">发起请求 <a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="http://127.0.0.1:8080/demo/insert-rollback?type=0&amp;exception=1">http://127.0.0.1:8080/demo/insert-rollback?type=0&amp;exception=1</a></h4><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/c289792ddfe8151cee2176263feb127607c262d400b7dbd65e3a7a265ad5ece6.png" alt="type 为 0" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">type 为 0</figcaption></figure><p>查看Wireshark 对应 mysql 协议的监控如图:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/975b8ee0babe412fd041536dd97f9201dc5b72c07f058f53bdb380cae93b1ed7.png" alt="此时的 mysql 协议多了一个请求,Close Statement" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">此时的 mysql 协议多了一个请求,Close Statement</figcaption></figure><p>通过 debug,事务也是交由 spring 进行管理,也执行了 rollback 操作,但是最终数据还是插入到数据库中:</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/ca8ec66fbd6209a3a4f02cf380405ff432a7ea0ec9f41fe3ded9453c20761ef2.png" alt="数据插入成功" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">数据插入成功</figcaption></figure><p>结合上述的现象,只能怀疑是因为数据库sql长度导致,排查hikari的配置项,修改</p><pre data-type="codeBlock" text="spring.datasource.hikari.data-source-properties.useServerPrepStmts=true
spring.datasource.hikari.data-source-properties.prepStmtCacheSize=250
spring.datasource.hikari.data-source-properties.prepStmtCacheSqlLimit=200
"><code>spring.datasource.hikari.data-source<span class="hljs-operator">-</span>properties.useServerPrepStmts=<span class="hljs-literal">true</span>
spring.datasource.hikari.data-source<span class="hljs-operator">-</span>properties.prepStmtCacheSize=<span class="hljs-number">250</span>
spring.datasource.hikari.data-source<span class="hljs-operator">-</span>properties.prepStmtCacheSqlLimit=<span class="hljs-number">200</span>
</code></pre><p>修改为 <code>prepStmtCacheSqlLimit=2048</code>,再次重复之前的测试,均进行正常回滚.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/8a43e8fdf043a005426103c009d0c6a8775769106528931f49cb53177fb5fc03.png" alt="测试不同配置导致的结果分支" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">测试不同配置导致的结果分支</figcaption></figure><hr><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">原因分析</h3><p>追踪代码发现 rollback 之前, Statement 已经 close.</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/4794f121c238c7b2b801cdb4e35248a60fe8155cb99683e4412fef0e74634629.png" alt="断点执行到 rollbackNoChecks() 时 ,wireshark监控到已经发送了close请求" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">断点执行到 rollbackNoChecks() 时 ,wireshark监控到已经发送了close请求</figcaption></figure><p>因为 serverPrepareStatement 进行缓存,但是超过了 sqllimit 的大小, 就调用了realclose方法,进行 statement 的释放</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/e396001175e6c2932d97b1fe6658ddb1a5733ca4011f9174bc7d578250d70a86.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/d0bf942e56f148135e8e73b2350f3b9796c591a80f6d3fd68c00000bfb3431ff.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p><strong>关键步骤:</strong> 发送了 Close() 方法,收到响应,设置 transcationInserver 的 statusFlag 为0</p><p>⚠️ 注意,如果执行的 sql 语句存在异常,这个值会在最后抛异常的时候,获取当前事务在服务端状态</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/aee39cd1953d4a20ffa53a03b7d304fc3eaeca1da3a977ae146d1e0b6eaeaa3b.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><p>最后判断是否执行 rollback 的时候, 直接 return //no-op,不发送 rollback 指令给 mysql server</p><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/15af9adaece7c34c49788a1fae4ec99de439caf9d2f056754780963eb1464e50.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><h4 id="h-2022-0117" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">补充代码执行大致流程 @2022-0117</h4><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/a19e0e906489aacfa1fdabf2ac69bba6945b9efe298ad3299f524abcf361157e.png" alt="" blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="hide-figcaption"></figcaption></figure><hr><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">参考资料如下:</h3><p><strong>transactions-are-not-getting-rollbacked-with-hikaricp</strong></p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://stackoverflow.com/questions/50234214/transactions-are-not-getting-rollbacked-with-hikaricp">https://stackoverflow.com/questions/50234214/transactions-are-not-getting-rollbacked-with-hikaricp</a></p><p><strong>HikariCP 的 MySQL-Configuration</strong></p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/brettwooldridge/HikariCP/wiki/MySQL-Configuration">https://github.com/brettwooldridge/HikariCP/wiki/MySQL-Configuration</a></p><p><strong>官方 bug 介绍 ( 网页内搜索 「Bug #20212882, Bug #75209」)</strong></p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://dev.mysql.com/doc/relnotes/connector-j/5.1/en/news-5-1-40.html">https://dev.mysql.com/doc/relnotes/connector-j/5.1/en/news-5-1-40.html</a></p><p><strong>官方文档 (5.3.5 Performance Extensions)</strong></p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://dev.mysql.com/doc/connector-j/5.1/en/connector-j-connp-props-performance-extensions.html">https://dev.mysql.com/doc/connector-j/5.1/en/connector-j-connp-props-performance-extensions.html</a></p><p>sql 监控组件 p6spy</p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://github.com/p6spy/p6spy">https://github.com/p6spy/p6spy</a></p><p><strong>Connection 和 Transaction</strong></p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://docstore.mik.ua/orelly/weblinux2/mysql/ch08_02.htm">https://docstore.mik.ua/orelly/weblinux2/mysql/ch08_02.htm</a></p><h4 id="h-" class="text-xl font-header !mt-6 !mb-3 first:!mt-0 first:!mb-0">扩展阅读:</h4><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://blog.csdn.net/yyb_gz/article/details/108428442?spm=1001.2014.3001.5501">Mysql Connector/J 源码分析（普通 Connection）</a></p><p><a target="_blank" rel="noopener noreferrer nofollow ugc" class="dont-break-out" href="https://cloud.tencent.com/developer/article/1710665">如果 MySQL 事务中发生了网络异常？</a></p><h3 id="h-" class="text-2xl font-header !mt-6 !mb-4 first:!mt-0 first:!mb-0">总结:</h3><pre data-type="codeBlock" text="公司的开发框架已经发布4年了, 使用次框架开发的产品、项目近百个从来没有遇到过此类问题.

平时的产品项目都会遵守一些分层、数据库使用规范,所以基本很难触发此问题.这次也是项目的开发在设计分层、接口功能拆分、SQL使用等方案不规范导致,没有严格遵守设计原则和开发规范.

此外,框架研发团队在使用开源组件的时候,尽量减少默认参数配置,把参数配置的能力暴露给框架的使用者,特别是所开发的功能作为团队中最基础的公用服务.
"><code>公司的开发框架已经发布<span class="hljs-number">4</span>年了, 使用次框架开发的产品、项目近百个从来没有遇到过此类问题.

平时的产品项目都会遵守一些分层、数据库使用规范,所以基本很难触发此问题.这次也是项目的开发在设计分层、接口功能拆分、SQL使用等方案不规范导致,没有严格遵守设计原则和开发规范.

此外,框架研发团队在使用开源组件的时候,尽量减少默认参数配置,把参数配置的能力暴露给框架的使用者,特别是所开发的功能作为团队中最基础的公用服务.
</code></pre><figure float="none" data-type="figure" class="img-center" style="max-width: null;"><img src="https://storage.googleapis.com/papyrus_images/3c9cac8e1beb67e3065f3351726b23400f0fbe4ad8183c0e592f0fd5cae465ea.png" alt="🌚 我猜测开发者直接网上在某些博客拷贝了对应的配置信息." blurdataurl="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=" nextheight="600" nextwidth="800" class="image-node embed"><figcaption HTMLAttributes="[object Object]" class="">🌚 我猜测开发者直接网上在某些博客拷贝了对应的配置信息.</figcaption></figure>]]></content:encoded>
            <author>lua@newsletter.paragraph.com (OutOfToken)</author>
            <enclosure url="https://storage.googleapis.com/papyrus_images/2ee510cf4614202f4eacf19f924023e35f0bf97e0f35469c1ece1e8a970390dc.png" length="0" type="image/png"/>
        </item>
    </channel>
</rss>