164 lines
4.2 KiB
Go
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)
|
|
}
|