From 185c35523da306dab60230c252cde7c73e9cb015 Mon Sep 17 00:00:00 2001 From: Dustin Brickwood Date: Fri, 13 Jul 2018 11:55:37 -0400 Subject: [PATCH] writing internals to db --- core/shyft_database_util.go | 4 +- eth/api_tracer.go | 85 +++++++++++ eth/shyft_tracer.go | 272 +----------------------------------- eth/tracers/tracer.go | 95 ++++++++++--- 4 files changed, 162 insertions(+), 294 deletions(-) diff --git a/core/shyft_database_util.go b/core/shyft_database_util.go index 5a660890dc..8320bc70d3 100644 --- a/core/shyft_database_util.go +++ b/core/shyft_database_util.go @@ -175,8 +175,6 @@ func SwriteTransactions(sqldb *sql.DB, tx *types.Transaction, blockHash common.H hash := txData.TxHash txHash := txData.TxHash.Hex() - IShyftTracer.GetTracerToRun(hash) - from := txData.From.Hex() blockHasher := txData.BlockHash amount := txData.Amount.String() @@ -231,6 +229,8 @@ func SwriteTransactions(sqldb *sql.DB, tx *types.Transaction, blockHash common.H } } + IShyftTracer.GetTracerToRun(hash) + return nil } diff --git a/eth/api_tracer.go b/eth/api_tracer.go index 33d6ad6f33..c4df438414 100644 --- a/eth/api_tracer.go +++ b/eth/api_tracer.go @@ -548,6 +548,91 @@ func (api *PrivateDebugAPI) TraceTransaction(ctx context.Context, hash common.Ha return api.traceTx(ctx, msg, vmctx, statedb, config) } +// TraceTransaction returns the structured logs created during the execution of EVM +// and returns them as a JSON object. +func (api *PrivateDebugAPI) STraceTransaction(ctx context.Context, hash common.Hash, config *TraceConfig) (interface{}, error) { + // NOTE:SHYFT + tx, blockHash, _, index := core.GetTransaction(api.eth.ChainDb(), hash) + if tx == nil { + return nil, fmt.Errorf("transaction %x not found", hash) + } + reexec := defaultTraceReexec + if config != nil && config.Reexec != nil { + reexec = *config.Reexec + } + msg, vmctx, statedb, err := api.computeTxEnv(blockHash, int(index), reexec) + if err != nil { + return nil, err + } + return api.StraceTx(ctx, msg, vmctx, statedb, config, hash) +} + +// traceTx configures a new tracer according to the provided configuration, and +// executes the given message in the provided environment. The return value will +// be tracer dependent. +func (api *PrivateDebugAPI) StraceTx(ctx context.Context, message core.Message, vmctx vm.Context, statedb *state.StateDB, config *TraceConfig, hash common.Hash) (interface{}, error) { + // Assemble the structured logger or the JavaScript tracer + var ( + tracer vm.Tracer + err error + ) + switch { + case config != nil && config.Tracer != nil: + // Define a meaningful timeout of a single transaction trace + + _ = defaultTraceTimeout + + if config.Timeout != nil { + if _, err = time.ParseDuration(*config.Timeout); err != nil { + return nil, err + } + } + // Constuct the JavaScript tracer to execute with + if tracer, err = tracers.New(*config.Tracer); err != nil { + return nil, err + } + // NOTE:SHYFT REMOVED CTX DEADLINE + // Handle timeouts and RPC cancellations + //deadlineCtx, cancel := context.WithTimeout(ctx, timeout) + //go func() { + // <-deadlineCtx.Done() + // tracer.(*tracers.Tracer).Stop(errors.New("execution timeout")) + //}() + //defer cancel() + + case config == nil: + tracer = vm.NewStructLogger(nil) + + default: + tracer = vm.NewStructLogger(config.LogConfig) + } + // Run the transaction with tracing enabled. + vmenv := vm.NewEVM(vmctx, statedb, api.config, vm.Config{Debug: true, Tracer: tracer}) + + ret, gas, failed, err := core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.Gas())) + if err != nil { + return nil, fmt.Errorf("tracing failed: %v", err) + } + // Depending on the tracer type, format and return the output + switch tracer := tracer.(type) { + case *vm.StructLogger: + return ðapi.ExecutionResult{ + Gas: gas, + Failed: failed, + ReturnValue: fmt.Sprintf("%x", ret), + StructLogs: ethapi.FormatLogs(tracer.StructLogs()), + }, nil + + case *tracers.Tracer: + return tracer.SGetResult(hash) + + default: + panic(fmt.Sprintf("bad tracer type %T", tracer)) + } +} + + + // traceTx configures a new tracer according to the provided configuration, and // executes the given message in the provided environment. The return value will // be tracer dependent. diff --git a/eth/shyft_tracer.go b/eth/shyft_tracer.go index fb39dd5e19..bd1b1baeec 100644 --- a/eth/shyft_tracer.go +++ b/eth/shyft_tracer.go @@ -28,7 +28,7 @@ func (st ShyftTracer) GetTracerToRun (hash common.Hash) (interface{}, error) { //var fullNode *Ethereum fullNode, _ := SNew(Global_config) privateAPI := NewPrivateDebugAPI(config2, fullNode) - return privateAPI.TraceTransaction(ctx2, hash, config) + return privateAPI.STraceTransaction(ctx2, hash, config) } func setEthObject(ethobj interface{}){ @@ -39,272 +39,4 @@ var Global_config *Config func setGlobalConfig(c *Config) { Global_config = c -} - -// -//import ( -// "github.com/ethereum/go-ethereum/common" -// "fmt" -// "github.com/ethereum/go-ethereum/core" -// "runtime" -// "context" -//) -// -////const ( -//// // defaultTraceReexec is the number of blocks the tracer is willing to go back -//// // and reexecute to produce missing historical state necessary to run a specific -//// // trace. -//// defaultTraceReexec = uint64(128) -////) -// -////var api *eth.PrivateDebugAPI -// -//var EthereumObject interface{} -// -//type ShyftTracer struct {} -// -//func (st ShyftTracer) MyTraceTransaction(hash string) (interface{}) { -// //fmt.Println("THE stringed hash is in MYTRACETRANSACTION") -// //fmt.Println(hash) -// //fmt.Println(ethObjectInterface.GetEthObject()) -// fmt.Println("CTXXXXXXXXXXXXXXX") -// common_hash := common.HexToHash(hash) -// -// -// fmt.Println("the chain db is in MyTraceTransaction") -// //fmt.Println(Chaindb_global) -// if Chaindb_global == nil { -// return nil -// } -// -// tx, blockHash, _, index := core.GetTransaction(Chaindb_global, common_hash) -// -// if tx == nil { -// fmt.Println("TRANSACTION NOT FOUND IN MyTraceTransaction +++++++++") -// } -// -// reexec := defaultTraceReexec -// //if config != nil && config.Reexec != nil { -// // reexec = *config.Reexec -// //} -// msg, vmctx, statedb, err := DebugApi.computeTxEnv(blockHash, int(index), reexec) -// -// fmt.Println("stuff and nonsense") -// fmt.Println(msg) -// fmt.Println(vmctx) -// fmt.Println(statedb) -// fmt.Println(err) -// fmt.Println("THIS CTX") -// //fmt.Println("the tx is ") -// //fmt.Println(tx) -// //fmt.Println(blockHash) -// //fmt.Println(index) -// //DebugApi.traceTxTest(msg, vmctx, statedb, config) -// return 42 -//} -// -//func (api *PrivateDebugAPI) TraceTransactionTest(ctx context.Context, hash common.Hash, config *TraceConfig) (interface{}, error) { -// fmt.Println("TRACE TRANSACTION ++++++!+!+!+!+!+!+!+!+!+!+!+!++!") -// _, file, no, ok := runtime.Caller(1) -// if ok { -// fmt.Printf("called from %s#%d\n", file, no) -// } -// _, file, no, ok = runtime.Caller(2) -// if ok { -// fmt.Printf("called from %s#%d\n", file, no) -// } -// _, file, no, ok = runtime.Caller(3) -// if ok { -// fmt.Printf("called from %s#%d\n", file, no) -// } -// _, file, no, ok = runtime.Caller(4) -// if ok { -// fmt.Printf("called from %s#%d\n", file, no) -// } -// _, file, no, ok = runtime.Caller(5) -// if ok { -// fmt.Printf("called from %s#%d\n", file, no) -// } -// _, file, no, ok = runtime.Caller(6) -// if ok { -// fmt.Printf("called from %s#%d\n", file, no) -// } -// _, file, no, ok = runtime.Caller(7) -// if ok { -// fmt.Printf("called from %s#%d\n", file, no) -// } -// _, file, no, ok = runtime.Caller(8) -// if ok { -// fmt.Printf("called from %s#%d\n", file, no) -// } -// _, file, no, ok = runtime.Caller(9) -// if ok { -// fmt.Printf("called from %s#%d\n", file, no) -// } -// _, file, no, ok = runtime.Caller(10) -// if ok { -// fmt.Printf("called from %s#%d\n", file, no) -// } -// _, file, no, ok = runtime.Caller(11) -// if ok { -// fmt.Printf("called from %s#%d\n", file, no) -// } -// _, file, no, ok = runtime.Caller(12) -// if ok { -// fmt.Printf("called from %s#%d\n", file, no) -// } -// _, file, no, ok = runtime.Caller(13) -// if ok { -// fmt.Printf("called from %s#%d\n", file, no) -// } -// _, file, no, ok = runtime.Caller(14) -// if ok { -// fmt.Printf("called from %s#%d\n", file, no) -// } -// _, file, no, ok = runtime.Caller(15) -// if ok { -// fmt.Printf("called from %s#%d\n", file, no) -// } -// _, file, no, ok = runtime.Caller(16) -// if ok { -// fmt.Printf("called from %s#%d\n", file, no) -// } -// _, file, no, ok = runtime.Caller(17) -// if ok { -// fmt.Printf("called from %s#%d\n", file, no) -// } -// _, file, no, ok = runtime.Caller(18) -// if ok { -// fmt.Printf("called from %s#%d\n", file, no) -// } -// _, file, no, ok = runtime.Caller(19) -// if ok { -// fmt.Printf("called from %s#%d\n", file, no) -// } -// _, file, no, ok = runtime.Caller(20) -// if ok { -// fmt.Printf("called from %s#%d\n", file, no) -// } -// _, file, no, ok = runtime.Caller(21) -// if ok { -// fmt.Printf("called from %s#%d\n", file, no) -// } -// _, file, no, ok = runtime.Caller(22) -// if ok { -// fmt.Printf("called from %s#%d\n", file, no) -// } -// _, file, no, ok = runtime.Caller(23) -// if ok { -// fmt.Printf("called from %s#%d\n", file, no) -// } -// _, file, no, ok = runtime.Caller(24) -// if ok { -// fmt.Printf("called from %s#%d\n", file, no) -// } -// _, file, no, ok = runtime.Caller(25) -// if ok { -// fmt.Printf("called from %s#%d\n", file, no) -// } -// _, file, no, ok = runtime.Caller(26) -// if ok { -// fmt.Printf("called from %s#%d\n", file, no) -// } -// _, file, no, ok = runtime.Caller(27) -// if ok { -// fmt.Printf("called from %s#%d\n", file, no) -// } -// _, file, no, ok = runtime.Caller(28) -// if ok { -// fmt.Printf("called from %s#%d\n", file, no) -// } -// _, file, no, ok = runtime.Caller(29) -// if ok { -// fmt.Printf("called from %s#%d\n", file, no) -// } -// _, file, no, ok = runtime.Caller(30) -// if ok { -// fmt.Printf("called from %s#%d\n", file, no) -// } -// _, file, no, ok = runtime.Caller(31) -// if ok { -// fmt.Printf("called from %s#%d\n", file, no) -// } -// _, file, no, ok = runtime.Caller(32) -// if ok { -// fmt.Printf("called from %s#%d\n", file, no) -// } -// _, file, no, ok = runtime.Caller(33) -// if ok { -// fmt.Printf("called from %s#%d\n", file, no) -// } -// _, file, no, ok = runtime.Caller(34) -// if ok { -// fmt.Printf("called from %s#%d\n", file, no) -// } -// _, file, no, ok = runtime.Caller(35) -// if ok { -// fmt.Printf("called from %s#%d\n", file, no) -// } -// _, file, no, ok = runtime.Caller(36) -// if ok { -// fmt.Printf("called from %s#%d\n", file, no) -// } -// _, file, no, ok = runtime.Caller(37) -// if ok { -// fmt.Printf("called from %s#%d\n", file, no) -// } -// _, file, no, ok = runtime.Caller(38) -// if ok { -// fmt.Printf("called from %s#%d\n", file, no) -// } -// _, file, no, ok = runtime.Caller(39) -// if ok { -// fmt.Printf("called from %s#%d\n", file, no) -// } -// _, file, no, ok = runtime.Caller(40) -// if ok { -// fmt.Printf("called from %s#%d\n", file, no) -// } -// fmt.Println("////////////// ++++++++++++++++ /////////////////// Phantom *(!*!*!*!*!*!**!*!*") -// _, file, no, ok = runtime.Caller(41) -// if ok { -// fmt.Printf("called from %s#%d\n", file, no) -// } -// _, file, no, ok = runtime.Caller(42) -// if ok { -// fmt.Printf("called from %s#%d\n", file, no) -// } -// _, file, no, ok = runtime.Caller(43) -// if ok { -// fmt.Printf("called from %s#%d\n", file, no) -// } -// _, file, no, ok = runtime.Caller(44) -// if ok { -// fmt.Printf("called from %s#%d\n", file, no) -// } -// fmt.Println("////////////// ++++++++++++++++ /////////////////// TraceTransaction *(!*!*!*!*!*!**!*!*") -// _, file, no, ok = runtime.Caller(45) -// if ok { -// fmt.Printf("called from %s#%d\n", file, no) -// } -// -// tx, blockHash, _, index := core.GetTransaction(api.eth.ChainDb(), hash) -// if tx == nil { -// return nil, fmt.Errorf("transaction %x not found", hash) -// } -// -// reexec := defaultTraceReexec -// if config != nil && config.Reexec != nil { -// reexec = *config.Reexec -// } -// msg, vmctx, statedb, err := api.computeTxEnv(blockHash, int(index), reexec) -// if err != nil { -// return nil, err -// } -// fmt.Println("CTX +++++++++++++++++++++++", ctx) -// return api.traceTxTest(ctx, msg, vmctx, statedb, config) -//} -// -//func setEthObject(ethobj interface{}){ -// EthereumObject = ethobj -//} +} \ No newline at end of file diff --git a/eth/tracers/tracer.go b/eth/tracers/tracer.go index 14c6a34874..225021c204 100644 --- a/eth/tracers/tracer.go +++ b/eth/tracers/tracer.go @@ -31,6 +31,7 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/log" "gopkg.in/olebedev/go-duktape.v3" + "database/sql" ) // bigIntegerJS is the minified version of https://github.com/peterolson/BigInteger.js. @@ -588,35 +589,37 @@ type Internals struct { Calls []*Internals } -//func (i *Internals) SWriteInteralTxs() { -// connStr := "user=postgres dbname=shyftdb sslmode=disable" -// sqldb, err := sql.Open("postgres", connStr) -// if err != nil { -// return -// } -// -// sqlStatement := `INSERT INTO internalTxs(type, txhash, from_addr, to_addr, amount, gas, gasUsed, time, input, output) VALUES(($1), ($2), ($3), ($4), ($5), ($6), ($7), ($8), ($9), ($10))` -// qerr := sqldb.QueryRow(sqlStatement, i.Type, txHash, i.From, i.To, i.Value, i.Gas, i.GasUsed, i.Time, i.Input, i.Output) -// -// if qerr != nil { -// panic(qerr) -// } -//} +func (i *Internals) SWriteInteralTxs(hash common.Hash) { + connStr := "user=postgres dbname=shyftdb sslmode=disable" + sqldb, err := sql.Open("postgres", connStr) + if err != nil { + return + } + gas, _ := hexutil.DecodeUint64(i.Gas) + gasUsed, _ := hexutil.DecodeUint64(i.GasUsed) -func (i *Internals) InternalRecursive() { + var returnValue string + sqlStatement := `INSERT INTO internaltxs(type, txhash, from_addr, to_addr, amount, gas, gasUsed, time, input, output) VALUES(($1), ($2), ($3), ($4), ($5), ($6), ($7), ($8), ($9), ($10)) RETURNING txHash` + qerr := sqldb.QueryRow(sqlStatement, i.Type, hash.Hex(), i.From, i.To, i.Value, gas, gasUsed, i.Time, i.Input, i.Output).Scan(&returnValue) + + if qerr != nil { + fmt.Println(qerr) + panic(qerr) + } +} + +func (i *Internals) InternalRecursive(hash common.Hash) { + i.SWriteInteralTxs(hash) lengthOfCalls := len(i.Calls) if lengthOfCalls == 0 { return } for _, val := range i.Calls { - val.InternalRecursive() + val.InternalRecursive(hash) } } - - - // GetResult calls the Javascript 'result' function and returns its value, or any accumulated error func (jst *Tracer) GetResult() (json.RawMessage, error) { // Transform the context into a JavaScript object and inject into the state @@ -662,8 +665,56 @@ func (jst *Tracer) GetResult() (json.RawMessage, error) { if err := json.Unmarshal(result, &dat); err != nil { panic(err) } - - dat.InternalRecursive() - return result, jst.err } + +// GetResult calls the Javascript 'result' function and returns its value, or any accumulated error +func (jst *Tracer) SGetResult(hash common.Hash) (json.RawMessage, error) { + // Transform the context into a JavaScript object and inject into the state + obj := jst.vm.PushObject() + + for key, val := range jst.ctx { + switch val := val.(type) { + case uint64: + jst.vm.PushUint(uint(val)) + + case string: + jst.vm.PushString(val) + + case []byte: + ptr := jst.vm.PushFixedBuffer(len(val)) + copy(makeSlice(ptr, uint(len(val))), val[:]) + + case common.Address: + ptr := jst.vm.PushFixedBuffer(20) + copy(makeSlice(ptr, 20), val[:]) + + case *big.Int: + pushBigInt(val, jst.vm) + + default: + panic(fmt.Sprintf("unsupported type: %T", val)) + } + jst.vm.PutPropString(obj, key) + } + jst.vm.PutPropString(jst.stateObject, "ctx") + + // Finalize the trace and return the results + result, err := jst.call("result", "ctx", "db") + if err != nil { + jst.err = wrapError("result", err) + } + // Clean up the JavaScript environment + jst.vm.DestroyHeap() + jst.vm.Destroy() + + var dat Internals + + if err := json.Unmarshal(result, &dat); err != nil { + panic(err) + } + fmt.Println("[THIS IS HASH]", hash.Hex()) + dat.InternalRecursive(hash) + + return result, jst.err +} \ No newline at end of file