Skip to content

Commit ba5fdd1

Browse files
committed
Merge bitcoin/bitcoin#30607: contrib: support reading XORed blocks in linearize-data.py script
77ff0ec contrib: support reading XORed blocks in linearize-data.py script (Sebastian Falbesoner) Pull request description: This PR is a small follow-up for #28052, adding support for the block linearization script to handle XORed blocksdir *.dat files. Note that if no xor.dat file exists, the XOR pattern is set to all-zeros, in order to still support blockdirs that have been created with versions earlier than 28.x. Partly fixes issue #30599. ACKs for top commit: achow101: ACK 77ff0ec tdb3: ACK 77ff0ec hodlinator: ACK 77ff0ec Tree-SHA512: 011eb02e2411de373cbbf4b26db4640fc693a20be8c2430529fba6e36a3a3abfdfdc3b005d330f9ec2846bfad9bfbf34231c574ba99289ef37dd51a68e6e7f3d
2 parents 5c5a298 + 77ff0ec commit ba5fdd1

File tree

2 files changed

+23
-9
lines changed

2 files changed

+23
-9
lines changed

contrib/linearize/linearize-data.py

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,16 @@ def getFirstBlockFileId(block_dir_path):
7676
blkId = int(firstBlkFn[3:8])
7777
return blkId
7878

79+
def read_xor_key(blocks_path):
80+
NUM_XOR_BYTES = 8 # From InitBlocksdirXorKey::xor_key.size()
81+
try:
82+
xor_filename = os.path.join(blocks_path, "xor.dat")
83+
with open(xor_filename, "rb") as xor_file:
84+
return xor_file.read(NUM_XOR_BYTES)
85+
# support also blockdirs created with pre-v28 versions, where no xor key exists yet
86+
except FileNotFoundError:
87+
return bytes([0] * NUM_XOR_BYTES)
88+
7989
# Block header and extent on disk
8090
BlockExtent = namedtuple('BlockExtent', ['fn', 'offset', 'inhdr', 'blkhdr', 'size'])
8191

@@ -95,6 +105,7 @@ def __init__(self, settings, blkindex, blkmap):
95105
self.outFname = None
96106
self.blkCountIn = 0
97107
self.blkCountOut = 0
108+
self.xor_key = read_xor_key(self.settings['input'])
98109

99110
self.lastDate = datetime.datetime(2000, 1, 1)
100111
self.highTS = 1408893517 - 315360000
@@ -113,6 +124,13 @@ def __init__(self, settings, blkindex, blkmap):
113124
self.outOfOrderData = {}
114125
self.outOfOrderSize = 0 # running total size for items in outOfOrderData
115126

127+
def read_xored(self, f, size):
128+
offset = f.tell()
129+
data = bytearray(f.read(size))
130+
for i in range(len(data)):
131+
data[i] ^= self.xor_key[(i + offset) % len(self.xor_key)]
132+
return bytes(data)
133+
116134
def writeBlock(self, inhdr, blk_hdr, rawblock):
117135
blockSizeOnDisk = len(inhdr) + len(blk_hdr) + len(rawblock)
118136
if not self.fileOutput and ((self.outsz + blockSizeOnDisk) > self.maxOutSz):
@@ -165,7 +183,7 @@ def fetchBlock(self, extent):
165183
'''Fetch block contents from disk given extents'''
166184
with open(self.inFileName(extent.fn), "rb") as f:
167185
f.seek(extent.offset)
168-
return f.read(extent.size)
186+
return self.read_xored(f, extent.size)
169187

170188
def copyOneBlock(self):
171189
'''Find the next block to be written in the input, and copy it to the output.'''
@@ -190,7 +208,7 @@ def run(self):
190208
print("Premature end of block data")
191209
return
192210

193-
inhdr = self.inF.read(8)
211+
inhdr = self.read_xored(self.inF, 8)
194212
if (not inhdr or (inhdr[0] == "\0")):
195213
self.inF.close()
196214
self.inF = None
@@ -207,7 +225,7 @@ def run(self):
207225
inLenLE = inhdr[4:]
208226
su = struct.unpack("<I", inLenLE)
209227
inLen = su[0] - 80 # length without header
210-
blk_hdr = self.inF.read(80)
228+
blk_hdr = self.read_xored(self.inF, 80)
211229
inExtent = BlockExtent(self.inFn, self.inF.tell(), inhdr, blk_hdr, inLen)
212230

213231
self.hash_str = calc_hash_str(blk_hdr)
@@ -224,7 +242,7 @@ def run(self):
224242

225243
if self.blkCountOut == blkHeight:
226244
# If in-order block, just copy
227-
rawblock = self.inF.read(inLen)
245+
rawblock = self.read_xored(self.inF, inLen)
228246
self.writeBlock(inhdr, blk_hdr, rawblock)
229247

230248
# See if we can catch up to prior out-of-order blocks
@@ -237,7 +255,7 @@ def run(self):
237255
# If there is space in the cache, read the data
238256
# Reading the data in file sequence instead of seeking and fetching it later is preferred,
239257
# but we don't want to fill up memory
240-
self.outOfOrderData[blkHeight] = self.inF.read(inLen)
258+
self.outOfOrderData[blkHeight] = self.read_xored(self.inF, inLen)
241259
self.outOfOrderSize += inLen
242260
else: # If no space in cache, seek forward
243261
self.inF.seek(inLen, os.SEEK_CUR)

test/functional/feature_loadblock.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,6 @@ def set_test_params(self):
2626
self.setup_clean_chain = True
2727
self.num_nodes = 2
2828
self.supports_cli = False
29-
self.extra_args = [
30-
["-blocksxor=0"], # TODO: The linearize scripts should be adjusted to apply any XOR
31-
[],
32-
]
3329

3430
def run_test(self):
3531
self.nodes[1].setnetworkactive(state=False)

0 commit comments

Comments
 (0)