blockbook/bchain/coins/avalanche/avalancherpc.go
2025-01-18 18:50:07 +01:00

164 lines
4.2 KiB
Go

package avalanche
import (
"context"
"encoding/json"
"fmt"
"net/url"
jsontypes "github.com/ava-labs/avalanchego/utils/json"
"github.com/ava-labs/coreth/core/types"
"github.com/ava-labs/coreth/ethclient"
"github.com/ava-labs/coreth/interfaces"
"github.com/ava-labs/coreth/rpc"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/golang/glog"
"github.com/juju/errors"
"github.com/trezor/blockbook/bchain"
"github.com/trezor/blockbook/bchain/coins/eth"
)
const (
// MainNet is production network
MainNet eth.Network = 43114
)
// AvalancheRPC is an interface to JSON-RPC avalanche service.
type AvalancheRPC struct {
*eth.EthereumRPC
info *rpc.Client
}
// NewAvalancheRPC returns new AvalancheRPC instance.
func NewAvalancheRPC(config json.RawMessage, pushHandler func(bchain.NotificationType)) (bchain.BlockChain, error) {
c, err := eth.NewEthereumRPC(config, pushHandler)
if err != nil {
return nil, err
}
s := &AvalancheRPC{
EthereumRPC: c.(*eth.EthereumRPC),
}
return s, nil
}
// Initialize avalanche rpc interface
func (b *AvalancheRPC) Initialize() error {
b.OpenRPC = func(url string) (bchain.EVMRPCClient, bchain.EVMClient, error) {
r, err := rpc.Dial(url)
if err != nil {
return nil, nil, err
}
rc := &AvalancheRPCClient{Client: r}
c := &AvalancheClient{Client: ethclient.NewClient(r)}
return rc, c, nil
}
rpcClient, client, err := b.OpenRPC(b.ChainConfig.RPCURL)
if err != nil {
return err
}
rpcUrl, err := url.Parse(b.ChainConfig.RPCURL)
if err != nil {
return err
}
scheme := "http"
if rpcUrl.Scheme == "wss" || rpcUrl.Scheme == "https" {
scheme = "https"
}
infoClient, err := rpc.DialHTTP(fmt.Sprintf("%s://%s/ext/info", scheme, rpcUrl.Host))
if err != nil {
return err
}
// set chain specific
b.Client = client
b.RPC = rpcClient
b.info = infoClient
b.MainNetChainID = MainNet
b.NewBlock = &AvalancheNewBlock{channel: make(chan *types.Header)}
b.NewTx = &AvalancheNewTx{channel: make(chan common.Hash)}
ctx, cancel := context.WithTimeout(context.Background(), b.Timeout)
defer cancel()
id, err := b.Client.NetworkID(ctx)
if err != nil {
return err
}
// parameters for getInfo request
switch eth.Network(id.Uint64()) {
case MainNet:
b.Testnet = false
b.Network = "livenet"
default:
return errors.Errorf("Unknown network id %v", id)
}
glog.Info("rpc: block chain ", b.Network)
return nil
}
// GetChainInfo returns information about the connected backend
func (b *AvalancheRPC) GetChainInfo() (*bchain.ChainInfo, error) {
ci, err := b.EthereumRPC.GetChainInfo()
if err != nil {
return nil, err
}
ctx, cancel := context.WithTimeout(context.Background(), b.Timeout)
defer cancel()
var v struct {
Version string `json:"version"`
DatabaseVersion string `json:"databaseVersion"`
RPCProtocolVersion jsontypes.Uint32 `json:"rpcProtocolVersion"`
GitCommit string `json:"gitCommit"`
VMVersions map[string]string `json:"vmVersions"`
}
if err := b.info.CallContext(ctx, &v, "info.getNodeVersion"); err != nil {
return nil, err
}
if avm, ok := v.VMVersions["avm"]; ok {
ci.Version = avm
}
return ci, nil
}
// EthereumTypeEstimateGas returns estimation of gas consumption for given transaction parameters
func (b *AvalancheRPC) EthereumTypeEstimateGas(params map[string]interface{}) (uint64, error) {
ctx, cancel := context.WithTimeout(context.Background(), b.Timeout)
defer cancel()
msg := interfaces.CallMsg{}
if s, ok := eth.GetStringFromMap("from", params); ok && len(s) > 0 {
msg.From = common.HexToAddress(s)
}
if s, ok := eth.GetStringFromMap("to", params); ok && len(s) > 0 {
a := common.HexToAddress(s)
msg.To = &a
}
if s, ok := eth.GetStringFromMap("data", params); ok && len(s) > 0 {
msg.Data = common.FromHex(s)
}
if s, ok := eth.GetStringFromMap("value", params); ok && len(s) > 0 {
msg.Value, _ = hexutil.DecodeBig(s)
}
if s, ok := eth.GetStringFromMap("gas", params); ok && len(s) > 0 {
msg.Gas, _ = hexutil.DecodeUint64(s)
}
if s, ok := eth.GetStringFromMap("gasPrice", params); ok && len(s) > 0 {
msg.GasPrice, _ = hexutil.DecodeBig(s)
}
return b.Client.EstimateGas(ctx, msg)
}