-
Notifications
You must be signed in to change notification settings - Fork 4
/
client.go
129 lines (116 loc) · 3.21 KB
/
client.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
package harmony
import (
"context"
"encoding/json"
"errors"
"fmt"
"math/big"
"strconv"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/rpc"
sdkrpc "github.com/harmony-one/go-sdk/pkg/rpc"
v1 "github.com/harmony-one/go-sdk/pkg/rpc/v1"
v2 "github.com/harmony-one/harmony/rpc/v2"
)
const (
MethodGetFullHeader = "hmyv2_getFullHeader"
MethodEpochLastBlock = "hmyv2_epochLastBlock"
MethodGetEpoch = "hmyv2_getEpoch"
MethodCall = "hmyv2_call"
)
type Client struct {
messenger *sdkrpc.HTTPMessenger
}
func NewHarmonyClient(endpoint string) *Client {
messenger := sdkrpc.NewHTTPHandler(endpoint)
return &Client{
messenger: messenger,
}
}
func NewETHClient(endpoint string) (*ethclient.Client, error) {
conn, err := rpc.DialHTTP(endpoint)
if err != nil {
return nil, err
}
return ethclient.NewClient(conn), nil
}
// BlockNumber returns the most recent block number
func (c *Client) BlockNumber(ctx context.Context) (uint64, error) {
invalidRes := uint64(0)
val, err := c.sendRPC(v1.Method.BlockNumber, nil)
if err != nil {
return invalidRes, err
}
bns, ok := val.(string)
if !ok {
return invalidRes, errors.New("could not get the latest block number")
}
return hexutil.DecodeUint64(bns)
}
// FullHeader returns the harmony full header for the given height.
// The complete header can be used to calculate the hash value.
func (c *Client) FullHeader(ctx context.Context, height uint64) (*v2.BlockHeader, error) {
var heightArg string
if height >= 0 {
heightArg = strconv.FormatUint(height, 10)
} else {
heightArg = "latest"
}
val, err := c.sendRPC(MethodGetFullHeader, []interface{}{heightArg})
if err != nil {
return nil, err
}
jsonStr, err := json.Marshal(val)
if err != nil {
return nil, err
}
var header v2.BlockHeader
if err := json.Unmarshal(jsonStr, &header); err != nil {
return nil, err
}
return &header, nil
}
// EpochLastBlockNumber returns the last block number of the given epoch.
// Note that it also returns the block number for a future epoch.
func (c *Client) EpochLastBlockNumber(ctx context.Context, epoch uint64) (uint64, error) {
val, err := c.sendRPC(MethodEpochLastBlock, []interface{}{epoch})
if err != nil {
return 0, err
}
num, ok := val.(float64)
if !ok {
return 0, errors.New("could not get the last block of epoch")
}
bn, _ := big.NewFloat(num).Int(nil)
return bn.Uint64(), nil
}
// if height <= 0, get the latest result
func (chain *Chain) CallOpts(ctx context.Context, height int64) *bind.CallOpts {
account, err := chain.getAccount()
if err != nil {
return &bind.CallOpts{
Context: ctx,
}
}
opts := &bind.CallOpts{
From: account.Address,
Context: ctx,
}
if height > 0 {
opts.BlockNumber = big.NewInt(height)
}
return opts
}
func (c *Client) sendRPC(meth string, params []interface{}) (interface{}, error) {
rep, err := c.messenger.SendRPC(meth, params)
if err != nil {
return nil, fmt.Errorf("rpc %s with params %v failed: %w", meth, params, err)
}
val, ok := rep["result"]
if !ok {
return nil, fmt.Errorf("rpc %s with params %v returns invalid response", meth, params)
}
return val, nil
}