-
Notifications
You must be signed in to change notification settings - Fork 809
feat(sync/customrawdb): migrate customrawdb package from coreth #4387
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 7 commits
daafc3c
f185407
136ba64
b79eeab
e6f5461
bf62dfb
fff1df9
7a1e70d
04094ec
65d6032
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
// Copyright (C) 2019-2025, Ava Labs, Inc. All rights reserved. | ||
// See the file LICENSE for licensing terms. | ||
|
||
package customrawdb | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"time" | ||
|
||
"github.com/ava-labs/libevm/common" | ||
"github.com/ava-labs/libevm/core/rawdb" | ||
"github.com/ava-labs/libevm/ethdb" | ||
"github.com/ava-labs/libevm/log" | ||
"github.com/ava-labs/libevm/params" | ||
"github.com/ava-labs/libevm/rlp" | ||
) | ||
|
||
// writeCurrentTimeMarker writes a marker of the current time in the db at `key`. | ||
func writeCurrentTimeMarker(db ethdb.KeyValueStore, key []byte) error { | ||
data, err := rlp.EncodeToBytes(uint64(time.Now().Unix())) | ||
if err != nil { | ||
return err | ||
} | ||
return db.Put(key, data) | ||
} | ||
|
||
// readTimeMarker reads the timestamp stored at `key` | ||
func readTimeMarker(db ethdb.KeyValueStore, key []byte) (time.Time, error) { | ||
data, err := db.Get(key) | ||
if err != nil { | ||
return time.Time{}, err | ||
} | ||
|
||
var unix uint64 | ||
if err := rlp.DecodeBytes(data, &unix); err != nil { | ||
return time.Time{}, err | ||
} | ||
|
||
return time.Unix(int64(unix), 0), nil | ||
} | ||
|
||
// WriteOfflinePruning writes a time marker of the last attempt to run offline pruning. | ||
// The marker is written when offline pruning completes and is deleted when the node | ||
// is started successfully with offline pruning disabled. This ensures users must | ||
// disable offline pruning and start their node successfully between runs of offline | ||
// pruning. | ||
func WriteOfflinePruning(db ethdb.KeyValueStore) error { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm noticing some inconsistency that some of our functions return errors, while others don't. It seems that we're following geth-style naming, so I'm also assuming we intended to follow geth's api style - referencing their state accessors here it seems that they don't return errors... they usually return a zero/nil value and log errors instead of letting the caller how to handle the error. It seems that they use We could deviate from geth's style but since we have inconsistency in our own package I want to ask if this was intended. If we're going to deviate from geth's style, I think it would just be easiest to return the error + let the caller handle the error and not have the caller infer failure from reasoning about the returned value of a read. |
||
return writeCurrentTimeMarker(db, offlinePruningKey) | ||
} | ||
|
||
// ReadOfflinePruning reads the most recent timestamp of an attempt to run offline | ||
// pruning if present. | ||
func ReadOfflinePruning(db ethdb.KeyValueStore) (time.Time, error) { | ||
return readTimeMarker(db, offlinePruningKey) | ||
} | ||
|
||
// DeleteOfflinePruning deletes any marker of the last attempt to run offline pruning. | ||
func DeleteOfflinePruning(db ethdb.KeyValueStore) error { | ||
return db.Delete(offlinePruningKey) | ||
} | ||
|
||
// WritePopulateMissingTries writes a marker for the current attempt to populate | ||
// missing tries. | ||
func WritePopulateMissingTries(db ethdb.KeyValueStore) error { | ||
return writeCurrentTimeMarker(db, populateMissingTriesKey) | ||
} | ||
|
||
// ReadPopulateMissingTries reads the most recent timestamp of an attempt to | ||
// re-populate missing trie nodes. | ||
func ReadPopulateMissingTries(db ethdb.KeyValueStore) (time.Time, error) { | ||
return readTimeMarker(db, populateMissingTriesKey) | ||
} | ||
|
||
// DeletePopulateMissingTries deletes any marker of the last attempt to | ||
// re-populate missing trie nodes. | ||
func DeletePopulateMissingTries(db ethdb.KeyValueStore) error { | ||
return db.Delete(populateMissingTriesKey) | ||
} | ||
|
||
// WritePruningDisabled writes a marker to track whether the node has ever run | ||
// with pruning disabled. | ||
func WritePruningDisabled(db ethdb.KeyValueStore) error { | ||
return db.Put(pruningDisabledKey, nil) | ||
} | ||
|
||
// HasPruningDisabled returns true if there is a marker present indicating that | ||
// the node has run with pruning disabled at some point. | ||
func HasPruningDisabled(db ethdb.KeyValueStore) (bool, error) { | ||
return db.Has(pruningDisabledKey) | ||
} | ||
|
||
// WriteAcceptorTip writes `hash` as the last accepted block that has been fully processed. | ||
func WriteAcceptorTip(db ethdb.KeyValueWriter, hash common.Hash) error { | ||
return db.Put(acceptorTipKey, hash[:]) | ||
} | ||
|
||
// ReadAcceptorTip reads the hash of the last accepted block that was fully processed. | ||
// If there is no value present (the index is being initialized for the first time), then the | ||
// empty hash is returned. | ||
func ReadAcceptorTip(db ethdb.KeyValueReader) (common.Hash, error) { | ||
has, err := db.Has(acceptorTipKey) | ||
|
||
if err != nil { | ||
return common.Hash{}, err | ||
} | ||
if !has { | ||
// If the index is not present on disk, the [acceptorTipKey] index has not been initialized yet. | ||
|
||
return common.Hash{}, nil | ||
} | ||
h, err := db.Get(acceptorTipKey) | ||
if err != nil { | ||
return common.Hash{}, err | ||
} | ||
if len(h) != common.HashLength { | ||
return common.Hash{}, fmt.Errorf("value has incorrect length %d", len(h)) | ||
} | ||
return common.BytesToHash(h), nil | ||
} | ||
|
||
// ReadChainConfig retrieves the consensus settings based on the given genesis hash. | ||
// The provided [upgradeConfig] (any JSON-unmarshalable type) will be populated if present on disk. | ||
|
||
func ReadChainConfig[T any](db ethdb.KeyValueReader, hash common.Hash, upgradeConfig *T) *params.ChainConfig { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same comment w.r.t the parameter for |
||
config := rawdb.ReadChainConfig(db, hash) | ||
|
||
upgrade, _ := db.Get(upgradeConfigKey(hash)) | ||
if len(upgrade) == 0 { | ||
return config | ||
} | ||
|
||
if err := json.Unmarshal(upgrade, upgradeConfig); err != nil { | ||
log.Error("Invalid upgrade config JSON", "err", err) | ||
return nil | ||
} | ||
|
||
return config | ||
} | ||
|
||
// WriteChainConfig writes the chain config settings to the database. | ||
// The provided [upgradeConfig] (any JSON-marshalable type) will be stored alongside the chain config. | ||
func WriteChainConfig[T any](db ethdb.KeyValueWriter, hash common.Hash, config *params.ChainConfig, upgradeConfig T) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This function signature looks like it changed from subnetevm and coreth. Why do we pass in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I changed the signature exactly because I wanted to decouple the |
||
rawdb.WriteChainConfig(db, hash, config) | ||
if config == nil { | ||
return | ||
} | ||
|
||
data, err := json.Marshal(upgradeConfig) | ||
if err != nil { | ||
log.Crit("Failed to JSON encode upgrade config", "err", err) | ||
} | ||
if err := db.Put(upgradeConfigKey(hash), data); err != nil { | ||
log.Crit("Failed to store upgrade config", "err", err) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
// Copyright (C) 2019-2025, Ava Labs, Inc. All rights reserved. | ||
// See the file LICENSE for licensing terms. | ||
|
||
package customrawdb | ||
|
||
import ( | ||
"github.com/ava-labs/libevm/common" | ||
"github.com/ava-labs/libevm/core/rawdb" | ||
"github.com/ava-labs/libevm/ethdb" | ||
"github.com/ava-labs/libevm/log" | ||
) | ||
|
||
// ReadSnapshotBlockHash retrieves the hash of the block whose state is contained in | ||
// the persisted snapshot. | ||
func ReadSnapshotBlockHash(db ethdb.KeyValueReader) common.Hash { | ||
data, _ := db.Get(snapshotBlockHashKey) | ||
if len(data) != common.HashLength { | ||
return common.Hash{} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It seems like when reads fail the rest of the geth rawdb Read* apis would error log |
||
} | ||
return common.BytesToHash(data) | ||
} | ||
|
||
// WriteSnapshotBlockHash stores the root of the block whose state is contained in | ||
// the persisted snapshot. | ||
func WriteSnapshotBlockHash(db ethdb.KeyValueWriter, blockHash common.Hash) { | ||
if err := db.Put(snapshotBlockHashKey, blockHash[:]); err != nil { | ||
log.Crit("Failed to store snapshot block hash", "err", err) | ||
} | ||
} | ||
|
||
// DeleteSnapshotBlockHash deletes the hash of the block whose state is contained in | ||
// the persisted snapshot. Since snapshots are not immutable, this method can | ||
// be used during updates, so a crash or failure will mark the entire snapshot | ||
// invalid. | ||
func DeleteSnapshotBlockHash(db ethdb.KeyValueWriter) { | ||
if err := db.Delete(snapshotBlockHashKey); err != nil { | ||
log.Crit("Failed to remove snapshot block hash", "err", err) | ||
} | ||
} | ||
|
||
// IterateAccountSnapshots returns an iterator for walking all of the accounts in the snapshot | ||
func IterateAccountSnapshots(db ethdb.Iteratee) ethdb.Iterator { | ||
powerslider marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
it := db.NewIterator(rawdb.SnapshotAccountPrefix, nil) | ||
keyLen := len(rawdb.SnapshotAccountPrefix) + common.HashLength | ||
return rawdb.NewKeyLengthIterator(it, keyLen) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does the
_ext
suffix on these files mean? Should we remove it?