From 377b7f06c5482354c82706b65e823e95ecd8e5ac Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Tue, 17 Jul 2018 10:34:32 -0400 Subject: [PATCH] Merge pull request #437: Code Size Lookup Cache --- Gopkg.lock | 46 ++++++++++++++-------------------------------- Gopkg.toml | 3 +++ main.go | 5 +++-- state/database.go | 24 ++++++++++++++++++++++-- 4 files changed, 42 insertions(+), 36 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index 1d5e1b6c..2245ec99 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -24,7 +24,7 @@ packages = [ "store", "types", - "wire", + "wire" ] revision = "1a1373cc220e402397ad536aee6b8f5b068914c6" version = "v0.21.0" @@ -71,7 +71,7 @@ "params", "rlp", "rpc", - "trie", + "trie" ] revision = "dea1ce052a10cd7d401a5c04f83f371a06fe293c" version = "v1.8.11" @@ -81,7 +81,7 @@ packages = [ "log", "log/level", - "log/term", + "log/term" ] revision = "4dc7be5d2d12881735283bcab7352178e190fc71" version = "v0.6.0" @@ -106,7 +106,7 @@ "proto", "protoc-gen-gogo/descriptor", "sortkeys", - "types", + "types" ] revision = "1adfc126b41513cc696b209667c8656ea7aac67c" version = "v1.0.0" @@ -118,7 +118,7 @@ "ptypes", "ptypes/any", "ptypes/duration", - "ptypes/timestamp", + "ptypes/timestamp" ] revision = "925541529c1fa6821df4e44ce2723319eb2be768" version = "v1.0.0" @@ -134,7 +134,7 @@ name = "github.com/hashicorp/golang-lru" packages = [ ".", - "simplelru", + "simplelru" ] revision = "0fb14efe8c47ae851c0034ed7a448854d3d34cf3" @@ -177,7 +177,7 @@ "leveldb/opt", "leveldb/storage", "leveldb/table", - "leveldb/util", + "leveldb/util" ] revision = "c4c61651e9e37fa117f53c5a906d3b63090d8445" @@ -187,7 +187,7 @@ packages = [ ".", "edwards25519", - "extra25519", + "extra25519" ] revision = "d8387025d2b9d158cf4efb07e7ebf814bcce2057" @@ -216,7 +216,7 @@ "libs/log", "libs/pubsub", "libs/pubsub/query", - "types", + "types" ] revision = "5ff65274b84ea905787a48512cc3124385bddf2f" version = "v0.22.2" @@ -231,7 +231,7 @@ "openpgp/errors", "poly1305", "ripemd160", - "salsa20/salsa", + "salsa20/salsa" ] revision = "a49355c7e3f8fe157a85be2f77e6e269a0f89602" @@ -246,7 +246,7 @@ "idna", "internal/timeseries", "trace", - "websocket", + "websocket" ] revision = "d0887baf81f4598189d4e12a37c6da86f0bba4d0" @@ -266,7 +266,7 @@ "unicode/bidi", "unicode/cldr", "unicode/norm", - "unicode/rangetable", + "unicode/rangetable" ] revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0" version = "v0.3.0" @@ -301,7 +301,7 @@ "stats", "status", "tap", - "transport", + "transport" ] revision = "d11072e7ca9811b1100b80ca0269ac831f06d024" version = "v1.11.3" @@ -327,24 +327,6 @@ [solve-meta] analyzer-name = "dep" analyzer-version = 1 - input-imports = [ - "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", - ] + inputs-digest = "df6cfdfe013b00b662a5b9ebd45319d0c114859e865b3034b0e984f15e698b45" solver-name = "gps-cdcl" solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml index 13dbbd48..0282dbf3 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -6,6 +6,9 @@ name = "github.com/cosmos/cosmos-sdk" version = "=0.21.0" +[[constraint]] + name = "github.com/hashicorp/golang-lru" + [[override]] name = "google.golang.org/genproto" revision = "7fd901a49ba6a7f87732eb344f6e3c5b19d1b200" diff --git a/main.go b/main.go index c97b6ff7..d7b80a02 100644 --- a/main.go +++ b/main.go @@ -29,6 +29,7 @@ import ( var cpuprofile = flag.String("cpuprofile", "", "write cpu profile `file`") var blockchain = flag.String("blockchain", "data/blockchain", "file containing blocks to load") +var datadir = flag.String("datadir", "", "directory for ethermint data") var ( // TODO: Document... @@ -52,8 +53,8 @@ func main() { defer pprof.StopCPUProfile() } - stateDB := dbm.NewDB("state", dbm.LevelDBBackend, "") - codeDB := dbm.NewDB("code", dbm.LevelDBBackend, "") + stateDB := dbm.NewDB("state", dbm.LevelDBBackend, *datadir) + codeDB := dbm.NewDB("code", dbm.LevelDBBackend, *datadir) ethermintDB, err := state.NewDatabase(stateDB, codeDB) if err != nil { diff --git a/state/database.go b/state/database.go index b097621e..da9b05f6 100644 --- a/state/database.go +++ b/state/database.go @@ -7,6 +7,7 @@ import ( ethcommon "github.com/ethereum/go-ethereum/common" ethstate "github.com/ethereum/go-ethereum/core/state" ethtrie "github.com/ethereum/go-ethereum/trie" + lru "github.com/hashicorp/golang-lru" dbm "github.com/tendermint/tendermint/libs/db" ) @@ -24,6 +25,13 @@ var ( 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. type Database struct { // stateStore will be used for the history of accounts (balance, nonce, @@ -43,7 +51,10 @@ type Database struct { codeDB dbm.DB 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 } @@ -75,6 +86,8 @@ func NewDatabase(stateDB, codeDB dbm.DB) (*Database, error) { db.codeDB = codeDB db.ethTrieDB = ethtrie.NewDatabase(&core.EthereumDB{CodeDB: codeDB}) + db.codeSizeCache, _ = lru.New(codeSizeCacheSize) + 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 // 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) { - 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 // return the contract byte code size for a given code hash. It will not return // an 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 }