mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-20 10:52:25 +00:00
core, trie: store bytecodes under a separate database prefix
This commit is contained in:
parent
fcf2b3d88e
commit
672d3afd2b
7 changed files with 96 additions and 39 deletions
|
|
@ -694,7 +694,15 @@ func (bc *BlockChain) GetUnclesInChain(block *types.Block, length int) []*types.
|
|||
// TrieNode retrieves a blob of data associated with a trie node (or code hash)
|
||||
// either from ephemeral in-memory cache, or from persistent storage.
|
||||
func (bc *BlockChain) TrieNode(hash common.Hash) ([]byte, error) {
|
||||
return bc.stateCache.TrieDB().Node(common.Hash{}, hash) // TODO(karalabe): make this work again
|
||||
// Attempt to satisfy this request with a trie node
|
||||
if blob, err := bc.stateCache.TrieDB().Node(hash); blob != nil && err == nil {
|
||||
return blob, nil
|
||||
}
|
||||
// Trie node not found, it may be a bytecode
|
||||
if blob := rawdb.ReadCode(bc.db, hash); blob != nil {
|
||||
return blob, nil
|
||||
}
|
||||
return nil, errors.New("not found")
|
||||
}
|
||||
|
||||
// Stop stops the blockchain service. If any imports are currently in progress
|
||||
|
|
|
|||
42
core/rawdb/accessors_state.go
Normal file
42
core/rawdb/accessors_state.go
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
// Copyright 2019 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// 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 rawdb
|
||||
|
||||
import (
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
)
|
||||
|
||||
// ReadCode retrieves the bytecode associated with a given hash.
|
||||
func ReadCode(db DatabaseReader, hash common.Hash) []byte {
|
||||
code, _ := db.Get(codeKey(hash))
|
||||
return code
|
||||
}
|
||||
|
||||
// WriteCode stores the bytecode associated with a given hash.
|
||||
func WriteCode(db DatabaseWriter, hash common.Hash, code []byte) {
|
||||
if err := db.Put(codeKey(hash), code); err != nil {
|
||||
log.Crit("Failed to store bytecode", "err", err)
|
||||
}
|
||||
}
|
||||
|
||||
// DeleteCode removes the bytecode associated with a given hash.
|
||||
func DeleteCode(db DatabaseDeleter, hash common.Hash) {
|
||||
if err := db.Delete(codeKey(hash)); err != nil {
|
||||
log.Crit("Failed to delete bytecode", "err", err)
|
||||
}
|
||||
}
|
||||
|
|
@ -53,6 +53,8 @@ var (
|
|||
txLookupPrefix = []byte("l") // txLookupPrefix + hash -> transaction/receipt lookup metadata
|
||||
bloomBitsPrefix = []byte("B") // bloomBitsPrefix + bit (uint16 big endian) + section (uint64 big endian) + hash -> bloom bits
|
||||
|
||||
codePrefix = []byte("c") // codePrefix + hash -> bytecode
|
||||
|
||||
preimagePrefix = []byte("secure-key-") // preimagePrefix + hash -> preimage
|
||||
configPrefix = []byte("ethereum-config-") // config prefix for the db
|
||||
|
||||
|
|
@ -123,6 +125,11 @@ func bloomBitsKey(bit uint, section uint64, hash common.Hash) []byte {
|
|||
return key
|
||||
}
|
||||
|
||||
// codeKey = codePrefix + hash
|
||||
func codeKey(hash common.Hash) []byte {
|
||||
return append(codePrefix, hash.Bytes()...)
|
||||
}
|
||||
|
||||
// preimageKey = preimagePrefix + hash
|
||||
func preimageKey(hash common.Hash) []byte {
|
||||
return append(preimagePrefix, hash.Bytes()...)
|
||||
|
|
|
|||
|
|
@ -17,10 +17,12 @@
|
|||
package state
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/trie"
|
||||
lru "github.com/hashicorp/golang-lru"
|
||||
|
|
@ -144,11 +146,11 @@ func (db *cachingDB) CopyTrie(t Trie) Trie {
|
|||
|
||||
// ContractCode retrieves a particular contract's code.
|
||||
func (db *cachingDB) ContractCode(addrHash, codeHash common.Hash) ([]byte, error) {
|
||||
code, err := db.db.Node(common.Hash{}, codeHash)
|
||||
if err == nil {
|
||||
if code := rawdb.ReadCode(db.db.DiskDB().(ethdb.Database), codeHash); code != nil {
|
||||
db.codeSizeCache.Add(codeHash, len(code))
|
||||
return code, nil
|
||||
}
|
||||
return code, err
|
||||
return nil, errors.New("not found")
|
||||
}
|
||||
|
||||
// ContractCodeSize retrieves a particular contracts code's size.
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import (
|
|||
"sort"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
|
|
@ -636,7 +637,8 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (root common.Hash, err error)
|
|||
case isDirty:
|
||||
// Write any contract code associated with the state object
|
||||
if stateObject.code != nil && stateObject.dirtyCode {
|
||||
s.db.TrieDB().DiskDB().(ethdb.Database).Put(stateObject.CodeHash(), stateObject.code)
|
||||
rawdb.WriteCode(s.db.TrieDB().DiskDB().(ethdb.Database), common.BytesToHash(stateObject.CodeHash()), stateObject.code)
|
||||
//s.db.TrieDB().DiskDB().(ethdb.Database).Put(stateObject.CodeHash(), stateObject.code)
|
||||
stateObject.dirtyCode = false
|
||||
}
|
||||
// Write any storage changes in the state object to its storage trie.
|
||||
|
|
|
|||
|
|
@ -631,7 +631,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
|
|||
if err != nil {
|
||||
continue
|
||||
}
|
||||
code, _ := statedb.Database().TrieDB().Node(common.Hash{}, common.BytesToHash(account.CodeHash)) // TODO(karalabe): make this work again
|
||||
code := rawdb.ReadCode(pm.chainDb, common.BytesToHash(account.CodeHash))
|
||||
|
||||
data = append(data, code)
|
||||
if bytes += len(code); bytes >= softResponseLimit {
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ func makeNodeKey(owner common.Hash, hash common.Hash) string {
|
|||
if owner == (common.Hash{}) {
|
||||
return string(hash[:])
|
||||
}
|
||||
return string(append(owner[:], hash[:]...))
|
||||
return string(append(hash[:], owner[:]...))
|
||||
}
|
||||
|
||||
// splitNodeKey returns the composing hashes of a trie node key.
|
||||
|
|
@ -87,7 +87,7 @@ func splitNodeKey(key string) (common.Hash, common.Hash) {
|
|||
return common.Hash{}, common.BytesToHash([]byte(key))
|
||||
|
||||
case 2 * common.HashLength:
|
||||
return common.BytesToHash([]byte(key[:common.HashLength])), common.BytesToHash([]byte(key[common.HashLength:]))
|
||||
return common.BytesToHash([]byte(key[common.HashLength:])), common.BytesToHash([]byte(key[:common.HashLength]))
|
||||
|
||||
default:
|
||||
panic(fmt.Sprintf("invalid node key: %s", key))
|
||||
|
|
@ -432,18 +432,6 @@ func (db *Database) DiskDB() DatabaseReader {
|
|||
return db.diskdb
|
||||
}
|
||||
|
||||
// InsertBlob writes a new reference tracked blob to the memory database if it's
|
||||
// yet unknown. This method should only be used for non-trie nodes that require
|
||||
// reference counting, since trie nodes are garbage collected directly through
|
||||
// their embedded children.
|
||||
func (db *Database) InsertBlob(owner common.Hash, hash common.Hash, blob []byte) {
|
||||
db.lock.Lock()
|
||||
defer db.lock.Unlock()
|
||||
|
||||
db.DiskDB().(ethdb.Database).Put([]byte(makeNodeKey(owner, hash)), blob)
|
||||
//db.insert(owner, hash, blob, rawNode(blob))
|
||||
}
|
||||
|
||||
// insert inserts a collapsed trie node into the memory database. This method is
|
||||
// a more generic version of InsertBlob, supporting both raw blob insertions as
|
||||
// well ex trie node insertions. The blob must always be specified to allow proper
|
||||
|
|
@ -526,9 +514,7 @@ func (db *Database) node(owner common.Hash, hash common.Hash, cachegen uint16) n
|
|||
|
||||
// Node retrieves an encoded cached trie node from memory. If it cannot be found
|
||||
// cached, the method queries the persistent database for the content.
|
||||
func (db *Database) Node(owner common.Hash, hash common.Hash) ([]byte, error) {
|
||||
key := makeNodeKey(owner, hash)
|
||||
|
||||
func (db *Database) Node(hash common.Hash) ([]byte, error) {
|
||||
// Retrieve the node from the clean cache if available
|
||||
if db.cleans != nil {
|
||||
if enc, err := db.cleans.Get(string(hash[:])); err == nil && enc != nil {
|
||||
|
|
@ -537,24 +523,34 @@ func (db *Database) Node(owner common.Hash, hash common.Hash) ([]byte, error) {
|
|||
return enc, nil
|
||||
}
|
||||
}
|
||||
// Retrieve the node from the dirty cache if available
|
||||
db.lock.RLock()
|
||||
dirty := db.dirties[key]
|
||||
db.lock.RUnlock()
|
||||
// TODO(karalabe): We need 2 new retrieval mechanisms:
|
||||
// - We need to retrieve from the dirty cache, needs some data struct extension (no owner)
|
||||
// - We need to retrieve from the database, needs prefix iteration support (just needs the interface ext)
|
||||
//
|
||||
// The code below is what's needed to work, just without the 'owner' being available
|
||||
/*
|
||||
// Retrieve the node from the dirty cache if available
|
||||
key := makeNodeKey(owner, hash)
|
||||
|
||||
if dirty != nil {
|
||||
return dirty.rlp(), nil
|
||||
}
|
||||
// Content unavailable in memory, attempt to retrieve from disk
|
||||
enc, err := db.diskdb.Get([]byte(key))
|
||||
if err == nil && enc != nil {
|
||||
if db.cleans != nil {
|
||||
db.cleans.Set(string(hash[:]), enc)
|
||||
memcacheCleanMissMeter.Mark(1)
|
||||
memcacheCleanWriteMeter.Mark(int64(len(enc)))
|
||||
db.lock.RLock()
|
||||
dirty := db.dirties[key]
|
||||
db.lock.RUnlock()
|
||||
|
||||
if dirty != nil {
|
||||
return dirty.rlp(), nil
|
||||
}
|
||||
}
|
||||
return enc, err
|
||||
// Content unavailable in memory, attempt to retrieve from disk
|
||||
enc, err := db.diskdb.Get([]byte(key))
|
||||
if err == nil && enc != nil {
|
||||
if db.cleans != nil {
|
||||
db.cleans.Set(string(hash[:]), enc)
|
||||
memcacheCleanMissMeter.Mark(1)
|
||||
memcacheCleanWriteMeter.Mark(int64(len(enc)))
|
||||
}
|
||||
}
|
||||
return enc, err
|
||||
*/
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// preimage retrieves a cached trie node pre-image from memory. If it cannot be
|
||||
|
|
|
|||
Loading…
Reference in a new issue