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)
|
// TrieNode retrieves a blob of data associated with a trie node (or code hash)
|
||||||
// either from ephemeral in-memory cache, or from persistent storage.
|
// either from ephemeral in-memory cache, or from persistent storage.
|
||||||
func (bc *BlockChain) TrieNode(hash common.Hash) ([]byte, error) {
|
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
|
// 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
|
txLookupPrefix = []byte("l") // txLookupPrefix + hash -> transaction/receipt lookup metadata
|
||||||
bloomBitsPrefix = []byte("B") // bloomBitsPrefix + bit (uint16 big endian) + section (uint64 big endian) + hash -> bloom bits
|
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
|
preimagePrefix = []byte("secure-key-") // preimagePrefix + hash -> preimage
|
||||||
configPrefix = []byte("ethereum-config-") // config prefix for the db
|
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
|
return key
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// codeKey = codePrefix + hash
|
||||||
|
func codeKey(hash common.Hash) []byte {
|
||||||
|
return append(codePrefix, hash.Bytes()...)
|
||||||
|
}
|
||||||
|
|
||||||
// preimageKey = preimagePrefix + hash
|
// preimageKey = preimagePrefix + hash
|
||||||
func preimageKey(hash common.Hash) []byte {
|
func preimageKey(hash common.Hash) []byte {
|
||||||
return append(preimagePrefix, hash.Bytes()...)
|
return append(preimagePrefix, hash.Bytes()...)
|
||||||
|
|
|
||||||
|
|
@ -17,10 +17,12 @@
|
||||||
package state
|
package state
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
lru "github.com/hashicorp/golang-lru"
|
lru "github.com/hashicorp/golang-lru"
|
||||||
|
|
@ -144,11 +146,11 @@ func (db *cachingDB) CopyTrie(t Trie) Trie {
|
||||||
|
|
||||||
// ContractCode retrieves a particular contract's code.
|
// ContractCode retrieves a particular contract's code.
|
||||||
func (db *cachingDB) ContractCode(addrHash, codeHash common.Hash) ([]byte, error) {
|
func (db *cachingDB) ContractCode(addrHash, codeHash common.Hash) ([]byte, error) {
|
||||||
code, err := db.db.Node(common.Hash{}, codeHash)
|
if code := rawdb.ReadCode(db.db.DiskDB().(ethdb.Database), codeHash); code != nil {
|
||||||
if err == nil {
|
|
||||||
db.codeSizeCache.Add(codeHash, len(code))
|
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.
|
// ContractCodeSize retrieves a particular contracts code's size.
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ import (
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"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/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
|
|
@ -636,7 +637,8 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (root common.Hash, err error)
|
||||||
case isDirty:
|
case isDirty:
|
||||||
// Write any contract code associated with the state object
|
// Write any contract code associated with the state object
|
||||||
if stateObject.code != nil && stateObject.dirtyCode {
|
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
|
stateObject.dirtyCode = false
|
||||||
}
|
}
|
||||||
// Write any storage changes in the state object to its storage trie.
|
// 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 {
|
if err != nil {
|
||||||
continue
|
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)
|
data = append(data, code)
|
||||||
if bytes += len(code); bytes >= softResponseLimit {
|
if bytes += len(code); bytes >= softResponseLimit {
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,7 @@ func makeNodeKey(owner common.Hash, hash common.Hash) string {
|
||||||
if owner == (common.Hash{}) {
|
if owner == (common.Hash{}) {
|
||||||
return string(hash[:])
|
return string(hash[:])
|
||||||
}
|
}
|
||||||
return string(append(owner[:], hash[:]...))
|
return string(append(hash[:], owner[:]...))
|
||||||
}
|
}
|
||||||
|
|
||||||
// splitNodeKey returns the composing hashes of a trie node key.
|
// 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))
|
return common.Hash{}, common.BytesToHash([]byte(key))
|
||||||
|
|
||||||
case 2 * common.HashLength:
|
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:
|
default:
|
||||||
panic(fmt.Sprintf("invalid node key: %s", key))
|
panic(fmt.Sprintf("invalid node key: %s", key))
|
||||||
|
|
@ -432,18 +432,6 @@ func (db *Database) DiskDB() DatabaseReader {
|
||||||
return db.diskdb
|
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
|
// 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
|
// 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
|
// 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
|
// Node retrieves an encoded cached trie node from memory. If it cannot be found
|
||||||
// cached, the method queries the persistent database for the content.
|
// cached, the method queries the persistent database for the content.
|
||||||
func (db *Database) Node(owner common.Hash, hash common.Hash) ([]byte, error) {
|
func (db *Database) Node(hash common.Hash) ([]byte, error) {
|
||||||
key := makeNodeKey(owner, hash)
|
|
||||||
|
|
||||||
// Retrieve the node from the clean cache if available
|
// Retrieve the node from the clean cache if available
|
||||||
if db.cleans != nil {
|
if db.cleans != nil {
|
||||||
if enc, err := db.cleans.Get(string(hash[:])); err == nil && enc != 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
|
return enc, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Retrieve the node from the dirty cache if available
|
// TODO(karalabe): We need 2 new retrieval mechanisms:
|
||||||
db.lock.RLock()
|
// - We need to retrieve from the dirty cache, needs some data struct extension (no owner)
|
||||||
dirty := db.dirties[key]
|
// - We need to retrieve from the database, needs prefix iteration support (just needs the interface ext)
|
||||||
db.lock.RUnlock()
|
//
|
||||||
|
// 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 {
|
db.lock.RLock()
|
||||||
return dirty.rlp(), nil
|
dirty := db.dirties[key]
|
||||||
}
|
db.lock.RUnlock()
|
||||||
// Content unavailable in memory, attempt to retrieve from disk
|
|
||||||
enc, err := db.diskdb.Get([]byte(key))
|
if dirty != nil {
|
||||||
if err == nil && enc != nil {
|
return dirty.rlp(), nil
|
||||||
if db.cleans != nil {
|
|
||||||
db.cleans.Set(string(hash[:]), enc)
|
|
||||||
memcacheCleanMissMeter.Mark(1)
|
|
||||||
memcacheCleanWriteMeter.Mark(int64(len(enc)))
|
|
||||||
}
|
}
|
||||||
}
|
// Content unavailable in memory, attempt to retrieve from disk
|
||||||
return enc, err
|
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
|
// preimage retrieves a cached trie node pre-image from memory. If it cannot be
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue