-
Notifications
You must be signed in to change notification settings - Fork 0
/
testEndpoints.go
149 lines (127 loc) · 3.87 KB
/
testEndpoints.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
package ethereum
import (
"context"
"fmt"
"log"
"math/big"
"os"
"sort"
"sync"
"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/spf13/cobra"
"go.uber.org/zap"
)
type TestEndpointsArgs struct {
*EthereumArgs
URLs []string
Repeat uint16
}
var testEndpointsArgs TestEndpointsArgs
var testEndpointsCmd = &cobra.Command{
Use: "test-endpoints",
Short: "Test Ethereum RPC endpoints",
Long: `Test Ethereum RPC endpoints`,
Run: func(cmd *cobra.Command, args []string) {
if err := RunTestEndpoints(testEndpointsArgs); err != nil {
testEndpointsArgs.Logger.Error("Error", zap.Error(err))
os.Exit(1)
}
},
}
func init() {
testEndpointsArgs.EthereumArgs = ðereumArgs
EthereumCmd.AddCommand(testEndpointsCmd)
testEndpointsCmd.PersistentFlags().StringSliceVar(&testEndpointsArgs.URLs, "rpc", nil, "Comma separated list of Ethereum RPC endpoints")
if err := testEndpointsCmd.MarkPersistentFlagRequired("rpc"); err != nil {
log.Fatalf("%v\n", err)
}
testEndpointsCmd.PersistentFlags().Uint16Var(&testEndpointsArgs.Repeat, "repeat", 1, "Repeat multiple times.")
}
func RunTestEndpoints(args TestEndpointsArgs) error {
var err error
endpoints := make([]RPCEndpoint, len(args.URLs))
for i, url := range args.URLs {
endpoints[i].URL = url
endpoints[i].Client, err = ethclient.Dial(url)
if err != nil {
return fmt.Errorf("Failed to connect to %s: %w", url, err)
}
}
for i := uint16(1); i <= args.Repeat; i++ {
GetLatestBlockBenchmark(endpoints)
SubscribeToEvents(endpoints)
}
return nil
}
type RPCEndpoint struct {
URL string
Client *ethclient.Client
}
type LatestBlockResult struct {
Endpoint RPCEndpoint
Block string
}
func GetLatestBlockBenchmark(endpoints []RPCEndpoint) {
var wg sync.WaitGroup
results := make(chan LatestBlockResult, len(endpoints))
for _, endpoint := range endpoints {
wg.Add(1)
go func(endpoint RPCEndpoint, wg *sync.WaitGroup, results chan LatestBlockResult) {
defer wg.Done()
header, err := endpoint.Client.HeaderByNumber(context.Background(), nil)
if err != nil {
log.Fatalf("Failed to get header for url %s, %s", endpoint.URL, err)
}
block := header.Number.String()
results <- LatestBlockResult{
Endpoint: endpoint,
Block: block,
}
}(endpoint, &wg, results)
}
wg.Wait()
close(results)
fmt.Print("Results:\n")
for res := range results {
fmt.Printf("- %s: %s\n", res.Endpoint.URL, res.Block)
}
}
func SubscribeToEvents(endpoints []RPCEndpoint) {
var wg sync.WaitGroup
usdcContractAddress := common.HexToAddress("0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48")
currentBlock, err := endpoints[0].Client.BlockNumber(context.Background())
if err != nil {
log.Fatalf("Failed to get block height for %s: %s", endpoints[0].URL, err)
}
usdcQuery := ethereum.FilterQuery{
Addresses: []common.Address{usdcContractAddress},
FromBlock: big.NewInt(int64(currentBlock - 10)),
}
fmt.Printf("Get events from block %d for USDC: %s\n", currentBlock-10, usdcContractAddress)
for _, endpoint := range endpoints {
wg.Add(1)
go func(endpoint RPCEndpoint) {
defer wg.Done()
logs, err := endpoint.Client.FilterLogs(context.Background(), usdcQuery)
if err != nil {
log.Fatalf("Failed on %s: %s", endpoint.URL, err)
}
evtNoPerBlock := make(map[uint64]int)
for _, vLog := range logs {
evtNoPerBlock[vLog.BlockNumber] += 1
//fmt.Printf("%s: %s: %s\n", time.Now().Format(time.RFC850), endpoint.URL, vLog.TxHash)
}
sortedBlocks := make([]uint64, 0, len(evtNoPerBlock))
for block := range evtNoPerBlock {
sortedBlocks = append(sortedBlocks, block)
}
sort.Slice(sortedBlocks, func(i, j int) bool { return sortedBlocks[i] < sortedBlocks[j] })
for _, block := range sortedBlocks {
fmt.Printf("%s [%d]: %d\n", endpoint.URL, block, evtNoPerBlock[block])
}
}(endpoint)
}
wg.Wait()
}