github.com/neatlab/neatio@v1.7.3-0.20220425043230-d903e92fcc75/neatcli/neatcli.go (about) 1 package neatcli 2 3 import ( 4 "context" 5 "encoding/json" 6 "errors" 7 "fmt" 8 "math/big" 9 10 "github.com/neatlab/neatio" 11 "github.com/neatlab/neatio/chain/core/types" 12 "github.com/neatlab/neatio/network/rpc" 13 "github.com/neatlab/neatio/utilities/common" 14 "github.com/neatlab/neatio/utilities/common/hexutil" 15 "github.com/neatlab/neatio/utilities/rlp" 16 ) 17 18 type Client struct { 19 c *rpc.Client 20 } 21 22 func Dial(rawurl string) (*Client, error) { 23 c, err := rpc.Dial(rawurl) 24 if err != nil { 25 return nil, err 26 } 27 return NewClient(c), nil 28 } 29 30 func NewClient(c *rpc.Client) *Client { 31 return &Client{c} 32 } 33 34 func (ec *Client) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) { 35 return ec.getBlock(ctx, "eth_getBlockByHash", hash, true) 36 } 37 38 func (ec *Client) BlockByNumber(ctx context.Context, number *big.Int) (*types.Block, error) { 39 return ec.getBlock(ctx, "eth_getBlockByNumber", toBlockNumArg(number), true) 40 } 41 42 type rpcBlock struct { 43 Hash common.Hash `json:"hash"` 44 Transactions []rpcTransaction `json:"transactions"` 45 UncleHashes []common.Hash `json:"uncles"` 46 } 47 48 func (ec *Client) getBlock(ctx context.Context, method string, args ...interface{}) (*types.Block, error) { 49 var raw json.RawMessage 50 err := ec.c.CallContext(ctx, &raw, method, args...) 51 if err != nil { 52 return nil, err 53 } else if len(raw) == 0 { 54 return nil, neatio.NotFound 55 } 56 57 var head *types.Header 58 var body rpcBlock 59 if err := json.Unmarshal(raw, &head); err != nil { 60 return nil, err 61 } 62 if err := json.Unmarshal(raw, &body); err != nil { 63 return nil, err 64 } 65 66 if head.UncleHash == types.EmptyUncleHash && len(body.UncleHashes) > 0 { 67 return nil, fmt.Errorf("server returned non-empty uncle list but block header indicates no uncles") 68 } 69 if head.UncleHash != types.EmptyUncleHash && len(body.UncleHashes) == 0 { 70 return nil, fmt.Errorf("server returned empty uncle list but block header indicates uncles") 71 } 72 if head.TxHash == types.EmptyRootHash && len(body.Transactions) > 0 { 73 return nil, fmt.Errorf("server returned non-empty transaction list but block header indicates no transactions") 74 } 75 if head.TxHash != types.EmptyRootHash && len(body.Transactions) == 0 { 76 return nil, fmt.Errorf("server returned empty transaction list but block header indicates transactions") 77 } 78 79 var uncles []*types.Header 80 if len(body.UncleHashes) > 0 { 81 uncles = make([]*types.Header, len(body.UncleHashes)) 82 reqs := make([]rpc.BatchElem, len(body.UncleHashes)) 83 for i := range reqs { 84 reqs[i] = rpc.BatchElem{ 85 Method: "eth_getUncleByBlockHashAndIndex", 86 Args: []interface{}{body.Hash, hexutil.EncodeUint64(uint64(i))}, 87 Result: &uncles[i], 88 } 89 } 90 if err := ec.c.BatchCallContext(ctx, reqs); err != nil { 91 return nil, err 92 } 93 for i := range reqs { 94 if reqs[i].Error != nil { 95 return nil, reqs[i].Error 96 } 97 if uncles[i] == nil { 98 return nil, fmt.Errorf("got null header for uncle %d of block %x", i, body.Hash[:]) 99 } 100 } 101 } 102 103 txs := make([]*types.Transaction, len(body.Transactions)) 104 for i, tx := range body.Transactions { 105 setSenderFromServer(tx.tx, tx.From, body.Hash) 106 txs[i] = tx.tx 107 } 108 return types.NewBlockWithHeader(head).WithBody(txs, uncles), nil 109 } 110 111 func (ec *Client) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) { 112 var head *types.Header 113 err := ec.c.CallContext(ctx, &head, "eth_getBlockByHash", hash, false) 114 if err == nil && head == nil { 115 err = neatio.NotFound 116 } 117 return head, err 118 } 119 120 func (ec *Client) HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error) { 121 var head *types.Header 122 err := ec.c.CallContext(ctx, &head, "eth_getBlockByNumber", toBlockNumArg(number), false) 123 if err == nil && head == nil { 124 err = neatio.NotFound 125 } 126 return head, err 127 } 128 129 type rpcTransaction struct { 130 tx *types.Transaction 131 txExtraInfo 132 } 133 134 type txExtraInfo struct { 135 BlockNumber *string 136 BlockHash common.Hash 137 From common.Address 138 } 139 140 func (tx *rpcTransaction) UnmarshalJSON(msg []byte) error { 141 if err := json.Unmarshal(msg, &tx.tx); err != nil { 142 return err 143 } 144 return json.Unmarshal(msg, &tx.txExtraInfo) 145 } 146 147 func (ec *Client) TransactionByHash(ctx context.Context, hash common.Hash) (tx *types.Transaction, isPending bool, err error) { 148 var json *rpcTransaction 149 err = ec.c.CallContext(ctx, &json, "eth_getTransactionByHash", hash) 150 if err != nil { 151 return nil, false, err 152 } else if json == nil { 153 return nil, false, neatio.NotFound 154 } else if _, r, _ := json.tx.RawSignatureValues(); r == nil { 155 return nil, false, fmt.Errorf("server returned transaction without signature") 156 } 157 setSenderFromServer(json.tx, json.From, json.BlockHash) 158 return json.tx, json.BlockNumber == nil, nil 159 } 160 161 func (ec *Client) TransactionSender(ctx context.Context, tx *types.Transaction, block common.Hash, index uint) (common.Address, error) { 162 163 sender, err := types.Sender(&senderFromServer{blockhash: block}, tx) 164 if err == nil { 165 return sender, nil 166 } 167 var meta struct { 168 Hash common.Hash 169 From common.Address 170 } 171 if err = ec.c.CallContext(ctx, &meta, "eth_getTransactionByBlockHashAndIndex", block, hexutil.Uint64(index)); err != nil { 172 return common.Address{}, err 173 } 174 if meta.Hash == (common.Hash{}) || meta.Hash != tx.Hash() { 175 return common.Address{}, errors.New("wrong inclusion block/index") 176 } 177 return meta.From, nil 178 } 179 180 func (ec *Client) TransactionCount(ctx context.Context, blockHash common.Hash) (uint, error) { 181 var num hexutil.Uint 182 err := ec.c.CallContext(ctx, &num, "eth_getBlockTransactionCountByHash", blockHash) 183 return uint(num), err 184 } 185 186 func (ec *Client) TransactionInBlock(ctx context.Context, blockHash common.Hash, index uint) (*types.Transaction, error) { 187 var json *rpcTransaction 188 err := ec.c.CallContext(ctx, &json, "eth_getTransactionByBlockHashAndIndex", blockHash, hexutil.Uint64(index)) 189 if err == nil { 190 if json == nil { 191 return nil, neatio.NotFound 192 } else if _, r, _ := json.tx.RawSignatureValues(); r == nil { 193 return nil, fmt.Errorf("server returned transaction without signature") 194 } 195 } 196 setSenderFromServer(json.tx, json.From, json.BlockHash) 197 return json.tx, err 198 } 199 200 func (ec *Client) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) { 201 var r *types.Receipt 202 err := ec.c.CallContext(ctx, &r, "eth_getTransactionReceipt", txHash) 203 if err == nil { 204 if r == nil { 205 return nil, neatio.NotFound 206 } 207 } 208 return r, err 209 } 210 211 func toBlockNumArg(number *big.Int) string { 212 if number == nil { 213 return "latest" 214 } 215 return hexutil.EncodeBig(number) 216 } 217 218 type rpcProgress struct { 219 StartingBlock hexutil.Uint64 220 CurrentBlock hexutil.Uint64 221 HighestBlock hexutil.Uint64 222 PulledStates hexutil.Uint64 223 KnownStates hexutil.Uint64 224 } 225 226 func (ec *Client) SyncProgress(ctx context.Context) (*neatio.SyncProgress, error) { 227 var raw json.RawMessage 228 if err := ec.c.CallContext(ctx, &raw, "eth_syncing"); err != nil { 229 return nil, err 230 } 231 232 var syncing bool 233 if err := json.Unmarshal(raw, &syncing); err == nil { 234 return nil, nil 235 } 236 var progress *rpcProgress 237 if err := json.Unmarshal(raw, &progress); err != nil { 238 return nil, err 239 } 240 return &neatio.SyncProgress{ 241 StartingBlock: uint64(progress.StartingBlock), 242 CurrentBlock: uint64(progress.CurrentBlock), 243 HighestBlock: uint64(progress.HighestBlock), 244 PulledStates: uint64(progress.PulledStates), 245 KnownStates: uint64(progress.KnownStates), 246 }, nil 247 } 248 249 func (ec *Client) SubscribeNewHead(ctx context.Context, ch chan<- *types.Header) (neatio.Subscription, error) { 250 return ec.c.EthSubscribe(ctx, ch, "newHeads", map[string]struct{}{}) 251 } 252 253 func (ec *Client) NetworkID(ctx context.Context) (*big.Int, error) { 254 version := new(big.Int) 255 var ver string 256 if err := ec.c.CallContext(ctx, &ver, "net_version"); err != nil { 257 return nil, err 258 } 259 if _, ok := version.SetString(ver, 10); !ok { 260 return nil, fmt.Errorf("invalid net_version result %q", ver) 261 } 262 return version, nil 263 } 264 265 func (ec *Client) BalanceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (*big.Int, error) { 266 var result hexutil.Big 267 err := ec.c.CallContext(ctx, &result, "eth_getBalance", account, toBlockNumArg(blockNumber)) 268 return (*big.Int)(&result), err 269 } 270 271 func (ec *Client) StorageAt(ctx context.Context, account common.Address, key common.Hash, blockNumber *big.Int) ([]byte, error) { 272 var result hexutil.Bytes 273 err := ec.c.CallContext(ctx, &result, "eth_getStorageAt", account, key, toBlockNumArg(blockNumber)) 274 return result, err 275 } 276 277 func (ec *Client) CodeAt(ctx context.Context, account common.Address, blockNumber *big.Int) ([]byte, error) { 278 var result hexutil.Bytes 279 err := ec.c.CallContext(ctx, &result, "eth_getCode", account, toBlockNumArg(blockNumber)) 280 return result, err 281 } 282 283 func (ec *Client) NonceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (uint64, error) { 284 var result hexutil.Uint64 285 err := ec.c.CallContext(ctx, &result, "eth_getTransactionCount", account, toBlockNumArg(blockNumber)) 286 return uint64(result), err 287 } 288 289 func (ec *Client) FilterLogs(ctx context.Context, q neatio.FilterQuery) ([]types.Log, error) { 290 var result []types.Log 291 err := ec.c.CallContext(ctx, &result, "eth_getLogs", toFilterArg(q)) 292 return result, err 293 } 294 295 func (ec *Client) SubscribeFilterLogs(ctx context.Context, q neatio.FilterQuery, ch chan<- types.Log) (neatio.Subscription, error) { 296 return ec.c.EthSubscribe(ctx, ch, "logs", toFilterArg(q)) 297 } 298 299 func toFilterArg(q neatio.FilterQuery) interface{} { 300 arg := map[string]interface{}{ 301 "fromBlock": toBlockNumArg(q.FromBlock), 302 "toBlock": toBlockNumArg(q.ToBlock), 303 "address": q.Addresses, 304 "topics": q.Topics, 305 } 306 if q.FromBlock == nil { 307 arg["fromBlock"] = "0x0" 308 } 309 return arg 310 } 311 312 func (ec *Client) PendingBalanceAt(ctx context.Context, account common.Address) (*big.Int, error) { 313 var result hexutil.Big 314 err := ec.c.CallContext(ctx, &result, "eth_getBalance", account, "pending") 315 return (*big.Int)(&result), err 316 } 317 318 func (ec *Client) PendingStorageAt(ctx context.Context, account common.Address, key common.Hash) ([]byte, error) { 319 var result hexutil.Bytes 320 err := ec.c.CallContext(ctx, &result, "eth_getStorageAt", account, key, "pending") 321 return result, err 322 } 323 324 func (ec *Client) PendingCodeAt(ctx context.Context, account common.Address) ([]byte, error) { 325 var result hexutil.Bytes 326 err := ec.c.CallContext(ctx, &result, "eth_getCode", account, "pending") 327 return result, err 328 } 329 330 func (ec *Client) PendingNonceAt(ctx context.Context, account common.Address) (uint64, error) { 331 var result hexutil.Uint64 332 err := ec.c.CallContext(ctx, &result, "eth_getTransactionCount", account, "pending") 333 return uint64(result), err 334 } 335 336 func (ec *Client) PendingTransactionCount(ctx context.Context) (uint, error) { 337 var num hexutil.Uint 338 err := ec.c.CallContext(ctx, &num, "eth_getBlockTransactionCountByNumber", "pending") 339 return uint(num), err 340 } 341 342 func (ec *Client) CallContract(ctx context.Context, msg neatio.CallMsg, blockNumber *big.Int) ([]byte, error) { 343 var hex hexutil.Bytes 344 err := ec.c.CallContext(ctx, &hex, "eth_call", toCallArg(msg), toBlockNumArg(blockNumber)) 345 if err != nil { 346 return nil, err 347 } 348 return hex, nil 349 } 350 351 func (ec *Client) PendingCallContract(ctx context.Context, msg neatio.CallMsg) ([]byte, error) { 352 var hex hexutil.Bytes 353 err := ec.c.CallContext(ctx, &hex, "eth_call", toCallArg(msg), "pending") 354 if err != nil { 355 return nil, err 356 } 357 return hex, nil 358 } 359 360 func (ec *Client) SuggestGasPrice(ctx context.Context) (*big.Int, error) { 361 var hex hexutil.Big 362 if err := ec.c.CallContext(ctx, &hex, "eth_gasPrice"); err != nil { 363 return nil, err 364 } 365 return (*big.Int)(&hex), nil 366 } 367 368 func (ec *Client) EstimateGas(ctx context.Context, msg neatio.CallMsg) (uint64, error) { 369 var hex hexutil.Uint64 370 err := ec.c.CallContext(ctx, &hex, "eth_estimateGas", toCallArg(msg)) 371 if err != nil { 372 return 0, err 373 } 374 return uint64(hex), nil 375 } 376 377 func (ec *Client) SendTransaction(ctx context.Context, tx *types.Transaction) error { 378 fmt.Printf("transaction args Client tx %v\n", tx) 379 data, err := rlp.EncodeToBytes(tx) 380 if err != nil { 381 return err 382 } 383 return ec.c.CallContext(ctx, nil, "eth_sendRawTransaction", common.ToHex(data)) 384 } 385 386 func toCallArg(msg neatio.CallMsg) interface{} { 387 arg := map[string]interface{}{ 388 "from": msg.From, 389 "to": msg.To, 390 } 391 if len(msg.Data) > 0 { 392 arg["data"] = hexutil.Bytes(msg.Data) 393 } 394 if msg.Value != nil { 395 arg["value"] = (*hexutil.Big)(msg.Value) 396 } 397 if msg.Gas != 0 { 398 arg["gas"] = hexutil.Uint64(msg.Gas) 399 } 400 if msg.GasPrice != nil { 401 arg["gasPrice"] = (*hexutil.Big)(msg.GasPrice) 402 } 403 return arg 404 }