Merge pull request #1507 from obscuren/batch-write

cmd/core,xeth: removed unneeded states & added batch writes
This commit is contained in:
Jeffrey Wilcke 2015-07-23 07:50:07 -07:00
commit adc7ab0dd6
5 changed files with 120 additions and 59 deletions

View File

@ -18,79 +18,129 @@
package main package main
import ( import (
"flag"
"fmt" "fmt"
"log"
"math/big" "math/big"
"os" "os"
"runtime" "runtime"
"time" "time"
"github.com/codegangsta/cli"
"github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/logger"
) )
var ( var (
code = flag.String("code", "", "evm code") app *cli.App
loglevel = flag.Int("log", 4, "log level") DebugFlag = cli.BoolFlag{
gas = flag.String("gas", "1000000000", "gas amount") Name: "debug",
price = flag.String("price", "0", "gas price") Usage: "output full trace logs",
value = flag.String("value", "0", "tx value") }
dump = flag.Bool("dump", false, "dump state after run") CodeFlag = cli.StringFlag{
data = flag.String("data", "", "data") Name: "code",
Usage: "EVM code",
}
GasFlag = cli.StringFlag{
Name: "gas",
Usage: "gas limit for the evm",
Value: "10000000000",
}
PriceFlag = cli.StringFlag{
Name: "price",
Usage: "price set for the evm",
Value: "0",
}
ValueFlag = cli.StringFlag{
Name: "value",
Usage: "value set for the evm",
Value: "0",
}
DumpFlag = cli.BoolFlag{
Name: "dump",
Usage: "dumps the state after the run",
}
InputFlag = cli.StringFlag{
Name: "input",
Usage: "input for the EVM",
}
SysStatFlag = cli.BoolFlag{
Name: "sysstat",
Usage: "display system stats",
}
) )
func perr(v ...interface{}) { func init() {
fmt.Println(v...) app = utils.NewApp("0.2", "the evm command line interface")
//os.Exit(1) app.Flags = []cli.Flag{
DebugFlag,
SysStatFlag,
CodeFlag,
GasFlag,
PriceFlag,
ValueFlag,
DumpFlag,
InputFlag,
}
app.Action = run
} }
func main() { func run(ctx *cli.Context) {
flag.Parse() vm.Debug = ctx.GlobalBool(DebugFlag.Name)
logger.AddLogSystem(logger.NewStdLogSystem(os.Stdout, log.LstdFlags, logger.LogLevel(*loglevel)))
vm.Debug = true
db, _ := ethdb.NewMemDatabase() db, _ := ethdb.NewMemDatabase()
statedb := state.New(common.Hash{}, db) statedb := state.New(common.Hash{}, db)
sender := statedb.CreateAccount(common.StringToAddress("sender")) sender := statedb.CreateAccount(common.StringToAddress("sender"))
receiver := statedb.CreateAccount(common.StringToAddress("receiver")) receiver := statedb.CreateAccount(common.StringToAddress("receiver"))
receiver.SetCode(common.Hex2Bytes(*code)) receiver.SetCode(common.Hex2Bytes(ctx.GlobalString(CodeFlag.Name)))
vmenv := NewEnv(statedb, common.StringToAddress("evmuser"), common.Big(*value)) vmenv := NewEnv(statedb, common.StringToAddress("evmuser"), common.Big(ctx.GlobalString(ValueFlag.Name)))
tstart := time.Now() tstart := time.Now()
ret, e := vmenv.Call(
sender,
receiver.Address(),
common.Hex2Bytes(ctx.GlobalString(InputFlag.Name)),
common.Big(ctx.GlobalString(GasFlag.Name)),
common.Big(ctx.GlobalString(PriceFlag.Name)),
common.Big(ctx.GlobalString(ValueFlag.Name)),
)
vmdone := time.Since(tstart)
ret, e := vmenv.Call(sender, receiver.Address(), common.Hex2Bytes(*data), common.Big(*gas), common.Big(*price), common.Big(*value))
logger.Flush()
if e != nil { if e != nil {
perr(e) fmt.Println(e)
os.Exit(1)
} }
if *dump { if ctx.GlobalBool(DumpFlag.Name) {
fmt.Println(string(statedb.Dump())) fmt.Println(string(statedb.Dump()))
} }
vm.StdErrFormat(vmenv.StructLogs()) vm.StdErrFormat(vmenv.StructLogs())
var mem runtime.MemStats if ctx.GlobalBool(SysStatFlag.Name) {
runtime.ReadMemStats(&mem) var mem runtime.MemStats
fmt.Printf("vm took %v\n", time.Since(tstart)) runtime.ReadMemStats(&mem)
fmt.Printf(`alloc: %d fmt.Printf("vm took %v\n", vmdone)
fmt.Printf(`alloc: %d
tot alloc: %d tot alloc: %d
no. malloc: %d no. malloc: %d
heap alloc: %d heap alloc: %d
heap objs: %d heap objs: %d
num gc: %d num gc: %d
`, mem.Alloc, mem.TotalAlloc, mem.Mallocs, mem.HeapAlloc, mem.HeapObjects, mem.NumGC) `, mem.Alloc, mem.TotalAlloc, mem.Mallocs, mem.HeapAlloc, mem.HeapObjects, mem.NumGC)
}
fmt.Printf("%x\n", ret) fmt.Printf("OUT: 0x%x\n", ret)
}
func main() {
if err := app.Run(os.Args); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
} }
type VMEnv struct { type VMEnv struct {

View File

@ -73,9 +73,6 @@ type ChainManager struct {
lastBlockHash common.Hash lastBlockHash common.Hash
currentGasLimit *big.Int currentGasLimit *big.Int
transState *state.StateDB
txState *state.ManagedState
cache *lru.Cache // cache is the LRU caching cache *lru.Cache // cache is the LRU caching
futureBlocks *lru.Cache // future blocks are blocks added for later processing futureBlocks *lru.Cache // future blocks are blocks added for later processing
@ -128,9 +125,7 @@ func NewChainManager(blockDb, stateDb, extraDb common.Database, pow pow.PoW, mux
} }
} }
bc.transState = bc.State().Copy()
// Take ownership of this particular state // Take ownership of this particular state
bc.txState = state.ManageState(bc.State().Copy())
bc.futureBlocks, _ = lru.New(maxFutureBlocks) bc.futureBlocks, _ = lru.New(maxFutureBlocks)
bc.makeCache() bc.makeCache()
@ -152,9 +147,6 @@ func (bc *ChainManager) SetHead(head *types.Block) {
bc.currentBlock = head bc.currentBlock = head
bc.makeCache() bc.makeCache()
statedb := state.New(head.Root(), bc.stateDb)
bc.txState = state.ManageState(statedb)
bc.transState = statedb.Copy()
bc.setTotalDifficulty(head.Td) bc.setTotalDifficulty(head.Td)
bc.insert(head) bc.insert(head)
bc.setLastState() bc.setLastState()
@ -203,17 +195,6 @@ func (self *ChainManager) State() *state.StateDB {
return state.New(self.CurrentBlock().Root(), self.stateDb) return state.New(self.CurrentBlock().Root(), self.stateDb)
} }
func (self *ChainManager) TransState() *state.StateDB {
self.tsmu.RLock()
defer self.tsmu.RUnlock()
return self.transState
}
func (self *ChainManager) setTransState(statedb *state.StateDB) {
self.transState = statedb
}
func (bc *ChainManager) recover() bool { func (bc *ChainManager) recover() bool {
data, _ := bc.blockDb.Get([]byte("checkpoint")) data, _ := bc.blockDb.Get([]byte("checkpoint"))
if len(data) != 0 { if len(data) != 0 {
@ -529,9 +510,6 @@ func (self *ChainManager) WriteBlock(block *types.Block, queued bool) (status wr
self.insert(block) self.insert(block)
self.mu.Unlock() self.mu.Unlock()
self.setTransState(state.New(block.Root(), self.stateDb))
self.txState.SetState(state.New(block.Root(), self.stateDb))
status = CanonStatTy status = CanonStatTy
} else { } else {
status = SideStatTy status = SideStatTy

View File

@ -392,7 +392,6 @@ func chm(genesis *types.Block, db common.Database) *ChainManager {
bc.futureBlocks, _ = lru.New(100) bc.futureBlocks, _ = lru.New(100)
bc.processor = bproc{} bc.processor = bproc{}
bc.ResetWithGenesisBlock(genesis) bc.ResetWithGenesisBlock(genesis)
bc.txState = state.ManageState(bc.State())
return bc return bc
} }

View File

@ -19,9 +19,11 @@ package core
import ( import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"github.com/syndtr/goleveldb/leveldb"
) )
var ( var (
@ -31,13 +33,21 @@ var (
// PutTransactions stores the transactions in the given database // PutTransactions stores the transactions in the given database
func PutTransactions(db common.Database, block *types.Block, txs types.Transactions) { func PutTransactions(db common.Database, block *types.Block, txs types.Transactions) {
batch := new(leveldb.Batch)
_, batchWrite := db.(*ethdb.LDBDatabase)
for i, tx := range block.Transactions() { for i, tx := range block.Transactions() {
rlpEnc, err := rlp.EncodeToBytes(tx) rlpEnc, err := rlp.EncodeToBytes(tx)
if err != nil { if err != nil {
glog.V(logger.Debug).Infoln("Failed encoding tx", err) glog.V(logger.Debug).Infoln("Failed encoding tx", err)
return return
} }
db.Put(tx.Hash().Bytes(), rlpEnc)
if batchWrite {
batch.Put(tx.Hash().Bytes(), rlpEnc)
} else {
db.Put(tx.Hash().Bytes(), rlpEnc)
}
var txExtra struct { var txExtra struct {
BlockHash common.Hash BlockHash common.Hash
@ -52,20 +62,44 @@ func PutTransactions(db common.Database, block *types.Block, txs types.Transacti
glog.V(logger.Debug).Infoln("Failed encoding tx meta data", err) glog.V(logger.Debug).Infoln("Failed encoding tx meta data", err)
return return
} }
db.Put(append(tx.Hash().Bytes(), 0x0001), rlpMeta)
if batchWrite {
batch.Put(append(tx.Hash().Bytes(), 0x0001), rlpMeta)
} else {
db.Put(append(tx.Hash().Bytes(), 0x0001), rlpMeta)
}
}
if db, ok := db.(*ethdb.LDBDatabase); ok {
if err := db.LDB().Write(batch, nil); err != nil {
glog.V(logger.Error).Infoln("db write err:", err)
}
} }
} }
// PutReceipts stores the receipts in the current database // PutReceipts stores the receipts in the current database
func PutReceipts(db common.Database, receipts types.Receipts) error { func PutReceipts(db common.Database, receipts types.Receipts) error {
batch := new(leveldb.Batch)
_, batchWrite := db.(*ethdb.LDBDatabase)
for _, receipt := range receipts { for _, receipt := range receipts {
storageReceipt := (*types.ReceiptForStorage)(receipt) storageReceipt := (*types.ReceiptForStorage)(receipt)
bytes, err := rlp.EncodeToBytes(storageReceipt) bytes, err := rlp.EncodeToBytes(storageReceipt)
if err != nil { if err != nil {
return err return err
} }
err = db.Put(append(receiptsPre, receipt.TxHash[:]...), bytes)
if err != nil { if batchWrite {
batch.Put(append(receiptsPre, receipt.TxHash[:]...), bytes)
} else {
err = db.Put(append(receiptsPre, receipt.TxHash[:]...), bytes)
if err != nil {
return err
}
}
}
if db, ok := db.(*ethdb.LDBDatabase); ok {
if err := db.LDB().Write(batch, nil); err != nil {
return err return err
} }
} }

View File

@ -123,7 +123,7 @@ func New(ethereum *eth.Ethereum, frontend Frontend) *XEth {
if frontend == nil { if frontend == nil {
xeth.frontend = dummyFrontend{} xeth.frontend = dummyFrontend{}
} }
xeth.state = NewState(xeth, xeth.backend.ChainManager().TransState()) xeth.state = NewState(xeth, xeth.backend.ChainManager().State())
go xeth.start() go xeth.start()
go xeth.filterManager.Start() go xeth.filterManager.Start()