From 4ad50d723c045bfafe6df33f15a7f2396a618450 Mon Sep 17 00:00:00 2001 From: Alexey Akhunov Date: Mon, 2 Jul 2018 23:28:39 +0100 Subject: [PATCH] Fixed commit issue, tx tracing introduced --- copied.go | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ main.go | 44 +++++++++++++++++++++++++++++++++++--------- 2 files changed, 89 insertions(+), 9 deletions(-) diff --git a/copied.go b/copied.go index 532f478f..68134f00 100644 --- a/copied.go +++ b/copied.go @@ -2,10 +2,13 @@ package main import ( + "fmt" "math/big" + "github.com/ethereum/go-ethereum/common/math" "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/consensus/ethash" "github.com/ethereum/go-ethereum/params" ) @@ -40,3 +43,54 @@ func accumulateRewards(config *params.ChainConfig, state *state.StateDB, header } state.AddBalance(header.Coinbase, reward) } + +// StructLogRes stores a structured log emitted by the EVM while replaying a +// transaction in debug mode +type StructLogRes struct { + Pc uint64 `json:"pc"` + Op string `json:"op"` + Gas uint64 `json:"gas"` + GasCost uint64 `json:"gasCost"` + Depth int `json:"depth"` + Error error `json:"error,omitempty"` + Stack *[]string `json:"stack,omitempty"` + Memory *[]string `json:"memory,omitempty"` + Storage *map[string]string `json:"storage,omitempty"` +} + + // formatLogs formats EVM returned structured logs for json output +func FormatLogs(logs []vm.StructLog) []StructLogRes { + formatted := make([]StructLogRes, len(logs)) + for index, trace := range logs { + formatted[index] = StructLogRes{ + Pc: trace.Pc, + Op: trace.Op.String(), + Gas: trace.Gas, + GasCost: trace.GasCost, + Depth: trace.Depth, + Error: trace.Err, + } + if trace.Stack != nil { + stack := make([]string, len(trace.Stack)) + for i, stackValue := range trace.Stack { + stack[i] = fmt.Sprintf("%x", math.PaddedBigBytes(stackValue, 32)) + } + formatted[index].Stack = &stack + } + if trace.Memory != nil { + memory := make([]string, 0, (len(trace.Memory)+31)/32) + for i := 0; i+32 <= len(trace.Memory); i += 32 { + memory = append(memory, fmt.Sprintf("%x", trace.Memory[i:i+32])) + } + formatted[index].Memory = &memory + } + if trace.Storage != nil { + storage := make(map[string]string) + for i, storageValue := range trace.Storage { + storage[fmt.Sprintf("%x", i)] = fmt.Sprintf("%x", storageValue) + } + formatted[index].Storage = &storage + } + } + return formatted +} diff --git a/main.go b/main.go index 2bd01382..f6e596c1 100644 --- a/main.go +++ b/main.go @@ -1,7 +1,9 @@ package main import ( + "bytes" "encoding/binary" + "encoding/json" "fmt" "io" "math/big" @@ -69,7 +71,7 @@ func OurNewDatabase(stateDb, codeDb dbm.DB) (*OurDatabase, error) { func (od *OurDatabase) OpenTrie(root eth_common.Hash) (eth_state.Trie, error) { // Look up version id to use hasData := root != (eth_common.Hash{}) - var versionId int64 + versionId := od.stateStore.LastCommitID().Version if hasData { // First 8 bytes encode version versionId = int64(binary.BigEndian.Uint64(root[:8])) @@ -83,25 +85,27 @@ func (od *OurDatabase) OpenTrie(root eth_common.Hash) (eth_state.Trie, error) { if od.accountsCache == nil { od.accountsCache = store.NewCacheKVStore(od.stateStore.GetCommitKVStore(AccountsKey)) } + fmt.Printf("OpenTrie version %d\n", versionId) return &OurTrie{od: od, versionId: versionId, st: od.accountsCache, prefix: nil, hasData: hasData}, nil } func (od *OurDatabase) OpenStorageTrie(addrHash, root eth_common.Hash) (eth_state.Trie, error) { hasData := root != (eth_common.Hash{}) - var versionId int64 + versionId := od.stateStore.LastCommitID().Version if hasData { // First 8 bytes encode version versionId = int64(binary.BigEndian.Uint64(root[:8])) if od.stateStore.LastCommitID().Version != versionId { - if err := od.stateStore.LoadVersion(versionId); err != nil { - return nil, err - } + //if err := od.stateStore.LoadVersion(versionId); err != nil { + // return nil, err + //} od.storageCache = nil } } if od.storageCache == nil { od.storageCache = store.NewCacheKVStore(od.stateStore.GetCommitKVStore(StorageKey)) } + fmt.Printf("OpenStorageTrie version %d\n", versionId) return &OurTrie{od:od, versionId: versionId, st: od.storageCache, prefix: addrHash[:], hasData: hasData}, nil } @@ -171,8 +175,8 @@ func (ot *OurTrie) Commit(onleaf eth_trie.LeafCallback) (eth_common.Hash, error) return eth_common.Hash{}, nil } var commitHash eth_common.Hash - // We assume here that the next committed version will be ot.versionId+1 - binary.BigEndian.PutUint64(commitHash[:8], uint64(ot.versionId+1)) + // We assume here that the next committed version will be od.stateStore.LastCommitID().Version+1 + binary.BigEndian.PutUint64(commitHash[:8], uint64(ot.od.stateStore.LastCommitID().Version+1)) if ot.prefix == nil { if ot.od.accountsCache != nil { ot.od.accountsCache.Write() @@ -351,6 +355,7 @@ func main() { prev_root := genesis_root d.tracing = true chainContext := &OurChainContext{} + vmConfig := eth_vm.Config{} for { if err = stream.Decode(&block); err == io.EOF { err = nil // Clear it @@ -379,7 +384,28 @@ func main() { } for i, tx := range block.Transactions() { statedb.Prepare(tx.Hash(), block.Hash(), i) - receipt, _, err := eth_core.ApplyTransaction(chainConfig, chainContext, nil, gp, statedb, header, tx, usedGas, eth_vm.Config{}) + var h eth_common.Hash = tx.Hash() + if bytes.Equal(h[:], eth_common.FromHex("0xc438cfcc3b74a28741bda361032f1c6362c34aa0e1cedff693f31ec7d6a12717")) { + vmConfig.Tracer = eth_vm.NewStructLogger(ð_vm.LogConfig{}) + vmConfig.Debug = true + } + receipt, _, err := eth_core.ApplyTransaction(chainConfig, chainContext, nil, gp, statedb, header, tx, usedGas, vmConfig) + if vmConfig.Tracer != nil { + w, err := os.Create("structlogs.txt") + if err != nil { + panic(err) + } + encoder := json.NewEncoder(w) + logs := FormatLogs(vmConfig.Tracer.(*eth_vm.StructLogger).StructLogs()) + if err := encoder.Encode(logs); err != nil { + panic(err) + } + if err := w.Close(); err != nil { + panic(err) + } + vmConfig.Debug = false + vmConfig.Tracer = nil + } if err != nil { panic(fmt.Errorf("at block %d, tx %x: %v", block.NumberU64(), tx.Hash(), err)) } @@ -393,7 +419,7 @@ func main() { if err != nil { panic(fmt.Errorf("at block %d: %v", block.NumberU64(), err)) } - //fmt.Printf("State root after block %d: %x\n", block.NumberU64(), prev_root) + fmt.Printf("State root after block %d: %x\n", block.NumberU64(), prev_root) d.stateStore.Commit() //fmt.Printf("CommitID after block %d: %v\n", block.NumberU64(), commitID) switch block.NumberU64() {