Skip to content

Commit

Permalink
Store EtxSet as collection of ETXs
Browse files Browse the repository at this point in the history
Previously, the ETX set was stored the full list of referencable ETXs at
a certain block. For example, if [ETX0, ETX1, ETX2] those ETXs would be
written as the EtxSet for block 1. Then, when processing block 2, we may
add some new ETXs to that set or remove some (perhaps none), and then
write the new set to db. e.g, say block 2 spent ETX1, but added ETX3.
The new EtxSet at block 2 would be [ETX0, ETX2, ETX3]. ETX0 and ETX2 are
duplicated in each copy of the EtxSet. This problem gets exacerbated in
real world scenarios with large numbers of ETXs.

This patch makes it so we only store each ETX once, and the EtxSet we
store is just a list of ETX hashes referencing the ETXs in the set. This
way we don't store duplicate ETXs in the db.

The tradeoff here, is that when we load the EtxSet, we now have to make
many db reads to load each ETX in the set. A future patch can add a
caching mechanism to mitigate this.
  • Loading branch information
wizeguyy committed Apr 4, 2023
1 parent a1d4b3b commit b2b243a
Showing 1 changed file with 33 additions and 1 deletion.
34 changes: 33 additions & 1 deletion core/rawdb/accessors_chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -1099,6 +1099,22 @@ func ReadHeadBlock(db ethdb.Reader) *types.Block {
return ReadBlock(db, headBlockHash, *headBlockNumber)
}

// ReadEtxRLP retrieves the specified ETX hash
func ReadEtxRLP(db ethdb.Reader, hash common.Hash) rlp.RawValue {
data, _ := db.Get(hash.Bytes())
if len(data) > 0 {
return data
}
return nil
}

// WriteEtxRLP stores the given ETX by its hash
func WriteEtxRLP(db ethdb.KeyValueWriter, hash common.Hash, rlp rlp.RawValue) {
if err := db.Put(hash.Bytes(), rlp); err != nil {
log.Crit("Failed to store etx set", "err", err)
}
}

// ReadEtxSetRLP retrieves the EtxSet corresponding to a given block, in RLP encoding.
func ReadEtxSetRLP(db ethdb.Reader, hash common.Hash, number uint64) rlp.RawValue {
// First try to look up the data in ancient database. Extra hash
Expand Down Expand Up @@ -1166,7 +1182,17 @@ func ReadEtxSet(db ethdb.Reader, hash common.Hash, number uint64) types.EtxSet {
}
etxSet := make(types.EtxSet)
for _, entry := range entries {
etxSet[entry.EtxHash] = types.EtxSetEntry{Height: entry.EtxHeight, ETX: entry.Etx}
etxRlp := ReadEtxRLP(db, entry.EtxHash)
if etxRlp == nil {
log.Error("Error looking up RLP transaction", "hash=", entry.EtxHash)
return nil
}
var etx types.Transaction
if err := rlp.Decode(bytes.NewReader(etxRlp), etx); err != nil {
log.Error("Invalid ETX RLP", "hash=", entry.EtxHash, "err", err)
return nil
}
etxSet[entry.EtxHash] = types.EtxSetEntry{Height: entry.EtxHeight, ETX: etx}
}
return etxSet
}
Expand All @@ -1175,6 +1201,12 @@ func ReadEtxSet(db ethdb.Reader, hash common.Hash, number uint64) types.EtxSet {
func WriteEtxSet(db ethdb.KeyValueWriter, hash common.Hash, number uint64, etxSet types.EtxSet) {
var entries []EtxSetEntry
for etxHash, entry := range etxSet {
etxRlp, err := rlp.EncodeToBytes(entry)
if err != nil {
log.Error("Failed to RLP encode ETX", "hash=", etxHash, "err", err)
return
}
WriteEtxRLP(db, etxHash, etxRlp)
entry := EtxSetEntry{EtxHash: etxHash, EtxHeight: entry.Height, Etx: entry.ETX}
entries = append(entries, entry)
}
Expand Down

0 comments on commit b2b243a

Please sign in to comment.