11import hashlib
2+ import struct
23import itertools
34from collections .abc import Iterator
45from typing import Callable , List , NamedTuple , Optional , Tuple
1112EMPTY_HASH = hashlib .sha256 ().digest ()
1213FAST_KEY_PREFIX = b"f"
1314METADATA_KEY_PREFIX = b"m"
14- NODE_KEY_PREFIX = b"n "
15+ NODE_KEY_PREFIX = b"s "
1516ORPHAN_KEY_PREFIX = b"o"
1617ROOT_KEY_PREFIX = b"r"
18+ LEGACY_NODE_KEY_PREFIX = b"n"
1719GetNode = Callable [bytes , Optional ["PersistedNode" ]]
1820
1921
@@ -131,13 +133,33 @@ def prefix_iteritems(
131133
132134
133135def root_key (v : int ) -> bytes :
136+ return struct .pack (">qI" , v , 1 )
137+
138+
139+ def legacy_root_key (v : int ) -> bytes :
134140 return ROOT_KEY_PREFIX + v .to_bytes (8 , "big" )
135141
136142
137143def node_key (hash : bytes ) -> bytes :
144+ if len (hash ) != 12 :
145+ raise ValueError ("Key must be 12 bytes" )
138146 return NODE_KEY_PREFIX + hash
139147
140148
149+ def legacy_node_key (hash : bytes ) -> bytes :
150+ return LEGACY_NODE_KEY_PREFIX + hash
151+
152+
153+ def parse_node_key (key : bytes ) -> tuple [int , int ]:
154+ if not key .startswith (NODE_KEY_PREFIX ):
155+ raise ValueError ("Key must start with root prefix 's'" )
156+ key = key [len (NODE_KEY_PREFIX ):]
157+ if len (key ) != 12 :
158+ raise ValueError ("Key must be 12 bytes after prefix" )
159+ version , nonce = struct .unpack (">qI" , key )
160+ return version , nonce
161+
162+
141163def fast_node_key (key : bytes ) -> bytes :
142164 return FAST_KEY_PREFIX + key
143165
@@ -246,10 +268,11 @@ def decode_fast_node(bz: bytes) -> (int, bytes, int):
246268
247269
248270def get_node (
249- db : DBM , hash : bytes , store : Optional [str ] = None
271+ db : DBM , hash : bytes , store : Optional [str ] = None , legacy = False ,
250272) -> Optional [PersistedNode ]:
251- prefix = store_prefix (store ) if store is not None else b""
252- bz = db .get (prefix + node_key (hash ))
273+ prefix = store_prefix (store ) if store else b""
274+ key = legacy_node_key (hash ) if legacy else node_key (hash )
275+ bz = db .get (prefix + key )
253276 if not bz :
254277 return
255278 node , _ = decode_node (bz , hash )
@@ -259,10 +282,13 @@ def get_node(
259282def get_root_node (
260283 db : DBM , version : int , store : Optional [str ] = None
261284) -> Optional [PersistedNode ]:
262- prefix = store_prefix (store ) if store is not None else b""
263- hash = db .get (prefix + root_key (version ))
285+ prefix = store_prefix (store ) if store else b""
286+ hash = db .get (prefix + node_key ( root_key (version ) ))
264287 if not hash :
265- return
288+ hash = db .get (prefix + legacy_root_key (version ))
289+ if not hash :
290+ return
291+ return get_node (db , hash , store , legacy = True )
266292 return get_node (db , hash , store )
267293
268294
@@ -312,7 +338,7 @@ def iter_iavl_tree(
312338 prefix = store_prefix (store ) if store is not None else b""
313339
314340 def get_node (hash : bytes ) -> PersistedNode :
315- n , _ = decode_node (db .get (prefix + node_key (hash )), hash )
341+ n , _ = decode_node (db .get (prefix + legacy_node_key (hash )), hash )
316342 return n
317343
318344 def prune_check (node : PersistedNode ) -> (bool , bool ):
0 commit comments