Last active
January 29, 2018 15:32
-
-
Save dimchansky/64d296080a92718c65b4423dcfb4a311 to your computer and use it in GitHub Desktop.
Converts PARITY trace JSON to Graphviz DOT file
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"encoding/json" | |
"fmt" | |
"io" | |
"math/big" | |
"os" | |
"strconv" | |
"strings" | |
) | |
type traceStep struct { | |
Action struct { | |
CallType string `json:"callType"` | |
From string `json:"from"` | |
Gas string `json:"gas"` | |
Input string `json:"input"` | |
To string `json:"to"` | |
Value string `json:"value"` | |
} `json:"action"` | |
BlockHash string `json:"blockHash"` | |
BlockNumber int `json:"blockNumber"` | |
Result struct { | |
GasUsed string `json:"gasUsed"` | |
Output string `json:"output"` | |
} `json:"result"` | |
Subtraces int `json:"subtraces"` | |
TraceAddress []interface{} `json:"traceAddress"` | |
TransactionHash string `json:"transactionHash"` | |
TransactionPosition int `json:"transactionPosition"` | |
Type string `json:"type"` | |
} | |
type trace []traceStep | |
func main() { | |
tr, err := loadTrace() | |
if err != nil { | |
fmt.Printf("Failed to load trace from JSON: %v\n", err) | |
return | |
} | |
// collect unique addresses | |
uniqueAddresses := make(map[string]struct{}) | |
for _, ts := range tr { | |
uniqueAddresses[ts.Action.From] = struct{}{} | |
uniqueAddresses[ts.Action.To] = struct{}{} | |
} | |
// output graph | |
fmt.Println("digraph G {") | |
for addr, _ := range uniqueAddresses { | |
quotAddr := strconv.Quote(addr) | |
fmt.Printf("\t%v [label=%v];\n", quotAddr, quotAddr) | |
} | |
fmt.Println() | |
for _, ts := range tr { | |
fmt.Printf("\t%v -> %v [label=\"%v: %v\\nvalue: %v ETH\\ngas: %v\\ngas used: %v\"];\n", | |
strconv.Quote(ts.Action.From), strconv.Quote(ts.Action.To), | |
ts.Action.CallType, truncateInputToCall(ts.Action.Input), | |
hexStrToETH(ts.Action.Value), | |
hexStrToBigInt(ts.Action.Gas), | |
hexStrToBigInt(ts.Result.GasUsed)) | |
} | |
fmt.Println("}") | |
} | |
var ether = big.NewInt(1000000000000000000) // 1 ether in wei | |
func truncateInputToCall(s string) string { | |
if len(s) > 10 { | |
return s[:10] | |
} | |
return s | |
} | |
func hexStrToETH(s string) float64 { | |
bi := hexStrToBigInt(s) | |
r := new(big.Rat).SetFrac(bi, ether) | |
eth, _ := r.Float64() | |
return eth | |
} | |
func hexStrToBigInt(s string) *big.Int { | |
bi, _ := new(big.Int).SetString(strings.TrimPrefix(s, "0x"), 16) | |
return bi | |
} | |
func loadTrace() (trace, error) { | |
if len(os.Args) == 2 { | |
return loadTraceFromFile(os.Args[1]) | |
} | |
return loadTraceFromReader(os.Stdin) | |
} | |
func loadTraceFromFile(file string) (trace, error) { | |
f, err := os.Open(file) | |
if err != nil { | |
return nil, fmt.Errorf("os.Open: %v", err) | |
} | |
defer f.Close() | |
return loadTraceFromReader(f) | |
} | |
func loadTraceFromReader(f io.Reader) (trace, error) { | |
jsonParser := json.NewDecoder(f) | |
var tr trace | |
if err := jsonParser.Decode(&tr); err != nil { | |
return nil, fmt.Errorf("jsonParser.Decode: %v", err) | |
} | |
return tr, nil | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment