@ethereumjs/trie (英语)
| 执行《公约》 修改后的梅克勒·帕特里夏·特里 一、导 言 黄纸 |
|---|
已修改的Merkle Patricia树(trie)提供了一个持续的数据结构来映射任意长的二进制数据(字节数组). 它被定义为可变数据结构来映射出256位二元碎片和任意长二元数据之间的相去. 三相体的核心,以及它在协议规格方面的唯一要求,是提供一个单一的32字节值,以识别出一组特定的键值对.
安装
要获得最新版本,只需使用 npm数字 :
npm install @ethereumjs/trie
使用量
此类执行基本 修改后的梅克勒·帕特里夏·特里 输入 Trie 基础类,您可以使用 useKeyHashing 选项设置为 true 创建三进制,将值存储在 keccak256 它的散列键(这是Ethereum生产系统中使用的Trie口味).
检查功能到 Trie 通过方法 checkpoint, (中文(简体) ), commit 财务报告和审定财务报表 revert。 。 。 .
最好选择最适合您独有的用例的变体 .
初始化和基本使用
// ./examples/basicUsage.ts
import { Trie } from '@ethereumjs/trie'
import { bytesToUtf8, MapDB, utf8ToBytes } from '@ethereumjs/util'
async function test() {
const trie = await Trie.create({ db: new MapDB() })
await trie.put(utf8ToBytes('test'), utf8ToBytes('one'))
const value = await trie.get(utf8ToBytes('test'))
console.log(value ? bytesToUtf8(value) : 'not found') // 'one'
}
test()
WASM 加密支持
这个库默认使用 JavaScript 执行,用于像散列键一样的基本标准加密原始. 见 @ethereumjs/common 读取 如何使用共享的WASM执行器等 common 举个例子.
使用静态构造器
创建新 Trie
// ./examples/basicUsage.ts
import { Trie } from '@ethereumjs/trie'
import { bytesToUtf8, MapDB, utf8ToBytes } from '@ethereumjs/util'
async function test() {
const trie = await Trie.create({ db: new MapDB() })
await trie.put(utf8ToBytes('test'), utf8ToBytes('one'))
const value = await trie.get(utf8ToBytes('test'))
console.log(value ? bytesToUtf8(value) : 'not found') // 'one'
}
test()
当静态 Trie.create 构造器在没有任何选项的情况下使用 trie 对象被即时化,并配置出与Ethereum生产谱相匹配的默认值(即密钥被用 SHA256 散列)。 它也坚持树的状态根在每次写入操作上,确保您下次启动应用程序时的三进制保留在您离开的状态.
从一个证明创建
三进制库支持基本创建 EIP-1186 (英语) 证据以及从现有证据中即兴尝试.
下面是使用该软件的例子 Trie.createFromProof() 静态构造器。 这只根据所提供的证据中包含的三者分支,即刻宣布一个新的部分三者.
// ./examples/createFromProof.ts
import { Trie } from '@ethereumjs/trie'
import { bytesToUtf8 } from '@ethereumjs/util'
import { utf8ToBytes } from 'ethereum-cryptography/utils'
async function main() {
const k1 = utf8ToBytes('keyOne')
const k2 = utf8ToBytes('keyTwo')
const someOtherTrie = new Trie({ useKeyHashing: true })
await someOtherTrie.put(k1, utf8ToBytes('valueOne'))
await someOtherTrie.put(k2, utf8ToBytes('valueTwo'))
const proof = await someOtherTrie.createProof(k1)
const trie = await Trie.createFromProof(proof, { useKeyHashing: true })
const otherProof = await someOtherTrie.createProof(k2)
// To add more proofs to the trie, use `updateFromProof`
await trie.updateFromProof(otherProof)
const value = await trie.get(k1)
console.log(bytesToUtf8(value!)) // valueOne
const otherValue = await trie.get(k2)
console.log(bytesToUtf8(otherValue!)) // valueTwo
}
main()
关于进一步的证据使用文件,见下文其他文件部分.
走着走着
从v6发布开始,有一个新的API用于行走并使用Aync行走生成器来活取一个三行,现在它能够行走尝试而无需改变行走控制器,现在也能够行走一个稀疏的(没有完全填满)三行.
新的行走功能可以使用如下:
// ./examples/trieWalking.ts
import { Trie } from '@ethereumjs/trie'
import { utf8ToBytes } from 'ethereum-cryptography/utils'
async function main() {
const trie = await Trie.create()
await trie.put(utf8ToBytes('key'), utf8ToBytes('val'))
const walk = trie.walkTrieIterable(trie.root())
for await (const { node, currentKey } of walk) {
// ... do something
console.log({ node, currentKey })
}
}
main()
Trie 配置选项
数据库选项
这个 DB 选择在 TrieOpts 允许您使用符合 DB 用于存储 tree 数据的界面。 我们提供几个 实例 数据库执行。 这个 职等.js 示例在 ethereumjs client 时 (日语) 是一种使用大众 语言数据库 作为其基础数据库.
若无 db 选项,由 一个 Javascript 地图 将履行这一角色(从 @ethereumjs/util,参见 映射数据库 页:1.
如果您想要使用替代数据库,可以通过写一个符合 DB 接口 (单位:千美元) @ethereumjs/util) (中文(简体) ). 这个 DB 界面定义方法 get, (中文(简体) ), put, (中文(简体) ), del, (中文(简体) ), batch 财务报告和审定财务报表 copy 具体落实《公约》 DB 接口需要执行.
级别DB
举个例子,利用 LevelDB 用于所有操作时,您应该创建文件 执行我们的食谱 在你的项目。 然后将您的 DB 和 trie 分解如下:
// ./examples/customLevelDB.ts#L127-L131
async function main() {
const trie = new Trie({ db: new LevelDB(new Level('MY_TRIE_DB_LOCATION') as any) })
console.log(await trie.database().db) // LevelDB { ...
}
main()
节点删除( 运行)
默认情况下,从基础数据库中删除三相节点并不会发生,以避免老三相状态腐败(截至 v4.2.0) (中文(简体) ). 如果您只希望与 trie 的最新状态合作, 您可以使用 : useNodePruning 构造器选项(详见更改日志中的相关释放注释).
根持久性
您可以通过设置 useRootPersistence 选项到 true 当建造一个三角穿行 Trie.create 函数。 因此,这个值在创建trie副本时被保存,一旦一个trie被即时修改后就无法被修改.
// ./examples/rootPersistence.ts
import { Trie } from '@ethereumjs/trie'
import { bytesToHex } from '@ethereumjs/util'
async function main() {
const trie = await Trie.create({
useRootPersistence: true,
})
// this logs the empty root value that has been persisted to the trie db
console.log(bytesToHex(trie.root())) // 0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421
}
main()
证据
默克勒证明
这个 createProof 财务报告和审定财务报表 verifyProof 函数允许您验证某个值是否存在于 Merkle Patricia 内 有给定根树.
列入证明
以下代码演示了如何构建并随后验证证实密钥存在的证据 test (与值相对应) one)在给定之三. 这也被称为"包容",因此名称为"Proof-of-incluation"
// ./examples/proofs.ts#L12-L16
// proof-of-inclusion
await trie.put(k1, v1)
let proof = await trie.createProof(k1)
let value = await trie.verifyProof(trie.root(), k1, proof)
console.log(value ? bytesToUtf8(value) : 'not found') // 'one'
排除证明
以下代码演示了如何构建并随后验证证实钥匙的证据 test3 不存在在给定的三进制中。 这也被称为排斥,因此取名"Proof-exclusion"
// ./examples/proofs.ts#L18-L23
// proof-of-exclusion
await trie.put(k1, v1)
await trie.put(k2, v2)
proof = await trie.createProof(utf8ToBytes('key3'))
value = await trie.verifyProof(trie.root(), utf8ToBytes('key3'), proof)
console.log(value ? bytesToUtf8(value) : 'null') // null
无效的证明
若为 verifyProof 检测无效的证明,它会丢出错误。 下面的例子说明了在一次验证器篡改了元数据时所产生的错误条件.
// ./examples/proofs.ts#L25-L34
// invalid proof
await trie.put(k1, v1)
await trie.put(k2, v2)
proof = await trie.createProof(k2)
proof[0].reverse()
try {
const value = await trie.verifyProof(trie.root(), k2, proof) // results in error
} catch (err) {
console.log(err)
}
范围证明
你可以用这个 Trie.verifyRangeProof() 函数来确认给定的叶子节点和边缘证明是否具有证明给定的三叶树叶范围与特定根相匹配的能力(例如,这有利于同步).
实例
您可以在详细解释后找到补充实例 这里。 。 。 .
浏览器
随着2023年夏季的断开发行回合,我们增加了混合无害环境管理/CJS,用于我们所有图书馆(见下文一节),并取消了以前阻止使用无摩擦浏览器的许多警告.
现在很容易在现代浏览器内运行一个EthereumJS图书馆的浏览器构建,使用所提供的无害环境管理构建。 关于设置的例子,见 ./例/浏览器.html。 。 。 .
API 密码
文档
生成类型Doc API 文档
混合 CJS/ESM 构建
随着2023年夏季发行的中断,我们开始将我们的图书馆与两个共同JS(共同JS)一起运送cjs 和建立无害环境管理esm 文件夹,参见 package.json 为详细设置.
如果你使用ES6型的话 import 将在您来自无害环境管理架构的代码文件中使用:
import { EthereumJSClass } from '@ethereumjs/[PACKAGE_NAME]'
如果您使用 Node.js 特定 require,CJS建筑将使用:
const { EthereumJSClass } = require('@ethereumjs/[PACKAGE_NAME]')
使用无害环境管理将比CJS给您更多的优势,超出浏览器的使用范围,如静态代码分析/树摇,CJS无法提供.
缓冲 - > Uint8 阵列
随着2023年夏天的解禁 我们取消了所有节点 Buffer 我们图书馆的用法,取而代之 Uint8 阵列 表示式,在Node.js和浏览器中都可以使用(Buffer 是一个子类 Uint8Array) (中文(简体) ).
我们已经将现有的缓冲转换方法转换为 Uint8Array 转换方法 @ethereumjs/用户 bytes 模块中,请参见相应的 README 部分.
BigInt 支持
BigInt是一种原始的,用来代表并操纵原始的 bigint 数值,原始数字因其数值而不能表示. ES2020 报告介绍了这一特点。 请注意,这一版本更新导致与数字相关的API签名被更改,最低构建目标现在设定为: ES2020。 。 。 .
基准制定
你会发现两个简单的 基准 输入 benchmarks 文件夹 :
random.ts随机运行PUT在树上操作,以及checkpointing.ts管理检查站,并犯PUT业务
还正在考虑第三个基准,利用主网数据模拟实际负荷.
您可以使用下列方法运行基准:
npm run benchmarks
运行一个 剖析器 编辑 random.ts 基准和生成火焰图 0个,您可以使用:
npm run profiling
0x 处理堆栈并生成一个 profile 文件夹(<pid>.0x包含 flamegraph.html。 。 。 .
调试
这个 Trie 类特性可选调试日志... 单个调试选择可在 CL 上激活 DEBUG=ethjs,[Logger Selection]。 。 。 .
ethjs 必须 列入 DEBUG 启用的环境变量 任意 木头.
附加的日志选择可以用逗号分隔列表来添加(没有空格). 带有扩展名的日志可以用冒号启用 :,以及 * 可用于包含所有扩展.
DEBUG=ethjs,thislog,thatlog,otherlog,otherlog:sublog,anotherLog:* node myscript.js
有以下备选方案:
| 锁定器 | 说明 |
|---|---|
trie | 所有 tree 方法的最小信息记录 |
trie:<METHOD> | 特定 tree 方法的调试记录 |
trie:<METHOD>:* | 特定 tree 方法的动词调试记录 |
trie:* | 所有 tree 方法的动词调试记录 |
观察不同级别的伐木情况:
最小记录运行 :
DEBUG=ethjs,trie npx vitest test/util/log.spec.ts
运行 设置 方法记录 :
DEBUG=ethjs,trie:PUT npx vitest test/util/log.spec.ts
运行 三进制 + 键 设置编号 :起来编号 :三角形 日志 :
DEBUG=ethjs,trie,trie:PUT,trie:GET,trie:DEL npx vitest test/util/log.spec.ts
运行 查找路径 调试日志 :
DEBUG=ethjs,trie:FIND_PATH npx vitest test/util/log.spec.ts
运行 查找路径 动词记录 :
DEBUG=ethjs,trie:FIND_PATH:* npx vitest test/util/log.spec.ts
使用最大记录运行 :
DEBUG=ethjs,trie:* npx vitest test/util/log.spec.ts
参考资料
- 维基
- 博客文章
- 伊特鲁姆的"梅克勒·帕特里夏树"——互动的JavaScript教程
- 默克林在伊特鲁姆
- 了解伊特鲁姆三重奏 (这是值得阅读的,但请注意过时的 Python 库)
- 视频
爱丽丝
看我们的组织 文档 介绍 EthereumJS 以及关于现行标准和最佳做法的资料。 如果你想参加工作或改进图书馆,请审查我们 捐款准则 先说.