Verifier: check the full block-hash-tree on each share

Removed the .todo from two test_repairer tests that check this. The only
remaining .todos are on the three crypttext-hash-tree tests.
This commit is contained in:
Brian Warner 2009-10-05 14:48:44 -07:00
parent e8f56af5a7
commit 504c767d03
3 changed files with 45 additions and 5 deletions

View File

@ -157,10 +157,12 @@ class Checker(log.PrefixingLogMixin):
d = vrbp.get_all_sharehashes()
# we fill share_hash_tree before fetching any blocks, so the
# block fetches won't send redundant share-hash-tree requests, to
# speed things up.
d.addCallbacks(lambda ign: vrbp)
# speed things up. Then we fetch+validate all the blockhashes.
d.addCallback(lambda ign: vrbp.get_all_blockhashes())
d.addCallback(lambda ign: vrbp)
return d
d.addCallbacks(_got_ueb)
d.addCallback(_got_ueb)
def _discard_result(r):
assert isinstance(r, str), r
# to free up the RAM

View File

@ -386,6 +386,39 @@ class ValidatedReadBucketProxy(log.PrefixingLogMixin):
d.addCallback(_got_share_hashes)
return d
def get_all_blockhashes(self):
"""Retrieve and validate all the block-hash-tree nodes that are
included in this share. Each share contains a full Merkle tree, but
we usually only fetch the minimal subset necessary for any particular
block. This function fetches everything at once. The Verifier uses
this function to validate the block hash tree.
Call this (and wait for the Deferred it returns to fire) after
calling get_all_sharehashes() and before calling get_block() for the
first time: this lets us check that the share contains all block
hashes and avoids downloading them multiple times.
I return a Deferred which errbacks upon failure, probably with
BadOrMissingHash.
"""
# get_block_hashes(anything) currently always returns everything
needed = list(range(len(self.block_hash_tree)))
d = self.bucket.get_block_hashes(needed)
def _got_block_hashes(blockhashes):
if len(blockhashes) < len(self.block_hash_tree):
raise BadOrMissingHash()
bh = dict(enumerate(blockhashes))
try:
self.block_hash_tree.set_hashes(bh)
except IndexError, le:
raise BadOrMissingHash(le)
except (hashtree.BadHashError, hashtree.NotEnoughHashesError), le:
raise BadOrMissingHash(le)
d.addCallback(_got_block_hashes)
return d
def get_block(self, blocknum):
# the first time we use this bucket, we need to fetch enough elements
# of the share hash tree to validate it from our share hash up to the

View File

@ -258,7 +258,6 @@ class Verifier(GridTestMixin, unittest.TestCase, RepairTestMixin):
self.basedir = "repairer/Verify/corrupt_block_hashtree_offset"
return self._help_test_verify(common._corrupt_offset_of_block_hashes,
self.judge_invisible_corruption)
test_corrupt_block_hashtree_offset.todo = "Verifier doesn't yet properly detect this kind of corruption."
def test_wrong_share_verno(self):
self.basedir = "repairer/Verify/wrong_share_verno"
@ -286,13 +285,19 @@ class Verifier(GridTestMixin, unittest.TestCase, RepairTestMixin):
self.basedir = "repairer/Verify/corrupt_block_hashtree"
return self._help_test_verify(common._corrupt_block_hashes,
self.judge_invisible_corruption)
test_corrupt_block_hashtree.todo = "Verifier doesn't yet properly detect this kind of corruption."
def test_corrupt_share_hashtree(self):
self.basedir = "repairer/Verify/corrupt_share_hashtree"
return self._help_test_verify(common._corrupt_share_hashes,
self.judge_invisible_corruption)
# TODO: the Verifier should decode to ciphertext and check it against the
# crypttext-hash-tree. Check this by constructing a bogus file, in which
# the crypttext-hash-tree is modified after encoding is done, but before
# the UEB is finalized. The Verifier should see a valid
# crypttext-hash-tree but then the ciphertext should show up as invalid.
# Normally this could only be triggered by a bug in FEC decode.
# We'll allow you to pass this test even if you trigger thirty-five times as
# many block sends and disk writes as would be optimal.
WRITE_LEEWAY = 35