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: try:
let decompressed = snappy.decode(data, maxDecompressedDbRecordSize) let decompressed = snappy.decode(data, maxDecompressedDbRecordSize)
if decompressed.len > 0: if decompressed.len > 0:
outputPtr[] = SSZ.decode(decompressed, T) outputPtr[] = SSZ.decode(decompressed, T, updateRoot = false)
status = GetResult.found status = GetResult.found
else: else:
warn "Corrupt snappy record found in database", typ = name(T) 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] = proc getBlock*(db: BeaconChainDB, key: Eth2Digest): Opt[TrustedSignedBeaconBlock] =
# We only store blocks that we trust in the database # 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: if db.get(subkey(SignedBeaconBlock, key), result.get) != GetResult.found:
result.err() result.err()
else:
# set root after deserializing (so it doesn't get zeroed)
result.get().root = key
proc getState*( proc getState*(
db: BeaconChainDB, key: Eth2Digest, output: var BeaconState, 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. ## The search will go on until the ancestor cannot be found.
var res: TrustedSignedBeaconBlock var
res.root = root res: TrustedSignedBeaconBlock
while db.get(subkey(SignedBeaconBlock, res.root), res) == GetResult.found: root = root
while db.get(subkey(SignedBeaconBlock, root), res) == GetResult.found:
res.root = root
yield res 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: if (input[^1] and forbiddenBitsMask) != 0:
raiseIncorrectSize ResulType 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 mixin fromSszBytes, toSszType
template readOffsetUnchecked(n: int): uint32 {.used.}= 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))) input.toOpenArray(int(startOffset), int(endOffset - 1)))
when val is SignedBeaconBlock | TrustedSignedBeaconBlock: when val is SignedBeaconBlock | TrustedSignedBeaconBlock:
val.root = hash_tree_root(val.message) if updateRoot:
val.root = hash_tree_root(val.message)
else: else:
unsupported T unsupported T

View File

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