github.com/nspcc-dev/neo-go@v0.105.2-0.20240517133400-6be757af3eba/pkg/rpcclient/rpc.go (about) 1 package rpcclient 2 3 import ( 4 "encoding/base64" 5 "encoding/hex" 6 "encoding/json" 7 "errors" 8 "fmt" 9 10 "github.com/google/uuid" 11 "github.com/nspcc-dev/neo-go/pkg/config" 12 "github.com/nspcc-dev/neo-go/pkg/core/block" 13 "github.com/nspcc-dev/neo-go/pkg/core/state" 14 "github.com/nspcc-dev/neo-go/pkg/core/transaction" 15 "github.com/nspcc-dev/neo-go/pkg/crypto/keys" 16 "github.com/nspcc-dev/neo-go/pkg/encoding/fixedn" 17 "github.com/nspcc-dev/neo-go/pkg/io" 18 "github.com/nspcc-dev/neo-go/pkg/neorpc" 19 "github.com/nspcc-dev/neo-go/pkg/neorpc/result" 20 "github.com/nspcc-dev/neo-go/pkg/network/payload" 21 "github.com/nspcc-dev/neo-go/pkg/smartcontract" 22 "github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger" 23 "github.com/nspcc-dev/neo-go/pkg/util" 24 "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" 25 ) 26 27 var errNetworkNotInitialized = errors.New("RPC client network is not initialized") 28 29 // CalculateNetworkFee calculates network fee for the transaction. The transaction may 30 // have empty witnesses for contract signers and may have only verification scripts 31 // filled for standard sig/multisig signers. 32 func (c *Client) CalculateNetworkFee(tx *transaction.Transaction) (int64, error) { 33 var ( 34 params = []any{tx.Bytes()} 35 resp = new(result.NetworkFee) 36 ) 37 if err := c.performRequest("calculatenetworkfee", params, resp); err != nil { 38 return 0, err 39 } 40 return resp.Value, nil 41 } 42 43 // GetApplicationLog returns a contract log based on the specified txid. 44 func (c *Client) GetApplicationLog(hash util.Uint256, trig *trigger.Type) (*result.ApplicationLog, error) { 45 var ( 46 params = []any{hash.StringLE()} 47 resp = new(result.ApplicationLog) 48 ) 49 if trig != nil { 50 params = append(params, trig.String()) 51 } 52 if err := c.performRequest("getapplicationlog", params, resp); err != nil { 53 return nil, err 54 } 55 return resp, nil 56 } 57 58 // GetBestBlockHash returns the hash of the tallest block in the blockchain. 59 func (c *Client) GetBestBlockHash() (util.Uint256, error) { 60 var resp = util.Uint256{} 61 if err := c.performRequest("getbestblockhash", nil, &resp); err != nil { 62 return resp, err 63 } 64 return resp, nil 65 } 66 67 // GetBlockCount returns the number of blocks in the blockchain. 68 func (c *Client) GetBlockCount() (uint32, error) { 69 var resp uint32 70 if err := c.performRequest("getblockcount", nil, &resp); err != nil { 71 return resp, err 72 } 73 return resp, nil 74 } 75 76 // GetBlockByIndex returns a block by its height. In-header stateroot option 77 // must be initialized with Init before calling this method. 78 func (c *Client) GetBlockByIndex(index uint32) (*block.Block, error) { 79 return c.getBlock(index) 80 } 81 82 // GetBlockByHash returns a block by its hash. In-header stateroot option 83 // must be initialized with Init before calling this method. 84 func (c *Client) GetBlockByHash(hash util.Uint256) (*block.Block, error) { 85 return c.getBlock(hash.StringLE()) 86 } 87 88 func (c *Client) getBlock(param any) (*block.Block, error) { 89 var ( 90 resp []byte 91 err error 92 b *block.Block 93 ) 94 if err = c.performRequest("getblock", []any{param}, &resp); err != nil { 95 return nil, err 96 } 97 r := io.NewBinReaderFromBuf(resp) 98 sr, err := c.stateRootInHeader() 99 if err != nil { 100 return nil, err 101 } 102 b = block.New(sr) 103 b.DecodeBinary(r) 104 if r.Err != nil { 105 return nil, r.Err 106 } 107 return b, nil 108 } 109 110 // GetBlockByIndexVerbose returns a block wrapper with additional metadata by 111 // its height. In-header stateroot option must be initialized with Init before 112 // calling this method. 113 // NOTE: to get transaction.ID and transaction.Size, use t.Hash() and io.GetVarSize(t) respectively. 114 func (c *Client) GetBlockByIndexVerbose(index uint32) (*result.Block, error) { 115 return c.getBlockVerbose(index) 116 } 117 118 // GetBlockByHashVerbose returns a block wrapper with additional metadata by 119 // its hash. In-header stateroot option must be initialized with Init before 120 // calling this method. 121 func (c *Client) GetBlockByHashVerbose(hash util.Uint256) (*result.Block, error) { 122 return c.getBlockVerbose(hash.StringLE()) 123 } 124 125 func (c *Client) getBlockVerbose(param any) (*result.Block, error) { 126 var ( 127 params = []any{param, 1} // 1 for verbose. 128 resp = &result.Block{} 129 err error 130 ) 131 sr, err := c.stateRootInHeader() 132 if err != nil { 133 return nil, err 134 } 135 resp.Header.StateRootEnabled = sr 136 if err = c.performRequest("getblock", params, resp); err != nil { 137 return nil, err 138 } 139 return resp, nil 140 } 141 142 // GetBlockHash returns the hash value of the corresponding block based on the specified index. 143 func (c *Client) GetBlockHash(index uint32) (util.Uint256, error) { 144 var ( 145 params = []any{index} 146 resp = util.Uint256{} 147 ) 148 if err := c.performRequest("getblockhash", params, &resp); err != nil { 149 return resp, err 150 } 151 return resp, nil 152 } 153 154 // GetBlockHeader returns the corresponding block header information from a serialized hex string 155 // according to the specified script hash. In-header stateroot option must be 156 // initialized with Init before calling this method. 157 func (c *Client) GetBlockHeader(hash util.Uint256) (*block.Header, error) { 158 var ( 159 params = []any{hash.StringLE()} 160 resp []byte 161 h *block.Header 162 ) 163 if err := c.performRequest("getblockheader", params, &resp); err != nil { 164 return nil, err 165 } 166 sr, err := c.stateRootInHeader() 167 if err != nil { 168 return nil, err 169 } 170 r := io.NewBinReaderFromBuf(resp) 171 h = new(block.Header) 172 h.StateRootEnabled = sr 173 h.DecodeBinary(r) 174 if r.Err != nil { 175 return nil, r.Err 176 } 177 return h, nil 178 } 179 180 // GetBlockHeaderCount returns the number of headers in the main chain. 181 func (c *Client) GetBlockHeaderCount() (uint32, error) { 182 var resp uint32 183 if err := c.performRequest("getblockheadercount", nil, &resp); err != nil { 184 return resp, err 185 } 186 return resp, nil 187 } 188 189 // GetBlockHeaderVerbose returns the corresponding block header information from a Json format string 190 // according to the specified script hash. In-header stateroot option must be 191 // initialized with Init before calling this method. 192 func (c *Client) GetBlockHeaderVerbose(hash util.Uint256) (*result.Header, error) { 193 var ( 194 params = []any{hash.StringLE(), 1} 195 resp = &result.Header{} 196 ) 197 if err := c.performRequest("getblockheader", params, resp); err != nil { 198 return nil, err 199 } 200 return resp, nil 201 } 202 203 // GetBlockSysFee returns the system fees of the block based on the specified index. 204 // This method is only supported by NeoGo servers. 205 func (c *Client) GetBlockSysFee(index uint32) (fixedn.Fixed8, error) { 206 var ( 207 params = []any{index} 208 resp fixedn.Fixed8 209 ) 210 if err := c.performRequest("getblocksysfee", params, &resp); err != nil { 211 return resp, err 212 } 213 return resp, nil 214 } 215 216 // GetConnectionCount returns the current number of the connections for the node. 217 func (c *Client) GetConnectionCount() (int, error) { 218 var resp int 219 220 if err := c.performRequest("getconnectioncount", nil, &resp); err != nil { 221 return resp, err 222 } 223 return resp, nil 224 } 225 226 // GetCommittee returns the current public keys of NEO nodes in the committee. 227 func (c *Client) GetCommittee() (keys.PublicKeys, error) { 228 var resp = new(keys.PublicKeys) 229 230 if err := c.performRequest("getcommittee", nil, resp); err != nil { 231 return nil, err 232 } 233 return *resp, nil 234 } 235 236 // GetContractStateByHash queries contract information according to the contract script hash. 237 func (c *Client) GetContractStateByHash(hash util.Uint160) (*state.Contract, error) { 238 return c.getContractState(hash.StringLE()) 239 } 240 241 // GetContractStateByAddressOrName queries contract information using the contract 242 // address or name. Notice that name-based queries work only for native contracts, 243 // non-native ones can't be requested this way. 244 func (c *Client) GetContractStateByAddressOrName(addressOrName string) (*state.Contract, error) { 245 return c.getContractState(addressOrName) 246 } 247 248 // GetContractStateByID queries contract information according to the contract ID. 249 // Notice that this is supported by all servers only for native contracts, 250 // non-native ones can be requested only from NeoGo servers. 251 func (c *Client) GetContractStateByID(id int32) (*state.Contract, error) { 252 return c.getContractState(id) 253 } 254 255 // getContractState is an internal representation of GetContractStateBy* methods. 256 func (c *Client) getContractState(param any) (*state.Contract, error) { 257 var ( 258 params = []any{param} 259 resp = &state.Contract{} 260 ) 261 if err := c.performRequest("getcontractstate", params, resp); err != nil { 262 return resp, err 263 } 264 return resp, nil 265 } 266 267 // GetNativeContracts queries information about native contracts. 268 func (c *Client) GetNativeContracts() ([]state.Contract, error) { 269 var resp []state.Contract 270 if err := c.performRequest("getnativecontracts", nil, &resp); err != nil { 271 return resp, err 272 } 273 274 // Update native contract hashes. 275 c.cacheLock.Lock() 276 for _, cs := range resp { 277 c.cache.nativeHashes[cs.Manifest.Name] = cs.Hash 278 } 279 c.cacheLock.Unlock() 280 281 return resp, nil 282 } 283 284 // GetNEP11Balances is a wrapper for getnep11balances RPC. 285 func (c *Client) GetNEP11Balances(address util.Uint160) (*result.NEP11Balances, error) { 286 params := []any{address.StringLE()} 287 resp := new(result.NEP11Balances) 288 if err := c.performRequest("getnep11balances", params, resp); err != nil { 289 return nil, err 290 } 291 return resp, nil 292 } 293 294 // GetNEP17Balances is a wrapper for getnep17balances RPC. 295 func (c *Client) GetNEP17Balances(address util.Uint160) (*result.NEP17Balances, error) { 296 params := []any{address.StringLE()} 297 resp := new(result.NEP17Balances) 298 if err := c.performRequest("getnep17balances", params, resp); err != nil { 299 return nil, err 300 } 301 return resp, nil 302 } 303 304 // GetNEP11Properties is a wrapper for getnep11properties RPC. We recommend using 305 // nep11 package and Properties method there to receive proper VM types and work with them. 306 // This method is provided mostly for the sake of completeness. For well-known 307 // attributes like "description", "image", "name" and "tokenURI" it returns strings, 308 // while for all others []byte (which can be nil). 309 func (c *Client) GetNEP11Properties(asset util.Uint160, token []byte) (map[string]any, error) { 310 params := []any{asset.StringLE(), hex.EncodeToString(token)} 311 resp := make(map[string]any) 312 if err := c.performRequest("getnep11properties", params, &resp); err != nil { 313 return nil, err 314 } 315 for k, v := range resp { 316 if v == nil { 317 continue 318 } 319 str, ok := v.(string) 320 if !ok { 321 return nil, errors.New("value is not a string") 322 } 323 if result.KnownNEP11Properties[k] { 324 continue 325 } 326 val, err := base64.StdEncoding.DecodeString(str) 327 if err != nil { 328 return nil, err 329 } 330 resp[k] = val 331 } 332 return resp, nil 333 } 334 335 // GetNEP11Transfers is a wrapper for getnep11transfers RPC. Address parameter 336 // is mandatory, while all others are optional. Limit and page parameters are 337 // only supported by NeoGo servers and can only be specified with start and stop. 338 func (c *Client) GetNEP11Transfers(address util.Uint160, start, stop *uint64, limit, page *int) (*result.NEP11Transfers, error) { 339 params, err := packTransfersParams(address, start, stop, limit, page) 340 if err != nil { 341 return nil, err 342 } 343 resp := new(result.NEP11Transfers) 344 if err := c.performRequest("getnep11transfers", params, resp); err != nil { 345 return nil, err 346 } 347 return resp, nil 348 } 349 350 func packTransfersParams(address util.Uint160, start, stop *uint64, limit, page *int) ([]any, error) { 351 params := []any{address.StringLE()} 352 if start != nil { 353 params = append(params, *start) 354 if stop != nil { 355 params = append(params, *stop) 356 if limit != nil { 357 params = append(params, *limit) 358 if page != nil { 359 params = append(params, *page) 360 } 361 } else if page != nil { 362 return nil, errors.New("bad parameters") 363 } 364 } else if limit != nil || page != nil { 365 return nil, errors.New("bad parameters") 366 } 367 } else if stop != nil || limit != nil || page != nil { 368 return nil, errors.New("bad parameters") 369 } 370 return params, nil 371 } 372 373 // GetNEP17Transfers is a wrapper for getnep17transfers RPC. Address parameter 374 // is mandatory while all the others are optional. Start and stop parameters 375 // are supported since neo-go 0.77.0 and limit and page since neo-go 0.78.0. 376 // These parameters are positional in the JSON-RPC call. For example, you can't specify the limit 377 // without specifying start/stop first. 378 func (c *Client) GetNEP17Transfers(address util.Uint160, start, stop *uint64, limit, page *int) (*result.NEP17Transfers, error) { 379 params, err := packTransfersParams(address, start, stop, limit, page) 380 if err != nil { 381 return nil, err 382 } 383 resp := new(result.NEP17Transfers) 384 if err := c.performRequest("getnep17transfers", params, resp); err != nil { 385 return nil, err 386 } 387 return resp, nil 388 } 389 390 // GetPeers returns a list of the nodes that the node is currently connected to/disconnected from. 391 func (c *Client) GetPeers() (*result.GetPeers, error) { 392 var resp = &result.GetPeers{} 393 394 if err := c.performRequest("getpeers", nil, resp); err != nil { 395 return resp, err 396 } 397 return resp, nil 398 } 399 400 // GetRawMemPool returns a list of unconfirmed transactions in the memory. 401 func (c *Client) GetRawMemPool() ([]util.Uint256, error) { 402 var resp = new([]util.Uint256) 403 404 if err := c.performRequest("getrawmempool", nil, resp); err != nil { 405 return *resp, err 406 } 407 return *resp, nil 408 } 409 410 // GetRawTransaction returns a transaction by hash. 411 func (c *Client) GetRawTransaction(hash util.Uint256) (*transaction.Transaction, error) { 412 var ( 413 params = []any{hash.StringLE()} 414 resp []byte 415 err error 416 ) 417 if err = c.performRequest("getrawtransaction", params, &resp); err != nil { 418 return nil, err 419 } 420 tx, err := transaction.NewTransactionFromBytes(resp) 421 if err != nil { 422 return nil, err 423 } 424 return tx, nil 425 } 426 427 // GetRawTransactionVerbose returns a transaction wrapper with additional 428 // metadata by transaction's hash. 429 // NOTE: to get transaction.ID and transaction.Size, use t.Hash() and io.GetVarSize(t) respectively. 430 func (c *Client) GetRawTransactionVerbose(hash util.Uint256) (*result.TransactionOutputRaw, error) { 431 var ( 432 params = []any{hash.StringLE(), 1} // 1 for verbose. 433 resp = &result.TransactionOutputRaw{} 434 err error 435 ) 436 if err = c.performRequest("getrawtransaction", params, resp); err != nil { 437 return nil, err 438 } 439 return resp, nil 440 } 441 442 // GetProof returns existence proof of storage item state by the given stateroot 443 // historical contract hash and historical item key. 444 func (c *Client) GetProof(stateroot util.Uint256, historicalContractHash util.Uint160, historicalKey []byte) (*result.ProofWithKey, error) { 445 var ( 446 params = []any{stateroot.StringLE(), historicalContractHash.StringLE(), historicalKey} 447 resp = &result.ProofWithKey{} 448 ) 449 if err := c.performRequest("getproof", params, resp); err != nil { 450 return nil, err 451 } 452 return resp, nil 453 } 454 455 // VerifyProof returns value by the given stateroot and proof. 456 func (c *Client) VerifyProof(stateroot util.Uint256, proof *result.ProofWithKey) ([]byte, error) { 457 var ( 458 params = []any{stateroot.StringLE(), proof.String()} 459 resp []byte 460 ) 461 if err := c.performRequest("verifyproof", params, &resp); err != nil { 462 return nil, err 463 } 464 return resp, nil 465 } 466 467 // GetState returns historical contract storage item state by the given stateroot, 468 // historical contract hash and historical item key. 469 func (c *Client) GetState(stateroot util.Uint256, historicalContractHash util.Uint160, historicalKey []byte) ([]byte, error) { 470 var ( 471 params = []any{stateroot.StringLE(), historicalContractHash.StringLE(), historicalKey} 472 resp []byte 473 ) 474 if err := c.performRequest("getstate", params, &resp); err != nil { 475 return nil, err 476 } 477 return resp, nil 478 } 479 480 // FindStates returns historical contract storage item states by the given stateroot, 481 // historical contract hash and historical prefix. If `start` path is specified, items 482 // starting from `start` path are being returned (excluding item located at the start path). 483 // If `maxCount` specified, the maximum number of items to be returned equals to `maxCount`. 484 func (c *Client) FindStates(stateroot util.Uint256, historicalContractHash util.Uint160, historicalPrefix []byte, 485 start []byte, maxCount *int) (result.FindStates, error) { 486 if historicalPrefix == nil { 487 historicalPrefix = []byte{} 488 } 489 var ( 490 params = []any{stateroot.StringLE(), historicalContractHash.StringLE(), historicalPrefix} 491 resp result.FindStates 492 ) 493 if start == nil && maxCount != nil { 494 start = []byte{} 495 } 496 if start != nil { 497 params = append(params, start) 498 } 499 if maxCount != nil { 500 params = append(params, *maxCount) 501 } 502 if err := c.performRequest("findstates", params, &resp); err != nil { 503 return resp, err 504 } 505 return resp, nil 506 } 507 508 // GetStateRootByHeight returns the state root for the specified height. 509 func (c *Client) GetStateRootByHeight(height uint32) (*state.MPTRoot, error) { 510 return c.getStateRoot(height) 511 } 512 513 // GetStateRootByBlockHash returns the state root for the block with the specified hash. 514 func (c *Client) GetStateRootByBlockHash(hash util.Uint256) (*state.MPTRoot, error) { 515 return c.getStateRoot(hash) 516 } 517 518 func (c *Client) getStateRoot(param any) (*state.MPTRoot, error) { 519 var resp = new(state.MPTRoot) 520 if err := c.performRequest("getstateroot", []any{param}, resp); err != nil { 521 return nil, err 522 } 523 return resp, nil 524 } 525 526 // GetStateHeight returns the current validated and local node state height. 527 func (c *Client) GetStateHeight() (*result.StateHeight, error) { 528 var resp = new(result.StateHeight) 529 530 if err := c.performRequest("getstateheight", nil, resp); err != nil { 531 return nil, err 532 } 533 return resp, nil 534 } 535 536 // GetStorageByID returns the stored value according to the contract ID and the stored key. 537 func (c *Client) GetStorageByID(id int32, key []byte) ([]byte, error) { 538 return c.getStorage([]any{id, key}) 539 } 540 541 // GetStorageByHash returns the stored value according to the contract script hash and the stored key. 542 func (c *Client) GetStorageByHash(hash util.Uint160, key []byte) ([]byte, error) { 543 return c.getStorage([]any{hash.StringLE(), key}) 544 } 545 546 func (c *Client) getStorage(params []any) ([]byte, error) { 547 var resp []byte 548 if err := c.performRequest("getstorage", params, &resp); err != nil { 549 return nil, err 550 } 551 return resp, nil 552 } 553 554 // GetStorageByIDHistoric returns the historical stored value according to the 555 // contract ID and, stored key and specified stateroot. 556 func (c *Client) GetStorageByIDHistoric(root util.Uint256, id int32, key []byte) ([]byte, error) { 557 return c.getStorageHistoric([]any{root.StringLE(), id, key}) 558 } 559 560 // GetStorageByHashHistoric returns the historical stored value according to the 561 // contract script hash, the stored key and specified stateroot. 562 func (c *Client) GetStorageByHashHistoric(root util.Uint256, hash util.Uint160, key []byte) ([]byte, error) { 563 return c.getStorageHistoric([]any{root.StringLE(), hash.StringLE(), key}) 564 } 565 566 func (c *Client) getStorageHistoric(params []any) ([]byte, error) { 567 var resp []byte 568 if err := c.performRequest("getstoragehistoric", params, &resp); err != nil { 569 return nil, err 570 } 571 return resp, nil 572 } 573 574 // FindStorageByHash returns contract storage items by the given contract hash and prefix. 575 // If `start` index is specified, items starting from `start` index are being returned 576 // (including item located at the start index). 577 func (c *Client) FindStorageByHash(contractHash util.Uint160, prefix []byte, start *int) (result.FindStorage, error) { 578 var params = []any{contractHash.StringLE(), prefix} 579 if start != nil { 580 params = append(params, *start) 581 } else { 582 // C# node expects `start` parameter in any case. 583 params = append(params, 0) 584 } 585 return c.findStorage(params) 586 } 587 588 // FindStorageByID returns contract storage items by the given contract ID and prefix. 589 // If `start` index is specified, items starting from `start` index are being returned 590 // (including item located at the start index). 591 func (c *Client) FindStorageByID(contractID int32, prefix []byte, start *int) (result.FindStorage, error) { 592 var params = []any{contractID, prefix} 593 if start != nil { 594 params = append(params, *start) 595 } else { 596 // C# node expects `start` parameter in any case. 597 params = append(params, 0) 598 } 599 return c.findStorage(params) 600 } 601 602 func (c *Client) findStorage(params []any) (result.FindStorage, error) { 603 var resp result.FindStorage 604 if err := c.performRequest("findstorage", params, &resp); err != nil { 605 return resp, err 606 } 607 return resp, nil 608 } 609 610 // FindStorageByHashHistoric returns historical contract storage items by the given stateroot, 611 // historical contract hash and historical prefix. If `start` index is specified, then items 612 // starting from `start` index are being returned (including item located at the start index). 613 func (c *Client) FindStorageByHashHistoric(stateroot util.Uint256, historicalContractHash util.Uint160, historicalPrefix []byte, 614 start *int) (result.FindStorage, error) { 615 if historicalPrefix == nil { 616 historicalPrefix = []byte{} 617 } 618 var params = []any{stateroot.StringLE(), historicalContractHash.StringLE(), historicalPrefix} 619 if start != nil { 620 params = append(params, start) 621 } 622 return c.findStorageHistoric(params) 623 } 624 625 // FindStorageByIDHistoric returns historical contract storage items by the given stateroot, 626 // historical contract ID and historical prefix. If `start` index is specified, then items 627 // starting from `start` index are being returned (including item located at the start index). 628 func (c *Client) FindStorageByIDHistoric(stateroot util.Uint256, historicalContractID int32, historicalPrefix []byte, 629 start *int) (result.FindStorage, error) { 630 if historicalPrefix == nil { 631 historicalPrefix = []byte{} 632 } 633 var params = []any{stateroot.StringLE(), historicalContractID, historicalPrefix} 634 if start != nil { 635 params = append(params, start) 636 } 637 return c.findStorageHistoric(params) 638 } 639 640 func (c *Client) findStorageHistoric(params []any) (result.FindStorage, error) { 641 var resp result.FindStorage 642 if err := c.performRequest("findstoragehistoric", params, &resp); err != nil { 643 return resp, err 644 } 645 return resp, nil 646 } 647 648 // GetTransactionHeight returns the block index where the transaction is found. 649 func (c *Client) GetTransactionHeight(hash util.Uint256) (uint32, error) { 650 var ( 651 params = []any{hash.StringLE()} 652 resp uint32 653 ) 654 if err := c.performRequest("gettransactionheight", params, &resp); err != nil { 655 return resp, err 656 } 657 return resp, nil 658 } 659 660 // GetUnclaimedGas returns the unclaimed GAS amount for the specified address. 661 func (c *Client) GetUnclaimedGas(address string) (result.UnclaimedGas, error) { 662 var ( 663 params = []any{address} 664 resp result.UnclaimedGas 665 ) 666 if err := c.performRequest("getunclaimedgas", params, &resp); err != nil { 667 return resp, err 668 } 669 return resp, nil 670 } 671 672 // GetCandidates returns the current list of NEO candidate node with voting data and 673 // validator status. 674 func (c *Client) GetCandidates() ([]result.Candidate, error) { 675 var resp = new([]result.Candidate) 676 677 if err := c.performRequest("getcandidates", nil, resp); err != nil { 678 return nil, err 679 } 680 return *resp, nil 681 } 682 683 // GetNextBlockValidators returns the current NEO consensus nodes information and voting data. 684 func (c *Client) GetNextBlockValidators() ([]result.Validator, error) { 685 var resp = new([]result.Validator) 686 687 if err := c.performRequest("getnextblockvalidators", nil, resp); err != nil { 688 return nil, err 689 } 690 return *resp, nil 691 } 692 693 // GetVersion returns the version information about the queried node. 694 func (c *Client) GetVersion() (*result.Version, error) { 695 var resp = &result.Version{} 696 697 if err := c.performRequest("getversion", nil, resp); err != nil { 698 return nil, err 699 } 700 return resp, nil 701 } 702 703 // InvokeScript returns the result of the given script after running it true the VM. 704 // NOTE: This is a test invoke and will not affect the blockchain. 705 func (c *Client) InvokeScript(script []byte, signers []transaction.Signer) (*result.Invoke, error) { 706 var p = []any{script} 707 return c.invokeSomething("invokescript", p, signers) 708 } 709 710 // InvokeScriptAtHeight returns the result of the given script after running it 711 // true the VM using the provided chain state retrieved from the specified chain 712 // height. 713 // NOTE: This is a test invoke and will not affect the blockchain. 714 func (c *Client) InvokeScriptAtHeight(height uint32, script []byte, signers []transaction.Signer) (*result.Invoke, error) { 715 var p = []any{height, script} 716 return c.invokeSomething("invokescripthistoric", p, signers) 717 } 718 719 // InvokeScriptWithState returns the result of the given script after running it 720 // true the VM using the provided chain state retrieved from the specified 721 // state root or block hash. 722 // NOTE: This is a test invoke and will not affect the blockchain. 723 func (c *Client) InvokeScriptWithState(stateOrBlock util.Uint256, script []byte, signers []transaction.Signer) (*result.Invoke, error) { 724 var p = []any{stateOrBlock.StringLE(), script} 725 return c.invokeSomething("invokescripthistoric", p, signers) 726 } 727 728 // InvokeFunction returns the results after calling the smart contract scripthash 729 // with the given operation and parameters. 730 // NOTE: this is test invoke and will not affect the blockchain. 731 func (c *Client) InvokeFunction(contract util.Uint160, operation string, params []smartcontract.Parameter, signers []transaction.Signer) (*result.Invoke, error) { 732 var p = []any{contract.StringLE(), operation, params} 733 return c.invokeSomething("invokefunction", p, signers) 734 } 735 736 // InvokeFunctionAtHeight returns the results after calling the smart contract 737 // with the given operation and parameters at the given blockchain state 738 // specified by the blockchain height. 739 // NOTE: this is test invoke and will not affect the blockchain. 740 func (c *Client) InvokeFunctionAtHeight(height uint32, contract util.Uint160, operation string, params []smartcontract.Parameter, signers []transaction.Signer) (*result.Invoke, error) { 741 var p = []any{height, contract.StringLE(), operation, params} 742 return c.invokeSomething("invokefunctionhistoric", p, signers) 743 } 744 745 // InvokeFunctionWithState returns the results after calling the smart contract 746 // with the given operation and parameters at the given blockchain state defined 747 // by the specified state root or block hash. 748 // NOTE: this is test invoke and will not affect the blockchain. 749 func (c *Client) InvokeFunctionWithState(stateOrBlock util.Uint256, contract util.Uint160, operation string, params []smartcontract.Parameter, signers []transaction.Signer) (*result.Invoke, error) { 750 var p = []any{stateOrBlock.StringLE(), contract.StringLE(), operation, params} 751 return c.invokeSomething("invokefunctionhistoric", p, signers) 752 } 753 754 // InvokeContractVerify returns the results after calling `verify` method of the smart contract 755 // with the given parameters under verification trigger type. 756 // NOTE: this is test invoke and will not affect the blockchain. 757 func (c *Client) InvokeContractVerify(contract util.Uint160, params []smartcontract.Parameter, signers []transaction.Signer, witnesses ...transaction.Witness) (*result.Invoke, error) { 758 var p = []any{contract.StringLE(), params} 759 return c.invokeSomething("invokecontractverify", p, signers, witnesses...) 760 } 761 762 // InvokeContractVerifyAtHeight returns the results after calling `verify` method 763 // of the smart contract with the given parameters under verification trigger type 764 // at the blockchain state specified by the blockchain height. 765 // NOTE: this is test invoke and will not affect the blockchain. 766 func (c *Client) InvokeContractVerifyAtHeight(height uint32, contract util.Uint160, params []smartcontract.Parameter, signers []transaction.Signer, witnesses ...transaction.Witness) (*result.Invoke, error) { 767 var p = []any{height, contract.StringLE(), params} 768 return c.invokeSomething("invokecontractverifyhistoric", p, signers, witnesses...) 769 } 770 771 // InvokeContractVerifyWithState returns the results after calling `verify` method 772 // of the smart contract with the given parameters under verification trigger type 773 // at the blockchain state specified by the state root or block hash. 774 // NOTE: this is test invoke and will not affect the blockchain. 775 func (c *Client) InvokeContractVerifyWithState(stateOrBlock util.Uint256, contract util.Uint160, params []smartcontract.Parameter, signers []transaction.Signer, witnesses ...transaction.Witness) (*result.Invoke, error) { 776 var p = []any{stateOrBlock.StringLE(), contract.StringLE(), params} 777 return c.invokeSomething("invokecontractverifyhistoric", p, signers, witnesses...) 778 } 779 780 // invokeSomething is an inner wrapper for Invoke* functions. 781 func (c *Client) invokeSomething(method string, p []any, signers []transaction.Signer, witnesses ...transaction.Witness) (*result.Invoke, error) { 782 var resp = new(result.Invoke) 783 if signers != nil { 784 if witnesses == nil { 785 p = append(p, signers) 786 } else { 787 if len(witnesses) != len(signers) { 788 return nil, fmt.Errorf("number of witnesses should match number of signers, got %d vs %d", len(witnesses), len(signers)) 789 } 790 signersWithWitnesses := make([]neorpc.SignerWithWitness, len(signers)) 791 for i := range signersWithWitnesses { 792 signersWithWitnesses[i] = neorpc.SignerWithWitness{ 793 Signer: signers[i], 794 Witness: witnesses[i], 795 } 796 } 797 p = append(p, signersWithWitnesses) 798 } 799 } 800 if err := c.performRequest(method, p, resp); err != nil { 801 return nil, err 802 } 803 return resp, nil 804 } 805 806 // SendRawTransaction broadcasts the given transaction to the Neo network. 807 // It always returns transaction hash, when successful (no error) this is the 808 // hash returned from server, when not it's a locally calculated rawTX hash. 809 func (c *Client) SendRawTransaction(rawTX *transaction.Transaction) (util.Uint256, error) { 810 var ( 811 params = []any{rawTX.Bytes()} 812 resp = new(result.RelayResult) 813 ) 814 if err := c.performRequest("sendrawtransaction", params, resp); err != nil { 815 return rawTX.Hash(), err 816 } 817 return resp.Hash, nil 818 } 819 820 // SubmitBlock broadcasts a raw block over the NEO network. 821 func (c *Client) SubmitBlock(b block.Block) (util.Uint256, error) { 822 var ( 823 params []any 824 resp = new(result.RelayResult) 825 ) 826 buf := io.NewBufBinWriter() 827 b.EncodeBinary(buf.BinWriter) 828 if err := buf.Err; err != nil { 829 return util.Uint256{}, err 830 } 831 params = []any{buf.Bytes()} 832 833 if err := c.performRequest("submitblock", params, resp); err != nil { 834 return util.Uint256{}, err 835 } 836 return resp.Hash, nil 837 } 838 839 // SubmitRawOracleResponse submits a raw oracle response to the oracle node. 840 // Raw params are used to avoid excessive marshalling. 841 func (c *Client) SubmitRawOracleResponse(ps []any) error { 842 return c.performRequest("submitoracleresponse", ps, new(result.RelayResult)) 843 } 844 845 // SubmitP2PNotaryRequest submits given P2PNotaryRequest payload to the RPC node. 846 // It returns fallback transaction hash. 847 func (c *Client) SubmitP2PNotaryRequest(req *payload.P2PNotaryRequest) (util.Uint256, error) { 848 var resp = new(result.RelayResult) 849 bytes, err := req.Bytes() 850 if err != nil { 851 return util.Uint256{}, fmt.Errorf("failed to encode request: %w", err) 852 } 853 params := []any{bytes} 854 if err := c.performRequest("submitnotaryrequest", params, resp); err != nil { 855 return util.Uint256{}, err 856 } 857 return resp.Hash, nil 858 } 859 860 // ValidateAddress verifies that the address is a correct NEO address. 861 // Consider using [address] package instead to do it locally. 862 func (c *Client) ValidateAddress(address string) error { 863 var ( 864 params = []any{address} 865 resp = &result.ValidateAddress{} 866 ) 867 868 if err := c.performRequest("validateaddress", params, resp); err != nil { 869 return err 870 } 871 if !resp.IsValid { 872 return errors.New("validateaddress returned false") 873 } 874 return nil 875 } 876 877 // stateRootInHeader returns true if the state root is contained in the block header. 878 // Requires Init() before use. 879 func (c *Client) stateRootInHeader() (bool, error) { 880 c.cacheLock.RLock() 881 defer c.cacheLock.RUnlock() 882 883 if !c.cache.initDone { 884 return false, errNetworkNotInitialized 885 } 886 return c.cache.stateRootInHeader, nil 887 } 888 889 // TraverseIterator returns a set of iterator values (maxItemsCount at max) for 890 // the specified iterator and session. If result contains no elements, then either 891 // Iterator has no elements or session was expired and terminated by the server. 892 // If maxItemsCount is non-positive, then config.DefaultMaxIteratorResultItems 893 // iterator values will be returned using single `traverseiterator` call. 894 // Note that iterator session lifetime is restricted by the RPC-server 895 // configuration and is being reset each time iterator is accessed. If session 896 // won't be accessed within session expiration time, then it will be terminated 897 // by the RPC-server automatically. 898 func (c *Client) TraverseIterator(sessionID, iteratorID uuid.UUID, maxItemsCount int) ([]stackitem.Item, error) { 899 if maxItemsCount <= 0 { 900 maxItemsCount = config.DefaultMaxIteratorResultItems 901 } 902 var ( 903 params = []any{sessionID.String(), iteratorID.String(), maxItemsCount} 904 resp []json.RawMessage 905 ) 906 if err := c.performRequest("traverseiterator", params, &resp); err != nil { 907 return nil, err 908 } 909 result := make([]stackitem.Item, len(resp)) 910 for i, iBytes := range resp { 911 itm, err := stackitem.FromJSONWithTypes(iBytes) 912 if err != nil { 913 return nil, fmt.Errorf("failed to unmarshal %d-th iterator value: %w", i, err) 914 } 915 result[i] = itm 916 } 917 918 return result, nil 919 } 920 921 // TerminateSession tries to terminate the specified session and returns `true` iff 922 // the specified session was found on server. 923 func (c *Client) TerminateSession(sessionID uuid.UUID) (bool, error) { 924 var resp bool 925 params := []any{sessionID.String()} 926 if err := c.performRequest("terminatesession", params, &resp); err != nil { 927 return false, err 928 } 929 930 return resp, nil 931 } 932 933 // GetRawNotaryTransaction returns main or fallback transaction from the 934 // RPC node's notary request pool. 935 func (c *Client) GetRawNotaryTransaction(hash util.Uint256) (*transaction.Transaction, error) { 936 var ( 937 params = []any{hash.StringLE()} 938 resp []byte 939 err error 940 ) 941 if err = c.performRequest("getrawnotarytransaction", params, &resp); err != nil { 942 return nil, err 943 } 944 return transaction.NewTransactionFromBytes(resp) 945 } 946 947 // GetRawNotaryTransactionVerbose returns main or fallback transaction from the 948 // RPC node's notary request pool. 949 // NOTE: to get transaction.ID and transaction.Size, use t.Hash() and 950 // io.GetVarSize(t) respectively. 951 func (c *Client) GetRawNotaryTransactionVerbose(hash util.Uint256) (*transaction.Transaction, error) { 952 var ( 953 params = []any{hash.StringLE(), 1} // 1 for verbose. 954 resp = &transaction.Transaction{} 955 err error 956 ) 957 if err = c.performRequest("getrawnotarytransaction", params, resp); err != nil { 958 return nil, err 959 } 960 return resp, nil 961 } 962 963 // GetRawNotaryPool returns hashes of main P2PNotaryRequest transactions that 964 // are currently in the RPC node's notary request pool with the corresponding 965 // hashes of fallback transactions. 966 func (c *Client) GetRawNotaryPool() (*result.RawNotaryPool, error) { 967 resp := &result.RawNotaryPool{} 968 if err := c.performRequest("getrawnotarypool", nil, resp); err != nil { 969 return nil, err 970 } 971 return resp, nil 972 }