Skip to content

Commit d960769

Browse files
Merge branch 'master' into lint-enable-gosec
2 parents b050e4f + ae43cea commit d960769

File tree

5 files changed

+73
-47
lines changed

5 files changed

+73
-47
lines changed

core/blockchain.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ const (
176176
// clean cache's underlying fastcache.
177177
trieCleanCacheStatsNamespace = "hashdb/memcache/clean/fastcache"
178178

179-
firewoodFileName = "firewood_state"
179+
firewoodFileName = "firewood.db"
180180
)
181181

182182
// CacheConfig contains the configuration values for the trie database

core/extstate/firewood_database.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,14 @@ func (db *firewoodAccessorDB) OpenTrie(root common.Hash) (state.Trie, error) {
2929
}
3030

3131
// OpenStorageTrie opens a wrapped version of the account trie.
32-
func (*firewoodAccessorDB) OpenStorageTrie(_ common.Hash, _ common.Address, accountRoot common.Hash, self state.Trie) (state.Trie, error) {
32+
//
33+
//nolint:revive // removing names loses context.
34+
func (*firewoodAccessorDB) OpenStorageTrie(stateRoot common.Hash, addr common.Address, accountRoot common.Hash, self state.Trie) (state.Trie, error) {
3335
accountTrie, ok := self.(*firewood.AccountTrie)
3436
if !ok {
3537
return nil, fmt.Errorf("invalid account trie type: %T", self)
3638
}
37-
return firewood.NewStorageTrie(accountTrie, accountRoot)
39+
return firewood.NewStorageTrie(accountTrie)
3840
}
3941

4042
// CopyTrie returns a deep copy of the given trie.

triedb/firewood/account_trie.go

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ import (
2424
// 2. The `Hash` method actually creates the proposal, since Firewood cannot calculate
2525
// the hash of the trie without committing it. It is immediately dropped, and this
2626
// can likely be optimized.
27+
//
28+
// Note this is not concurrent safe.
2729
type AccountTrie struct {
2830
fw *Database
2931
parentRoot common.Hash
@@ -49,7 +51,10 @@ func NewAccountTrie(root common.Hash, db *Database) (*AccountTrie, error) {
4951
}, nil
5052
}
5153

52-
// GetAccount implements state.Trie.
54+
// GetAccount returns the state account associated with an address.
55+
// - If the account has been updated, the new value is returned.
56+
// - If the account has been deleted, (nil, nil) is returned.
57+
// - If the account does not exist, (nil, nil) is returned.
5358
func (a *AccountTrie) GetAccount(addr common.Address) (*types.StateAccount, error) {
5459
key := crypto.Keccak256Hash(addr.Bytes()).Bytes()
5560

@@ -82,7 +87,10 @@ func (a *AccountTrie) GetAccount(addr common.Address) (*types.StateAccount, erro
8287
return account, err
8388
}
8489

85-
// GetStorage implements state.Trie.
90+
// GetStorage returns the value associated with a storage key for a given account address.
91+
// - If the storage slot has been updated, the new value is returned.
92+
// - If the storage slot has been deleted, (nil, nil) is returned.
93+
// - If the storage slot does not exist, (nil, nil) is returned.
8694
func (a *AccountTrie) GetStorage(addr common.Address, key []byte) ([]byte, error) {
8795
// If the account has been deleted, we should return nil
8896
accountKey := crypto.Keccak256Hash(addr.Bytes()).Bytes()
@@ -117,7 +125,8 @@ func (a *AccountTrie) GetStorage(addr common.Address, key []byte) ([]byte, error
117125
return decoded, err
118126
}
119127

120-
// UpdateAccount implements state.Trie.
128+
// UpdateAccount replaces or creates the state account associated with an address.
129+
// This new value will be returned for subsequent `GetAccount` calls.
121130
func (a *AccountTrie) UpdateAccount(addr common.Address, account *types.StateAccount) error {
122131
// Queue the keys and values for later commit
123132
key := crypto.Keccak256Hash(addr.Bytes()).Bytes()
@@ -132,7 +141,8 @@ func (a *AccountTrie) UpdateAccount(addr common.Address, account *types.StateAcc
132141
return nil
133142
}
134143

135-
// UpdateStorage implements state.Trie.
144+
// UpdateStorage replaces or creates the value associated with a storage key for a given account address.
145+
// This new value will be returned for subsequent `GetStorage` calls.
136146
func (a *AccountTrie) UpdateStorage(addr common.Address, key []byte, value []byte) error {
137147
var combinedKey [2 * common.HashLength]byte
138148
accountKey := crypto.Keccak256Hash(addr.Bytes()).Bytes()
@@ -153,7 +163,7 @@ func (a *AccountTrie) UpdateStorage(addr common.Address, key []byte, value []byt
153163
return nil
154164
}
155165

156-
// DeleteAccount implements state.Trie.
166+
// DeleteAccount removes the state account associated with an address.
157167
func (a *AccountTrie) DeleteAccount(addr common.Address) error {
158168
key := crypto.Keccak256Hash(addr.Bytes()).Bytes()
159169
// Queue the key for deletion
@@ -164,7 +174,7 @@ func (a *AccountTrie) DeleteAccount(addr common.Address) error {
164174
return nil
165175
}
166176

167-
// DeleteStorage implements state.Trie.
177+
// DeleteStorage removes the value associated with a storage key for a given account address.
168178
func (a *AccountTrie) DeleteStorage(addr common.Address, key []byte) error {
169179
var combinedKey [2 * common.HashLength]byte
170180
accountKey := crypto.Keccak256Hash(addr.Bytes()).Bytes()
@@ -180,7 +190,9 @@ func (a *AccountTrie) DeleteStorage(addr common.Address, key []byte) error {
180190
return nil
181191
}
182192

183-
// Hash implements state.Trie.
193+
// Hash returns the current hash of the state trie.
194+
// This will create a proposal and drop it, so it is not efficient to call for each transaction.
195+
// If there are no changes since the last call, the cached root is returned.
184196
func (a *AccountTrie) Hash() common.Hash {
185197
hash, err := a.hash()
186198
if err != nil {
@@ -203,7 +215,9 @@ func (a *AccountTrie) hash() (common.Hash, error) {
203215
return a.root, nil
204216
}
205217

206-
// Commit implements state.Trie.
218+
// Commit returns the new root hash of the trie and a NodeSet containing all modified accounts and storage slots.
219+
// The format of the NodeSet is different than in go-ethereum's trie implementation due to Firewood's design.
220+
// This boolean is ignored, as it is a relic of the StateTrie implementation.
207221
func (a *AccountTrie) Commit(bool) (common.Hash, *trienode.NodeSet, error) {
208222
// Get the hash of the trie.
209223
hash, err := a.hash()
@@ -212,7 +226,7 @@ func (a *AccountTrie) Commit(bool) (common.Hash, *trienode.NodeSet, error) {
212226
}
213227

214228
// Create the NodeSet. This will be sent to `triedb.Update` later.
215-
nodeset := trienode.NewNodeSet(a.parentRoot)
229+
nodeset := trienode.NewNodeSet(common.Hash{})
216230
for i, key := range a.updateKeys {
217231
nodeset.AddNode(key, &trienode.Node{
218232
Blob: a.updateValues[i],
@@ -229,16 +243,19 @@ func (*AccountTrie) UpdateContractCode(common.Address, common.Hash, []byte) erro
229243
}
230244

231245
// GetKey implements state.Trie.
246+
// This should not be used, since any user should not be accessing by raw key.
232247
func (*AccountTrie) GetKey([]byte) []byte {
233-
return nil // Not implemented, as this is only used in APIs
248+
return nil
234249
}
235250

236251
// NodeIterator implements state.Trie.
252+
// Firewood does not support iterating over internal nodes.
237253
func (*AccountTrie) NodeIterator([]byte) (trie.NodeIterator, error) {
238254
return nil, errors.New("NodeIterator not implemented for Firewood")
239255
}
240256

241257
// Prove implements state.Trie.
258+
// Firewood does not yet support providing key proofs.
242259
func (*AccountTrie) Prove([]byte, ethdb.KeyValueWriter) error {
243260
return errors.New("Prove not implemented for Firewood")
244261
}

triedb/firewood/database.go

Lines changed: 32 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,12 @@ var Defaults = Config{
7676
ReadCacheStrategy: ffi.CacheAllReads,
7777
}
7878

79-
func (c Config) BackendConstructor(_ ethdb.Database) triedb.DBOverride {
80-
return New(&c)
79+
func (c Config) BackendConstructor(ethdb.Database) triedb.DBOverride {
80+
db, err := New(c)
81+
if err != nil {
82+
log.Crit("firewood: error creating database", "error", err)
83+
}
84+
return db
8185
}
8286

8387
type Database struct {
@@ -94,32 +98,24 @@ type Database struct {
9498

9599
// New creates a new Firewood database with the given disk database and configuration.
96100
// Any error during creation will cause the program to exit.
97-
func New(config *Config) *Database {
98-
//nolint:staticcheck // this nolint is required for the config.* nolints to work.
99-
if config == nil {
100-
log.Crit("firewood: config must be provided")
101-
}
102-
103-
//nolint:staticcheck // false positive, if config is nil then we will have exited.
104-
err := validatePath(config.FilePath)
105-
if err != nil {
106-
log.Crit("firewood: error validating config", "error", err)
101+
func New(config Config) (*Database, error) {
102+
if err := validatePath(config.FilePath); err != nil {
103+
return nil, err
107104
}
108105

109-
//nolint:staticcheck // false positive, if config is nil then we will have exited.
110106
fw, err := ffi.New(config.FilePath, &ffi.Config{
111107
NodeCacheEntries: uint(config.CleanCacheSize) / 256, // TODO: estimate 256 bytes per node
112108
FreeListCacheEntries: config.FreeListCacheEntries,
113109
Revisions: config.Revisions,
114110
ReadCacheStrategy: config.ReadCacheStrategy,
115111
})
116112
if err != nil {
117-
log.Crit("firewood: error creating firewood database", "error", err)
113+
return nil, err
118114
}
119115

120116
currentRoot, err := fw.Root()
121117
if err != nil {
122-
log.Crit("firewood: error getting current root", "error", err)
118+
return nil, err
123119
}
124120

125121
return &Database{
@@ -128,7 +124,7 @@ func New(config *Config) *Database {
128124
proposalTree: &ProposalContext{
129125
Root: common.Hash(currentRoot),
130126
},
131-
}
127+
}, nil
132128
}
133129

134130
func validatePath(path string) error {
@@ -138,17 +134,28 @@ func validatePath(path string) error {
138134

139135
// Check that the directory exists
140136
dir := filepath.Dir(path)
141-
_, err := os.Stat(dir)
142-
if err == nil {
143-
return nil // Directory exists
144-
}
145-
if !os.IsNotExist(err) {
137+
switch info, err := os.Stat(dir); {
138+
case os.IsNotExist(err):
139+
log.Info("Database directory not found, creating", "path", dir)
140+
if err := os.MkdirAll(dir, 0o755); err != nil {
141+
return fmt.Errorf("error creating database directory: %w", err)
142+
}
143+
return nil
144+
case err != nil:
146145
return fmt.Errorf("error checking database directory: %w", err)
146+
case !info.IsDir():
147+
return fmt.Errorf("database directory path is not a directory: %s", dir)
147148
}
148-
log.Info("Database directory not found, creating", "path", dir)
149-
if err := os.MkdirAll(dir, 0o755); err != nil {
150-
return fmt.Errorf("error creating database directory: %w", err)
149+
150+
// TODO(#1253): remove this after testing infrastructure is updated
151+
oldPath := filepath.Join(dir, "firewood_state")
152+
if _, err := os.Stat(oldPath); err == nil {
153+
log.Warn("Found old database file, moving to new location", "old", oldPath, "new", path)
154+
if err := os.Rename(oldPath, path); err != nil {
155+
return fmt.Errorf("failed to move old database file: %w", err)
156+
}
151157
}
158+
152159
return nil
153160
}
154161

@@ -164,7 +171,7 @@ func (*Database) Scheme() string {
164171
}
165172

166173
// Initialized checks whether a non-empty genesis block has been written.
167-
func (db *Database) Initialized(_ common.Hash) bool {
174+
func (db *Database) Initialized(common.Hash) bool {
168175
rootBytes, err := db.fwDisk.Root()
169176
if err != nil {
170177
log.Error("firewood: error getting current root", "error", err)

triedb/firewood/storage_trie.go

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,28 +10,28 @@ import (
1010

1111
type StorageTrie struct {
1212
*AccountTrie
13-
storageRoot common.Hash
1413
}
1514

1615
// `NewStorageTrie` returns a wrapper around an `AccountTrie` since Firewood
1716
// does not require a separate storage trie. All changes are managed by the account trie.
18-
func NewStorageTrie(accountTrie *AccountTrie, storageRoot common.Hash) (*StorageTrie, error) {
17+
func NewStorageTrie(accountTrie *AccountTrie) (*StorageTrie, error) {
1918
return &StorageTrie{
2019
AccountTrie: accountTrie,
21-
storageRoot: storageRoot,
2220
}, nil
2321
}
2422

2523
// Actual commit is handled by the account trie.
26-
// Return the old storage root as if there was no change - we don't want to use the
27-
// actual account trie hash and nodeset here.
28-
func (s *StorageTrie) Commit(bool) (common.Hash, *trienode.NodeSet, error) {
29-
return s.storageRoot, nil, nil
24+
// Return the old storage root as if there was no change since Firewood
25+
// will manage the hash calculations without it.
26+
// All changes are managed by the account trie.
27+
func (*StorageTrie) Commit(bool) (common.Hash, *trienode.NodeSet, error) {
28+
return common.Hash{}, nil, nil
3029
}
3130

3231
// Firewood doesn't require tracking storage roots inside of an account.
33-
func (s *StorageTrie) Hash() common.Hash {
34-
return s.storageRoot // only used in statedb to populate a `StateAccount`
32+
// They will be updated in place when hashing of the proposal takes place.
33+
func (*StorageTrie) Hash() common.Hash {
34+
return common.Hash{}
3535
}
3636

3737
// Copy should never be called on a storage trie, as it is just a wrapper around the account trie.

0 commit comments

Comments
 (0)