avoid hash tree root calculation when loading blocks from database (#1572)

This commit is contained in:
Jacek Sieka 2020-09-04 08:35:10 +02:00 committed by Mamy Ratsimbazafy
parent c2384246bc
commit 29e56232a7
3 changed files with 22 additions and 13 deletions

View File

@ -112,7 +112,7 @@ proc get[T](db: BeaconChainDB, key: openArray[byte], output: var T): GetResult =
try:
let decompressed = snappy.decode(data, maxDecompressedDbRecordSize)
if decompressed.len > 0:
outputPtr[] = SSZ.decode(decompressed, T)
outputPtr[] = SSZ.decode(decompressed, T, updateRoot = false)
status = GetResult.found
else:
warn "Corrupt snappy record found in database", typ = name(T)
@ -164,9 +164,12 @@ proc putTailBlock*(db: BeaconChainDB, key: Eth2Digest) =
proc getBlock*(db: BeaconChainDB, key: Eth2Digest): Opt[TrustedSignedBeaconBlock] =
# We only store blocks that we trust in the database
result.ok(TrustedSignedBeaconBlock(root: key))
result.ok(TrustedSignedBeaconBlock())
if db.get(subkey(SignedBeaconBlock, key), result.get) != GetResult.found:
result.err()
else:
# set root after deserializing (so it doesn't get zeroed)
result.get().root = key
proc getState*(
db: BeaconChainDB, key: Eth2Digest, output: var BeaconState,
@ -214,8 +217,10 @@ iterator getAncestors*(db: BeaconChainDB, root: Eth2Digest):
##
## The search will go on until the ancestor cannot be found.
var res: TrustedSignedBeaconBlock
var
res: TrustedSignedBeaconBlock
root = root
while db.get(subkey(SignedBeaconBlock, root), res) == GetResult.found:
res.root = root
while db.get(subkey(SignedBeaconBlock, res.root), res) == GetResult.found:
yield res
res.root = res.message.parent_root
root = res.message.parent_root

View File

@ -84,7 +84,8 @@ template checkForForbiddenBits(ResulType: type,
if (input[^1] and forbiddenBitsMask) != 0:
raiseIncorrectSize ResulType
func readSszValue*[T](input: openarray[byte], val: var T) {.raisesssz.} =
func readSszValue*[T](input: openarray[byte],
val: var T, updateRoot: bool = true) {.raisesssz.} =
mixin fromSszBytes, toSszType
template readOffsetUnchecked(n: int): uint32 {.used.}=
@ -268,6 +269,7 @@ func readSszValue*[T](input: openarray[byte], val: var T) {.raisesssz.} =
input.toOpenArray(int(startOffset), int(endOffset - 1)))
when val is SignedBeaconBlock | TrustedSignedBeaconBlock:
if updateRoot:
val.root = hash_tree_root(val.message)
else:
unsupported T

View File

@ -19,6 +19,7 @@ export
type
SszReader* = object
stream: InputStream
updateRoot: bool
SszWriter* = object
stream: OutputStream
@ -41,8 +42,10 @@ template sizePrefixed*[TT](x: TT): untyped =
type T = TT
SizePrefixed[T](x)
proc init*(T: type SszReader, stream: InputStream): T {.raises: [Defect].} =
T(stream: stream)
proc init*(T: type SszReader,
stream: InputStream,
updateRoot: bool = true): T {.raises: [Defect].} =
T(stream: stream, updateRoot: updateRoot)
proc writeFixedSized(s: var (OutputStream|WriteCursor), x: auto) {.raises: [Defect, IOError].} =
mixin toSszType
@ -226,11 +229,10 @@ proc readValue*[T](r: var SszReader, val: var T) {.raises: [Defect, MalformedSsz
when isFixedSize(T):
const minimalSize = fixedPortionSize(T)
if r.stream.readable(minimalSize):
readSszValue(r.stream.read(minimalSize), val)
readSszValue(r.stream.read(minimalSize), val, r.updateRoot)
else:
raise newException(MalformedSszError, "SSZ input of insufficient size")
else:
# TODO Read the fixed portion first and precisely measure the size of
# the dynamic portion to consume the right number of bytes.
readSszValue(r.stream.read(r.stream.len.get), val)
readSszValue(r.stream.read(r.stream.len.get), val, r.updateRoot)