upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/scripts/bitflash_chain.py
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/bitflash_chain.py')
-rw-r--r--scripts/bitflash_chain.py69
1 files changed, 33 insertions, 36 deletions
diff --git a/scripts/bitflash_chain.py b/scripts/bitflash_chain.py
index f3688f1..4a3231c 100644
--- a/scripts/bitflash_chain.py
+++ b/scripts/bitflash_chain.py
@@ -4,6 +4,7 @@
4import datetime as _dt 4import datetime as _dt
5import hashlib 5import hashlib
6import json 6import json
7import mmap
7import os 8import os
8import struct 9import struct
9from pathlib import Path 10from pathlib import Path
@@ -11,6 +12,9 @@ from pathlib import Path
11 12
12MAGIC = bytes([0xBF, 0x20, 0x5C, 0xFD]) 13MAGIC = bytes([0xBF, 0x20, 0x5C, 0xFD])
13MAX_BLOCK_PAYLOAD = 32 * 1024 * 1024 14MAX_BLOCK_PAYLOAD = 32 * 1024 * 1024
15UTXO_LEAF_DOMAIN = "BTFUTXO1"
16UTXO_NODE_DOMAIN_TAG = "BTFNODE1"
17UTXO_NODE_DOMAIN = (UTXO_NODE_DOMAIN_TAG + "|").encode("ascii")
14COIN = 100_000_000 18COIN = 100_000_000
15GENESIS_HASH = "5bd7cb255d814e48cebcdfb72da4dc87b34bd774227f8ceb546c5640f4bdc169" 19GENESIS_HASH = "5bd7cb255d814e48cebcdfb72da4dc87b34bd774227f8ceb546c5640f4bdc169"
16GENESIS_MERKLE = "1a45b4482532abb29b10e234d3f13132230525a339ecea91658ffa675a5b1325" 20GENESIS_MERKLE = "1a45b4482532abb29b10e234d3f13132230525a339ecea91658ffa675a5b1325"
@@ -181,40 +185,33 @@ def iter_block_files(datadir):
181def iter_blocks_from_file(path): 185def iter_blocks_from_file(path):
182 path = Path(path) 186 path = Path(path)
183 with path.open("rb") as f: 187 with path.open("rb") as f:
184 window = f.read(4) 188 f.seek(0, os.SEEK_END)
185 offset = 0 189 file_size = f.tell()
186 while len(window) == 4: 190 if file_size == 0:
187 if window != MAGIC: 191 return
188 nxt = f.read(1) 192 f.seek(0)
189 if not nxt: 193 mm = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ)
194 try:
195 pos = 0
196 while True:
197 offset = mm.find(MAGIC, pos)
198 if offset < 0 or offset + 8 > file_size:
190 break 199 break
191 window = window[1:] + nxt 200 size = struct.unpack("<I", mm[offset + 4:offset + 8])[0]
192 offset += 1 201 payload_offset = offset + 8
193 continue 202 end = payload_offset + size
194 203 if size == 0 or size > MAX_BLOCK_PAYLOAD or end > file_size:
195 size_bytes = f.read(4) 204 pos = offset + 1
196 if len(size_bytes) != 4: 205 continue
197 break 206 payload = mm[payload_offset:end]
198 size = struct.unpack("<I", size_bytes)[0] 207 try:
199 if size == 0 or size > MAX_BLOCK_PAYLOAD: 208 yield parse_block(payload, path.name, payload_offset)
200 offset += 1 209 except ParseError:
201 f.seek(offset) 210 pos = offset + 1
202 window = f.read(4) 211 continue
203 continue 212 pos = end
204 payload_offset = offset + 8 213 finally:
205 payload = f.read(size) 214 mm.close()
206 if len(payload) != size:
207 break
208 try:
209 yield parse_block(payload, path.name, payload_offset)
210 except ParseError:
211 offset += 1
212 f.seek(offset)
213 window = f.read(4)
214 continue
215
216 offset = f.tell()
217 window = f.read(4)
218 215
219 216
220def read_blocks_from_files(paths, max_blocks=0): 217def read_blocks_from_files(paths, max_blocks=0):
@@ -265,7 +262,7 @@ def is_coinbase(tx):
265 262
266def utxo_leaf_hash(outpoint, utxo): 263def utxo_leaf_hash(outpoint, utxo):
267 payload = "|".join([ 264 payload = "|".join([
268 "BTFUTXO1", 265 UTXO_LEAF_DOMAIN,
269 outpoint, 266 outpoint,
270 str(utxo["value_satoshis"]), 267 str(utxo["value_satoshis"]),
271 utxo["script_pub_key_hex"], 268 utxo["script_pub_key_hex"],
@@ -285,7 +282,7 @@ def utxo_root(utxos):
285 for i in range(0, len(layer), 2): 282 for i in range(0, len(layer), 2):
286 left = layer[i] 283 left = layer[i]
287 right = layer[i + 1] if i + 1 < len(layer) else left 284 right = layer[i + 1] if i + 1 < len(layer) else left
288 nxt.append(sha256(b"BTFNODE1|" + left + right)) 285 nxt.append(sha256(UTXO_NODE_DOMAIN + left + right))
289 layer = nxt 286 layer = nxt
290 return layer[0].hex() 287 return layer[0].hex()
291 288
@@ -327,9 +324,9 @@ def apply_blocks(blocks, strict_duplicates=False):
327 for n, out in enumerate(tx["vout"]): 324 for n, out in enumerate(tx["vout"]):
328 key = "%s:%d" % (tx["txid"], n) 325 key = "%s:%d" % (tx["txid"], n)
329 if key in utxos: 326 if key in utxos:
330 duplicate_outputs.append({"height": height, "outpoint": key})
331 if strict_duplicates: 327 if strict_duplicates:
332 raise ParseError("duplicate output at height %d: %s" % (height, key)) 328 raise ParseError("duplicate output at height %d: %s" % (height, key))
329 duplicate_outputs.append({"height": height, "outpoint": key})
333 utxos[key] = { 330 utxos[key] = {
334 "txid": tx["txid"], 331 "txid": tx["txid"],
335 "vout": n, 332 "vout": n,