mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-05-24 08:49:29 +00:00
Merge b673e63a73 into 12eabbd76d
This commit is contained in:
commit
add82fcad6
5 changed files with 97 additions and 31 deletions
|
|
@ -422,3 +422,7 @@ func (f *chainFreezer) TruncateTail(items uint64) (uint64, error) {
|
|||
func (f *chainFreezer) SyncAncient() error {
|
||||
return f.ancients.SyncAncient()
|
||||
}
|
||||
|
||||
func (f *chainFreezer) EraStore() *eradb.Store {
|
||||
return f.eradb
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/rawdb/eradb"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/ethdb/memorydb"
|
||||
|
|
@ -86,6 +87,27 @@ func (frdb *freezerdb) Freeze() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// Unwrapper allows retrieving the underlying database from a wrapper.
|
||||
type Unwrapper interface {
|
||||
Unwrap() ethdb.Database
|
||||
}
|
||||
|
||||
// EraStore returns the eradb.Store from the database if available.
|
||||
// Returns nil if the database does not have an era store (e.g. in-memory or no freezer).
|
||||
func EraStore(db ethdb.Database) *eradb.Store {
|
||||
for {
|
||||
if frdb, ok := db.(*freezerdb); ok {
|
||||
return frdb.EraStore()
|
||||
}
|
||||
if unwrapper, ok := db.(Unwrapper); ok {
|
||||
db = unwrapper.Unwrap()
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// nofreezedb is a database wrapper that disables freezer data retrievals.
|
||||
type nofreezedb struct {
|
||||
ethdb.KeyValueStore
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// Package eradb implements a history backend using era1 files.
|
||||
// Package eradb implements a history backend using era1 and erae files.
|
||||
package eradb
|
||||
|
||||
import (
|
||||
|
|
@ -26,7 +26,9 @@ import (
|
|||
"sync"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common/lru"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/internal/era"
|
||||
"github.com/ethereum/go-ethereum/internal/era/execdb"
|
||||
"github.com/ethereum/go-ethereum/internal/era/onedb"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
|
|
@ -36,7 +38,7 @@ const openFileLimit = 64
|
|||
|
||||
var errClosed = errors.New("era store is closed")
|
||||
|
||||
// Store manages read access to a directory of era1 files.
|
||||
// Store manages read access to a directory of era1 and erae files.
|
||||
// The getter methods are thread-safe.
|
||||
type Store struct {
|
||||
datadir string
|
||||
|
|
@ -52,7 +54,7 @@ type Store struct {
|
|||
type fileCacheEntry struct {
|
||||
refcount int // reference count. This is protected by Store.mu!
|
||||
opened chan struct{} // signals opening of file has completed
|
||||
file *onedb.Era // the file
|
||||
file era.Era // the file (era1 or erae)
|
||||
err error // error from opening the file
|
||||
}
|
||||
|
||||
|
|
@ -101,6 +103,21 @@ func (db *Store) Close() {
|
|||
}
|
||||
}
|
||||
|
||||
// GetBlockByNumber returns the block for a given block number.
|
||||
func (db *Store) GetBlockByNumber(number uint64) (*types.Block, error) {
|
||||
epoch := number / uint64(era.MaxSize)
|
||||
entry := db.getEraByEpoch(epoch)
|
||||
if entry.err != nil {
|
||||
if errors.Is(entry.err, fs.ErrNotExist) {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, entry.err
|
||||
}
|
||||
defer db.doneWithFile(epoch, entry)
|
||||
|
||||
return entry.file.GetBlockByNumber(number)
|
||||
}
|
||||
|
||||
// GetRawBody returns the raw body for a given block number.
|
||||
func (db *Store) GetRawBody(number uint64) ([]byte, error) {
|
||||
epoch := number / uint64(era.MaxSize)
|
||||
|
|
@ -250,7 +267,7 @@ func (db *Store) getCacheEntry(epoch uint64) (stat fileCacheStatus, entry *fileC
|
|||
}
|
||||
|
||||
// fileOpened is called after an era file has been successfully opened.
|
||||
func (db *Store) fileOpened(epoch uint64, entry *fileCacheEntry, file *onedb.Era) {
|
||||
func (db *Store) fileOpened(epoch uint64, entry *fileCacheEntry, file era.Era) {
|
||||
db.mu.Lock()
|
||||
defer db.mu.Unlock()
|
||||
|
||||
|
|
@ -283,32 +300,41 @@ func (db *Store) fileFailedToOpen(epoch uint64, entry *fileCacheEntry, err error
|
|||
entry.err = err
|
||||
}
|
||||
|
||||
func (db *Store) openEraFile(epoch uint64) (*onedb.Era, error) {
|
||||
// File name scheme is <network>-<epoch>-<root>.
|
||||
glob := fmt.Sprintf("*-%05d-*.era1", epoch)
|
||||
matches, err := filepath.Glob(filepath.Join(db.datadir, glob))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
func (db *Store) openEraFile(epoch uint64) (era.Era, error) {
|
||||
// File name scheme is <network>-<epoch>-<root>.<ext>
|
||||
// Try era1 first, then erae.
|
||||
for _, ext := range []string{"era1", "erae"} {
|
||||
glob := fmt.Sprintf("*-%05d-*.%s", epoch, ext)
|
||||
matches, err := filepath.Glob(filepath.Join(db.datadir, glob))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(matches) > 1 {
|
||||
return nil, fmt.Errorf("multiple %s files found for epoch %d", ext, epoch)
|
||||
}
|
||||
if len(matches) == 0 {
|
||||
continue
|
||||
}
|
||||
filename := matches[0]
|
||||
var e era.Era
|
||||
switch ext {
|
||||
case "era1":
|
||||
e, err = onedb.Open(filename)
|
||||
case "erae":
|
||||
e, err = execdb.Open(filename)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Sanity-check start block.
|
||||
if e.Start()%uint64(era.MaxSize) != 0 {
|
||||
e.Close()
|
||||
return nil, fmt.Errorf("%s file has invalid boundary. %d %% %d != 0", ext, e.Start(), era.MaxSize)
|
||||
}
|
||||
log.Debug("Opened era file", "type", ext, "epoch", epoch)
|
||||
return e, nil
|
||||
}
|
||||
if len(matches) > 1 {
|
||||
return nil, fmt.Errorf("multiple era1 files found for epoch %d", epoch)
|
||||
}
|
||||
if len(matches) == 0 {
|
||||
return nil, fs.ErrNotExist
|
||||
}
|
||||
filename := matches[0]
|
||||
|
||||
e, err := onedb.Open(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Sanity-check start block.
|
||||
if e.Start()%uint64(era.MaxSize) != 0 {
|
||||
e.Close()
|
||||
return nil, fmt.Errorf("pre-merge era1 file has invalid boundary. %d %% %d != 0", e.Start(), era.MaxSize)
|
||||
}
|
||||
log.Debug("Opened era1 file", "epoch", epoch)
|
||||
return e.(*onedb.Era), nil
|
||||
return nil, fs.ErrNotExist
|
||||
}
|
||||
|
||||
// doneWithFile signals that the caller has finished using a file.
|
||||
|
|
|
|||
|
|
@ -157,10 +157,19 @@ func (b *EthAPIBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumbe
|
|||
bn = b.HistoryPruningCutoff()
|
||||
}
|
||||
block := b.eth.blockchain.GetBlockByNumber(bn)
|
||||
if block == nil && bn < b.HistoryPruningCutoff() {
|
||||
if block != nil {
|
||||
return block, nil
|
||||
}
|
||||
// Block not found in the local database, try the ERA store as a fallback.
|
||||
if eraStore := rawdb.EraStore(b.eth.chainDb); eraStore != nil {
|
||||
if eraBlock, err := eraStore.GetBlockByNumber(bn); err == nil && eraBlock != nil {
|
||||
return eraBlock, nil
|
||||
}
|
||||
}
|
||||
if bn < b.HistoryPruningCutoff() {
|
||||
return nil, &history.PrunedHistoryError{}
|
||||
}
|
||||
return block, nil
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (b *EthAPIBackend) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) {
|
||||
|
|
|
|||
|
|
@ -777,6 +777,11 @@ func (db *closeTrackingDB) Close() error {
|
|||
return db.Database.Close()
|
||||
}
|
||||
|
||||
// Unwrap returns the underlying database.
|
||||
func (db *closeTrackingDB) Unwrap() ethdb.Database {
|
||||
return db.Database
|
||||
}
|
||||
|
||||
// wrapDatabase ensures the database will be auto-closed when Node is closed.
|
||||
func (n *Node) wrapDatabase(db ethdb.Database) ethdb.Database {
|
||||
wrapper := &closeTrackingDB{db, n}
|
||||
|
|
|
|||
Loading…
Reference in a new issue