5

我正在编写一个脚本来收集所有比特币块的哈希值。程序 bitcoind,如果更改了某个设置,会将所有块的元数据存储在 LevelDB 数据库中。每组元数据的键是块的哈希,通常用作它的标识符。本质上,我试图从每个块中获取元数据的特定部分(事务 ID)。我正在编写的脚本是在 Haskell 中编写的,尽管如果需要,我总是可以执行 shell 命令。概括地说我的问题,我不确定最简单的方法是否是找到所有块哈希(密钥),然后调用 bitcoind 来获取每个块的元数据。如果有任何方法可以直接从 LevelDB 数据库中获取每个值,那也可以。最简单有效的方法是什么?

4

2 回答 2

5

我不确切知道如何使用 haskell 完成此操作,但使用 C++ 执行此操作的最有效方法是使用 leveldb::Iterator 并迭代整个键范围

0x00000000 -> 0xFFFFFFFF(32 位密钥)
0x0000000000000000 -> 0xFFFFFFFFFFFFFFFF(64 位密钥)

示例

leveldb::Slice start = ...; // 0x00000000
leveldb::Slice end = ...; // 0xFFFFFFFFFFFFFFFF

该示例显示,当您迭代时,可以加载键和值:

leveldb::Slice key = it->key();
leveldb::Slice value = it->value();

由于您不关心值,您可以跳过查询的部分it->value(),只需收集您需要的键(在本例中为所有键),您应该会很好。我不会担心不必要地加载值对性能的影响。

然而,这里要注意一件大事:在 bitcoind 运行时你不能这样做!!!

出现这种情况的原因是因为在任何给定时间只能打开一个级别 DB 的实时实例,并且 bitcoind 很可能已经保持该 db 实例打开,尝试打开另一个实例(即使只是为了读取)将导致一个错误。您可以获取数据库的快照并迭代快照。快照允许您保证 bitcoind 的最短停机时间。

最后,如果您无法承受您的 bitcoind 客户端的任何停机时间,那么您可能需要为 bitcoind 或 leveldb 编写一个包装器。您将不得不在某处引入抽象级别。

围绕bitcoind的包装:

  1. 在制作快照时关闭 bitcoind。
  2. 缓冲对 bitcoind 的任何请求,直到您完成快照。
  3. 再次启动比特币。

包装 leveldb:

围绕级别 db 的包装有点困难,您必须保持对数据库实例的控制,并且您必须实际进入并修改 bitcoind 代码,然后构建 bitcoind 并运行它。

于 2013-06-10T15:23:48.313 回答
0

如果有任何方法可以直接从 LevelDB 数据库中获取每个值,那也可以。最简单有效的方法是什么?

leveldb doc这是使用 c++ 从 leveldb 数据库中获取所有键和值的方法。

#include <cassert>
#include "leveldb/db.h"
#include <iostream>
using namespace std;

void get_all_data() {
  leveldb::DB* db;
  leveldb::Options options;
  options.create_if_missing = true;

  // open the database
  leveldb::Status status = leveldb::DB::Open(options, "/tmp/testdb", &db);
  assert(status.ok());
  
  // iterate all keys and values
  leveldb::Iterator* it = db->NewIterator(leveldb::ReadOptions());
  for (it->SeekToFirst(); it->Valid(); it->Next()) {
    cout << it->key().ToString() << ": "  << it->value().ToString() << endl;
  }
  assert(it->status().ok());  // Check for any errors found during the scan
  delete it;

  // When you are done with a database, just delete the database object.
  delete db;
}
于 2022-02-15T08:43:43.460 回答