Merge pull request #437: Code Size Lookup Cache

This commit is contained in:
Aleksandr Bezobchuk 2018-07-17 10:34:32 -04:00
parent 759c2292f4
commit 377b7f06c5
4 changed files with 42 additions and 36 deletions

46
Gopkg.lock generated
View File

@ -24,7 +24,7 @@
packages = [ packages = [
"store", "store",
"types", "types",
"wire", "wire"
] ]
revision = "1a1373cc220e402397ad536aee6b8f5b068914c6" revision = "1a1373cc220e402397ad536aee6b8f5b068914c6"
version = "v0.21.0" version = "v0.21.0"
@ -71,7 +71,7 @@
"params", "params",
"rlp", "rlp",
"rpc", "rpc",
"trie", "trie"
] ]
revision = "dea1ce052a10cd7d401a5c04f83f371a06fe293c" revision = "dea1ce052a10cd7d401a5c04f83f371a06fe293c"
version = "v1.8.11" version = "v1.8.11"
@ -81,7 +81,7 @@
packages = [ packages = [
"log", "log",
"log/level", "log/level",
"log/term", "log/term"
] ]
revision = "4dc7be5d2d12881735283bcab7352178e190fc71" revision = "4dc7be5d2d12881735283bcab7352178e190fc71"
version = "v0.6.0" version = "v0.6.0"
@ -106,7 +106,7 @@
"proto", "proto",
"protoc-gen-gogo/descriptor", "protoc-gen-gogo/descriptor",
"sortkeys", "sortkeys",
"types", "types"
] ]
revision = "1adfc126b41513cc696b209667c8656ea7aac67c" revision = "1adfc126b41513cc696b209667c8656ea7aac67c"
version = "v1.0.0" version = "v1.0.0"
@ -118,7 +118,7 @@
"ptypes", "ptypes",
"ptypes/any", "ptypes/any",
"ptypes/duration", "ptypes/duration",
"ptypes/timestamp", "ptypes/timestamp"
] ]
revision = "925541529c1fa6821df4e44ce2723319eb2be768" revision = "925541529c1fa6821df4e44ce2723319eb2be768"
version = "v1.0.0" version = "v1.0.0"
@ -134,7 +134,7 @@
name = "github.com/hashicorp/golang-lru" name = "github.com/hashicorp/golang-lru"
packages = [ packages = [
".", ".",
"simplelru", "simplelru"
] ]
revision = "0fb14efe8c47ae851c0034ed7a448854d3d34cf3" revision = "0fb14efe8c47ae851c0034ed7a448854d3d34cf3"
@ -177,7 +177,7 @@
"leveldb/opt", "leveldb/opt",
"leveldb/storage", "leveldb/storage",
"leveldb/table", "leveldb/table",
"leveldb/util", "leveldb/util"
] ]
revision = "c4c61651e9e37fa117f53c5a906d3b63090d8445" revision = "c4c61651e9e37fa117f53c5a906d3b63090d8445"
@ -187,7 +187,7 @@
packages = [ packages = [
".", ".",
"edwards25519", "edwards25519",
"extra25519", "extra25519"
] ]
revision = "d8387025d2b9d158cf4efb07e7ebf814bcce2057" revision = "d8387025d2b9d158cf4efb07e7ebf814bcce2057"
@ -216,7 +216,7 @@
"libs/log", "libs/log",
"libs/pubsub", "libs/pubsub",
"libs/pubsub/query", "libs/pubsub/query",
"types", "types"
] ]
revision = "5ff65274b84ea905787a48512cc3124385bddf2f" revision = "5ff65274b84ea905787a48512cc3124385bddf2f"
version = "v0.22.2" version = "v0.22.2"
@ -231,7 +231,7 @@
"openpgp/errors", "openpgp/errors",
"poly1305", "poly1305",
"ripemd160", "ripemd160",
"salsa20/salsa", "salsa20/salsa"
] ]
revision = "a49355c7e3f8fe157a85be2f77e6e269a0f89602" revision = "a49355c7e3f8fe157a85be2f77e6e269a0f89602"
@ -246,7 +246,7 @@
"idna", "idna",
"internal/timeseries", "internal/timeseries",
"trace", "trace",
"websocket", "websocket"
] ]
revision = "d0887baf81f4598189d4e12a37c6da86f0bba4d0" revision = "d0887baf81f4598189d4e12a37c6da86f0bba4d0"
@ -266,7 +266,7 @@
"unicode/bidi", "unicode/bidi",
"unicode/cldr", "unicode/cldr",
"unicode/norm", "unicode/norm",
"unicode/rangetable", "unicode/rangetable"
] ]
revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0" revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0"
version = "v0.3.0" version = "v0.3.0"
@ -301,7 +301,7 @@
"stats", "stats",
"status", "status",
"tap", "tap",
"transport", "transport"
] ]
revision = "d11072e7ca9811b1100b80ca0269ac831f06d024" revision = "d11072e7ca9811b1100b80ca0269ac831f06d024"
version = "v1.11.3" version = "v1.11.3"
@ -327,24 +327,6 @@
[solve-meta] [solve-meta]
analyzer-name = "dep" analyzer-name = "dep"
analyzer-version = 1 analyzer-version = 1
input-imports = [ inputs-digest = "df6cfdfe013b00b662a5b9ebd45319d0c114859e865b3034b0e984f15e698b45"
"github.com/cosmos/cosmos-sdk/store",
"github.com/cosmos/cosmos-sdk/types",
"github.com/ethereum/go-ethereum/common",
"github.com/ethereum/go-ethereum/common/math",
"github.com/ethereum/go-ethereum/consensus",
"github.com/ethereum/go-ethereum/consensus/ethash",
"github.com/ethereum/go-ethereum/consensus/misc",
"github.com/ethereum/go-ethereum/core",
"github.com/ethereum/go-ethereum/core/state",
"github.com/ethereum/go-ethereum/core/types",
"github.com/ethereum/go-ethereum/core/vm",
"github.com/ethereum/go-ethereum/ethdb",
"github.com/ethereum/go-ethereum/params",
"github.com/ethereum/go-ethereum/rlp",
"github.com/ethereum/go-ethereum/rpc",
"github.com/ethereum/go-ethereum/trie",
"github.com/tendermint/tendermint/libs/db",
]
solver-name = "gps-cdcl" solver-name = "gps-cdcl"
solver-version = 1 solver-version = 1

View File

@ -6,6 +6,9 @@
name = "github.com/cosmos/cosmos-sdk" name = "github.com/cosmos/cosmos-sdk"
version = "=0.21.0" version = "=0.21.0"
[[constraint]]
name = "github.com/hashicorp/golang-lru"
[[override]] [[override]]
name = "google.golang.org/genproto" name = "google.golang.org/genproto"
revision = "7fd901a49ba6a7f87732eb344f6e3c5b19d1b200" revision = "7fd901a49ba6a7f87732eb344f6e3c5b19d1b200"

View File

@ -29,6 +29,7 @@ import (
var cpuprofile = flag.String("cpuprofile", "", "write cpu profile `file`") var cpuprofile = flag.String("cpuprofile", "", "write cpu profile `file`")
var blockchain = flag.String("blockchain", "data/blockchain", "file containing blocks to load") var blockchain = flag.String("blockchain", "data/blockchain", "file containing blocks to load")
var datadir = flag.String("datadir", "", "directory for ethermint data")
var ( var (
// TODO: Document... // TODO: Document...
@ -52,8 +53,8 @@ func main() {
defer pprof.StopCPUProfile() defer pprof.StopCPUProfile()
} }
stateDB := dbm.NewDB("state", dbm.LevelDBBackend, "") stateDB := dbm.NewDB("state", dbm.LevelDBBackend, *datadir)
codeDB := dbm.NewDB("code", dbm.LevelDBBackend, "") codeDB := dbm.NewDB("code", dbm.LevelDBBackend, *datadir)
ethermintDB, err := state.NewDatabase(stateDB, codeDB) ethermintDB, err := state.NewDatabase(stateDB, codeDB)
if err != nil { if err != nil {

View File

@ -7,6 +7,7 @@ import (
ethcommon "github.com/ethereum/go-ethereum/common" ethcommon "github.com/ethereum/go-ethereum/common"
ethstate "github.com/ethereum/go-ethereum/core/state" ethstate "github.com/ethereum/go-ethereum/core/state"
ethtrie "github.com/ethereum/go-ethereum/trie" ethtrie "github.com/ethereum/go-ethereum/trie"
lru "github.com/hashicorp/golang-lru"
dbm "github.com/tendermint/tendermint/libs/db" dbm "github.com/tendermint/tendermint/libs/db"
) )
@ -24,6 +25,13 @@ var (
CodeKey = types.NewKVStoreKey("code") CodeKey = types.NewKVStoreKey("code")
) )
const (
// codeSizeCacheSize is the number of codehash to size associations to
// keep in cached memory. This is to address any DoS attempts on
// EXTCODESIZE calls.
codeSizeCacheSize = 100000
)
// Database implements the Ethereum state.Database interface. // Database implements the Ethereum state.Database interface.
type Database struct { type Database struct {
// stateStore will be used for the history of accounts (balance, nonce, // stateStore will be used for the history of accounts (balance, nonce,
@ -43,7 +51,10 @@ type Database struct {
codeDB dbm.DB codeDB dbm.DB
ethTrieDB *ethtrie.Database ethTrieDB *ethtrie.Database
// TODO: Do we need this/document? // codeSizeCache contains an LRU cache of a specified capacity to cache
// EXTCODESIZE calls.
codeSizeCache *lru.Cache
Tracing bool Tracing bool
} }
@ -75,6 +86,8 @@ func NewDatabase(stateDB, codeDB dbm.DB) (*Database, error) {
db.codeDB = codeDB db.codeDB = codeDB
db.ethTrieDB = ethtrie.NewDatabase(&core.EthereumDB{CodeDB: codeDB}) db.ethTrieDB = ethtrie.NewDatabase(&core.EthereumDB{CodeDB: codeDB})
db.codeSizeCache, _ = lru.New(codeSizeCacheSize)
return db, nil return db, nil
} }
@ -151,13 +164,20 @@ func (db *Database) CopyTrie(ethstate.Trie) ethstate.Trie {
// ContractCode implements Ethereum's state.Database interface. It will return // ContractCode implements Ethereum's state.Database interface. It will return
// the contract byte code for a given code hash. It will not return an error. // the contract byte code for a given code hash. It will not return an error.
func (db *Database) ContractCode(addrHash, codeHash ethcommon.Hash) ([]byte, error) { func (db *Database) ContractCode(addrHash, codeHash ethcommon.Hash) ([]byte, error) {
return db.codeDB.Get(codeHash[:]), nil code := db.codeDB.Get(codeHash[:])
db.codeSizeCache.Add(codeHash, code)
return code, nil
} }
// ContractCodeSize implements Ethereum's state.Database interface. It will // ContractCodeSize implements Ethereum's state.Database interface. It will
// return the contract byte code size for a given code hash. It will not return // return the contract byte code size for a given code hash. It will not return
// an error. // an error.
func (db *Database) ContractCodeSize(addrHash, codeHash ethcommon.Hash) (int, error) { func (db *Database) ContractCodeSize(addrHash, codeHash ethcommon.Hash) (int, error) {
if cached, ok := db.codeSizeCache.Get(codeHash); ok {
return cached.(int), nil
}
return len(db.codeDB.Get(codeHash[:])), nil return len(db.codeDB.Get(codeHash[:])), nil
} }