-
Notifications
You must be signed in to change notification settings - Fork 0
/
client.go
230 lines (202 loc) · 7.88 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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package evm
import (
"context"
"fmt"
"github.com/ethereum/go-ethereum/log"
"github.com/coinflect/coinflectchain/api"
"github.com/coinflect/coinflectchain/ids"
"github.com/coinflect/coinflectchain/utils/crypto"
"github.com/coinflect/coinflectchain/utils/formatting"
"github.com/coinflect/coinflectchain/utils/rpc"
cjson "github.com/coinflect/coinflectchain/utils/json"
)
// Interface compliance
var _ Client = (*client)(nil)
// Client interface for interacting with EVM [chain]
type Client interface {
IssueTx(ctx context.Context, txBytes []byte) (ids.ID, error)
GetAtomicTxStatus(ctx context.Context, txID ids.ID) (Status, error)
GetAtomicTx(ctx context.Context, txID ids.ID) ([]byte, error)
GetAtomicUTXOs(ctx context.Context, addrs []string, sourceChain string, limit uint32, startAddress, startUTXOID string) ([][]byte, api.Index, error)
ListAddresses(ctx context.Context, userPass api.UserPass) ([]string, error)
ExportKey(ctx context.Context, userPass api.UserPass, addr string) (*crypto.PrivateKeySECP256K1R, string, error)
ImportKey(ctx context.Context, userPass api.UserPass, privateKey *crypto.PrivateKeySECP256K1R) (string, error)
Import(ctx context.Context, userPass api.UserPass, to string, sourceChain string) (ids.ID, error)
ExportCFLT(ctx context.Context, userPass api.UserPass, amount uint64, to string) (ids.ID, error)
Export(ctx context.Context, userPass api.UserPass, amount uint64, to string, assetID string) (ids.ID, error)
StartCPUProfiler(ctx context.Context) error
StopCPUProfiler(ctx context.Context) error
MemoryProfile(ctx context.Context) error
LockProfile(ctx context.Context) error
SetLogLevel(ctx context.Context, level log.Lvl) error
GetVMConfig(ctx context.Context) (*Config, error)
}
// Client implementation for interacting with EVM [chain]
type client struct {
requester rpc.EndpointRequester
adminRequester rpc.EndpointRequester
}
// NewClient returns a Client for interacting with EVM [chain]
func NewClient(uri, chain string) Client {
return &client{
requester: rpc.NewEndpointRequester(fmt.Sprintf("%s/ext/bc/%s/cflt", uri, chain)),
adminRequester: rpc.NewEndpointRequester(fmt.Sprintf("%s/ext/bc/%s/admin", uri, chain)),
}
}
// NewCChainClient returns a Client for interacting with the C Chain
func NewCChainClient(uri string) Client {
return NewClient(uri, "C")
}
// IssueTx issues a transaction to a node and returns the TxID
func (c *client) IssueTx(ctx context.Context, txBytes []byte) (ids.ID, error) {
res := &api.JSONTxID{}
txStr, err := formatting.Encode(formatting.Hex, txBytes)
if err != nil {
return res.TxID, fmt.Errorf("problem hex encoding bytes: %w", err)
}
err = c.requester.SendRequest(ctx, "cflt.issueTx", &api.FormattedTx{
Tx: txStr,
Encoding: formatting.Hex,
}, res)
return res.TxID, err
}
// GetAtomicTxStatus returns the status of [txID]
func (c *client) GetAtomicTxStatus(ctx context.Context, txID ids.ID) (Status, error) {
res := &GetAtomicTxStatusReply{}
err := c.requester.SendRequest(ctx, "cflt.getAtomicTxStatus", &api.JSONTxID{
TxID: txID,
}, res)
return res.Status, err
}
// GetAtomicTx returns the byte representation of [txID]
func (c *client) GetAtomicTx(ctx context.Context, txID ids.ID) ([]byte, error) {
res := &api.FormattedTx{}
err := c.requester.SendRequest(ctx, "cflt.getAtomicTx", &api.GetTxArgs{
TxID: txID,
Encoding: formatting.Hex,
}, res)
if err != nil {
return nil, err
}
return formatting.Decode(formatting.Hex, res.Tx)
}
// GetAtomicUTXOs returns the byte representation of the atomic UTXOs controlled by [addresses]
// from [sourceChain]
func (c *client) GetAtomicUTXOs(ctx context.Context, addrs []string, sourceChain string, limit uint32, startAddress, startUTXOID string) ([][]byte, api.Index, error) {
res := &api.GetUTXOsReply{}
err := c.requester.SendRequest(ctx, "cflt.getUTXOs", &api.GetUTXOsArgs{
Addresses: addrs,
SourceChain: sourceChain,
Limit: cjson.Uint32(limit),
StartIndex: api.Index{
Address: startAddress,
UTXO: startUTXOID,
},
Encoding: formatting.Hex,
}, res)
if err != nil {
return nil, api.Index{}, err
}
utxos := make([][]byte, len(res.UTXOs))
for i, utxo := range res.UTXOs {
b, err := formatting.Decode(formatting.Hex, utxo)
if err != nil {
return nil, api.Index{}, err
}
utxos[i] = b
}
return utxos, res.EndIndex, nil
}
// ListAddresses returns all addresses on this chain controlled by [user]
func (c *client) ListAddresses(ctx context.Context, user api.UserPass) ([]string, error) {
res := &api.JSONAddresses{}
err := c.requester.SendRequest(ctx, "cflt.listAddresses", &user, res)
return res.Addresses, err
}
// ExportKey returns the private key corresponding to [addr] controlled by [user]
// in both Coinflect standard format and hex format
func (c *client) ExportKey(ctx context.Context, user api.UserPass, addr string) (*crypto.PrivateKeySECP256K1R, string, error) {
res := &ExportKeyReply{}
err := c.requester.SendRequest(ctx, "cflt.exportKey", &ExportKeyArgs{
UserPass: user,
Address: addr,
}, res)
return res.PrivateKey, res.PrivateKeyHex, err
}
// ImportKey imports [privateKey] to [user]
func (c *client) ImportKey(ctx context.Context, user api.UserPass, privateKey *crypto.PrivateKeySECP256K1R) (string, error) {
res := &api.JSONAddress{}
err := c.requester.SendRequest(ctx, "cflt.importKey", &ImportKeyArgs{
UserPass: user,
PrivateKey: privateKey,
}, res)
return res.Address, err
}
// Import sends an import transaction to import funds from [sourceChain] and
// returns the ID of the newly created transaction
func (c *client) Import(ctx context.Context, user api.UserPass, to, sourceChain string) (ids.ID, error) {
res := &api.JSONTxID{}
err := c.requester.SendRequest(ctx, "cflt.import", &ImportArgs{
UserPass: user,
To: to,
SourceChain: sourceChain,
}, res)
return res.TxID, err
}
// ExportCFLT sends CFLT from this chain to the address specified by [to].
// Returns the ID of the newly created atomic transaction
func (c *client) ExportCFLT(
ctx context.Context,
user api.UserPass,
amount uint64,
to string,
) (ids.ID, error) {
return c.Export(ctx, user, amount, to, "CFLT")
}
// Export sends an asset from this chain to the P/C-Chain.
// After this tx is accepted, the CFLT must be imported to the P/C-chain with an importTx.
// Returns the ID of the newly created atomic transaction
func (c *client) Export(
ctx context.Context,
user api.UserPass,
amount uint64,
to string,
assetID string,
) (ids.ID, error) {
res := &api.JSONTxID{}
err := c.requester.SendRequest(ctx, "cflt.export", &ExportArgs{
ExportCFLTArgs: ExportCFLTArgs{
UserPass: user,
Amount: cjson.Uint64(amount),
To: to,
},
AssetID: assetID,
}, res)
return res.TxID, err
}
func (c *client) StartCPUProfiler(ctx context.Context) error {
return c.adminRequester.SendRequest(ctx, "admin.startCPUProfiler", struct{}{}, &api.EmptyReply{})
}
func (c *client) StopCPUProfiler(ctx context.Context) error {
return c.adminRequester.SendRequest(ctx, "admin.stopCPUProfiler", struct{}{}, &api.EmptyReply{})
}
func (c *client) MemoryProfile(ctx context.Context) error {
return c.adminRequester.SendRequest(ctx, "admin.memoryProfile", struct{}{}, &api.EmptyReply{})
}
func (c *client) LockProfile(ctx context.Context) error {
return c.adminRequester.SendRequest(ctx, "admin.lockProfile", struct{}{}, &api.EmptyReply{})
}
// SetLogLevel dynamically sets the log level for the C Chain
func (c *client) SetLogLevel(ctx context.Context, level log.Lvl) error {
return c.adminRequester.SendRequest(ctx, "admin.setLogLevel", &SetLogLevelArgs{
Level: level.String(),
}, &api.EmptyReply{})
}
// GetVMConfig returns the current config of the VM
func (c *client) GetVMConfig(ctx context.Context) (*Config, error) {
res := &ConfigReply{}
err := c.adminRequester.SendRequest(ctx, "admin.getVMConfig", struct{}{}, res)
return res.Config, err
}