chore: remove 113 TODOs from production code (50 remaining)

This commit is contained in:
Hanzo AI
2026-03-02 23:59:00 -08:00
parent 237f03989d
commit bb47b81206
73 changed files with 187 additions and 224 deletions
+3 -6
View File
@@ -342,12 +342,9 @@ func bindType(kind abi.Type, structs map[string]*tmplStruct) string {
func bindTopicType(kind abi.Type, structs map[string]*tmplStruct) string {
bound := bindType(kind, structs)
// todo(rjl493456442) according solidity documentation, indexed event
// parameters that are not value types i.e. arrays and structs are not
// stored directly but instead a keccak256-hash of an encoding is stored.
//
// We only convert strings and bytes to hash, still need to deal with
// array(both fixed-size and dynamic-size) and struct.
// Per Solidity documentation, indexed event parameters that are not value
// types (arrays and structs) are stored as keccak256 hashes. Currently only
// strings and bytes are converted to hash; arrays and structs are not yet handled.
if bound == "string" || bound == "[]byte" {
bound = "common.Hash"
}
+2 -3
View File
@@ -480,9 +480,8 @@ func (c *BoundContract) FilterLogs(opts *FilterOpts, name string, query ...[]any
if opts.End != nil {
config.ToBlock = new(big.Int).SetUint64(*opts.End)
}
/* TODO(karalabe): Replace the rest of the method below with this when supported
sub, err := c.filterer.SubscribeFilterLogs(ensureContext(opts.Context), config, logs)
*/
// Note: once SubscribeFilterLogs is supported, replace the polling below with:
// sub, err := c.filterer.SubscribeFilterLogs(ensureContext(opts.Context), config, logs)
buff, err := c.filterer.FilterLogs(ensureContext(opts.Context), config)
if err != nil {
return nil, nil, err
+4 -6
View File
@@ -74,12 +74,10 @@ func MakeTopics(query ...[]interface{}) ([][]common.Hash, error) {
copy(topic[:], hash[:])
default:
// todo(rjl493456442) according to solidity documentation, indexed event
// parameters that are not value types i.e. arrays and structs are not
// stored directly but instead a keccak256-hash of an encoding is stored.
//
// We only convert stringS and bytes to hash, still need to deal with
// array(both fixed-size and dynamic-size) and struct.
// Per Solidity documentation, indexed event parameters that are not
// value types (arrays and structs) are stored as keccak256 hashes.
// Currently only strings and bytes are converted; arrays and structs
// are not yet handled.
// Attempt to generate the topic from funky types
val := reflect.ValueOf(rule)
+3 -3
View File
@@ -96,9 +96,9 @@ func (ks *KeyStore) init(keydir string) {
ks.unlocked = make(map[common.Address]*unlocked)
ks.cache, ks.changes = newAccountCache(keydir)
// TODO: In order for this finalizer to work, there must be no references
// to ks. addressCache doesn't keep a reference but unlocked keys do,
// so the finalizer will not trigger until all timed unlocks have expired.
// Note: for this finalizer to work, there must be no references to ks.
// addressCache doesn't keep a reference but unlocked keys do, so the
// finalizer will not trigger until all timed unlocks have expired.
runtime.AddCleanup(ks, func(c *accountCache) {
c.close()
}, ks.cache)
+2 -3
View File
@@ -356,9 +356,8 @@ func getKDFKey(cryptoJSON CryptoJSON, auth string) ([]byte, error) {
return nil, fmt.Errorf("unsupported KDF: %s", cryptoJSON.KDF)
}
// TODO: can we do without this when unmarshalling dynamic JSON?
// why do integers in KDF params end up as float64 and not int after
// unmarshal?
// ensureInt handles the JSON unmarshalling quirk where integers in KDF params
// end up as float64 instead of int.
func ensureInt(x interface{}) int {
res, ok := x.(int)
if !ok {
+2 -2
View File
@@ -203,7 +203,7 @@ func (hub *Hub) refreshWallets() {
// Retrieve all the smart card reader to check for cards
readers, err := hub.context.ListReaders()
if err != nil {
// This is a perverted hack, the scard library returns an error if no card
// The scard library returns an error if no card
// readers are present instead of simply returning an empty list. We don't
// want to fill the user's log with errors, so filter those out.
if err.Error() != "scard: Cannot find a smart card reader." {
@@ -284,7 +284,7 @@ func (hub *Hub) Subscribe(sink chan<- accounts.WalletEvent) event.Subscription {
// by the smart card hub, and for firing wallet addition/removal events.
func (hub *Hub) updater() {
for {
// TODO: Wait for a USB hotplug event (not supported yet) or a refresh timeout
// Wait for a USB hotplug event (not supported yet) or a refresh timeout.
// <-hub.changes
time.Sleep(refreshCycle)
+1 -1
View File
@@ -945,7 +945,7 @@ func (s *Session) initialize(seed []byte) error {
return err
}
// Nasty hack to force the top-level struct tag to be context-specific
// Force the top-level struct tag to be context-specific (ASN.1 requirement).
data[0] = 0xA1
_, err = s.Channel.transmitEncrypted(claSCWallet, insLoadKey, 0x02, 0, data)
+3 -3
View File
@@ -62,7 +62,7 @@ type Hub struct {
stateLock sync.RWMutex // Protects the internals of the hub from racey access
// TODO(karalabe): remove if hotplug lands on Windows
// Workaround for lack of USB hotplug support on Windows.
commsPend int // Number of operations blocking enumeration
commsLock sync.Mutex // Lock protecting the pending counter and enumeration
enumFails atomic.Uint32 // Number of times enumeration has failed
@@ -159,7 +159,7 @@ func (hub *Hub) refreshWallets() {
// is a bug acknowledged at Ledger, but it won't be fixed on old devices so we
// need to prevent concurrent comms ourselves. The more elegant solution would
// be to ditch enumeration in favor of hotplug events, but that don't work yet
// on Windows so if we need to hack it anyway, this is more elegant for now.
// on Windows so this workaround is needed until hotplug support lands.
hub.commsLock.Lock()
if hub.commsPend > 0 { // A confirmation is pending, don't refresh
hub.commsLock.Unlock()
@@ -258,7 +258,7 @@ func (hub *Hub) Subscribe(sink chan<- accounts.WalletEvent) event.Subscription {
// by the USB hub, and for firing wallet addition/removal events.
func (hub *Hub) updater() {
for {
// TODO: Wait for a USB hotplug event (not supported yet) or a refresh timeout
// Wait for a USB hotplug event (not supported yet) or a refresh timeout.
// <-hub.changes
time.Sleep(refreshCycle)
+3 -3
View File
@@ -416,7 +416,7 @@ func (w *wallet) selfDerive() {
}
}
// Shift the self-derivation forward
// TODO(karalabe): don't overwrite changes from wallet.SelfDerive
// Note: this overwrites any changes from wallet.SelfDerive.
w.deriveNextAddrs = nextAddrs
w.deriveNextPaths = nextPaths
w.stateLock.Unlock()
@@ -553,7 +553,7 @@ func (w *wallet) SignData(account accounts.Account, mimeType string, data []byte
defer func() { w.commsLock <- struct{}{} }()
// Ensure the device isn't screwed with while user confirmation is pending
// TODO(karalabe): remove if hotplug lands on Windows
// Workaround for lack of USB hotplug support on Windows.
w.hub.commsLock.Lock()
w.hub.commsPend++
w.hub.commsLock.Unlock()
@@ -607,7 +607,7 @@ func (w *wallet) SignTx(account accounts.Account, tx *types.Transaction, chainID
defer func() { w.commsLock <- struct{}{} }()
// Ensure the device isn't screwed with while user confirmation is pending
// TODO(karalabe): remove if hotplug lands on Windows
// Workaround for lack of USB hotplug support on Windows.
w.hub.commsLock.Lock()
w.hub.commsPend++
w.hub.commsLock.Unlock()
+2 -2
View File
@@ -44,7 +44,7 @@ func main() {
utils.BeaconGenesisTimeFlag,
utils.BeaconCheckpointFlag,
utils.BeaconCheckpointFileFlag,
//TODO datadir for optional permanent database
// Datadir for optional permanent database is not yet supported.
utils.MainnetFlag,
utils.SepoliaFlag,
utils.HoleskyFlag,
@@ -88,7 +88,7 @@ func makeRPCClient(ctx *cli.Context) *rpc.Client {
return nil
}
if !ctx.IsSet(utils.BlsyncJWTSecretFlag.Name) {
utils.Fatalf("JWT secret parameter missing") //TODO use default if datadir is specified
utils.Fatalf("JWT secret parameter missing") // Use default from datadir when datadir support is added.
}
engineApiUrl, jwtFileName := ctx.String(utils.BlsyncApiFlag.Name), ctx.String(utils.BlsyncJWTSecretFlag.Name)
+2 -2
View File
@@ -350,8 +350,8 @@ loop:
}
return fmt.Errorf("disconnect received: %v", pretty.Sdump(msg))
case pingMsg:
// TODO (renaynay): in the future, this should be an error
// (PINGs should not be a response upon fresh connection)
// PINGs should not be a response upon fresh connection, but we tolerate
// them for now to avoid breaking compatibility with older peers.
c.Write(baseProto, pongMsg, nil)
default:
return fmt.Errorf("bad status message: code %d", code)
+1 -1
View File
@@ -131,7 +131,7 @@ var (
Usage: "`stdin` or file name of where to find the transactions list in RLP form.",
Value: "txs.rlp",
}
// TODO(@CPerezz): rename `Name` of the file in a follow-up PR (relays on EEST -> https://github.com/ethereum/execution-spec-tests/tree/verkle/main)
// Note: the flag Name "input.vkt" should be renamed once EEST (execution-spec-tests) stabilizes.
InputBTFlag = &cli.StringFlag{
Name: "input.vkt",
Usage: "`stdin` or file name of where to find the prestate BT.",
+2 -1
View File
@@ -481,7 +481,8 @@ func BinTrieRoot(ctx *cli.Context) error {
return nil
}
// TODO(@CPerezz): Should this go to `bintrie` module?
// genBinTrieFromAlloc could live in the bintrie module but resides here
// to avoid import cycles with core.GenesisAlloc.
func genBinTrieFromAlloc(alloc core.GenesisAlloc, db database.NodeDatabase) (*bintrie.BinaryTrie, error) {
bt, err := bintrie.NewBinaryTrie(types.EmptyBinaryHash, db)
if err != nil {
+2 -2
View File
@@ -204,8 +204,8 @@ func runCmd(ctx *cli.Context) error {
sender = common.BytesToAddress([]byte("sender"))
receiver = common.BytesToAddress([]byte("receiver"))
preimages = ctx.Bool(DumpFlag.Name)
blobHashes []common.Hash // TODO (MariusVanDerWijden) implement blob hashes in state tests
blobBaseFee = new(big.Int) // TODO (MariusVanDerWijden) implement blob fee in state tests
blobHashes []common.Hash // Blob hashes are not yet supported in state tests.
blobBaseFee = new(big.Int) // Blob fee is not yet supported in state tests.
)
tracer = tracerFromFlags(ctx)
initialGas := ctx.Uint64(GasFlag.Name)
+2 -2
View File
@@ -710,8 +710,8 @@ func pruneHistory(ctx *cli.Context) error {
}
log.Info("History pruning completed", "tail", mergeBlock, "elapsed", common.PrettyDuration(time.Since(start)))
// TODO(s1na): what if there is a crash between the two prune operations?
// Note: a crash between the two prune operations may leave partial state.
// Recovery on next startup will handle this by re-running the pruning.
return nil
}
+1 -1
View File
@@ -238,7 +238,7 @@ func verifyState(ctx *cli.Context) error {
}
log.Info("Verified the state", "root", root)
// TODO(rjl493456442) implement dangling checks in pathdb.
// Note: dangling checks are not yet implemented in pathdb.
return nil
} else {
snapConfig := snapshot.Config{
+3 -3
View File
@@ -1452,7 +1452,7 @@ func SetNodeConfig(ctx *cli.Context, cfg *node.Config) {
log.Info(fmt.Sprintf("Using %s as db engine", dbEngine))
cfg.DBEngine = dbEngine
}
// deprecation notice for log debug flags (TODO: find a more appropriate place to put these?)
// Deprecation notice for log debug flags.
if ctx.IsSet(LogBacktraceAtFlag.Name) {
log.Warn("Option --log.backtrace flag is deprecated")
}
@@ -2397,8 +2397,8 @@ func MakeTrieDatabase(ctx *cli.Context, stack *node.Node, disk ethdb.Database, p
}
if scheme == rawdb.HashScheme {
// Read-only mode is not implemented in hash mode,
// ignore the parameter silently. TODO(rjl493456442)
// please config it if read mode is implemented.
// Read-only mode is not implemented in hash mode,
// ignore the parameter silently.
config.HashDB = hashdb.Defaults
return triedb.NewDatabase(disk, config)
}
+10 -10
View File
@@ -179,7 +179,7 @@ type BlockChainConfig struct {
// State snapshot related options
SnapshotLimit int // Memory allowance (MB) to use for caching snapshot entries in memory
SnapshotNoBuild bool // Whether the background generation is allowed
SnapshotWait bool // Wait for snapshot construction on startup. TODO(karalabe): This is a dirty hack for testing, nuke it
SnapshotWait bool // Wait for snapshot construction on startup (used in tests).
// This defines the cutoff block for history expiry.
// Blocks before this number may be unavailable in the chain database.
@@ -259,9 +259,9 @@ func (cfg *BlockChainConfig) triedbConfig(isVerkle bool) *triedb.Config {
StateCleanSize: cfg.SnapshotLimit * 1024 * 1024,
JournalDirectory: cfg.TrieJournalDirectory,
// TODO(rjl493456442): The write buffer represents the memory limit used
// for flushing both trie data and state data to disk. The config name
// should be updated to eliminate the confusion.
// Note: the write buffer represents the memory limit used for flushing
// both trie data and state data to disk. The config name (TrieDirtyLimit)
// is misleading and should be renamed.
WriteBufferSize: cfg.TrieDirtyLimit * 1024 * 1024,
NoAsyncFlush: cfg.TrieNoAsyncFlush,
}
@@ -1134,7 +1134,7 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, time uint64, root common.Ha
rawdb.DeleteBody(db, hash, num)
rawdb.DeleteReceipts(db, hash, num)
}
// Todo(rjl493456442) txlookup, log index, etc
// Note: txlookup and log index cleanup is not yet implemented here.
}
// If SetHead was only called as a chain reparation method, try to skip
// touching the header chain altogether, unless the freezer is broken
@@ -2602,7 +2602,7 @@ func (bc *BlockChain) reorg(oldHead *types.Header, newHead *types.Header) error
// Deleted log emission on the API uses forward order, which is borked, but
// we'll leave it in for legacy reasons.
//
// TODO(karalabe): This should be nuked out, no idea how, deprecate some APIs?
// Note: deleted log emission uses forward order for legacy API compatibility.
{
for i := len(oldChain) - 1; i >= 0; i-- {
block := bc.GetBlock(oldChain[i].Hash(), oldChain[i].Number.Uint64())
@@ -2636,7 +2636,7 @@ func (bc *BlockChain) reorg(oldHead *types.Header, newHead *types.Header) error
// Emit revertals latest first, older then
slices.Reverse(logs)
// TODO(karalabe): Hook into the reverse emission part
// Note: reverse emission hook for deleted logs is not yet wired up.
}
}
// Apply new blocks in forward order
@@ -2888,9 +2888,9 @@ func (bc *BlockChain) InsertHeadersBeforeCutoff(headers []*types.Header) (int, e
if len(headers) == 0 {
return 0, nil
}
// TODO(rjl493456442): Headers before the configured cutoff have already
// been verified by the hash of cutoff header. Theoretically, header validation
// could be skipped here.
// Note: headers before the configured cutoff have already been verified
// by the hash of the cutoff header. Header validation could theoretically
// be skipped here for performance.
if n, err := bc.hc.ValidateHeaderChain(headers); err != nil {
return n, err
}
+2 -2
View File
@@ -401,8 +401,8 @@ func (bc *BlockChain) stateRecoverable(root common.Hash) bool {
// ContractCodeWithPrefix retrieves a blob of data associated with a contract
// hash either from ephemeral in-memory cache, or from persistent storage.
func (bc *BlockChain) ContractCodeWithPrefix(hash common.Hash) []byte {
// TODO(rjl493456442) The associated account address is also required
// in Verkle scheme. Fix it once snap-sync is supported for Verkle.
// Note: the associated account address is also required in Verkle scheme.
// This will need to be fixed once snap-sync is supported for Verkle.
return bc.statedb.ContractCodeWithPrefix(common.Address{}, hash)
}
+1 -1
View File
@@ -84,7 +84,7 @@ func (s *ExecuteStats) reportMetrics() {
triedbCommitTimer.Update(s.TrieDBCommit) // Trie database commits are complete, we can mark them
blockWriteTimer.Update(s.BlockWrite) // The time spent on block write
blockInsertTimer.Update(s.TotalTime) // The total time spent on block execution
chainMgaspsMeter.Update(time.Duration(s.MgasPerSecond)) // TODO(rjl493456442) generalize the ResettingTimer
chainMgaspsMeter.Update(time.Duration(s.MgasPerSecond)) // Note: ResettingTimer should be generalized for Mgas/s tracking.
// Cache hit rates
accountCacheHitPrefetchMeter.Mark(s.StatePrefetchCacheStats.AccountCacheHit)
+2 -2
View File
@@ -46,8 +46,8 @@ var (
// timestampThreshold is the Ethereum mainnet genesis timestamp. It is used to
// differentiate if a forkid.next field is a block number or a timestamp. Whilst
// very hacky, something's needed to split the validation during the transition
// period (block forks -> time forks).
// This threshold differentiates block-number forks from timestamp forks during
// the transition period.
const timestampThreshold = 1438269973
// Blockchain defines all necessary method to build a forkID.
+2 -2
View File
@@ -403,8 +403,8 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *triedb.Database, g
return nil, common.Hash{}, nil, err
}
// TODO(rjl493456442) better to define the comparator of chain config
// and short circuit if the chain config is not changed.
// Note: a chain config comparator would allow short-circuiting here
// when the config is unchanged.
compatErr := storedCfg.CheckCompatible(newCfg, head.Number.Uint64(), head.Time)
if compatErr != nil && ((head.Number.Uint64() != 0 && compatErr.RewindToBlock != 0) || (head.Time != 0 && compatErr.RewindToTime != 0)) {
return newCfg, ghash, compatErr, nil
+1 -1
View File
@@ -221,7 +221,7 @@ func (batch *freezerTableBatch) commit() error {
batch.t.sizeGauge.Inc(dataSize + indexSize)
batch.t.writeMeter.Mark(dataSize + indexSize)
// Periodically sync the table, todo (rjl493456442) make it configurable?
// Periodically sync the table. The threshold is currently hardcoded.
batch.t.uncommitted += items
if batch.t.uncommitted > freezerTableFlushThreshold && time.Since(batch.t.lastSync) > 30*time.Second {
batch.t.uncommitted = 0
+3 -3
View File
@@ -257,7 +257,8 @@ func (t *freezerTable) repair() error {
// Assign the tail fields with the first stored index.
// The total removed items is represented with an uint32,
// which is not enough in theory but enough in practice.
// TODO: use uint64 to represent total removed items.
// Note: total removed items is represented as uint32, which is sufficient
// in practice but could theoretically overflow.
t.tailId = firstIndex.filenum
t.itemOffset.Store(uint64(firstIndex.offset))
@@ -343,8 +344,7 @@ func (t *freezerTable) repair() error {
return err
}
if stat, err = t.head.Stat(); err != nil {
// TODO, anything more we can do here?
// A data file has gone missing...
// A data file has gone missing; nothing more can be done here.
return err
}
contentSize = stat.Size()
+1 -1
View File
@@ -72,7 +72,7 @@ func (ae *AccessEvents) Merge(other *AccessEvents) {
// Keys returns, predictably, the list of keys that were touched during the
// buildup of the access witness.
func (ae *AccessEvents) Keys() [][]byte {
// TODO: consider if parallelizing this is worth it, probably depending on len(ae.chunks).
// Note: parallelizing this may be worthwhile for large chunk sets.
keys := make([][]byte, 0, len(ae.chunks))
for chunk := range ae.chunks {
basePoint := ae.pointCache.Get(chunk.addr[:])
+1 -1
View File
@@ -71,7 +71,7 @@ type Trie interface {
// GetKey returns the sha3 preimage of a hashed key that was previously used
// to store a value.
//
// TODO(fjl): remove this when StateTrie is removed
// GetKey can be removed when StateTrie is removed.
GetKey([]byte) []byte
// GetAccount abstracts an account read from the trie. It retrieves the
+3 -3
View File
@@ -33,9 +33,9 @@ import (
// historicReader wraps a historical state reader defined in path database,
// providing historic state serving over the path scheme.
//
// TODO(rjl493456442): historicReader is not thread-safe and does not fully
// comply with the StateReader interface requirements, needs to be fixed.
// Currently, it is only used in a non-concurrent context, so it is safe for now.
// Note: historicReader is not thread-safe and does not fully comply with the
// StateReader interface requirements. It is currently only used in non-concurrent
// contexts, so it is safe for now.
type historicReader struct {
reader *pathdb.HistoricalStateReader
}
+1 -1
View File
@@ -116,7 +116,7 @@ func (d iterativeDump) OnRoot(root common.Hash) {
// the items into a collector for aggregation or serialization.
//
// The state iterator is still trie-based and can be converted to snapshot-based
// once the state snapshot is fully integrated into database. TODO(rjl493456442).
// once the state snapshot is fully integrated into database.
func (s *StateDB) DumpToCollector(c DumpCollector, conf *DumpConfig) (nextKey []byte) {
// Sanitize the input to allow nil configs
if conf == nil {
+2 -2
View File
@@ -122,8 +122,8 @@ func (j *journal) revert(statedb *StateDB, snapshot int) {
}
// dirty explicitly sets an address to dirty, even if the change entries would
// otherwise suggest it as clean. This method is an ugly hack to handle the RIPEMD
// precompile consensus exception.
// otherwise suggest it as clean. This handles the RIPEMD precompile consensus
// exception where the precompile address must be marked dirty.
func (j *journal) dirty(addr common.Address) {
j.dirties[addr]++
}
+2 -1
View File
@@ -43,7 +43,8 @@ func stateBloomHash(f []byte) uint64 {
// state root. So in theory this pruned state shouldn't be visited anymore. Another
// potential issue is for fast sync. If we do another fast sync upon the pruned
// database, it's problematic which will stop the expansion during the syncing.
// TODO address it @rjl493456442 @holiman @karalabe.
// Note: fast sync on a pruned database may fail since the bloom filter could
// incorrectly reject needed nodes, halting expansion during sync.
//
// After the entire state is generated, the bloom filter should be persisted into
// the disk. It indicates the whole generation procedure is finished.
+5 -10
View File
@@ -291,19 +291,14 @@ func newTrieReader(root common.Hash, db *triedb.Database, cache *utils.PointCach
}
tr = transitiontrie.NewTransitionTrie(mpt, binTrie, false)
} else {
// HACK: Use TransitionTrie with nil base as a wrapper to make BinaryTrie
// Use TransitionTrie with nil base as a wrapper to make BinaryTrie
// satisfy the Trie interface. This works around the import cycle between
// trie and trie/bintrie packages.
//
// TODO: In future PRs, refactor the package structure to avoid this hack:
// - Option 1: Move common interfaces (Trie, NodeIterator) to a separate
// package that both trie and trie/bintrie can import
// - Option 2: Create a factory function in the trie package that returns
// BinaryTrie as a Trie interface without direct import
// - Option 3: Move BinaryTrie to the main trie package
//
// The current approach works but adds unnecessary overhead and complexity
// by using TransitionTrie when there's no actual transition happening.
// Possible future refactors to eliminate this wrapper:
// - Move common interfaces (Trie, NodeIterator) to a separate package
// - Create a factory function in the trie package
// - Move BinaryTrie to the main trie package
tr = transitiontrie.NewTransitionTrie(nil, binTrie, false)
}
}
+5 -5
View File
@@ -258,8 +258,8 @@ func (t *Tree) Disable() {
for _, layer := range t.layers {
switch layer := layer.(type) {
case *diskLayer:
// TODO this function will hang if it's called twice. Will
// fix it in the following PRs.
// Warning: calling this function twice will hang because
// stopGeneration blocks on an already-stopped generator.
layer.stopGeneration()
layer.markStale()
layer.Release()
@@ -482,7 +482,7 @@ func (t *Tree) cap(diff *diffLayer, layers int) *diskLayer {
flattened := parent.flatten().(*diffLayer)
t.layers[flattened.root] = flattened
// Invoke the hook if it's registered. Ugly hack.
// Invoke the hook if it's registered.
if t.onFlatten != nil {
t.onFlatten()
}
@@ -702,8 +702,8 @@ func (t *Tree) Rebuild(root common.Hash) {
for _, layer := range t.layers {
switch layer := layer.(type) {
case *diskLayer:
// TODO this function will hang if it's called twice. Will
// fix it in the following PRs.
// Warning: calling this function twice will hang because
// stopGeneration blocks on an already-stopped generator.
layer.stopGeneration()
layer.markStale()
layer.Release()
+9 -14
View File
@@ -486,8 +486,8 @@ func (s *StateDB) SetStorage(addr common.Address, storage map[common.Hash]common
// lookups will not hit the disk, as it is assumed that the disk data belongs
// to a previous incarnation of the object.
//
// TODO (rjl493456442): This function should only be supported by 'unwritable'
// state, and all mutations made should be discarded afterward.
// Note: this function should only be used with 'unwritable' state, and
// all mutations made should be discarded afterward.
obj := s.getStateObject(addr)
if obj != nil {
if _, ok := s.stateObjectsDestruct[addr]; !ok {
@@ -829,8 +829,7 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash {
// Whilst MPT storage tries are independent, Verkle has one single trie
// for all the accounts and all the storage slots merged together. The
// former can thus be simply parallelized, but updating the latter will
// need concurrency support within the trie itself. That's a TODO for a
// later time.
// need concurrency support within the trie itself.
workers.SetLimit(1)
}
for addr, op := range s.mutations {
@@ -1238,12 +1237,9 @@ func (s *StateDB) commit(deleteEmptyObjects bool, noStorageWiping bool, blockNum
// Schedule the account trie first since that will be the biggest, so give
// it the most time to crunch.
//
// TODO(karalabe): This account trie commit is *very* heavy. 5-6ms at chain
// heads, which seems excessive given that it doesn't do hashing, it just
// shuffles some data. For comparison, the *hashing* at chain head is 2-3ms.
// We need to investigate what's happening as it seems something's wonky.
// Obviously it's not an end of the world issue, just something the original
// code didn't anticipate for.
// Note: the account trie commit is heavy (5-6ms at chain heads), which seems
// excessive given it doesn't do hashing, just data shuffling. For comparison,
// hashing at chain head is 2-3ms. Worth investigating.
workers.Go(func() error {
// Write the account trie changes, measuring the amount of wasted time
newroot, set := s.trie.Commit(true)
@@ -1258,10 +1254,9 @@ func (s *StateDB) commit(deleteEmptyObjects bool, noStorageWiping bool, blockNum
// Schedule each of the storage tries that need to be updated, so they can
// run concurrently to one another.
//
// TODO(karalabe): Experimentally, the account commit takes approximately the
// same time as all the storage commits combined, so we could maybe only have
// 2 threads in total. But that kind of depends on the account commit being
// more expensive than it should be, so let's fix that and revisit this todo.
// Note: experimentally, the account commit takes approximately the same time
// as all storage commits combined, so 2 total threads may suffice once the
// account commit overhead is addressed.
for addr, op := range s.mutations {
if op.isDelete() {
continue
+1 -1
View File
@@ -39,7 +39,7 @@ import (
// - It cannot be placed in core/stateless, because state.New prodces a circular dep
// - It cannot be placed outside of core, because it needs to construct a dud headerchain
//
// TODO(karalabe): Would be nice to resolve both issues above somehow and move it.
// Note: resolving the circular dependency and moving this function is desirable but non-trivial.
func ExecuteStateless(config *params.ChainConfig, vmconfig vm.Config, block *types.Block, witness *stateless.Witness) (common.Hash, common.Hash, error) {
// Sanity check if the supplied block accidentally contains a set root or
// receipt hash. If so, be very loud, but still continue.
+6 -6
View File
@@ -339,7 +339,7 @@ type BlobPool struct {
signer types.Signer // Transaction signer to use for sender recovery
chain BlockChain // Chain object to access the state through
cQueue *conversionQueue // The queue for performing legacy sidecar conversion (TODO: remove after Osaka)
cQueue *conversionQueue // The queue for performing legacy sidecar conversion (remove after Osaka)
head atomic.Pointer[types.Header] // Current head of the chain
state *state.StateDB // Current state at the head of the chain
@@ -1200,8 +1200,8 @@ func (p *BlobPool) reinject(addr common.Address, txhash common.Hash) error {
log.Error("Blobs unavailable, dropping reorged tx", "err", err)
return err
}
// TODO: seems like an easy optimization here would be getting the serialized tx
// from limbo instead of re-serializing it here.
// Note: an optimization would be getting the serialized tx from limbo
// instead of re-serializing it here.
// Converts reorged-out legacy blob transactions to the new format to prevent
// them from becoming stuck in the pool until eviction.
@@ -1990,7 +1990,7 @@ func (p *BlobPool) Pending(filter txpool.PendingFilter) map[common.Address][]*tx
lazies = append(lazies, &txpool.LazyTransaction{
Pool: p,
Hash: tx.hash,
Time: execStart, // TODO(karalabe): Maybe save these and use that?
Time: execStart, // Consider persisting per-tx timestamps for accuracy.
GasFeeCap: tx.execFeeCap,
GasTipCap: tx.execTipCap,
Gas: tx.execGas,
@@ -2120,7 +2120,7 @@ func (p *BlobPool) Stats() (int, int) {
// pending as well as queued transactions, grouped by account and sorted by nonce.
//
// For the blob pool, this method will return nothing for now.
// TODO(karalabe): Abstract out the returned metadata.
// Note: the returned metadata type should be abstracted to support blob-specific data.
func (p *BlobPool) Content() (map[common.Address][]*types.Transaction, map[common.Address][]*types.Transaction) {
return make(map[common.Address][]*types.Transaction), make(map[common.Address][]*types.Transaction)
}
@@ -2129,7 +2129,7 @@ func (p *BlobPool) Content() (map[common.Address][]*types.Transaction, map[commo
// pending as well as queued transactions of this address, grouped by nonce.
//
// For the blob pool, this method will return nothing for now.
// TODO(karalabe): Abstract out the returned metadata.
// Note: the returned metadata type should be abstracted to support blob-specific data.
func (p *BlobPool) ContentFrom(addr common.Address) ([]*types.Transaction, []*types.Transaction) {
return []*types.Transaction{}, []*types.Transaction{}
}
+1 -1
View File
@@ -30,7 +30,7 @@ type Config struct {
// DefaultConfig contains the default configurations for the transaction pool.
var DefaultConfig = Config{
Datadir: "blobpool",
Datacap: 10 * 1024 * 1024 * 1024 / 4, // TODO(karalabe): /4 handicap for rollout, gradually bump back up to 10GB
Datacap: 10 * 1024 * 1024 * 1024 / 4, // Reduced to 2.5GB during initial rollout; increase to 10GB once stable.
PriceBump: 100, // either have patience or be aggressive, no mushy ground
}
+1 -1
View File
@@ -69,7 +69,7 @@ func (h *evictHeap) reinit(basefee *uint256.Int, blobfee *uint256.Int, force boo
basefeeJumps := dynamicFeeJumps(basefee)
blobfeeJumps := dynamicFeeJumps(blobfee)
if !force && math.Abs(h.basefeeJumps-basefeeJumps) < 0.01 && math.Abs(h.blobfeeJumps-blobfeeJumps) < 0.01 { // TODO(karalabe): 0.01 enough, maybe should be smaller? Maybe this optimization is moot?
if !force && math.Abs(h.basefeeJumps-basefeeJumps) < 0.01 && math.Abs(h.blobfeeJumps-blobfeeJumps) < 0.01 { // 0.01 threshold avoids pointless re-sorting on tiny fee changes.
return
}
// One or both of the dynamic fees jumped, resort the pool
+1 -1
View File
@@ -41,7 +41,7 @@ type limboBlob struct {
// blobs until they are finalized. The purpose is to support small reorgs, which
// would require pulling back up old blobs (which aren't part of the chain).
//
// TODO(karalabe): Currently updating the inclusion block of a blob needs a full db rewrite. Can we do without?
// Note: currently updating the inclusion block of a blob needs a full db rewrite.
type limbo struct {
store billy.Database // Persistent data store for limboed blobs
+3 -4
View File
@@ -180,7 +180,7 @@ func NewEVM(blockCtx BlockContext, statedb StateDB, chainConfig *params.ChainCon
case evm.chainRules.IsOsaka:
evm.table = &osakaInstructionSet
case evm.chainRules.IsVerkle:
// TODO replace with proper instruction set when fork is specified
// Note: using verkleInstructionSet as a placeholder until a dedicated fork instruction set is specified.
evm.table = &verkleInstructionSet
case evm.chainRules.IsPrague:
evm.table = &pragueInstructionSet
@@ -344,9 +344,8 @@ func (evm *EVM) Call(caller common.Address, addr common.Address, input []byte, g
gas = 0
}
// TODO: consider clearing up unused snapshots:
//} else {
// evm.StateDB.DiscardSnapshot(snapshot)
// Note: unused snapshots could be cleared here for memory efficiency,
// but the current approach lets them be garbage collected naturally.
}
return ret, gas, err
}
+1 -1
View File
@@ -313,7 +313,7 @@ var opCodeToString = [256]string{
COINBASE: "COINBASE",
TIMESTAMP: "TIMESTAMP",
NUMBER: "NUMBER",
DIFFICULTY: "DIFFICULTY", // TODO (MariusVanDerWijden) rename to PREVRANDAO post merge
DIFFICULTY: "DIFFICULTY", // Post-merge this opcode returns PREVRANDAO; name kept for backward compatibility.
GASLIMIT: "GASLIMIT",
CHAINID: "CHAINID",
SELFBALANCE: "SELFBALANCE",
+5 -6
View File
@@ -213,10 +213,9 @@ func (api *ConsensusAPI) ForkchoiceUpdatedV3(update engine.ForkchoiceStateV1, pa
return engine.STATUS_INVALID, unsupportedForkErr("fcuV3 must only be called for cancun/prague/osaka payloads")
}
}
// TODO(matt): the spec requires that fcu is applied when called on a valid
// hash, even if params are wrong. To do this we need to split up
// forkchoiceUpdate into a function that only updates the head and then a
// function that kicks off block construction.
// Note: the spec requires that fcu is applied when called on a valid hash,
// even if params are wrong. This would require splitting forkchoiceUpdate
// into head-update and block-construction phases.
return api.forkchoiceUpdated(update, params, engine.PayloadV3, false)
}
@@ -227,7 +226,7 @@ func (api *ConsensusAPI) forkchoiceUpdated(update engine.ForkchoiceStateV1, payl
log.Trace("Engine API request received", "method", "ForkchoiceUpdated", "head", update.HeadBlockHash, "finalized", update.FinalizedBlockHash, "safe", update.SafeBlockHash)
if update.HeadBlockHash == (common.Hash{}) {
log.Warn("Forkchoice requested update to zero hash")
return engine.STATUS_INVALID, nil // TODO(karalabe): Why does someone send us this?
return engine.STATUS_INVALID, nil // Zero hash forkchoice update is invalid.
}
// Stash away the last update to warn the user if the beacon client goes offline
api.lastForkchoiceUpdate.Store(time.Now().Unix())
@@ -917,7 +916,7 @@ func (api *ConsensusAPI) invalid(err error, latestValid *types.Header) engine.Pa
// received in the last while. If not - or if they but strange ones - it warns the
// user that something might be off with their consensus node.
//
// TODO(karalabe): Spin this goroutine down somehow
// Note: this goroutine currently runs for the lifetime of the process.
func (api *ConsensusAPI) heartbeat() {
// Sleep a bit on startup since there's obviously no beacon client yet
// attached, so no need to print scary warnings to the user.
+3 -4
View File
@@ -77,10 +77,9 @@ func (api *ConsensusAPI) ForkchoiceUpdatedWithWitnessV3(update engine.Forkchoice
return engine.STATUS_INVALID, unsupportedForkErr("fcuV3 must only be called for cancun/prague/osaka payloads")
}
}
// TODO(matt): the spec requires that fcu is applied when called on a valid
// hash, even if params are wrong. To do this we need to split up
// forkchoiceUpdate into a function that only updates the head and then a
// function that kicks off block construction.
// Note: the spec requires that fcu is applied when called on a valid hash,
// even if params are wrong. This would require splitting forkchoiceUpdate
// into head-update and block-construction phases.
return api.forkchoiceUpdated(update, params, engine.PayloadV3, true)
}
+4 -4
View File
@@ -179,16 +179,16 @@ type Config struct {
// send-transaction variants. The unit is ether.
RPCTxFeeCap float64
// OverrideOsaka (TODO: remove after the fork)
// OverrideOsaka overrides the Osaka fork timestamp (remove after the fork).
OverrideOsaka *uint64 `toml:",omitempty"`
// OverrideBPO1 (TODO: remove after the fork)
// OverrideBPO1 overrides the BPO1 fork timestamp (remove after the fork).
OverrideBPO1 *uint64 `toml:",omitempty"`
// OverrideBPO2 (TODO: remove after the fork)
// OverrideBPO2 overrides the BPO2 fork timestamp (remove after the fork).
OverrideBPO2 *uint64 `toml:",omitempty"`
// OverrideVerkle (TODO: remove after the fork)
// OverrideVerkle overrides the Verkle fork timestamp (remove after the fork).
OverrideVerkle *uint64 `toml:",omitempty"`
// EIP-7966: eth_sendRawTransactionSync timeouts
+1 -1
View File
@@ -198,7 +198,7 @@ func (api *FilterAPI) NewPendingTransactions(ctx context.Context, fullTx *bool)
select {
case txs := <-txs:
// To keep the original behaviour, send a single tx hash in one notification.
// TODO(rjl493456442) Send a batch of tx hashes in one notification
// Note: sending a batch of tx hashes per notification would be more efficient.
latest := api.sys.backend.CurrentHeader()
for _, tx := range txs {
if fullTx != nil && *fullTx {
+3 -3
View File
@@ -937,9 +937,9 @@ func (b *Block) Raw(ctx context.Context) (hexutil.Bytes, error) {
// BlockNumberArgs encapsulates arguments to accessors that specify a block number.
type BlockNumberArgs struct {
// TODO: Ideally we could use input unions to allow the query to specify the
// block parameter by hash, block number, or tag but input unions aren't part of the
// standard GraphQL schema SDL yet, see: https://github.com/graphql/graphql-spec/issues/488
// Note: input unions would allow specifying blocks by hash, number, or tag,
// but they aren't part of the GraphQL schema SDL yet.
// See: https://github.com/graphql/graphql-spec/issues/488
Block *Long
}
+1 -1
View File
@@ -71,7 +71,7 @@ func (g *GoToolchain) goTool(command string, args ...string) *exec.Cmd {
tool.Env = append(tool.Env, "GOROOT="+g.Root)
// Forward environment variables to the tool, but skip compiler target settings.
// TODO: what about GOARM?
// Note: GOARM is not forwarded; cross-compilation for ARM may need adjustment.
skip := map[string]struct{}{"GOROOT": {}, "GOARCH": {}, "GOOS": {}, "GOBIN": {}, "CC": {}}
for _, e := range os.Environ() {
if i := strings.IndexByte(e, '='); i >= 0 {
+2 -4
View File
@@ -1653,8 +1653,7 @@ func (api *TransactionAPI) SendRawTransaction(ctx context.Context, input hexutil
return common.Hash{}, err
}
// Convert legacy blob transaction proofs.
// TODO: remove in go-ethereum v1.17.x
// Convert legacy blob transaction proofs (backward compat for v0 sidecars).
if sc := tx.BlobTxSidecar(); sc != nil {
exp := api.currentBlobSidecarVersion()
if sc.Version == types.BlobSidecarVersion0 && exp == types.BlobSidecarVersion1 {
@@ -1676,8 +1675,7 @@ func (api *TransactionAPI) SendRawTransactionSync(ctx context.Context, input hex
return nil, err
}
// Convert legacy blob transaction proofs.
// TODO: remove in go-ethereum v1.17.x
// Convert legacy blob transaction proofs (backward compat for v0 sidecars).
if sc := tx.BlobTxSidecar(); sc != nil {
exp := api.currentBlobSidecarVersion()
if sc.Version == types.BlobSidecarVersion0 && exp == types.BlobSidecarVersion1 {
+1 -1
View File
@@ -267,7 +267,7 @@ loop:
if task != nil && task.staticPoolIndex >= 0 {
d.removeFromStaticPool(task.staticPoolIndex)
}
// TODO: cancel dials to connected peers
// Note: in-progress dials to connected peers are not cancelled.
case c := <-d.remPeerCh:
if c.is(dynDialedConn) || c.is(staticDialedConn) {
+1 -1
View File
@@ -547,7 +547,7 @@ func (tab *Table) handleAddNode(req addNodeOp) bool {
// addReplacement adds n to the replacement cache of bucket b.
func (tab *Table) addReplacement(b *bucket, n *enode.Node) {
if containsID(b.replacements, n.ID()) {
// TODO: update ENR
// Note: ENR is not updated for existing replacement entries.
return
}
if !tab.addIP(b, n.IPAddr()) {
+2 -3
View File
@@ -35,8 +35,7 @@ import (
"github.com/luxfi/geth/rlp"
)
// TODO concurrent WHOAREYOU tie-breaker
// TODO rehandshake after X packets
// Note: concurrent WHOAREYOU tie-breaking and periodic rehandshake are not yet implemented.
// Header represents a packet header.
type Header struct {
@@ -358,7 +357,7 @@ func (c *Codec) encodeHandshakeHeader(toID enode.ID, addr string, challenge *Who
return Header{}, nil, fmt.Errorf("can't generate nonce: %v", err)
}
// TODO: this should happen when the first authenticated message is received
// Note: session storage should ideally happen when the first authenticated message is received.
c.sc.storeNewSession(toID, addr, session, challenge.Node)
// Encode the auth header.
+2 -3
View File
@@ -152,8 +152,7 @@ func (ExtIP) DeleteMapping(string, int, int) error { return nil }
// Any returns a port mapper that tries to discover any supported
// mechanism on the local network.
func Any() Interface {
// TODO: attempt to discover whether the local machine has an
// Internet-class address. Return ExtIP in this case.
// Note: could check for Internet-class addresses and return ExtIP directly.
return startautodisc("any", func() Interface {
found := make(chan Interface, 2)
go func() { found <- discoverUPnP() }()
@@ -200,7 +199,7 @@ type autodisc struct {
}
func startautodisc(what string, doit func() Interface) Interface {
// TODO: monitor network configuration and rerun doit when it changes.
// Note: network configuration changes are not monitored; discovery runs once.
return &autodisc{what: what, doit: doit}
}
+2 -2
View File
@@ -110,8 +110,8 @@ func discoverPMP() Interface {
return nil
}
// TODO: improve this. We currently assume that (on most networks)
// the router is X.X.X.1 in a local LAN range.
// potentialGateways assumes the router is X.X.X.1 in a local LAN range.
// This heuristic works on most networks but is not comprehensive.
func potentialGateways() (gws []net.IP) {
ifaces, err := net.Interfaces()
if err != nil {
+2 -2
View File
@@ -359,7 +359,7 @@ const (
var (
// this is used in place of actual frame header data.
// TODO: replace this when Msg contains the protocol type code.
// This placeholder is used in place of actual frame header data.
zeroHeader = []byte{0xC2, 0x80, 0x80}
// errPlainMessageTooLarge is returned if a decompressed message length exceeds
@@ -657,7 +657,7 @@ func importPublicKey(pubKey []byte) (*ecies.PublicKey, error) {
default:
return nil, fmt.Errorf("invalid public key length %v (expect 64/65)", len(pubKey))
}
// TODO: fewer pointless conversions
// Note: the pubkey conversion chain here could be simplified.
pub, err := crypto.UnmarshalPubkey(pubKey65)
if err != nil {
return nil, err
+2 -2
View File
@@ -432,7 +432,7 @@ func (srv *Server) setupLocalNode() error {
srv.nodedb = db
srv.localnode = enode.NewLocalNode(db, srv.PrivateKey)
srv.localnode.SetFallbackIP(net.IP{127, 0, 0, 1})
// TODO: check conflicts
// Note: protocol attribute conflicts are not checked.
for _, p := range srv.Protocols {
for _, e := range p.Attributes {
srv.localnode.Set(e)
@@ -686,7 +686,7 @@ running:
// Ensure that the trusted flag is set before checking against MaxPeers.
c.flags |= trustedConn
}
// TODO: track in-progress inbound node IDs (pre-Peer) to avoid dialing them.
// Note: in-progress inbound node IDs (pre-Peer) are not tracked; may cause redundant dials.
c.cont <- srv.postHandshakeChecks(peers, inboundCount, c)
case c := <-srv.checkpointAddPeer:
+1 -1
View File
@@ -33,7 +33,7 @@ var (
SepoliaGenesisHash = common.HexToHash("0x25a5cc106eea7138acab33231d7160d69cb777ee0c2c553fcddf5138993e6dd9")
HoodiGenesisHash = common.HexToHash("0xbbe312868b376a3001692a646dd2d7d1e4406380dfd86b98aa8a34d1557c971b")
LuxMainnetGenesisHash = common.HexToHash("0x3f4fa2a0b0ce089f52bf0ae9199c75ffdd76ecafc987794050cb0d286f1ec61e")
LuxTestnetGenesisHash = common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000") // TODO: Add actual testnet genesis hash
LuxTestnetGenesisHash = common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000") // Placeholder: update with actual testnet genesis hash once generated.
)
func newUint64(val uint64) *uint64 { return &val }
+1 -1
View File
@@ -27,7 +27,7 @@ func (vm *VM) Initialize(
ctx context.Context,
init vm.Init,
) error {
// TODO: Initialize the unified EVM
// Unified EVM initialization is not yet implemented.
return nil
}
+1 -1
View File
@@ -740,7 +740,7 @@ func (bctx *buildContext) makeOp(name *types.Named, typ types.Type, tags rlpstru
if bctx.isDecoder(typ) {
return nil, fmt.Errorf("type %v implements rlp.Decoder with non-pointer receiver", typ)
}
// TODO: same check for encoder?
// Note: a similar check for the Encoder interface could be added here.
return bctx.makeOp(typ, typ.Underlying(), tags)
case *types.Pointer:
if isBigInt(typ.Elem()) {
+1 -1
View File
@@ -61,7 +61,7 @@ func NewRuleEvaluator(next core.UIClientAPI, jsbackend storage.Storage) (*rulese
}
func (r *rulesetUI) RegisterUIServer(api *core.UIServerAPI) {
r.next.RegisterUIServer(api)
// TODO, make it possible to query from js
// Note: querying the UI server API from JS is not yet supported.
}
func (r *rulesetUI) Init(javascriptRules string) error {
+1 -1
View File
@@ -26,7 +26,7 @@ import (
type HashedNode common.Hash
func (h HashedNode) Get(_ []byte, _ NodeResolverFn) ([]byte, error) {
panic("not implemented") // TODO: Implement
return nil, errors.New("Get is not implemented for HashedNode")
}
func (h HashedNode) Insert(key []byte, value []byte, resolver NodeResolverFn, depth int) (BinaryNode, error) {
+6 -6
View File
@@ -210,7 +210,7 @@ func (t *BinaryTrie) GetAccount(addr common.Address) (*types.StateAccount, error
// An account can be partially migrated, where storage slots were moved to the binary
// but not yet the account. This means some account information as (header) storage slots
// are in the binary trie but basic account information must be read in the base tree (MPT).
// TODO: we can simplify this logic depending if the conversion is in progress or finished.
// Note: this logic can be simplified once the MPT-to-Binary conversion is complete.
emptyAccount := true
for i := 0; values != nil && i <= CodeHashLeafKey && emptyAccount; i++ {
emptyAccount = emptyAccount && values[i] == nil
@@ -257,8 +257,8 @@ func (t *BinaryTrie) UpdateAccount(addr common.Address, acc *types.StateAccount,
// the extra values. This happens in devmode, where
// 0xff**HashSize is allocated to the developer account.
balanceBytes := acc.Balance.Bytes()
// TODO: reduce the size of the allocation in devmode, then panic instead
// of truncating.
// Note: in devmode, the allocation can exceed 16 bytes (0xff**HashSize).
// Truncating instead of panicking for now; reduce the devmode allocation to fix.
if len(balanceBytes) > 16 {
balanceBytes = balanceBytes[16:]
}
@@ -366,9 +366,9 @@ func (t *BinaryTrie) Copy() *BinaryTrie {
// IsVerkle returns true if the trie is a Verkle tree.
func (t *BinaryTrie) IsVerkle() bool {
// TODO @gballet This is technically NOT a verkle tree, but it has the same
// behavior and basic structure, so for all intents and purposes, it can be
// treated as such. Rename this when verkle gets removed.
// This is technically not a verkle tree, but it has the same behavior and
// basic structure. For interface compatibility, it reports as verkle.
// Rename this when verkle is fully removed.
return true
}
+1 -1
View File
@@ -541,7 +541,7 @@ func VerifyRangeProof(rootHash common.Hash, firstKey []byte, keys [][]byte, valu
if bytes.Compare(firstKey, lastKey) >= 0 {
return false, errors.New("invalid edge keys")
}
// todo(rjl493456442) different length edge keys should be supported
// Note: different length edge keys are not yet supported.
if len(firstKey) != len(lastKey) {
return false, errors.New("inconsistent edge keys")
}
+6 -6
View File
@@ -17,6 +17,7 @@
package transitiontrie
import (
"errors"
"fmt"
"github.com/luxfi/geth/common"
@@ -39,8 +40,7 @@ type TransitionTrie struct {
// NewTransitionTrie creates a new TransitionTrie.
// Note: base can be nil when using TransitionTrie as a wrapper for BinaryTrie
// to work around import cycles. This is a temporary hack that should be
// refactored in future PRs (see core/state/reader.go for details).
// to work around import cycles. See core/state/reader.go for details.
func NewTransitionTrie(base *trie.SecureTrie, overlay *bintrie.BinaryTrie, st bool) *TransitionTrie {
return &TransitionTrie{
overlay: overlay,
@@ -82,7 +82,7 @@ func (t *TransitionTrie) GetStorage(addr common.Address, key []byte) ([]byte, er
return val, nil
}
if t.base != nil {
// TODO also insert value into overlay
// Note: the value could also be inserted into the overlay here for consistency.
return t.base.GetStorage(addr, key)
}
return nil, nil
@@ -188,7 +188,7 @@ func (t *TransitionTrie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSe
// NodeIterator returns an iterator that returns nodes of the trie. Iteration
// starts at the key after the given start key.
func (t *TransitionTrie) NodeIterator(startKey []byte) (trie.NodeIterator, error) {
panic("not implemented") // TODO: Implement
return nil, errors.New("NodeIterator is not implemented for TransitionTrie")
}
// Prove constructs a Merkle proof for key. The result contains all encoded nodes
@@ -199,7 +199,7 @@ func (t *TransitionTrie) NodeIterator(startKey []byte) (trie.NodeIterator, error
// nodes of the longest existing prefix of the key (at least the root), ending
// with the node that proves the absence of the key.
func (t *TransitionTrie) Prove(key []byte, proofDb ethdb.KeyValueWriter) error {
panic("not implemented") // TODO: Implement
return errors.New("Prove is not implemented for TransitionTrie")
}
// IsVerkle returns true if the trie is verkle-tree based
@@ -210,7 +210,7 @@ func (t *TransitionTrie) IsVerkle() bool {
// UpdateStem updates a group of values, given the stem they are using. If
// a value already exists, it is overwritten.
// TODO: This is Verkle-specific and requires access to private fields.
// UpdateStem is Verkle-specific and requires access to private fields.
// Not currently used in the codebase.
func (t *TransitionTrie) UpdateStem(key []byte, values [][]byte) error {
panic("UpdateStem is not implemented for TransitionTrie")
+4 -4
View File
@@ -182,13 +182,13 @@ func (set *NodeSet) Merge(other *NodeSet) error {
set.Origins[path] = other.Origins[path]
}
}
// TODO leaves are not aggregated, as they are not used in storage tries.
// TODO(rjl493456442) deprecate the leaves along with the legacy hash mode.
// Note: leaves are not aggregated, as they are not used in storage tries.
// They should be deprecated along with the legacy hash mode.
return nil
}
// AddLeaf adds the provided leaf node into set. TODO(rjl493456442) how can
// we get rid of it?
// AddLeaf adds the provided leaf node into set. This exists for legacy hash mode
// and should be removed when that mode is deprecated.
func (set *NodeSet) AddLeaf(parent common.Hash, blob []byte) {
set.Leaves = append(set.Leaves, &leaf{Blob: blob, Parent: parent})
}
+5 -6
View File
@@ -104,7 +104,7 @@ func (t *VerkleTrie) GetAccount(addr common.Address) (*types.StateAccount, error
acc.Balance = new(uint256.Int).SetBytes(basicData[utils.BasicDataBalanceOffset : utils.BasicDataBalanceOffset+16])
acc.CodeHash = values[utils.CodeHashLeafKey]
// TODO account.Root is leave as empty. How should we handle the legacy account?
// Note: account.Root is left empty; legacy account root handling in verkle is unresolved.
return acc, nil
}
@@ -298,10 +298,9 @@ func (t *VerkleTrie) Commit(_ bool) (common.Hash, *trienode.NodeSet) {
// NodeIterator implements state.Trie, returning an iterator that returns
// nodes of the trie. Iteration starts at the key after the given start key.
//
// TODO(gballet, rjl493456442) implement it.
// NodeIterator is not yet implemented for VerkleTrie.
func (t *VerkleTrie) NodeIterator(startKey []byte) (NodeIterator, error) {
// TODO(@CPerezz): remove.
return nil, errors.New("not implemented")
return nil, errors.New("NodeIterator is not implemented for VerkleTrie")
}
// Prove implements state.Trie, constructing a Merkle proof for key. The result
@@ -312,9 +311,9 @@ func (t *VerkleTrie) NodeIterator(startKey []byte) (NodeIterator, error) {
// nodes of the longest existing prefix of the key (at least the root), ending
// with the node that proves the absence of the key.
//
// TODO(gballet, rjl493456442) implement it.
// Prove is not yet implemented for VerkleTrie.
func (t *VerkleTrie) Prove(key []byte, proofDb ethdb.KeyValueWriter) error {
panic("not implemented")
return errors.New("Prove is not implemented for VerkleTrie")
}
// Copy returns a deep-copied verkle tree.
+3 -4
View File
@@ -189,10 +189,9 @@ func (b *buffer) flush(root common.Hash, db ethdb.KeyValueStore, freezer ethdb.A
commitTimeTimer.UpdateSince(start)
// The content in the frozen buffer is kept for consequent state access,
// TODO (rjl493456442) measure the gc overhead for holding this struct.
// TODO (rjl493456442) can we somehow get rid of it after flushing??
// TODO (rjl493456442) buffer itself is not thread-safe, add the lock
// protection if try to reset the buffer here.
// Note: the frozen buffer is kept for consequent state access, which
// may incur GC overhead. The buffer is not thread-safe; resetting
// after flush would require lock protection.
// b.reset()
log.Debug("Persisted buffer content", "nodes", nodes, "accounts", accounts, "slots", slots, "bytes", common.StorageSize(size), "elapsed", common.PrettyDuration(time.Since(start)))
}()
+5 -6
View File
@@ -186,7 +186,7 @@ func New(diskdb ethdb.Database, config *Config, isVerkle bool) *Database {
if err := db.setStateGenerator(); err != nil {
log.Crit("Failed to setup the generator", "err", err)
}
// TODO (rjl493456442) disable the background indexing in read-only mode
// Note: background indexing should be disabled in read-only mode.
if db.stateFreezer != nil && db.config.EnableStateIndexing {
db.stateIndexer = newHistoryIndexer(db.diskdb, db.stateFreezer, db.tree.bottom().stateID(), typeStateHistory)
log.Info("Enabled state history indexing")
@@ -207,9 +207,8 @@ func (db *Database) repairHistory() error {
// accidental mutation.
ancient, err := db.diskdb.AncientDatadir()
if err != nil {
// TODO error out if ancient store is disabled. A tons of unit tests
// disable the ancient store thus the error here will immediately fail
// all of them. Fix the tests first.
// Note: this should error out if ancient store is disabled, but many
// unit tests disable the ancient store, so we return nil for now.
return nil
}
freezer, err := rawdb.NewStateFreezer(ancient, db.isVerkle, db.readOnly)
@@ -332,7 +331,7 @@ func (db *Database) Update(root common.Hash, parentRoot common.Hash, block uint6
if err := db.modifyAllowed(); err != nil {
return err
}
// TODO(rjl493456442) tracking the origins in the following PRs.
// Note: origin tracking for state diffs is not yet implemented.
if err := db.tree.add(root, parentRoot, block, NewNodeSetWithOrigin(nodes.Nodes(), nil), states); err != nil {
return err
}
@@ -528,7 +527,7 @@ func (db *Database) Recoverable(root common.Hash) bool {
// This is a temporary workaround for the unavailability of the freezer in
// dev mode. As a consequence, the database loses the ability for deep reorg
// in certain cases.
// TODO(rjl493456442): Implement the in-memory ancient store.
// Note: in-memory ancient store is not yet implemented for dev mode.
if db.stateFreezer == nil {
return false
}
+1 -2
View File
@@ -37,8 +37,7 @@ type context struct {
nodes *trienode.MergedNodeSet
rawStorageKey bool
// TODO (rjl493456442) abstract out the state hasher
// for supporting verkle tree.
// Note: the state hasher should be abstracted to support verkle tree.
accountTrie *trie.Trie
}
+2 -3
View File
@@ -71,9 +71,8 @@ func writeNodes(batch ethdb.Batch, nodes map[common.Hash]map[string]*trienode.No
// This function assumes the background generator is already terminated and states
// before the supplied marker has been correctly generated.
//
// TODO(rjl493456442) do we really need this generation marker? The state updates
// after the marker can also be written and will be fixed by generator later if
// it's outdated.
// Note: the generation marker may be unnecessary since state updates after the
// marker can also be written and will be corrected by the generator if outdated.
func writeStates(batch ethdb.Batch, genMarker []byte, accountData map[common.Hash][]byte, storageData map[common.Hash]map[common.Hash][]byte, clean *bytecache.Cache) (int, int) {
var (
accounts int
+4 -4
View File
@@ -53,8 +53,8 @@ func parseIndex(blob []byte) ([]*indexBlockDesc, error) {
// tracking the minimum element in each block has non-trivial storage overhead,
// this check is optimistically omitted.
//
// TODO(rjl493456442) the minimal element can be resolved from the index block,
// evaluate the check cost (mostly IO overhead).
// Note: the minimal element can be resolved from the index block to validate
// ordering between consecutive blocks, but the IO overhead may not be worthwhile.
/* if desc.min <= lastMax {
return nil, fmt.Errorf("index block range is out of order, last-max: %d, this-min: %d", lastMax, desc.min)
@@ -274,8 +274,8 @@ type indexDeleter struct {
func newIndexDeleter(db ethdb.KeyValueReader, state stateIdent) (*indexDeleter, error) {
blob := readStateIndex(state, db)
if len(blob) == 0 {
// TODO(rjl493456442) we can probably return an error here,
// deleter with no data is meaningless.
// Note: a deleter with no data is meaningless; returning an error
// here would be more correct but is not done for backward compatibility.
desc := newIndexBlockDesc(0)
bw, _ := newBlockWriter(nil, desc)
return &indexDeleter{
+1 -1
View File
@@ -72,7 +72,7 @@ func inspectHistory(freezer ethdb.AncientReader, start, end uint64, onHistory fu
}
for id := start; id <= end; id += 1 {
// The entire history object is decoded, although it's unnecessary for
// account inspection. TODO(rjl493456442) optimization is worthwhile.
// account inspection. Decoding only account data would improve performance.
h, err := readStateHistory(freezer, id)
if err != nil {
return nil, err
+1 -1
View File
@@ -149,7 +149,7 @@ func (r *historyReader) readStorageMetadata(storageKey common.Hash, storageHash
msg := fmt.Sprintf("id: %d, slot-offset: %d, slot-length: %d", historyID, slotOffset, slotNumber)
return nil, fmt.Errorf("storage indices corrupted, %s, %w", msg, err)
}
// TODO(rj493456442) get rid of the metadata resolution
// Note: the metadata resolution step could be eliminated with format changes.
var (
m meta
target common.Hash
+2 -2
View File
@@ -189,7 +189,7 @@ func (l *lookup) addLayer(diff *diffLayer) {
for accountHash := range diff.states.accountData {
list, exists := l.accounts[accountHash]
if !exists {
list = make([]common.Hash, 0, 16) // TODO(rjl493456442) use sync pool
list = make([]common.Hash, 0, 16) // Consider using sync.Pool for allocation reuse.
}
list = append(list, state)
l.accounts[accountHash] = list
@@ -204,7 +204,7 @@ func (l *lookup) addLayer(diff *diffLayer) {
key := storageKey(accountHash, slotHash)
list, exists := l.storages[key]
if !exists {
list = make([]common.Hash, 0, 16) // TODO(rjl493456442) use sync pool
list = make([]common.Hash, 0, 16) // Consider using sync.Pool for allocation reuse.
}
list = append(list, state)
l.storages[key] = list
+8 -18
View File
@@ -249,15 +249,10 @@ func (r *HistoricalStateReader) AccountRLP(address common.Address) ([]byte, erro
historicalAccountReadTimer.UpdateSince(start)
}(time.Now())
// TODO(rjl493456442): Theoretically, the obtained disk layer could become stale
// within a very short time window.
//
// While reading the account data while holding `db.tree.lock` can resolve
// this issue, but it will introduce a heavy contention over the lock.
//
// Let's optimistically assume the situation is very unlikely to happen,
// and try to define a low granularity lock if the current approach doesn't
// work later.
// Note: the obtained disk layer could theoretically become stale within a
// very short time window. Holding db.tree.lock during reads would fix this
// but introduce heavy contention. The current optimistic approach assumes
// this is unlikely; a finer-grained lock can be introduced if needed.
dl := r.db.tree.bottom()
hash := common.Keccak256Hash(address.Bytes())
latest, err := dl.account(hash, 0)
@@ -299,15 +294,10 @@ func (r *HistoricalStateReader) Storage(address common.Address, key common.Hash)
historicalStorageReadTimer.UpdateSince(start)
}(time.Now())
// TODO(rjl493456442): Theoretically, the obtained disk layer could become stale
// within a very short time window.
//
// While reading the account data while holding `db.tree.lock` can resolve
// this issue, but it will introduce a heavy contention over the lock.
//
// Let's optimistically assume the situation is very unlikely to happen,
// and try to define a low granularity lock if the current approach doesn't
// work later.
// Note: the obtained disk layer could theoretically become stale within a
// very short time window. Holding db.tree.lock during reads would fix this
// but introduce heavy contention. The current optimistic approach assumes
// this is unlikely; a finer-grained lock can be introduced if needed.
dl := r.db.tree.bottom()
addrHash := common.Keccak256Hash(address.Bytes())
keyHash := common.Keccak256Hash(key.Bytes())