github.com/dim4egster/coreth@v0.10.2/plugin/evm/client.go (about) 1 // (c) 2019-2020, Ava Labs, Inc. All rights reserved. 2 // See the file LICENSE for licensing terms. 3 4 package evm 5 6 import ( 7 "context" 8 "fmt" 9 10 "github.com/ethereum/go-ethereum/log" 11 12 "github.com/dim4egster/qmallgo/api" 13 "github.com/dim4egster/qmallgo/ids" 14 "github.com/dim4egster/qmallgo/utils/crypto" 15 "github.com/dim4egster/qmallgo/utils/formatting" 16 "github.com/dim4egster/qmallgo/utils/rpc" 17 18 cjson "github.com/dim4egster/qmallgo/utils/json" 19 ) 20 21 // Interface compliance 22 var _ Client = (*client)(nil) 23 24 // Client interface for interacting with EVM [chain] 25 type Client interface { 26 IssueTx(ctx context.Context, txBytes []byte) (ids.ID, error) 27 GetAtomicTxStatus(ctx context.Context, txID ids.ID) (Status, error) 28 GetAtomicTx(ctx context.Context, txID ids.ID) ([]byte, error) 29 GetAtomicUTXOs(ctx context.Context, addrs []string, sourceChain string, limit uint32, startAddress, startUTXOID string) ([][]byte, api.Index, error) 30 ListAddresses(ctx context.Context, userPass api.UserPass) ([]string, error) 31 ExportKey(ctx context.Context, userPass api.UserPass, addr string) (*crypto.PrivateKeySECP256K1R, string, error) 32 ImportKey(ctx context.Context, userPass api.UserPass, privateKey *crypto.PrivateKeySECP256K1R) (string, error) 33 Import(ctx context.Context, userPass api.UserPass, to string, sourceChain string) (ids.ID, error) 34 ExportAVAX(ctx context.Context, userPass api.UserPass, amount uint64, to string) (ids.ID, error) 35 Export(ctx context.Context, userPass api.UserPass, amount uint64, to string, assetID string) (ids.ID, error) 36 StartCPUProfiler(ctx context.Context) error 37 StopCPUProfiler(ctx context.Context) error 38 MemoryProfile(ctx context.Context) error 39 LockProfile(ctx context.Context) error 40 SetLogLevel(ctx context.Context, level log.Lvl) error 41 GetVMConfig(ctx context.Context) (*Config, error) 42 } 43 44 // Client implementation for interacting with EVM [chain] 45 type client struct { 46 requester rpc.EndpointRequester 47 adminRequester rpc.EndpointRequester 48 } 49 50 // NewClient returns a Client for interacting with EVM [chain] 51 func NewClient(uri, chain string) Client { 52 return &client{ 53 requester: rpc.NewEndpointRequester(fmt.Sprintf("%s/ext/bc/%s/avax", uri, chain), "avax"), 54 adminRequester: rpc.NewEndpointRequester(fmt.Sprintf("%s/ext/bc/%s/admin", uri, chain), "admin"), 55 } 56 } 57 58 // NewCChainClient returns a Client for interacting with the C Chain 59 func NewCChainClient(uri string) Client { 60 return NewClient(uri, "C") 61 } 62 63 // IssueTx issues a transaction to a node and returns the TxID 64 func (c *client) IssueTx(ctx context.Context, txBytes []byte) (ids.ID, error) { 65 res := &api.JSONTxID{} 66 txStr, err := formatting.Encode(formatting.Hex, txBytes) 67 if err != nil { 68 return res.TxID, fmt.Errorf("problem hex encoding bytes: %w", err) 69 } 70 err = c.requester.SendRequest(ctx, "issueTx", &api.FormattedTx{ 71 Tx: txStr, 72 Encoding: formatting.Hex, 73 }, res) 74 return res.TxID, err 75 } 76 77 // GetAtomicTxStatus returns the status of [txID] 78 func (c *client) GetAtomicTxStatus(ctx context.Context, txID ids.ID) (Status, error) { 79 res := &GetAtomicTxStatusReply{} 80 err := c.requester.SendRequest(ctx, "getAtomicTxStatus", &api.JSONTxID{ 81 TxID: txID, 82 }, res) 83 return res.Status, err 84 } 85 86 // GetAtomicTx returns the byte representation of [txID] 87 func (c *client) GetAtomicTx(ctx context.Context, txID ids.ID) ([]byte, error) { 88 res := &api.FormattedTx{} 89 err := c.requester.SendRequest(ctx, "getAtomicTx", &api.GetTxArgs{ 90 TxID: txID, 91 Encoding: formatting.Hex, 92 }, res) 93 if err != nil { 94 return nil, err 95 } 96 97 return formatting.Decode(formatting.Hex, res.Tx) 98 } 99 100 // GetAtomicUTXOs returns the byte representation of the atomic UTXOs controlled by [addresses] 101 // from [sourceChain] 102 func (c *client) GetAtomicUTXOs(ctx context.Context, addrs []string, sourceChain string, limit uint32, startAddress, startUTXOID string) ([][]byte, api.Index, error) { 103 res := &api.GetUTXOsReply{} 104 err := c.requester.SendRequest(ctx, "getUTXOs", &api.GetUTXOsArgs{ 105 Addresses: addrs, 106 SourceChain: sourceChain, 107 Limit: cjson.Uint32(limit), 108 StartIndex: api.Index{ 109 Address: startAddress, 110 UTXO: startUTXOID, 111 }, 112 Encoding: formatting.Hex, 113 }, res) 114 if err != nil { 115 return nil, api.Index{}, err 116 } 117 118 utxos := make([][]byte, len(res.UTXOs)) 119 for i, utxo := range res.UTXOs { 120 b, err := formatting.Decode(formatting.Hex, utxo) 121 if err != nil { 122 return nil, api.Index{}, err 123 } 124 utxos[i] = b 125 } 126 return utxos, res.EndIndex, nil 127 } 128 129 // ListAddresses returns all addresses on this chain controlled by [user] 130 func (c *client) ListAddresses(ctx context.Context, user api.UserPass) ([]string, error) { 131 res := &api.JSONAddresses{} 132 err := c.requester.SendRequest(ctx, "listAddresses", &user, res) 133 return res.Addresses, err 134 } 135 136 // ExportKey returns the private key corresponding to [addr] controlled by [user] 137 // in both Avalanche standard format and hex format 138 func (c *client) ExportKey(ctx context.Context, user api.UserPass, addr string) (*crypto.PrivateKeySECP256K1R, string, error) { 139 res := &ExportKeyReply{} 140 err := c.requester.SendRequest(ctx, "exportKey", &ExportKeyArgs{ 141 UserPass: user, 142 Address: addr, 143 }, res) 144 return res.PrivateKey, res.PrivateKeyHex, err 145 } 146 147 // ImportKey imports [privateKey] to [user] 148 func (c *client) ImportKey(ctx context.Context, user api.UserPass, privateKey *crypto.PrivateKeySECP256K1R) (string, error) { 149 res := &api.JSONAddress{} 150 err := c.requester.SendRequest(ctx, "importKey", &ImportKeyArgs{ 151 UserPass: user, 152 PrivateKey: privateKey, 153 }, res) 154 return res.Address, err 155 } 156 157 // Import sends an import transaction to import funds from [sourceChain] and 158 // returns the ID of the newly created transaction 159 func (c *client) Import(ctx context.Context, user api.UserPass, to, sourceChain string) (ids.ID, error) { 160 res := &api.JSONTxID{} 161 err := c.requester.SendRequest(ctx, "import", &ImportArgs{ 162 UserPass: user, 163 To: to, 164 SourceChain: sourceChain, 165 }, res) 166 return res.TxID, err 167 } 168 169 // ExportAVAX sends AVAX from this chain to the address specified by [to]. 170 // Returns the ID of the newly created atomic transaction 171 func (c *client) ExportAVAX( 172 ctx context.Context, 173 user api.UserPass, 174 amount uint64, 175 to string, 176 ) (ids.ID, error) { 177 return c.Export(ctx, user, amount, to, "AVAX") 178 } 179 180 // Export sends an asset from this chain to the P/C-Chain. 181 // After this tx is accepted, the AVAX must be imported to the P/C-chain with an importTx. 182 // Returns the ID of the newly created atomic transaction 183 func (c *client) Export( 184 ctx context.Context, 185 user api.UserPass, 186 amount uint64, 187 to string, 188 assetID string, 189 ) (ids.ID, error) { 190 res := &api.JSONTxID{} 191 err := c.requester.SendRequest(ctx, "export", &ExportArgs{ 192 ExportAVAXArgs: ExportAVAXArgs{ 193 UserPass: user, 194 Amount: cjson.Uint64(amount), 195 To: to, 196 }, 197 AssetID: assetID, 198 }, res) 199 return res.TxID, err 200 } 201 202 func (c *client) StartCPUProfiler(ctx context.Context) error { 203 return c.adminRequester.SendRequest(ctx, "startCPUProfiler", struct{}{}, &api.EmptyReply{}) 204 } 205 206 func (c *client) StopCPUProfiler(ctx context.Context) error { 207 return c.adminRequester.SendRequest(ctx, "stopCPUProfiler", struct{}{}, &api.EmptyReply{}) 208 } 209 210 func (c *client) MemoryProfile(ctx context.Context) error { 211 return c.adminRequester.SendRequest(ctx, "memoryProfile", struct{}{}, &api.EmptyReply{}) 212 } 213 214 func (c *client) LockProfile(ctx context.Context) error { 215 return c.adminRequester.SendRequest(ctx, "lockProfile", struct{}{}, &api.EmptyReply{}) 216 } 217 218 // SetLogLevel dynamically sets the log level for the C Chain 219 func (c *client) SetLogLevel(ctx context.Context, level log.Lvl) error { 220 return c.adminRequester.SendRequest(ctx, "setLogLevel", &SetLogLevelArgs{ 221 Level: level.String(), 222 }, &api.EmptyReply{}) 223 } 224 225 // GetVMConfig returns the current config of the VM 226 func (c *client) GetVMConfig(ctx context.Context) (*Config, error) { 227 res := &ConfigReply{} 228 err := c.adminRequester.SendRequest(ctx, "getVMConfig", struct{}{}, res) 229 return res.Config, err 230 }