package main
import (
"context"
"fmt"
"time"
"math/big"
"github.com/ava-labs/avalanchego/utils/crypto"
"github.com/ava-labs/avalanchego/utils/formatting"
"github.com/ava-labs/coreth/ethclient"
"github.com/ava-labs/coreth/plugin/evm"
"github.com/ava-labs/coreth"
"github.com/ava-labs/coreth/core/types"
"github.com/ethereum/go-ethereum/common"
)
var (
key = "ewoqjP7PxY4yr3iLTpLisriqt94hdyDFNgchSxGGztUrTXtNN"
prefixedPrivateKey = fmt.Sprintf("PrivateKey-%s", key)
ipAddr = "127.0.0.1"
port = 9650
)
type ethWSAPITestExecutor struct {
uri string
requestTimeout time.Duration
}
// ExecuteTest ...
func (e *ethWSAPITestExecutor) ExecuteTest() error {
client, err := ethclient.Dial(e.uri)
if err != nil {
return fmt.Errorf("Failed to create ethclient: %w", err)
}
fmt.Printf("Created ethclient\n")
ctx := context.Background()
cb58 := formatting.CB58{}
factory := crypto.FactorySECP256K1R{}
_ = cb58.FromString(key)
pk, _ := factory.ToPrivateKey(cb58.Bytes)
secpKey := pk.(*crypto.PrivateKeySECP256K1R)
ethAddr := evm.GetEthAddress(secpKey)
if err := testSubscription(ctx, client); err != nil {
return fmt.Errorf("Subscription Test failed: %w", err)
}
if err := testHeaderAndBlockCalls(ctx, client, ethAddr); err != nil {
return fmt.Errorf("HeaderAndBlockCalls Test failed: %w", err)
}
return nil
}
type ethRPCAPITestExecutor struct {
uri string
requestTimeout time.Duration
}
// ExecuteTest ...
func (e *ethRPCAPITestExecutor) ExecuteTest() error {
client, err := ethclient.Dial(e.uri)
if err != nil {
return fmt.Errorf("Failed to create ethclient: %w", err)
}
fmt.Printf("Created ethclient\n")
ctx := context.Background()
cb58 := formatting.CB58{}
factory := crypto.FactorySECP256K1R{}
_ = cb58.FromString(key)
pk, _ := factory.ToPrivateKey(cb58.Bytes)
secpKey := pk.(*crypto.PrivateKeySECP256K1R)
ethAddr := evm.GetEthAddress(secpKey)
if err := testHeaderAndBlockCalls(ctx, client, ethAddr); err != nil {
return fmt.Errorf("HeaderAndBlockCalls Test failed: %w", err)
}
return nil
}
func testSubscription(ctx context.Context, client *ethclient.Client) error {
headerChan := make(chan *types.Header)
subscription, err := client.SubscribeNewHead(ctx, headerChan)
if err != nil {
return fmt.Errorf("Failed to create subscription: %s", err)
}
fmt.Printf("Created subscription: %s\n", subscription)
suggestedGasPrice, err := client.SuggestGasPrice(ctx)
if err != nil {
return fmt.Errorf("Failed to get suggested gas price: %s", err)
}
fmt.Printf("Suggested gas price: %d\n", suggestedGasPrice.Uint64())
logChan := make(chan types.Log)
query := coreth.FilterQuery{
BlockHash: nil,
FromBlock: nil,
ToBlock: nil,
Addresses: []common.Address{},
Topics: [][]common.Hash{},
}
subscription, err = client.SubscribeFilterLogs(ctx, query, logChan)
if err != nil {
return fmt.Errorf("Failed to create subscription: %s", err)
}
fmt.Printf("Created subscription: %s\n", subscription)
return nil
}
func testHeaderAndBlockCalls(ctx context.Context, client *ethclient.Client, ethAddr common.Address) error {
// Test Header and Block ByNumber work for special cases
for i := 0; i > -3; i-- {
if err := checkHeaderAndBlocks(ctx, client, i, ethAddr); err != nil {
return err
}
}
return nil
}
func checkHeaderAndBlocks(ctx context.Context, client *ethclient.Client, i int, ethAddr common.Address) error {
fmt.Printf("Checking HeaderAndBlocks for i = %d\n", i)
header1, err := client.HeaderByNumber(ctx, big.NewInt(int64(i)))
if err != nil {
return fmt.Errorf("Failed to retrieve HeaderByNumber: %w", err)
}
fmt.Printf("HeaderByNumber (Block Number: %d, Block Hash: %s)\n", header1.Number, header1.Hash().Hex())
originalHash := header1.Hash()
originalBlockNumber := header1.Number
if i >= 0 && int(originalBlockNumber.Int64()) != i {
return fmt.Errorf("Requested block number %d, but found block number %d", i, originalBlockNumber)
}
header2, err := client.HeaderByHash(ctx, header1.Hash())
if err != nil {
return fmt.Errorf("Failed to retrieve HeaderByHash: %w", err)
}
fmt.Printf("HeaderByNumber (Block Number: %d, Block Hash: %s)\n", header2.Number, header2.Hash().Hex())
if originalHash.Hex() != header2.Hash().Hex() {
return fmt.Errorf("Expected HeaderByHash with Hash: %s, but found: %s", originalHash.Hex(), header2.Hash().Hex())
}
if originalBlockNumber.Cmp(header2.Number) != 0 {
return fmt.Errorf("Expected HeaderByHash with Number: %d, but found %d", originalBlockNumber, header2.Number)
}
block1, err := client.BlockByNumber(ctx, big.NewInt(int64(i)))
if err != nil {
return fmt.Errorf("Failed to retrieve BlockByNumber: %w", err)
}
header3 := block1.Header()
fmt.Printf("BlockByNumber (Block Number: %d, Block Hash: %s)\n", header3.Number, header3.Hash().Hex())
if originalHash.Hex() != header3.Hash().Hex() {
return fmt.Errorf("Expected HeaderByHash with Hash: %s, but found: %s", originalHash.Hex(), header3.Hash().Hex())
}
if originalBlockNumber.Cmp(header3.Number) != 0 {
return fmt.Errorf("Expected HeaderByHash with Number: %d, but found %d", originalBlockNumber, header3.Number)
}
block2, err := client.BlockByHash(ctx, header1.Hash())
if err != nil {
return fmt.Errorf("Failed to retrieve BlockByHash: %w", err)
}
header4 := block2.Header()
fmt.Printf("BlockByHash (Block Number: %d, Block Hash: %s)\n", header4.Number, header4.Hash().Hex())
if originalHash.Hex() != header4.Hash().Hex() {
return fmt.Errorf("Expected HeaderByHash with Hash: %s, but found: %s", originalHash.Hex(), header4.Hash().Hex())
}
if originalBlockNumber.Cmp(header4.Number) != 0 {
return fmt.Errorf("Expected HeaderByHash with Number: %d, but found %d", originalBlockNumber, header4.Number)
}
balance, err := client.BalanceAt(ctx, ethAddr, big.NewInt(int64(i)))
if err != nil {
return fmt.Errorf("Failed to get balance: %s", err)
}
fmt.Printf("Balance: %d for address: %s\n", balance, ethAddr.Hex())
return nil
}
func main() {
wsURI := fmt.Sprintf("ws://%s:%d/ext/bc/C/ws", ipAddr, port)
wsTest := ðWSAPITestExecutor{
uri: wsURI,
requestTimeout: 3 * time.Second,
}
if err := wsTest.ExecuteTest(); err != nil {
fmt.Printf("WebSocket Test failed due to %s\n", err)
} else {
fmt.Printf("WebSocket Test succeeded!\n")
}
rpcURI := fmt.Sprintf("http://%s:%d/ext/bc/C/rpc", ipAddr, port)
rpcTest := ðRPCAPITestExecutor{
uri: rpcURI,
requestTimeout: 3 * time.Second,
}
if err := rpcTest.ExecuteTest(); err != nil {
fmt.Printf("RPC Test failed due to %s\n", err)
} else {
fmt.Printf("RPC Test succeeded!\n")
}
}