mirror of
https://gitlab.com/pulsechaincom/erigon-pulse.git
synced 2025-01-16 07:48:20 +00:00
0c6a44b5e5
* Index bits * Fix linter * Fix linter * Not to call getModifiedAccountsByNumber for go-ethereum * Remove the 0x000 kludge
1568 lines
48 KiB
Go
1568 lines
48 KiB
Go
package main
|
|
|
|
import (
|
|
"bufio"
|
|
"bytes"
|
|
"encoding/base64"
|
|
"encoding/json"
|
|
"flag"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"os"
|
|
"path"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/ledgerwatch/turbo-geth/common"
|
|
"github.com/ledgerwatch/turbo-geth/common/hexutil"
|
|
"github.com/ledgerwatch/turbo-geth/core/state"
|
|
"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.Uint64 `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"`
|
|
}
|
|
|
|
type DebugAccountRange struct {
|
|
CommonResponse
|
|
Result state.IteratorDump `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 {
|
|
log.Info("Getting", "url", url, "request", request)
|
|
start := time.Now()
|
|
r, err := client.Post(url, "application/json", strings.NewReader(request))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer r.Body.Close()
|
|
if r.StatusCode != 200 {
|
|
return fmt.Errorf("status %s", r.Status)
|
|
}
|
|
decoder := json.NewDecoder(r.Body)
|
|
err = decoder.Decode(response)
|
|
log.Info("Got in", "time", 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 (ma *DebugModifiedAccounts) Print() {
|
|
r := ma.Result
|
|
rset := make(map[common.Address]struct{})
|
|
for _, a := range r {
|
|
rset[a] = struct{}{}
|
|
}
|
|
for a := range rset {
|
|
fmt.Printf("%x\n", a)
|
|
}
|
|
}
|
|
|
|
func extractAccountMap(ma *DebugModifiedAccounts) map[common.Address]struct{} {
|
|
r := ma.Result
|
|
rset := make(map[common.Address]struct{})
|
|
for _, a := range r {
|
|
rset[a] = struct{}{}
|
|
}
|
|
return rset
|
|
}
|
|
|
|
func printStorageRange(sm map[common.Hash]storageEntry) {
|
|
for k := range sm {
|
|
fmt.Printf("%x\n", k)
|
|
}
|
|
}
|
|
|
|
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 v.Key == nil {
|
|
fmt.Printf("v.Key == nil for %x\n", k)
|
|
return false
|
|
}
|
|
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, v := range smg {
|
|
if _, ok := sm[k]; !ok {
|
|
fmt.Printf("%x not present in sm\n", k)
|
|
return false
|
|
}
|
|
if k != crypto.Keccak256Hash(v.Key[:]) {
|
|
fmt.Printf("Sec key (g) %x does not match key %x\n", k, *v.Key)
|
|
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
|
|
}
|
|
|
|
const Geth = "geth"
|
|
const TurboGeth = "turbo_geth"
|
|
|
|
var routes = map[string]string{
|
|
Geth: "http://192.168.1.238:8545",
|
|
TurboGeth: "http://192.168.1.126:8545",
|
|
}
|
|
|
|
type CallResult struct {
|
|
Target string
|
|
Took time.Duration
|
|
RequestID int
|
|
Method string
|
|
RequestBody string
|
|
Err error
|
|
}
|
|
type RequestGenerator struct {
|
|
reqID int
|
|
client *http.Client
|
|
}
|
|
|
|
func (g *RequestGenerator) blockNumber() string {
|
|
const template = `{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":%d}`
|
|
return fmt.Sprintf(template, g.reqID)
|
|
}
|
|
func (g *RequestGenerator) getBlockByNumber(blockNum int) string {
|
|
const template = `{"jsonrpc":"2.0","method":"eth_getBlockByNumber","params":["0x%x",true],"id":%d}`
|
|
return fmt.Sprintf(template, blockNum, g.reqID)
|
|
}
|
|
|
|
func (g *RequestGenerator) storageRangeAt(hash common.Hash, i int, to *common.Address, nextKey common.Hash) string {
|
|
const template = `{"jsonrpc":"2.0","method":"debug_storageRangeAt","params":["0x%x", %d,"0x%x","0x%x",%d],"id":%d}`
|
|
return fmt.Sprintf(template, hash, i, to, nextKey, 1024, g.reqID)
|
|
}
|
|
|
|
func (g *RequestGenerator) traceTransaction(hash string) string {
|
|
const template = `{"jsonrpc":"2.0","method":"debug_traceTransaction","params":["%s"],"id":%d}`
|
|
return fmt.Sprintf(template, hash, g.reqID)
|
|
}
|
|
|
|
func (g *RequestGenerator) getTransactionReceipt(hash string) string {
|
|
const template = `{"jsonrpc":"2.0","method":"eth_getTransactionReceipt","params":["%s"],"id":%d}`
|
|
return fmt.Sprintf(template, hash, g.reqID)
|
|
}
|
|
|
|
func (g *RequestGenerator) getBalance(miner common.Address, bn int) string {
|
|
const template = `{"jsonrpc":"2.0","method":"eth_getBalance","params":["0x%x", "0x%x"],"id":%d}`
|
|
return fmt.Sprintf(template, miner, bn, g.reqID)
|
|
}
|
|
|
|
func (g *RequestGenerator) getModifiedAccountsByNumber(prevBn int, bn int) string {
|
|
const template = `{"jsonrpc":"2.0","method":"debug_getModifiedAccountsByNumber","params":[%d, %d],"id":%d}`
|
|
return fmt.Sprintf(template, prevBn, bn, g.reqID)
|
|
}
|
|
|
|
func (g *RequestGenerator) getLogs(prevBn int, bn int, account common.Address) string {
|
|
const template = `{"jsonrpc":"2.0","method":"eth_getLogs","params":[{"fromBlock": "0x%x", "toBlock": "0x%x", "address": "0x%x"}],"id":%d}`
|
|
return fmt.Sprintf(template, prevBn, bn, account, g.reqID)
|
|
}
|
|
|
|
func (g *RequestGenerator) accountRange(bn int, page []byte) string {
|
|
const template = `{ "jsonrpc": "2.0", "method": "debug_accountRange", "params": ["0x%x", "%s", %d, true, true, true], "id":%d}`
|
|
encodedKey := base64.StdEncoding.EncodeToString(page)
|
|
return fmt.Sprintf(template, bn, encodedKey, 256, g.reqID)
|
|
}
|
|
|
|
func (g *RequestGenerator) call(target string, method, body string, response interface{}) CallResult {
|
|
start := time.Now()
|
|
err := post(g.client, routes[target], body, response)
|
|
return CallResult{
|
|
RequestBody: body,
|
|
Target: target,
|
|
Took: time.Since(start),
|
|
RequestID: g.reqID,
|
|
Method: method,
|
|
Err: err,
|
|
}
|
|
}
|
|
func (g *RequestGenerator) Geth(method, body string, response interface{}) CallResult {
|
|
return g.call(Geth, method, body, response)
|
|
}
|
|
|
|
func (g *RequestGenerator) TurboGeth(method, body string, response interface{}) CallResult {
|
|
return g.call(TurboGeth, method, body, response)
|
|
}
|
|
|
|
// vegetaWrite (to be run as a goroutine) writing results of server calls into several files:
|
|
// results to /$tmp$/turbo_geth_stress_test/results_*.csv
|
|
// vegeta format going to files /$tmp$/turbo_geth_stress_test/vegeta_*.txt
|
|
func vegetaWrite(enabled bool, resultsCh chan CallResult) {
|
|
var err error
|
|
var files map[string]map[string]*os.File
|
|
var vegetaFiles map[string]map[string]*os.File
|
|
if enabled {
|
|
files = map[string]map[string]*os.File{
|
|
Geth: make(map[string]*os.File),
|
|
TurboGeth: make(map[string]*os.File),
|
|
}
|
|
vegetaFiles = map[string]map[string]*os.File{
|
|
Geth: make(map[string]*os.File),
|
|
TurboGeth: make(map[string]*os.File),
|
|
}
|
|
tmpDir := os.TempDir()
|
|
fmt.Printf("tmp dir is: %s\n", tmpDir)
|
|
dir := path.Join(tmpDir, "turbo_geth_stress_test")
|
|
if err = os.MkdirAll(dir, 0770); err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
for _, route := range []string{Geth, TurboGeth} {
|
|
for _, method := range []string{"eth_getBlockByNumber", "debug_storageRangeAt"} {
|
|
file := path.Join(dir, "results_"+route+"_"+method+".csv")
|
|
files[route][method], err = os.OpenFile(file, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
for _, route := range []string{Geth, TurboGeth} {
|
|
for _, method := range []string{"eth_getBlockByNumber", "debug_storageRangeAt"} {
|
|
file := path.Join(dir, "vegeta_"+route+"_"+method+".txt")
|
|
vegetaFiles[route][method], err = os.OpenFile(file, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for res := range resultsCh {
|
|
// If not enabled, simply keep draining the results channel
|
|
if enabled {
|
|
if res.Err != nil {
|
|
fmt.Printf("error response. target: %s, err: %s\n", res.Target, res.Err)
|
|
}
|
|
// files with call stats
|
|
if f, ok := files[res.Target][res.Method]; ok {
|
|
row := fmt.Sprintf("%d, %s, %d\n", res.RequestID, res.Method, res.Took.Microseconds())
|
|
if _, err := fmt.Fprint(f, row); err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
// vegeta files, write into all target files
|
|
// because if "needCompare" is false - then we don't have responses from TurboGeth
|
|
// but we still have enough information to build vegeta file for TurboGeth
|
|
for _, target := range []string{Geth, TurboGeth} {
|
|
if f, ok := vegetaFiles[target][res.Method]; ok {
|
|
template := `{"method": "POST", "url": "%s", "body": "%s", "header": {"Content-Type": ["application/json"]}}`
|
|
row := fmt.Sprintf(template, routes[target], base64.StdEncoding.EncodeToString([]byte(res.RequestBody)))
|
|
|
|
if _, err := fmt.Fprint(f, row+"\n"); err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// bench1 compares response of TurboGeth with Geth
|
|
// but also can be used for comparing RPCDaemon with Geth
|
|
// parameters:
|
|
// needCompare - if false - doesn't call TurboGeth and doesn't compare responses
|
|
// use false value - to generate vegeta files, it's faster but we can generate vegeta files for Geth and Turbogeth
|
|
// fullTest - if false - then call only methods which RPCDaemon currently supports
|
|
func bench1(needCompare bool, fullTest bool) {
|
|
var client = &http.Client{
|
|
Timeout: time.Second * 600,
|
|
}
|
|
|
|
resultsCh := make(chan CallResult, 1000)
|
|
defer close(resultsCh)
|
|
go vegetaWrite(false, resultsCh)
|
|
|
|
var res CallResult
|
|
reqGen := &RequestGenerator{
|
|
client: client,
|
|
}
|
|
|
|
reqGen.reqID++
|
|
var blockNumber EthBlockNumber
|
|
res = reqGen.TurboGeth("eth_blockNumber", reqGen.blockNumber(), &blockNumber)
|
|
resultsCh <- res
|
|
if res.Err != nil {
|
|
fmt.Printf("Could not get block number: %v\n", res.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
|
|
if lastBlock > 5000000 {
|
|
lastBlock = 5000000
|
|
}
|
|
fmt.Printf("Last block: %d\n", lastBlock)
|
|
accounts := make(map[common.Address]struct{})
|
|
firstBn := 49000
|
|
prevBn := firstBn
|
|
storageCounter := 0
|
|
for bn := firstBn; bn <= int(lastBlock); bn++ {
|
|
reqGen.reqID++
|
|
var b EthBlockByNumber
|
|
res = reqGen.Geth("eth_getBlockByNumber", reqGen.getBlockByNumber(bn), &b)
|
|
resultsCh <- res
|
|
if res.Err != nil {
|
|
fmt.Printf("Could not retrieve block %d: %v\n", bn, res.Err)
|
|
return
|
|
}
|
|
|
|
if b.Error != nil {
|
|
fmt.Printf("Error retrieving block: %d %s\n", b.Error.Code, b.Error.Message)
|
|
}
|
|
|
|
if needCompare {
|
|
var bg EthBlockByNumber
|
|
res = reqGen.TurboGeth("eth_getBlockByNumber", reqGen.getBlockByNumber(bn), &bg)
|
|
if res.Err != nil {
|
|
fmt.Printf("Could not retrieve block g %d: %v\n", bn, res.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
|
|
var sm map[common.Hash]storageEntry
|
|
var smGeth map[common.Hash]storageEntry
|
|
nextKey := &common.Hash{}
|
|
nextKeyGeth := &common.Hash{}
|
|
var sr DebugStorageRange
|
|
var srGeth DebugStorageRange
|
|
counter := 16
|
|
for nextKey != nil && counter > 0 {
|
|
sm = make(map[common.Hash]storageEntry)
|
|
smGeth = make(map[common.Hash]storageEntry)
|
|
reqGen.reqID++
|
|
res = reqGen.TurboGeth("debug_storageRangeAt", reqGen.storageRangeAt(b.Result.Hash, i, tx.To, *nextKey), &sr)
|
|
resultsCh <- res
|
|
if res.Err != nil {
|
|
fmt.Printf("Could not get storageRange: %s: %v\n", tx.Hash, res.Err)
|
|
break
|
|
}
|
|
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
|
|
}
|
|
}
|
|
res = reqGen.Geth("debug_storageRangeAt", reqGen.storageRangeAt(b.Result.Hash, i, tx.To, *nextKeyGeth), &srGeth)
|
|
resultsCh <- res
|
|
if res.Err != nil {
|
|
fmt.Printf("Could not get storageRange geth: %s: %v\n", tx.Hash, res.Err)
|
|
break
|
|
}
|
|
if srGeth.Error != nil {
|
|
fmt.Printf("Error getting storageRange geth: %d %s\n", srGeth.Error.Code, srGeth.Error.Message)
|
|
break
|
|
} else {
|
|
nextKeyGeth = srGeth.Result.NextKey
|
|
for k, v := range srGeth.Result.Storage {
|
|
smGeth[k] = v
|
|
}
|
|
}
|
|
if nextKey != nil && nextKeyGeth != nil && *nextKey != *nextKeyGeth {
|
|
fmt.Printf("Non matching nextKey %x %x\n", *nextKey, *nextKeyGeth)
|
|
fmt.Printf("len(sm) %d, len(smg) %d\n", len(sm), len(smGeth))
|
|
fmt.Printf("================sm\n")
|
|
printStorageRange(sm)
|
|
fmt.Printf("================smg\n")
|
|
printStorageRange(smGeth)
|
|
return
|
|
}
|
|
if !compareStorageRanges(sm, smGeth) {
|
|
fmt.Printf("len(sm) %d, len(smGeth) %d\n", len(sm), len(smGeth))
|
|
fmt.Printf("================sm\n")
|
|
printStorageRange(sm)
|
|
fmt.Printf("================smg\n")
|
|
printStorageRange(smGeth)
|
|
return
|
|
}
|
|
counter--
|
|
}
|
|
}
|
|
}
|
|
|
|
if !fullTest {
|
|
continue // TODO: remove me
|
|
}
|
|
|
|
reqGen.reqID++
|
|
|
|
var trace EthTxTrace
|
|
res = reqGen.Geth("debug_traceTransaction", reqGen.traceTransaction(tx.Hash), &trace)
|
|
resultsCh <- res
|
|
if res.Err != nil {
|
|
fmt.Printf("Could not trace transaction %s: %v\n", tx.Hash, res.Err)
|
|
print(client, routes[Geth], reqGen.traceTransaction(tx.Hash))
|
|
}
|
|
|
|
if trace.Error != nil {
|
|
fmt.Printf("Error tracing transaction: %d %s\n", trace.Error.Code, trace.Error.Message)
|
|
}
|
|
|
|
if needCompare {
|
|
var traceg EthTxTrace
|
|
res = reqGen.TurboGeth("debug_traceTransaction", reqGen.traceTransaction(tx.Hash), &traceg)
|
|
resultsCh <- res
|
|
if res.Err != nil {
|
|
fmt.Printf("Could not trace transaction g %s: %v\n", tx.Hash, res.Err)
|
|
print(client, routes[TurboGeth], reqGen.traceTransaction(tx.Hash))
|
|
return
|
|
}
|
|
if traceg.Error != nil {
|
|
fmt.Printf("Error tracing transaction g: %d %s\n", traceg.Error.Code, traceg.Error.Message)
|
|
return
|
|
}
|
|
if res.Err == nil && trace.Error == nil {
|
|
if !compareTraces(&trace, &traceg) {
|
|
fmt.Printf("Different traces block %d, tx %s\n", bn, tx.Hash)
|
|
return
|
|
}
|
|
}
|
|
}
|
|
reqGen.reqID++
|
|
|
|
var receipt EthReceipt
|
|
res = reqGen.Geth("eth_getTransactionReceipt", reqGen.getTransactionReceipt(tx.Hash), &receipt)
|
|
resultsCh <- res
|
|
if res.Err != nil {
|
|
fmt.Printf("Count not get receipt: %s: %v\n", tx.Hash, res.Err)
|
|
print(client, routes[Geth], reqGen.getTransactionReceipt(tx.Hash))
|
|
return
|
|
}
|
|
if receipt.Error != nil {
|
|
fmt.Printf("Error getting receipt: %d %s\n", receipt.Error.Code, receipt.Error.Message)
|
|
return
|
|
}
|
|
if needCompare {
|
|
var receiptg EthReceipt
|
|
res = reqGen.TurboGeth("eth_getTransactionReceipt", reqGen.getTransactionReceipt(tx.Hash), &receiptg)
|
|
resultsCh <- res
|
|
if res.Err != nil {
|
|
fmt.Printf("Count not get receipt g: %s: %v\n", tx.Hash, res.Err)
|
|
print(client, routes[TurboGeth], reqGen.getTransactionReceipt(tx.Hash))
|
|
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, routes[Geth], reqGen.getTransactionReceipt(tx.Hash))
|
|
print(client, routes[TurboGeth], reqGen.getTransactionReceipt(tx.Hash))
|
|
return
|
|
}
|
|
}
|
|
}
|
|
reqGen.reqID++
|
|
|
|
var balance EthBalance
|
|
res = reqGen.Geth("eth_getBalance", reqGen.getBalance(b.Result.Miner, bn), &balance)
|
|
resultsCh <- res
|
|
if res.Err != nil {
|
|
fmt.Printf("Could not get account balance: %v\n", res.Err)
|
|
return
|
|
}
|
|
if balance.Error != nil {
|
|
fmt.Printf("Error getting account balance: %d %s", balance.Error.Code, balance.Error.Message)
|
|
return
|
|
}
|
|
if needCompare {
|
|
var balanceg EthBalance
|
|
res = reqGen.TurboGeth("eth_getBalance", reqGen.getBalance(b.Result.Miner, bn), &balanceg)
|
|
resultsCh <- res
|
|
if res.Err != nil {
|
|
fmt.Printf("Could not get account balance g: %v\n", res.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
|
|
reqGen.reqID++
|
|
var mag DebugModifiedAccounts
|
|
res = reqGen.TurboGeth("debug_getModifiedAccountsByNumber", reqGen.getModifiedAccountsByNumber(prevBn, bn), &mag)
|
|
resultsCh <- res
|
|
if res.Err != nil {
|
|
fmt.Printf("Could not get modified accounts g: %v\n", res.Err)
|
|
return
|
|
}
|
|
if mag.Error != nil {
|
|
fmt.Printf("Error getting modified accounts g: %d %s\n", mag.Error.Code, mag.Error.Message)
|
|
return
|
|
}
|
|
if res.Err == nil && mag.Error == nil {
|
|
accountSet := extractAccountMap(&mag)
|
|
for account := range accountSet {
|
|
reqGen.reqID++
|
|
var logs EthLogs
|
|
res = reqGen.Geth("eth_getLogs", reqGen.getLogs(prevBn, bn, account), &logs)
|
|
resultsCh <- res
|
|
if res.Err != nil {
|
|
fmt.Printf("Could not get logs for account %x: %v\n", account, res.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
|
|
res = reqGen.TurboGeth("eth_getLogs", reqGen.getLogs(prevBn, bn, account), &logsg)
|
|
resultsCh <- res
|
|
if res.Err != nil {
|
|
fmt.Printf("Could not get logs for account g %x: %v\n", account, res.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\n", prevBn, bn, len(mag.Result))
|
|
|
|
page := common.Hash{}.Bytes()
|
|
pageGeth := common.Hash{}.Bytes()
|
|
|
|
var accRangeTG map[common.Address]state.DumpAccount
|
|
var accRangeGeth map[common.Address]state.DumpAccount
|
|
|
|
for len(page) > 0 {
|
|
accRangeTG = make(map[common.Address]state.DumpAccount)
|
|
accRangeGeth = make(map[common.Address]state.DumpAccount)
|
|
var sr DebugAccountRange
|
|
reqGen.reqID++
|
|
res = reqGen.TurboGeth("debug_accountRange", reqGen.accountRange(bn, page), &sr)
|
|
resultsCh <- res
|
|
|
|
if res.Err != nil {
|
|
fmt.Printf("Could not get accountRange: %v\n", res.Err)
|
|
return
|
|
}
|
|
|
|
if sr.Error != nil {
|
|
fmt.Printf("Error getting accountRange: %d %s\n", sr.Error.Code, sr.Error.Message)
|
|
break
|
|
} else {
|
|
page = sr.Result.Next
|
|
for k, v := range sr.Result.Accounts {
|
|
accRangeTG[k] = v
|
|
}
|
|
}
|
|
var srGeth DebugAccountRange
|
|
res = reqGen.Geth("debug_accountRange", reqGen.accountRange(bn, pageGeth), &srGeth)
|
|
resultsCh <- res
|
|
if res.Err != nil {
|
|
fmt.Printf("Could not get accountRange geth: %v\n", res.Err)
|
|
return
|
|
}
|
|
if srGeth.Error != nil {
|
|
fmt.Printf("Error getting accountRange geth: %d %s\n", srGeth.Error.Code, srGeth.Error.Message)
|
|
break
|
|
} else {
|
|
pageGeth = srGeth.Result.Next
|
|
for k, v := range srGeth.Result.Accounts {
|
|
accRangeGeth[k] = v
|
|
}
|
|
}
|
|
if !bytes.Equal(page, pageGeth) {
|
|
fmt.Printf("Different next page keys: %x geth %x", page, pageGeth)
|
|
}
|
|
if !compareAccountRanges(accRangeTG, accRangeGeth) {
|
|
fmt.Printf("Different in account ranges tx\n")
|
|
return
|
|
}
|
|
}
|
|
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
|
|
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
|
|
|
|
pageSize := 256
|
|
req_id++
|
|
template := `{ "jsonrpc": "2.0", "method": "debug_accountRange", "params": ["0x1", "%s", %d, true, true, true], "id":%d}`
|
|
|
|
page := common.Hash{}.Bytes()
|
|
|
|
accRangeTG := make(map[common.Address]state.DumpAccount)
|
|
|
|
for len(page) > 0 {
|
|
encodedKey := base64.StdEncoding.EncodeToString(page)
|
|
var sr DebugAccountRange
|
|
if err := post(client, turbogeth_url, fmt.Sprintf(template, encodedKey, pageSize, req_id), &sr); err != nil {
|
|
fmt.Printf("Could not get accountRange: %v\n", err)
|
|
return
|
|
}
|
|
if sr.Error != nil {
|
|
fmt.Printf("Error getting accountRange: %d %s\n", sr.Error.Code, sr.Error.Message)
|
|
break
|
|
} else {
|
|
page = sr.Result.Next
|
|
for k, v := range sr.Result.Accounts {
|
|
accRangeTG[k] = v
|
|
}
|
|
}
|
|
}
|
|
|
|
accRangeGeth := make(map[common.Address]state.DumpAccount)
|
|
|
|
page = common.Hash{}.Bytes()
|
|
for len(page) > 0 {
|
|
encodedKey := base64.StdEncoding.EncodeToString(page)
|
|
var sr DebugAccountRange
|
|
if err := post(client, geth_url, fmt.Sprintf(template, encodedKey, pageSize, req_id), &sr); err != nil {
|
|
|
|
fmt.Printf("Could not get accountRange: %v\n", err)
|
|
return
|
|
}
|
|
if sr.Error != nil {
|
|
fmt.Printf("Error getting accountRange: %d %s\n", sr.Error.Code, sr.Error.Message)
|
|
break
|
|
} else {
|
|
page = sr.Result.Next
|
|
for k, v := range sr.Result.Accounts {
|
|
accRangeTG[k] = v
|
|
}
|
|
}
|
|
}
|
|
|
|
if !compareAccountRanges(accRangeTG, accRangeGeth) {
|
|
fmt.Printf("Different in account ranges tx\n")
|
|
return
|
|
}
|
|
fmt.Println("debug_accountRanges... OK!")
|
|
|
|
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 compareAccountRanges(tg, geth map[common.Address]state.DumpAccount) bool {
|
|
allAddresses := make(map[common.Address]struct{})
|
|
for k := range tg {
|
|
allAddresses[k] = struct{}{}
|
|
}
|
|
|
|
for k := range geth {
|
|
allAddresses[k] = struct{}{}
|
|
}
|
|
|
|
for addr := range allAddresses {
|
|
tgAcc, tgOk := tg[addr]
|
|
if !tgOk {
|
|
fmt.Printf("missing account in TurboGeth %x\n", addr)
|
|
return false
|
|
}
|
|
|
|
gethAcc, gethOk := geth[addr]
|
|
if !gethOk {
|
|
fmt.Printf("missing account in Geth %x\n", addr)
|
|
return false
|
|
}
|
|
different := false
|
|
if tgAcc.Balance != gethAcc.Balance {
|
|
fmt.Printf("Different balance for %x: turbo %s, geth %s\n", addr, tgAcc.Balance, gethAcc.Balance)
|
|
different = true
|
|
}
|
|
if tgAcc.Nonce != gethAcc.Nonce {
|
|
fmt.Printf("Different nonce for %x: turbo %d, geth %d\n", addr, tgAcc.Nonce, gethAcc.Nonce)
|
|
different = true
|
|
}
|
|
// We do not compare Root, because Turbo-geth does not compute it
|
|
if tgAcc.CodeHash != gethAcc.CodeHash {
|
|
fmt.Printf("Different codehash for %x: turbo %s, geth %s\n", addr, tgAcc.CodeHash, gethAcc.CodeHash)
|
|
different = true
|
|
}
|
|
if tgAcc.Code != gethAcc.Code {
|
|
fmt.Printf("Different codehash for %x: turbo %s, geth %s\n", addr, tgAcc.Code, gethAcc.Code)
|
|
different = true
|
|
}
|
|
if different {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
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,
|
|
}
|
|
turbogethURL := routes[TurboGeth]
|
|
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, turbogethURL, 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
|
|
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 bench7() {
|
|
var client = &http.Client{
|
|
Timeout: time.Second * 600,
|
|
}
|
|
turbogethURL := routes[TurboGeth]
|
|
gethURL := routes[Geth]
|
|
blockhash := common.HexToHash("0xdd3eb495312b11621669be45a2d50f8a66f2616bc72a610e2cbf1aebf9e4a9aa")
|
|
reqID := 1
|
|
to := common.HexToAddress("0xbb9bc244d798123fde783fcc1c72d3bb8c189413")
|
|
var sm map[common.Hash]storageEntry
|
|
var smg map[common.Hash]storageEntry
|
|
start := common.HexToHash("0x4a17477338cba00d8a94336ef62ea15f68e77ad0ca738fa405daa13bf0874134")
|
|
|
|
reqID++
|
|
template := `
|
|
{"jsonrpc":"2.0","method":"debug_storageRangeAt","params":["0x%x", %d,"0x%x","0x%x",%d],"id":%d}
|
|
`
|
|
i := 0
|
|
nextKey := &start
|
|
nextKeyG := &start
|
|
for nextKey != nil {
|
|
sm = make(map[common.Hash]storageEntry)
|
|
smg = make(map[common.Hash]storageEntry)
|
|
var sr DebugStorageRange
|
|
if err := post(client, turbogethURL, fmt.Sprintf(template, blockhash, i, to, *nextKey, 2, reqID), &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
|
|
if v.Key == nil {
|
|
fmt.Printf("%x: %x", k, v)
|
|
}
|
|
}
|
|
}
|
|
var srg DebugStorageRange
|
|
if err := post(client, gethURL, fmt.Sprintf(template, blockhash, i, to, *nextKeyG, 2, reqID), &srg); err != nil {
|
|
fmt.Printf("Could not get storageRange: %v\n", err)
|
|
return
|
|
}
|
|
if srg.Error != nil {
|
|
fmt.Printf("Error getting storageRange: %d %s\n", sr.Error.Code, sr.Error.Message)
|
|
break
|
|
} else {
|
|
for k, v := range srg.Result.Storage {
|
|
smg[k] = v
|
|
if v.Key == nil {
|
|
fmt.Printf("%x: %x", k, v)
|
|
}
|
|
}
|
|
nextKeyG = srg.Result.NextKey
|
|
if *nextKey != *nextKeyG {
|
|
fmt.Printf("Non matching nextKey %x %x\n", *nextKey, *nextKeyG)
|
|
fmt.Printf("len(sm) %d, len(smg) %d\n", len(sm), len(smg))
|
|
fmt.Printf("================sm\n")
|
|
printStorageRange(sm)
|
|
fmt.Printf("================smg\n")
|
|
printStorageRange(smg)
|
|
return
|
|
}
|
|
}
|
|
if !compareStorageRanges(sm, smg) {
|
|
fmt.Printf("len(sm) %d, len(smg) %d\n", len(sm), len(smg))
|
|
fmt.Printf("================sm\n")
|
|
printStorageRange(sm)
|
|
fmt.Printf("================smg\n")
|
|
printStorageRange(smg)
|
|
return
|
|
}
|
|
}
|
|
fmt.Printf("storageRange: %d\n", len(sm))
|
|
}
|
|
|
|
func bench8() {
|
|
var client = &http.Client{
|
|
Timeout: time.Second * 600,
|
|
}
|
|
turbogethURL := "http://localhost:8545"
|
|
reqID := 1
|
|
to := common.HexToAddress("0x9653c9859b18f8777fe4eec9a67c9f64f3d6f62a")
|
|
|
|
reqID++
|
|
template := `{"jsonrpc":"2.0","method":"eth_getLogs","params":[{"fromBlock": "0x%x", "toBlock": "0x%x", "address": "0x%x"}],"id":%d}`
|
|
var logs EthLogs
|
|
if err := post(client, turbogethURL, fmt.Sprintf(template, 49000, 49100, to, reqID), &logs); err != nil {
|
|
fmt.Printf("Could not get eth_getLogs: %v\n", err)
|
|
return
|
|
}
|
|
if logs.Error != nil {
|
|
fmt.Printf("Error getting eth_getLogs: %d %s\n", logs.Error.Code, logs.Error.Message)
|
|
}
|
|
}
|
|
|
|
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()
|
|
switch *action {
|
|
case "proofs":
|
|
proofs(*chaindata, *url, *block)
|
|
case "fixState":
|
|
fixState(*chaindata, *url)
|
|
case "bench1":
|
|
bench1(true, true)
|
|
case "bench3":
|
|
bench3()
|
|
case "bench7":
|
|
bench7()
|
|
case "bench8":
|
|
bench8()
|
|
}
|
|
}
|