package main import ( "bufio" "bytes" "encoding/json" "flag" "fmt" "io" "net/http" "os" "strings" "time" "github.com/ledgerwatch/turbo-geth/common" "github.com/ledgerwatch/turbo-geth/common/hexutil" "github.com/ledgerwatch/turbo-geth/crypto" "github.com/ledgerwatch/turbo-geth/log" "github.com/mattn/go-colorable" "github.com/mattn/go-isatty" ) var action = flag.String("action", "", "action to execute") var url = flag.String("url", "", "URL to use for RPC requests") var block = flag.Int("block", 1, "specifies a block number for operation") var chaindata = flag.String("chaindata", "chaindata", "path to the chaindata database file") type EthError struct { Code int `json:"code"` Message string `json:"message"` } type CommonResponse struct { Version string `json:"jsonrpc"` RequestId int `json:"id"` Error *EthError `json:"error"` } type EthBlockNumber struct { CommonResponse Number hexutil.Big `json:"result"` } type EthBalance struct { CommonResponse Balance hexutil.Big `json:"result"` } type EthTransaction struct { From common.Address `json:"from"` To *common.Address `json:"to"` // Pointer because it might be missing Hash string `json:"hash"` Gas hexutil.Big `json:"gas"` } type EthBlockByNumberResult struct { Difficulty hexutil.Big `json:"difficulty"` Miner common.Address `json:"miner"` Transactions []EthTransaction `json:"transactions"` TxRoot common.Hash `json:"transactionsRoot"` Hash common.Hash `json:"hash"` } type EthBlockByNumber struct { CommonResponse Result EthBlockByNumberResult `json:"result"` } type StructLog struct { Op string `json:"op"` Pc uint64 `json:"pc"` Depth uint64 `json:"depth"` Error *EthError `json:"error"` Gas uint64 `json:"gas"` GasCost uint64 `json:"gasCost"` Memory []string `json:"memory"` Stack []string `json:"stack"` Storage map[string]string `json:"storage"` } type EthTxTraceResult struct { Gas uint64 `json:"gas"` Failed bool `json:"failed"` ReturnValue string `json:"returnValue"` StructLogs []StructLog `json:"structLogs"` } type EthTxTrace struct { CommonResponse Result EthTxTraceResult `json:"result"` } type DebugModifiedAccounts struct { CommonResponse Result []common.Address `json:"result"` } // StorageRangeResult is the result of a debug_storageRangeAt API call. type StorageRangeResult struct { Storage storageMap `json:"storage"` NextKey *common.Hash `json:"nextKey"` // nil if Storage includes the last key in the trie. } type storageMap map[common.Hash]storageEntry type storageEntry struct { Key *common.Hash `json:"key"` Value common.Hash `json:"value"` } type DebugStorageRange struct { CommonResponse Result StorageRangeResult `json:"result"` } // Log represents a contract log event. These events are generated by the LOG opcode and // stored/indexed by the node. type Log struct { // Consensus fields: // address of the contract that generated the event Address common.Address `json:"address" gencodec:"required"` // list of topics provided by the contract. Topics []common.Hash `json:"topics" gencodec:"required"` // supplied by the contract, usually ABI-encoded Data hexutil.Bytes `json:"data" gencodec:"required"` // Derived fields. These fields are filled in by the node // but not secured by consensus. // block in which the transaction was included BlockNumber hexutil.Uint64 `json:"blockNumber"` // hash of the transaction TxHash common.Hash `json:"transactionHash" gencodec:"required"` // index of the transaction in the block TxIndex hexutil.Uint `json:"transactionIndex" gencodec:"required"` // hash of the block in which the transaction was included BlockHash common.Hash `json:"blockHash"` // index of the log in the receipt Index hexutil.Uint `json:"logIndex" gencodec:"required"` // The Removed field is true if this log was reverted due to a chain reorganisation. // You must pay attention to this field if you receive logs through a filter query. Removed bool `json:"removed"` } type Receipt struct { // Consensus fields PostState common.Hash `json:"root"` Status hexutil.Uint64 `json:"status"` CumulativeGasUsed hexutil.Uint64 `json:"cumulativeGasUsed" gencodec:"required"` Bloom hexutil.Bytes `json:"logsBloom" gencodec:"required"` Logs []*Log `json:"logs" gencodec:"required"` // Implementation fields (don't reorder!) TxHash common.Hash `json:"transactionHash" gencodec:"required"` ContractAddress *common.Address `json:"contractAddress"` GasUsed hexutil.Uint64 `json:"gasUsed" gencodec:"required"` } type EthReceipt struct { CommonResponse Result Receipt `json:"result"` } type EthLogs struct { CommonResponse Result []*Log `json:"result"` } func post(client *http.Client, url, request string, response interface{}) error { start := time.Now() r, err := client.Post(url, "application/json", strings.NewReader(request)) if err != nil { return err } if r.StatusCode != 200 { return fmt.Errorf("Status %s", r.Status) } decoder := json.NewDecoder(r.Body) defer r.Body.Close() err = decoder.Decode(response) fmt.Printf("%s %s %f\n", url, request, time.Since(start).Seconds()) return err } func print(client *http.Client, url, request string) { r, err := client.Post(url, "application/json", strings.NewReader(request)) if err != nil { fmt.Printf("Could not print: %v\n", err) return } if r.StatusCode != 200 { fmt.Printf("Status %s", r.Status) return } fmt.Printf("ContentLength: %d\n", r.ContentLength) buf := make([]byte, 2000000) l, err := r.Body.Read(buf) if err != nil && err != io.EOF { fmt.Printf("Could not read response: %v\n", err) return } if l < len(buf) { fmt.Printf("Could not read response: %d out of %d\n", l, len(buf)) //return } fmt.Printf("%s\n", buf[:l]) } func compareBlocks(b, bg *EthBlockByNumber) bool { r := b.Result rg := bg.Result if r.Difficulty.ToInt().Cmp(rg.Difficulty.ToInt()) != 0 { fmt.Printf("Difficulty difference %d %d\n", r.Difficulty.ToInt(), rg.Difficulty.ToInt()) return false } if r.Miner != rg.Miner { fmt.Printf("Miner different %x %x\n", r.Miner, rg.Miner) return false } if len(r.Transactions) != len(rg.Transactions) { fmt.Printf("Num of txs different: %d %d\n", len(r.Transactions), len(rg.Transactions)) return false } for i, tx := range r.Transactions { txg := rg.Transactions[i] if tx.From != txg.From { fmt.Printf("Tx %d different From: %x %x\n", i, tx.From, txg.From) return false } if (tx.To == nil && txg.To != nil) || (tx.To != nil && txg.To == nil) { fmt.Printf("Tx %d different To nilness: %t %t\n", i, (tx.To == nil), (txg.To == nil)) return false } if tx.To != nil && txg.To != nil && *tx.To != *txg.To { fmt.Printf("Tx %d different To: %x %x\n", i, *tx.To, *txg.To) return false } if tx.Hash != txg.Hash { fmt.Printf("Tx %x different Hash: %s %s\n", i, tx.Hash, txg.Hash) return false } } return true } func compareTraces(trace, traceg *EthTxTrace) bool { r := trace.Result rg := traceg.Result if r.Gas != rg.Gas { fmt.Printf("Trace different Gas: %d %d\n", r.Gas, rg.Gas) return false } if r.Failed != rg.Failed { fmt.Printf("Trace different Failed: %t %t\n", r.Failed, rg.Failed) return false } if r.ReturnValue != rg.ReturnValue { fmt.Printf("Trace different ReturnValue: %s %s\n", r.ReturnValue, rg.ReturnValue) return false } if len(r.StructLogs) != len(rg.StructLogs) { fmt.Printf("Trace different length: %d %d\n", len(r.StructLogs), len(rg.StructLogs)) return false } for i, l := range r.StructLogs { lg := rg.StructLogs[i] if l.Op != lg.Op { fmt.Printf("Trace different Op: %d %s %s\n", i, l.Op, lg.Op) return false } if l.Pc != lg.Pc { fmt.Printf("Trace different Pc: %d %d %d\n", i, l.Pc, lg.Pc) return false } } return true } func compareBalances(balance, balanceg *EthBalance) bool { if balance.Balance.ToInt().Cmp(balanceg.Balance.ToInt()) != 0 { fmt.Printf("Different balance: %d %d\n", balance.Balance.ToInt(), balanceg.Balance.ToInt()) return false } return true } func compareModifiedAccounts(ma, mag *DebugModifiedAccounts) (bool, map[common.Address]struct{}) { r := ma.Result rg := mag.Result rset := make(map[common.Address]struct{}) rsetg := make(map[common.Address]struct{}) for _, a := range r { rset[a] = struct{}{} } for _, a := range rg { rsetg[a] = struct{}{} } for _, a := range r { if _, ok := rsetg[a]; !ok { fmt.Printf("%x not present in rg\n", a) // We tolerate that //return false } } for _, a := range rg { if _, ok := rset[a]; !ok { fmt.Printf("%x not present in r\n", a) return false, nil } } return true, rset } func compareStorageRanges(sm, smg map[common.Hash]storageEntry) bool { for k, v := range sm { if vg, ok := smg[k]; !ok { fmt.Printf("%x not present in smg\n", k) return false } else { if k != crypto.Keccak256Hash(v.Key[:]) { fmt.Printf("Sec key %x does not match key %x\n", k, *v.Key) return false } if v.Value != vg.Value { fmt.Printf("Different values for %x: %x %x [%x]\n", k, v.Value, vg.Value, *v.Key) return false } } } for k := range smg { if _, ok := sm[k]; !ok { fmt.Printf("%x not present in sm\n", k) return false } } return true } /* // Derived fields. These fields are filled in by the node // but not secured by consensus. // block in which the transaction was included BlockNumber hexutil.Uint64 `json:"blockNumber"` // hash of the transaction TxHash common.Hash `json:"transactionHash" gencodec:"required"` // index of the transaction in the block TxIndex hexutil.Uint `json:"transactionIndex" gencodec:"required"` // hash of the block in which the transaction was included BlockHash common.Hash `json:"blockHash"` // index of the log in the receipt Index hexutil.Uint `json:"logIndex" gencodec:"required"` // The Removed field is true if this log was reverted due to a chain reorganisation. // You must pay attention to this field if you receive logs through a filter query. Removed bool `json:"removed"` */ func compareReceipts(receipt, receiptg *EthReceipt) bool { r := receipt.Result rg := receiptg.Result if r.TxHash != rg.TxHash { fmt.Printf("Different tx hashes: %x %x\n", r.TxHash, rg.TxHash) return false } if r.Status != rg.Status { //fmt.Printf("Different status: %d %d\n", r.Status, rg.Status) //return false } if r.CumulativeGasUsed != rg.CumulativeGasUsed { fmt.Printf("Different cumulativeGasUsed: %d %d\n", r.CumulativeGasUsed, rg.CumulativeGasUsed) return false } if !bytes.Equal(r.Bloom, rg.Bloom) { fmt.Printf("Different blooms: %x %x\n", r.Bloom, rg.Bloom) return false } if r.ContractAddress == nil && rg.ContractAddress != nil { fmt.Printf("Different contract addresses: nil %x\n", rg.ContractAddress) return false } if r.ContractAddress != nil && rg.ContractAddress == nil { fmt.Printf("Different contract addresses: %x nil\n", r.ContractAddress) return false } if r.ContractAddress != nil && rg.ContractAddress != nil && *r.ContractAddress != *rg.ContractAddress { fmt.Printf("Different contract addresses: %x %x\n", r.ContractAddress, rg.ContractAddress) return false } if r.GasUsed != rg.GasUsed { fmt.Printf("Different gasUsed: %d %d\n", r.GasUsed, rg.GasUsed) return false } if len(r.Logs) != len(rg.Logs) { fmt.Printf("Different log lenths: %d %d\n", len(r.Logs), len(rg.Logs)) return false } for i, l := range r.Logs { lg := rg.Logs[i] if l.Address != lg.Address { fmt.Printf("Different log %d addresses: %x %x\n", i, l.Address, lg.Address) return false } if len(l.Topics) != len(lg.Topics) { fmt.Printf("Different log %d topic lengths: %d %d\n", i, len(l.Topics), len(lg.Topics)) return false } for j, t := range l.Topics { tg := lg.Topics[j] if t != tg { fmt.Printf("Different log %d topics %d: %x %x\n", i, j, t, tg) return false } } if !bytes.Equal(l.Data, lg.Data) { fmt.Printf("Different log %d data: %x %x\n", i, l.Data, lg.Data) return false } } return true } func compareLogs(logs, logsg *EthLogs) bool { r := logs.Result rg := logsg.Result if len(r) != len(rg) { fmt.Printf("Different log lenths: %d %d\n", len(r), len(rg)) return false } for i, l := range r { lg := rg[i] if l.Address != lg.Address { fmt.Printf("Different log %d addresses: %x %x\n", i, l.Address, lg.Address) return false } if len(l.Topics) != len(lg.Topics) { fmt.Printf("Different log %d topic lengths: %d %d\n", i, len(l.Topics), len(lg.Topics)) return false } for j, t := range l.Topics { tg := lg.Topics[j] if t != tg { fmt.Printf("Different log %d topics %d: %x %x\n", i, j, t, tg) return false } } if !bytes.Equal(l.Data, lg.Data) { fmt.Printf("Different log %d data: %x %x\n", i, l.Data, lg.Data) return false } } return true } func bench1() { var client = &http.Client{ Timeout: time.Second * 600, } req_id := 0 //geth_url := "http://192.168.1.96:8545" geth_url := "http://localhost:8545" turbogeth_url := "http://localhost:9545" req_id++ template := `{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":%d}` var blockNumber EthBlockNumber if err := post(client, turbogeth_url, fmt.Sprintf(template, req_id), &blockNumber); err != nil { fmt.Printf("Could not get block number: %v\n", err) return } if blockNumber.Error != nil { fmt.Printf("Error getting block number: %d %s\n", blockNumber.Error.Code, blockNumber.Error.Message) return } lastBlock := blockNumber.Number.ToInt().Int64() fmt.Printf("Last block: %d\n", lastBlock) accounts := make(map[common.Address]struct{}) firstBn := 5250001 prevBn := firstBn storageCounter := 0 for bn := firstBn; bn <= int(lastBlock); bn++ { req_id++ template := `{"jsonrpc":"2.0","method":"eth_getBlockByNumber","params":["0x%x",true],"id":%d}` var b EthBlockByNumber if err := post(client, turbogeth_url, fmt.Sprintf(template, bn, req_id), &b); err != nil { fmt.Printf("Could not retrieve block %d: %v\n", bn, err) return } if b.Error != nil { fmt.Printf("Error retrieving block: %d %s\n", b.Error.Code, b.Error.Message) } var bg EthBlockByNumber if err := post(client, geth_url, fmt.Sprintf(template, bn, req_id), &bg); err != nil { fmt.Printf("Could not retrieve block g %d: %v\n", bn, err) return } if bg.Error != nil { fmt.Printf("Error retrieving block g: %d %s\n", bg.Error.Code, bg.Error.Message) return } if !compareBlocks(&b, &bg) { fmt.Printf("Block difference for %d\n", bn) return } accounts[b.Result.Miner] = struct{}{} for i, tx := range b.Result.Transactions { accounts[tx.From] = struct{}{} if tx.To != nil { accounts[*tx.To] = struct{}{} } if tx.To != nil && tx.Gas.ToInt().Uint64() > 21000 { storageCounter++ if storageCounter == 100 { storageCounter = 0 req_id++ template = `{"jsonrpc":"2.0","method":"debug_storageRangeAt","params":["0x%x", %d,"0x%x","0x%x",%d],"id":%d}` sm := make(map[common.Hash]storageEntry) nextKey := &common.Hash{} for nextKey != nil { var sr DebugStorageRange if err := post(client, turbogeth_url, fmt.Sprintf(template, b.Result.Hash, i, tx.To, *nextKey, 1024, req_id), &sr); err != nil { fmt.Printf("Could not get storageRange: %s: %v\n", tx.Hash, err) return } if sr.Error != nil { fmt.Printf("Error getting storageRange: %d %s\n", sr.Error.Code, sr.Error.Message) break } else { nextKey = sr.Result.NextKey for k, v := range sr.Result.Storage { sm[k] = v } } } fmt.Printf("storageRange: %d\n", len(sm)) smg := make(map[common.Hash]storageEntry) nextKey = &common.Hash{} for nextKey != nil { var srg DebugStorageRange if err := post(client, geth_url, fmt.Sprintf(template, b.Result.Hash, i, tx.To, *nextKey, 1024, req_id), &srg); err != nil { fmt.Printf("Could not get storageRange g: %s: %v\n", tx.Hash, err) return } if srg.Error != nil { fmt.Printf("Error getting storageRange g: %d %s\n", srg.Error.Code, srg.Error.Message) break } else { nextKey = srg.Result.NextKey for k, v := range srg.Result.Storage { smg[k] = v } } } fmt.Printf("storageRange g: %d\n", len(smg)) if !compareStorageRanges(sm, smg) { fmt.Printf("Different in storage ranges tx %s\n", tx.Hash) return } } } req_id++ template = `{"jsonrpc":"2.0","method":"debug_traceTransaction","params":["%s"],"id":%d}` var trace EthTxTrace if err := post(client, turbogeth_url, fmt.Sprintf(template, tx.Hash, req_id), &trace); err != nil { fmt.Printf("Could not trace transaction %s: %v\n", tx.Hash, err) print(client, turbogeth_url, fmt.Sprintf(template, tx.Hash, req_id)) return } if trace.Error != nil { fmt.Printf("Error tracing transaction: %d %s\n", trace.Error.Code, trace.Error.Message) } var traceg EthTxTrace if err := post(client, geth_url, fmt.Sprintf(template, tx.Hash, req_id), &traceg); err != nil { fmt.Printf("Could not trace transaction g %s: %v\n", tx.Hash, err) print(client, geth_url, fmt.Sprintf(template, tx.Hash, req_id)) return } if traceg.Error != nil { fmt.Printf("Error tracing transaction g: %d %s\n", traceg.Error.Code, traceg.Error.Message) return } if !compareTraces(&trace, &traceg) { fmt.Printf("Different traces block %d, tx %s\n", bn, tx.Hash) return } req_id++ template = `{"jsonrpc":"2.0","method":"eth_getTransactionReceipt","params":["%s"],"id":%d}` var receipt EthReceipt if err := post(client, turbogeth_url, fmt.Sprintf(template, tx.Hash, req_id), &receipt); err != nil { fmt.Printf("Count not get receipt: %s: %v\n", tx.Hash, err) print(client, turbogeth_url, fmt.Sprintf(template, tx.Hash, req_id)) return } if receipt.Error != nil { fmt.Printf("Error getting receipt: %d %s\n", receipt.Error.Code, receipt.Error.Message) return } var receiptg EthReceipt if err := post(client, geth_url, fmt.Sprintf(template, tx.Hash, req_id), &receiptg); err != nil { fmt.Printf("Count not get receipt g: %s: %v\n", tx.Hash, err) print(client, geth_url, fmt.Sprintf(template, tx.Hash, req_id)) return } if receiptg.Error != nil { fmt.Printf("Error getting receipt g: %d %s\n", receiptg.Error.Code, receiptg.Error.Message) return } if !compareReceipts(&receipt, &receiptg) { fmt.Printf("Different receipts block %d, tx %s\n", bn, tx.Hash) print(client, turbogeth_url, fmt.Sprintf(template, tx.Hash, req_id)) print(client, geth_url, fmt.Sprintf(template, tx.Hash, req_id)) return } } req_id++ template = `{"jsonrpc":"2.0","method":"eth_getBalance","params":["0x%x", "0x%x"],"id":%d}` var balance EthBalance if err := post(client, turbogeth_url, fmt.Sprintf(template, b.Result.Miner, bn, req_id), &balance); err != nil { fmt.Printf("Could not get account balance: %v\n", err) return } if balance.Error != nil { fmt.Printf("Error getting account balance: %d %s", balance.Error.Code, balance.Error.Message) return } var balanceg EthBalance if err := post(client, geth_url, fmt.Sprintf(template, b.Result.Miner, bn, req_id), &balanceg); err != nil { fmt.Printf("Could not get account balance g: %v\n", err) return } if balanceg.Error != nil { fmt.Printf("Error getting account balance g: %d %s\n", balanceg.Error.Code, balanceg.Error.Message) return } if !compareBalances(&balance, &balanceg) { fmt.Printf("Miner %x balance difference for block %d\n", b.Result.Miner, bn) return } if prevBn < bn && bn%100 == 0 { // Checking modified accounts req_id++ template = `{"jsonrpc":"2.0","method":"debug_getModifiedAccountsByNumber","params":[%d, %d],"id":%d}` var ma DebugModifiedAccounts if err := post(client, turbogeth_url, fmt.Sprintf(template, prevBn, bn, req_id), &ma); err != nil { fmt.Printf("Could not get modified accounts: %v\n", err) return } if ma.Error != nil { fmt.Printf("Error getting modified accounts: %d %s\n", ma.Error.Code, ma.Error.Message) return } var mag DebugModifiedAccounts if err := post(client, geth_url, fmt.Sprintf(template, prevBn, bn, req_id), &mag); err != nil { fmt.Printf("Could not get modified accounts g: %v\n", err) return } if mag.Error != nil { fmt.Printf("Error getting modified accounts g: %d %s\n", mag.Error.Code, mag.Error.Message) return } ok, accountSet := compareModifiedAccounts(&ma, &mag) if !ok { fmt.Printf("Modified accouts different for blocks %d-%d\n", prevBn, bn) return } req_id++ template = `{"jsonrpc":"2.0","method":"eth_getLogs","params":[{"fromBlock": "0x%x", "toBlock": "0x%x", "address": "0x%x"}],"id":%d}` for account := range accountSet { var logs EthLogs if err := post(client, turbogeth_url, fmt.Sprintf(template, prevBn, bn, account, req_id), &logs); err != nil { fmt.Printf("Could not get logs for account %x: %v\n", account, err) return } if logs.Error != nil { fmt.Printf("Error getting logs for account %x: %d %s\n", account, logs.Error.Code, logs.Error.Message) return } var logsg EthLogs if err := post(client, geth_url, fmt.Sprintf(template, prevBn, bn, account, req_id), &logsg); err != nil { fmt.Printf("Could not get logs for account g %x: %v\n", account, err) return } if logsg.Error != nil { fmt.Printf("Error getting logs for account g %x: %d %s\n", account, logsg.Error.Code, logsg.Error.Message) return } if !compareLogs(&logs, &logsg) { fmt.Printf("Different logs for account %x and block %d-%d\n", account, prevBn, bn) return } } fmt.Printf("Done blocks %d-%d, modified accounts: %d (%d)\n", prevBn, bn, len(ma.Result), len(mag.Result)) prevBn = bn } } } func bench2() { var client = &http.Client{ Timeout: time.Second * 600, } req_id := 0 turbogeth_url := "http://localhost:8545" req_id++ template := ` {"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":%d} ` var blockNumber EthBlockNumber if err := post(client, turbogeth_url, fmt.Sprintf(template, req_id), &blockNumber); err != nil { fmt.Printf("Could not get block number: %v\n", err) return } if blockNumber.Error != nil { fmt.Printf("Error getting block number: %d %s\n", blockNumber.Error.Code, blockNumber.Error.Message) return } lastBlock := blockNumber.Number.ToInt().Int64() fmt.Printf("Last block: %d\n", lastBlock) firstBn := 1720000 - 2 prevBn := firstBn for bn := firstBn; bn <= int(lastBlock); bn++ { req_id++ template := ` {"jsonrpc":"2.0","method":"eth_getBlockByNumber","params":["0x%x",true],"id":%d} ` var b EthBlockByNumber if err := post(client, turbogeth_url, fmt.Sprintf(template, bn, req_id), &b); err != nil { fmt.Printf("Could not retrieve block %d: %v\n", bn, err) return } if b.Error != nil { fmt.Printf("Error retrieving block: %d %s\n", b.Error.Code, b.Error.Message) } for i, tx := range b.Result.Transactions { if tx.To != nil && tx.Gas.ToInt().Uint64() > 21000 { // Request storage range // blockHash common.Hash, txIndex int, contractAddress common.Address, keyStart hexutil.Bytes, maxResult int req_id++ template = ` {"jsonrpc":"2.0","method":"debug_storageRangeAt","params":["0x%x", %d,"0x%x","0x%x",%d],"id":%d} ` sm := make(map[common.Hash]storageEntry) nextKey := &common.Hash{} for nextKey != nil { var sr DebugStorageRange if err := post(client, turbogeth_url, fmt.Sprintf(template, b.Result.Hash, i, tx.To, *nextKey, 1024, req_id), &sr); err != nil { fmt.Printf("Could not get storageRange: %x: %v\n", tx.Hash, err) return } if sr.Error != nil { fmt.Printf("Error getting storageRange: %d %s\n", sr.Error.Code, sr.Error.Message) break } else { nextKey = sr.Result.NextKey for k, v := range sr.Result.Storage { sm[k] = v if v.Key == nil { fmt.Printf("No key for sec key: %x\n", k) } else if k != crypto.Keccak256Hash(v.Key[:]) { fmt.Printf("Different sec key: %x %x (%x), value %x\n", k, crypto.Keccak256Hash(v.Key[:]), *(v.Key), v.Value) } else { fmt.Printf("Keys: %x %x, value %x\n", *(v.Key), k, v.Value) } } } } fmt.Printf("storageRange: %d\n", len(sm)) } } if prevBn < bn && bn%1000 == 0 { // Checking modified accounts req_id++ template = ` {"jsonrpc":"2.0","method":"debug_getModifiedAccountsByNumber","params":[%d, %d],"id":%d} ` var ma DebugModifiedAccounts if err := post(client, turbogeth_url, fmt.Sprintf(template, prevBn, bn, req_id), &ma); err != nil { fmt.Printf("Could not get modified accounts: %v\n", err) return } if ma.Error != nil { fmt.Printf("Error getting modified accounts: %d %s\n", ma.Error.Code, ma.Error.Message) return } fmt.Printf("Done blocks %d-%d, modified accounts: %d\n", prevBn, bn, len(ma.Result)) prevBn = bn } } } func bench3() { var client = &http.Client{ Timeout: time.Second * 600, } geth_url := "http://localhost:8545" turbogeth_url := "http://localhost:9545" blockhash := common.HexToHash("0xdf15213766f00680c6a20ba76ba2cc9534435e19bc490039f3a7ef42095c8d13") req_id := 1 template := ` {"jsonrpc":"2.0","method":"eth_getBlockByNumber","params":["0x%x",true],"id":%d} ` var b EthBlockByNumber if err := post(client, turbogeth_url, fmt.Sprintf(template, 1720000, req_id), &b); err != nil { fmt.Printf("Could not retrieve block %d: %v\n", 1720000, err) return } if b.Error != nil { fmt.Printf("Error retrieving block: %d %s\n", b.Error.Code, b.Error.Message) } for txindex := 0; txindex < 18; txindex++ { txhash := b.Result.Transactions[txindex].Hash req_id++ template = ` {"jsonrpc":"2.0","method":"debug_traceTransaction","params":["%s"],"id":%d} ` var trace EthTxTrace if err := post(client, turbogeth_url, fmt.Sprintf(template, txhash, req_id), &trace); err != nil { fmt.Printf("Could not trace transaction %s: %v\n", txhash, err) print(client, turbogeth_url, fmt.Sprintf(template, txhash, req_id)) return } if trace.Error != nil { fmt.Printf("Error tracing transaction: %d %s\n", trace.Error.Code, trace.Error.Message) } var traceg EthTxTrace if err := post(client, geth_url, fmt.Sprintf(template, txhash, req_id), &traceg); err != nil { fmt.Printf("Could not trace transaction g %s: %v\n", txhash, err) print(client, geth_url, fmt.Sprintf(template, txhash, req_id)) return } if traceg.Error != nil { fmt.Printf("Error tracing transaction g: %d %s\n", traceg.Error.Code, traceg.Error.Message) return } //print(client, turbogeth_url, fmt.Sprintf(template, txhash, req_id)) if !compareTraces(&trace, &traceg) { fmt.Printf("Different traces block %d, tx %s\n", 1720000, txhash) return } } to := common.HexToAddress("0xbb9bc244d798123fde783fcc1c72d3bb8c189413") sm := make(map[common.Hash]storageEntry) start := common.HexToHash("0x5aa12c260b07325d83f0c9170a2c667948d0247cad4ad999cd00148658b0552d") req_id++ template = ` {"jsonrpc":"2.0","method":"debug_storageRangeAt","params":["0x%x", %d,"0x%x","0x%x",%d],"id":%d} ` i := 18 nextKey := &start for nextKey != nil { var sr DebugStorageRange if err := post(client, turbogeth_url, fmt.Sprintf(template, blockhash, i, to, *nextKey, 1024, req_id), &sr); err != nil { fmt.Printf("Could not get storageRange: %v\n", err) return } if sr.Error != nil { fmt.Printf("Error getting storageRange: %d %s\n", sr.Error.Code, sr.Error.Message) break } else { nextKey = sr.Result.NextKey for k, v := range sr.Result.Storage { sm[k] = v } } } fmt.Printf("storageRange: %d\n", len(sm)) smg := make(map[common.Hash]storageEntry) nextKey = &start for nextKey != nil { var srg DebugStorageRange if err := post(client, geth_url, fmt.Sprintf(template, blockhash, i, to, *nextKey, 1024, req_id), &srg); err != nil { fmt.Printf("Could not get storageRange g: %v\n", err) return } if srg.Error != nil { fmt.Printf("Error getting storageRange g: %d %s\n", srg.Error.Code, srg.Error.Message) break } else { nextKey = srg.Result.NextKey for k, v := range srg.Result.Storage { smg[k] = v } } } fmt.Printf("storageRange g: %d\n", len(smg)) if !compareStorageRanges(sm, smg) { fmt.Printf("Different in storage ranges tx\n") return } } func bench4() { var client = &http.Client{ Timeout: time.Second * 600, } turbogeth_url := "http://localhost:9545" blockhash := common.HexToHash("0xdf15213766f00680c6a20ba76ba2cc9534435e19bc490039f3a7ef42095c8d13") req_id := 1 template := ` {"jsonrpc":"2.0","method":"eth_getBlockByNumber","params":["0x%x",true],"id":%d} ` var b EthBlockByNumber if err := post(client, turbogeth_url, fmt.Sprintf(template, 1720000, req_id), &b); err != nil { fmt.Printf("Could not retrieve block %d: %v\n", 1720000, err) return } if b.Error != nil { fmt.Printf("Error retrieving block: %d %s\n", b.Error.Code, b.Error.Message) } for txindex := 0; txindex < 6; txindex++ { txhash := b.Result.Transactions[txindex].Hash req_id++ template = ` {"jsonrpc":"2.0","method":"debug_traceTransaction","params":["%s"],"id":%d} ` var trace EthTxTrace if err := post(client, turbogeth_url, fmt.Sprintf(template, txhash, req_id), &trace); err != nil { fmt.Printf("Could not trace transaction %s: %v\n", txhash, err) print(client, turbogeth_url, fmt.Sprintf(template, txhash, req_id)) return } if trace.Error != nil { fmt.Printf("Error tracing transaction: %d %s\n", trace.Error.Code, trace.Error.Message) } print(client, turbogeth_url, fmt.Sprintf(template, txhash, req_id)) } to := common.HexToAddress("0x8b3b3b624c3c0397d3da8fd861512393d51dcbac") sm := make(map[common.Hash]storageEntry) start := common.HexToHash("0xa283ff49a55f86420a4acd5835658d8f45180db430c7b0d7ae98da5c64f620dc") req_id++ template = ` {"jsonrpc":"2.0","method":"debug_storageRangeAt","params":["0x%x", %d,"0x%x","0x%x",%d],"id":%d} ` i := 6 nextKey := &start for nextKey != nil { var sr DebugStorageRange if err := post(client, turbogeth_url, fmt.Sprintf(template, blockhash, i, to, *nextKey, 1024, req_id), &sr); err != nil { fmt.Printf("Could not get storageRange: %v\n", err) return } if sr.Error != nil { fmt.Printf("Error getting storageRange: %d %s\n", sr.Error.Code, sr.Error.Message) break } else { nextKey = sr.Result.NextKey for k, v := range sr.Result.Storage { sm[k] = v } } } fmt.Printf("storageRange: %d\n", len(sm)) } func bench5() { var client = &http.Client{ Timeout: time.Second * 600, } turbogeth_url := "http://localhost:9545" file, err := os.Open("txs.txt") if err != nil { panic(err) } req_id := 0 template := `{"jsonrpc":"2.0","method":"eth_getTransactionReceipt","params":["0x%s"],"id":%d}` var receipt EthReceipt scanner := bufio.NewScanner(file) for scanner.Scan() { req_id++ if err := post(client, turbogeth_url, fmt.Sprintf(template, scanner.Text(), req_id), &receipt); err != nil { fmt.Printf("Count not get receipt: %s: %v\n", scanner.Text(), err) return } if receipt.Error != nil { fmt.Printf("Error getting receipt: %d %s\n", receipt.Error.Code, receipt.Error.Message) return } } err = scanner.Err() if err != nil { panic(err) } } func bench6() { var client = &http.Client{ Timeout: time.Second * 600, } req_id := 0 turbogeth_url := "http://localhost:8545" req_id++ template := ` {"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":%d} ` var blockNumber EthBlockNumber if err := post(client, turbogeth_url, fmt.Sprintf(template, req_id), &blockNumber); err != nil { fmt.Printf("Could not get block number: %v\n", err) return } if blockNumber.Error != nil { fmt.Printf("Error getting block number: %d %s\n", blockNumber.Error.Code, blockNumber.Error.Message) return } lastBlock := blockNumber.Number.ToInt().Int64() fmt.Printf("Last block: %d\n", lastBlock) accounts := make(map[common.Address]struct{}) firstBn := 100000 for bn := firstBn; bn <= int(lastBlock); bn++ { req_id++ template := ` {"jsonrpc":"2.0","method":"eth_getBlockByNumber","params":["0x%x",true],"id":%d} ` var b EthBlockByNumber if err := post(client, turbogeth_url, fmt.Sprintf(template, bn, req_id), &b); err != nil { fmt.Printf("Could not retrieve block %d: %v\n", bn, err) return } if b.Error != nil { fmt.Printf("Error retrieving block: %d %s\n", b.Error.Code, b.Error.Message) } accounts[b.Result.Miner] = struct{}{} for _, tx := range b.Result.Transactions { accounts[tx.From] = struct{}{} if tx.To != nil { accounts[*tx.To] = struct{}{} } req_id++ template = ` {"jsonrpc":"2.0","method":"eth_getTransactionReceipt","params":["%s"],"id":%d} ` var receipt EthReceipt if err := post(client, turbogeth_url, fmt.Sprintf(template, tx.Hash, req_id), &receipt); err != nil { fmt.Printf("Count not get receipt: %s: %v\n", tx.Hash, err) print(client, turbogeth_url, fmt.Sprintf(template, tx.Hash, req_id)) return } if receipt.Error != nil { fmt.Printf("Error getting receipt: %d %s\n", receipt.Error.Code, receipt.Error.Message) return } } } } func main() { var ( ostream log.Handler glogger *log.GlogHandler ) usecolor := (isatty.IsTerminal(os.Stderr.Fd()) || isatty.IsCygwinTerminal(os.Stderr.Fd())) && os.Getenv("TERM") != "dumb" output := io.Writer(os.Stderr) if usecolor { output = colorable.NewColorableStderr() } ostream = log.StreamHandler(output, log.TerminalFormat(usecolor)) glogger = log.NewGlogHandler(ostream) log.Root().SetHandler(glogger) glogger.Verbosity(log.Lvl(3)) // 3 == verbosity INFO flag.Parse() if *action == "proofs" { proofs(*chaindata, *url, *block) } if *action == "fixState" { fixState(*chaindata, *url) } }