-
Notifications
You must be signed in to change notification settings - Fork 0
/
store.go
156 lines (127 loc) · 4.23 KB
/
store.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
package evmstore
import (
"sync"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/state/snapshot"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/trie"
"github.com/metatechchain/meta-base/hash"
"github.com/metatechchain/meta-base/kvdb"
"github.com/metatechchain/meta-base/kvdb/nokeyiserr"
"github.com/metatechchain/meta-base/kvdb/table"
"github.com/metatechchain/meta-base/utils/wlru"
"github.com/syndtr/goleveldb/leveldb/opt"
"github.com/metatechchain/go-metatechchain/logger"
"github.com/metatechchain/go-metatechchain/topicsdb"
"github.com/metatechchain/go-metatechchain/utils/adapters/kvdb2ethdb"
"github.com/metatechchain/go-metatechchain/utils/rlpstore"
)
const nominalSize uint = 1
// Store is a node persistent storage working over physical key-value database.
type Store struct {
cfg StoreConfig
mainDB kvdb.Store
table struct {
// API-only tables
Receipts kvdb.Store `table:"r"`
TxPositions kvdb.Store `table:"x"`
Txs kvdb.Store `table:"X"`
Evm ethdb.Database
EvmState state.Database
EvmLogs *topicsdb.Index
Snaps *snapshot.Tree
}
cache struct {
TxPositions *wlru.Cache `cache:"-"` // store by pointer
Receipts *wlru.Cache `cache:"-"` // store by value
EvmBlocks *wlru.Cache `cache:"-"` // store by pointer
}
mutex struct {
Inc sync.Mutex
}
rlp rlpstore.Helper
snaps *snapshot.Tree // Snapshot tree for fast trie leaf access
logger.Instance
}
// NewStore creates store over key-value db.
func NewStore(mainDB kvdb.Store, cfg StoreConfig) *Store {
s := &Store{
cfg: cfg,
mainDB: mainDB,
Instance: logger.MakeInstance(),
rlp: rlpstore.Helper{logger.MakeInstance()},
}
table.MigrateTables(&s.table, s.mainDB)
evmTable := nokeyiserr.Wrap(s.EvmKvdbTable()) // ETH expects that "not found" is an error
s.table.Evm = rawdb.NewDatabase(kvdb2ethdb.Wrap(evmTable))
s.table.EvmState = state.NewDatabaseWithConfig(s.table.Evm, &trie.Config{
Cache: cfg.Cache.EvmDatabase / opt.MiB,
Preimages: cfg.EnablePreimageRecording,
})
s.table.EvmLogs = topicsdb.New(table.New(s.mainDB, []byte("L")))
s.initCache()
return s
}
func (s *Store) initCache() {
s.cache.Receipts = s.makeCache(s.cfg.Cache.ReceiptsSize, s.cfg.Cache.ReceiptsBlocks)
s.cache.TxPositions = s.makeCache(nominalSize*uint(s.cfg.Cache.TxPositions), s.cfg.Cache.TxPositions)
s.cache.EvmBlocks = s.makeCache(s.cfg.Cache.EvmBlocksSize, s.cfg.Cache.EvmBlocksNum)
}
func (s *Store) InitEvmSnapshot(root hash.Hash) (err error) {
s.table.Snaps, err = snapshot.New(kvdb2ethdb.Wrap(nokeyiserr.Wrap(s.EvmKvdbTable())), s.table.EvmState.TrieDB(), s.cfg.Cache.EvmSnap/opt.MiB, common.Hash(root), false, true, false)
return err
}
// Commit changes.
func (s *Store) Commit(root hash.Hash) error {
// Flush trie on the DB
err := s.table.EvmState.TrieDB().Commit(common.Hash(root), false, nil)
if err != nil {
s.Log.Error("Failed to flush trie DB into main DB", "err", err)
}
return err
}
func (s *Store) Cap(max, min int) {
maxSize := common.StorageSize(max)
minSize := common.StorageSize(min)
size, preimagesSize := s.table.EvmState.TrieDB().Size()
if size >= maxSize || preimagesSize >= maxSize {
_ = s.table.EvmState.TrieDB().Cap(minSize)
}
}
// StateDB returns state database.
func (s *Store) StateDB(from hash.Hash) (*state.StateDB, error) {
return state.NewWithSnapLayers(common.Hash(from), s.table.EvmState, s.table.Snaps, 0)
}
// IndexLogs indexes EVM logs
func (s *Store) IndexLogs(recs ...*types.Log) {
err := s.table.EvmLogs.Push(recs...)
if err != nil {
s.Log.Crit("DB logs index error", "err", err)
}
}
func (s *Store) EvmKvdbTable() kvdb.Store {
return table.New(s.mainDB, []byte("M"))
}
func (s *Store) EvmTable() ethdb.Database {
return s.table.Evm
}
func (s *Store) EvmDatabase() state.Database {
return s.table.EvmState
}
func (s *Store) EvmLogs() *topicsdb.Index {
return s.table.EvmLogs
}
/*
* Utils:
*/
func (s *Store) makeCache(weight uint, size int) *wlru.Cache {
cache, err := wlru.New(weight, size)
if err != nil {
s.Log.Crit("Failed to create LRU cache", "err", err)
return nil
}
return cache
}