Blockchain

分析海量區塊鏈數據

  • November 23, 2022

我正在嘗試查看過去 4 年比特幣區塊鏈上每個區塊的所有交易數據。每個區塊幾乎有 2k 筆交易,每個區塊將需要大量查詢。我有一個在本地執行的完整節點,我嘗試了兩種方法:

帶有 RPC 的 Python:這非常慢並且在一段時間後不斷失去連接 (httpx.ReadTimeout)

帶有 os.popen 命令的 Python:沒有連接問題,但仍然很慢。

還有別的辦法嗎?關於如何分析來自區塊鏈的批量數據有什麼建議嗎?考慮到所需的時間,上面列出的方法是不可行的。

編輯:問題不是記憶體,而是比特幣節點回答查詢所花費的時間。

每個區塊幾乎有 2k 筆交易,每個區塊將需要大量查詢。

getblockRPC支持一個參數,該verbosity=2參數將塊中的所有交易作為 JSON 對象返回,因此您可以對每個塊進行一次查詢。

使用RPC 批處理(即在單個請求中發送多個命令),您可以做得更好!您可以僅使用 2 個 RPC 請求查詢塊的事務n:一個用於獲取所有塊雜湊,一個用於獲取塊(帶有事務)。下面的程式碼片段展示瞭如何實現這兩種方法,並包含一個簡單的性能基準。在我的機器上,批處理方法在查詢前 2000 個塊時快了約 13 倍。

一個範例 Python 實現,如果出現以下情況,它應該開箱即用:

  • requests已安裝 ( pip3 install requests)
  • bitcoind -signet -rpcuser=user -rpcpassword=pass
import json
import time
from typing import List

import requests


def get_n_blockhashes(n: int, start_height: int = 0):
   data = [{
       "method": "getblockhash",
       "params": [height]
   } for height in range(start_height, start_height + n)]
   hashes = [item["result"] for item in make_request(data)]
   return hashes


def get_block_transactions_single(block_hashes: List[str]):
   transactions = []
   for block_hash in block_hashes:
       data = {
           "method": "getblock",
           "params": [block_hash, 2]
       }
       block_data = make_request(data)["result"]
       transactions.append(block_data["tx"])

   return transactions


def get_block_transactions_batch(block_hashes: List[str]):
   data = [
       {
           "method": "getblock",
           "params": [block_hash, 2]
       } for block_hash in block_hashes
   ]
   transactions = [item["result"]["tx"] for item in make_request(data)]

   return transactions


def make_request(data):
   url = "http://user:pass@127.0.0.1:38332/"
   r = requests.post(url, data=json.dumps(data))
   assert r.status_code == 200
   return r.json()


def time_function(fn, *args: str, **kwargs) -> float:
   """Return average fn time execution and check that the last obtained blockheader hash matches last_hash_check """
   iters = 5
   start = time.perf_counter()
   for i in range(iters):
       fn(*args, **kwargs)
   avg_duration = (time.perf_counter() - start) / iters
   return avg_duration


if __name__ == '__main__':
   block_hashes = get_n_blockhashes(2000)
   print(f"single: {time_function(get_block_transactions_single, block_hashes):.4f}s")
   print(f"batch: {time_function(get_block_transactions_batch, block_hashes):.4f}s")

我認為最快的方法是按順序處理所有 blkNNNNN.dat 文件,並在記憶體中保留一個事務雜湊表 -> 塊時間戳。

您可以僅使用散列的前 64 位/8 字節作為索引來縮小該表。我將parallel-hashmap用於快速記憶體索引。

然後對於每筆交易,您可以查找輸入的塊時間戳,並從目前塊的時間戳中減去它。… 並根據需要計算您的統計數據。

我認為在現代筆記型電腦上處理整個區塊鏈需要幾個小時,區塊鏈儲存在 SSD 上。

我認為您需要大約 64G 的 RAM。這至少對我有用。…我查了一下:目前有將近 800M 個 txns,因此對於一個包含 16 字節條目的表,您需要大約 13G 的數據。也許這甚至適合 32G 的 RAM。

順便說一句,python 非常適合高級程式碼,但對於快速處理 500G 數據來說就不是那麼好了。我會在 C++ 中執行此操作。

btw2:我注意到按時間戳排序塊的順序與按塊高度排序塊的順序不同。而且,塊以另一種順序儲存在 blkNNNN.dat 文件中。所以你可能要考慮到這一點。

引用自:https://bitcoin.stackexchange.com/questions/116053