Merge pull request #1507 from obscuren/batch-write
cmd/core,xeth: removed unneeded states & added batch writes
This commit is contained in:
commit
adc7ab0dd6
112
cmd/evm/main.go
112
cmd/evm/main.go
@ -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 {
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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()
|
||||||
|
Loading…
Reference in New Issue
Block a user