RPC 调用方法
RpcClient
封装了所有 RpcServer
提供的接口,可以通过该模块中提供的标准方法在代码中发送 RPC 请求,只需要传入相应的参数,SDK 就会根据参数构造相应的 JSON-RPC 请求,进而获得节点返回的数据。
初始化
发送 RPC 请求需要先初始化 RpcClient
类型,可以根据自己的需要选择一个 Neo 节点的 RPC Server 端口,这里举例说明:
测试网节点:
// TestNet Node
RpcClient client = new RpcClient(new Uri("http://seed1.neo.org:20332"), null, null, ProtocolSettings.Load("config.json"));
本地节点(本地节点是本地维护的 Neo-CLI,可以根据配置连接主网,测试网或者私链):
// Local Node
RpcClient client = new RpcClient(new Uri("http://localhost:20332"), null, null, ProtocolSettings.Load("config.json"));
一个应用程序中一般只需要初始化一个
RpcClient
实例,而不需要在每个方法中初始化。
区块链数据
获取最新区块哈希
获取区块链中高度最大的区块的哈希:
string hexString = await client.GetBestBlockHashAsync().ConfigureAwait(false);
byte[] hashBytes = hexString.HexToBytes();
UInt256 hash256 = UInt256.Parse(hexString);
获取区块完整信息
可以通过区块散列值或者区块索引获取具体的区块信息:
RpcBlock rpcBlock = await client.GetBlockAsync("773dd2dae4a9c9275290f89b56e67d7363ea4826dfd4fc13cc01cf73a44b0d0e").ConfigureAwait(false);
Block block = rpcBlock.Block;
或者
RpcBlock rpcBlock = await client.GetBlockAsync("1024").ConfigureAwait(false);
Block block = rpcBlock.Block;
也可以通过区块散列值或者区块索引获取序列化后的区块信息:
string serializedBlock = await client.GetBlockHexAsync("773dd2dae4a9c9275290f89b56e67d7363ea4826dfd4fc13cc01cf73a44b0d0e").ConfigureAwait(false);
获取当前区块数量
区块索引(Index) = 区块高度(Height) = 区块数量(Count) - 1
uint blockCount = await client.GetBlockCountAsync().ConfigureAwait(false);
根据区块索引获取区块的散列:
string hexString = await client.GetBlockHashAsync(10000).ConfigureAwait(false);
byte[] hashBytes = hexString.HexToBytes();
UInt256 hash256 = UInt256.Parse(hexString);
获取区块头信息
可以通过区块散列值或者区块索引获取具体的区块头信息:
RpcBlockHeader blockHeader = await client.GetBlockHeaderAsync("a5508c9b6ed0fc09a531a62bc0b3efcb6b8a9250abaf72ab8e9591294c1f6957").ConfigureAwait(false);
Header header = blockHeader.Header;
或者
RpcBlockHeader blockHeader = await client.GetBlockHeaderAsync("10000").ConfigureAwait(false);
Header header = blockHeader.Header;
也可以通过区块散列值或者区块索引获取序列化后的区块头信息:
string serializedBlockHeader = await client.GetBlockHeaderHexAsync("a5508c9b6ed0fc09a531a62bc0b3efcb6b8a9250abaf72ab8e9591294c1f6957").ConfigureAwait(false);
或者
string serializedBlockHeader = await client.GetBlockHeaderHexAsync("10000").ConfigureAwait(false);
获取合约信息
通过合约哈希获取合约信息:
ContractState contractState = await client.GetContractStateAsync("dc675afc61a7c0f7b3d2682bf6e1d8ed865a0e5f").ConfigureAwait(false);
获取内存中的交易列表
只获取内存中已确认的交易散列列表:
string[] verifiedTransactions = await client.GetRawMempoolAsync().ConfigureAwait(false);
同时获取内存中已确认和未确认的交易散列列表:
RpcRawMemPool memPool = await client.GetRawMempoolBothAsync().ConfigureAwait(false);
string[] verifiedTransactions = memPool.Verified;
string[] unverifiedTransactions = memPool.UnVerified;
获取交易信息
通过交易哈希来获取对应的交易信息:
RpcTransaction rpcTransaction = await client.GetRawTransactionAsync("f4250dab094c38d8265acc15c366dc508d2e14bf5699e12d9df26577ed74d657").ConfigureAwait(false);
Transaction transaction = rpcTransaction.Transaction;
也可以通过交易哈希来获取对应的序列化后的交易:
string serializedTransaction = await client.GetRawTransactionHexAsync("f4250dab094c38d8265acc15c366dc508d2e14bf5699e12d9df26577ed74d657").ConfigureAwait(false);
计算交易网络费
计算指定交易的网络费用 `c# long networkFee = await rpcClient.CalculateNetworkFeeAsync(transaction).ConfigureAwait(false);
`
获取合约存储区的值
通过合约脚本散列和存储的 键
(需要转化为 hex string)获取对应存储的值:
string value = await client.GetStorageAsync("03febccf81ac85e3d795bc5cbd4e84e907812aa3", "5065746572").ConfigureAwait(false);
获取指定交易的高度
通过交易哈希获取指定交易所在的区块高度:
uint height = await client.GetTransactionHeightAsync("f4250dab094c38d8265acc15c366dc508d2e14bf5699e12d9df26577ed74d657").ConfigureAwait(false);
获取下一轮共识节点的信息
获取网络中下一轮共识节点的信息及投票情况:
RpcValidator[] rpcValidators = await client.GetNextBlockValidatorsAsync().ConfigureAwait(false);
foreach (var validator in rpcValidators)
{
string publicKey = validator.PublicKey;
BigInteger voteCount = validator.Votes;
bool isActive = validator.Active;
}
获取当前委员会成员
获取网络中当前委员会成员公钥列表
string[] committees = await client.GetCommitteeAsync().ConfigureAwait(false);
节点
获取节点连接数
获取连接到该节点的节点数量:
int connectionCount = await client.GetConnectionCountAsync().ConfigureAwait(false);
获取已连接/未连接的节点
获得该节点当前已连接/未连接的节点列表,包括 IP 地址和端口:
RpcPeers rpcPeers = await client.GetPeersAsync().ConfigureAwait(false);;
RpcPeer[] connected = rpcPeers.Connected;
RpcPeer[] unconnected = rpcPeers.Unconnected;
if (connected.Length > 0)
{
RpcPeer peer = connected[1];
string address = peer.Address;
int port = peer.Port;
}
获取节点的版本信息
获取接收 RPC 请求的节点的版本信息:
RpcVersion rpcVersion = await client.GetVersionAsync().ConfigureAwait(false);
string version = rpcVersion.UserAgent;
广播交易
发送并广播序列化后的交易:
UInt256 txHash = await client.SendRawTransactionAsync("80000001195876cb34364dc38b730077156c6bc3a7fc570044a66fbfeeea56f71327e8ab0000029b7cffdaa674beae0f930ebe6085af9093e5fe56b34a5c220ccdcf6efc336fc500c65eaf440000000f9a23e06f74cf86b8827a9108ec2e0f89ad956c9b7cffdaa674beae0f930ebe6085af9093e5fe56b34a5c220ccdcf6efc336fc50092e14b5e00000030aab52ad93f6ce17ca07fa88fc191828c58cb71014140915467ecd359684b2dc358024ca750609591aa731a0b309c7fb3cab5cd0836ad3992aa0a24da431f43b68883ea5651d548feb6bd3c8e16376e6e426f91f84c58232103322f35c7819267e721335948d385fae5be66e7ba8c748ac15467dcca0693692dac".HexToBytes()).ConfigureAwait(false);
或者将交易对象tx在网络中进行广播:
UInt256 txHash = await client.SendRawTransactionAsync(transaction).ConfigureAwait(false);
广播区块
发送并广播序列化后的区块:
UInt256 blockHash = await client.SubmitBlockAsync("000000000000000000000000000000000000000000000000000000000000000000000000845c34e7c1aed302b1718e914da0c42bf47c476ac4d89671f278d8ab6d27aa3d65fc8857000000001dac2b7c00000000be48d3a3f5d10013ab9ffee489706078714f1ea2010001510400001dac2b7c00000000400000455b7b226c616e67223a227a682d434e222c226e616d65223a22e5b08fe89a81e882a1227d2c7b226c616e67223a22656e222c226e616d65223a22416e745368617265227d5d0000c16ff28623000000da1745e9b549bd0bfa1a569971c77eba30cd5a4b00000000400001445b7b226c616e67223a227a682d434e222c226e616d65223a22e5b08fe89a81e5b881227d2c7b226c616e67223a22656e222c226e616d65223a22416e74436f696e227d5d0000c16ff286230008009f7fd096d37ed2c0e3f7f0cfc924beef4ffceb680000000001000000019b7cffdaa674beae0f930ebe6085af9093e5fe56b34a5c220ccdcf6efc336fc50000c16ff2862300be48d3a3f5d10013ab9ffee489706078714f1ea201000151".HexToBytes()).ConfigureAwait(false);
智能合约
调用智能合约的特定方法
通过指定的智能合约脚本散列、方法名和参数在虚拟机中运行后返回结果:
string contractHash = "0xd2a4cff31913016155e38e474a2c06d08be276cf";
string method = "transfer";
RpcStack from = new RpcStack()
{
Type = "Hash160",
Value = "0x262678399f390ee9f0cfd9ac8c65df8c149b4e9c"
};
RpcStack to = new RpcStack()
{
Type = "Hash160",
Value = "0x753b9b069ef88dea7323a0f1ba6cb24486584f05"
};
RpcStack amount = new RpcStack()
{
Type = "Integer",
Value = "120000000"
};
RpcStack data = new RpcStack()
{
Type = "String",
Value = "my data"
};
Signer signer0 = new Signer()
{
Account = UInt160.Parse("0x262678399f390ee9f0cfd9ac8c65df8c149b4e9c")
};
RpcInvokeResult rpcInvokeResult = await _rpcClient.InvokeFunctionAsync(contractHash, method, new RpcStack[] { from, to, amount, data }, signer0).ConfigureAwait(false);
string script = rpcInvokeResult.Script;
var engineState = rpcInvokeResult.State;
long gasConsumed = rpcInvokeResult.GasConsumed;
调用指定脚本
通过在虚拟机中运行指定脚本后返回结果:
byte[] script = "00046e616d656724058e5e1b6008847cd662728549088a9ee82191".HexToBytes();
RpcInvokeResult rpcInvokeResult = await client.InvokeScriptAsync(script).ConfigureAwait(false);
获取未领取的Gas
获取指定地址未领取的Gas数量:
RpcUnclaimedGas unclaimedGas = await client.GetUnclaimedGasAsync("NXsG3zwpwcfvBiA3bNMx6mWZGEro9ZqTqM").ConfigureAwait(false);
BigInteger unclaimed = unclaimedGas.Unclaimed;
string address = unclaimedGas.Address;
工具
获取插件信息
显示节点已加载的插件列表:
RpcPlugin[] rpcPlugins = await client.ListPluginsAsync().ConfigureAwait(false);
foreach (var item in rpcPlugins)
{
string name = item.Name;
string version = item.Version;
}
验证地址
验证指定地址是否是正确的 Neo 地址:
RpcValidateAddressResult result = await client.ValidateAddressAsync("AQVh2pG732YvtNaxEGkQUei3YA4cvo7d2i").ConfigureAwait(false);
string address = result.Address;
bool isValid = result.IsValid;
节点本地钱包
节点本地钱包接口包含可以访问节点本地钱包文件的功能,使用该部分的方法之前需要先通过 openwallet
方法打开钱包。
节点的配置文件默认禁用此方法,因为有很高的安全风险。
打开钱包
打开节点所在机器中的钱包文件:
string path = "D:/temp/123.json";
string password = "Password***";
bool result = await client.OpenWalletAsync(path, password).ConfigureAwait(false);
关闭钱包
关闭钱包将清除内存中的钱包信息:
bool result = await client.CloseWalletAsync().ConfigureAwait(false);
导出私钥
导出指定地址的私钥:
string wif = await client.DumpPrivKeyAsync("NVVwFw6XyhtRCFQ8SpUTMdPyYt4Vd9A1XQ").ConfigureAwait(false);
余额查询
根据指定的资产哈希,返回钱包中对应资产的余额信息。该方法适用于原生合约资产及符合 NEP-17 标准的合约资产:
BigDecimal balance = await client.GetWalletBalanceAsync(NativeContract.NEO.Hash.ToString()).ConfigureAwait(false);
创建账号
在打开的钱包文件中创建一个新的账号,并返回该账号的地址:
string address = await client.GetNewAddressAsync().ConfigureAwait(false);
获取可提取的 GAS 数量
显示钱包中可提取的 GAS 数量:
BigInteger amount = await client.GetWalletUnclaimedGasAsync().ConfigureAwait(false);
导入私钥
导入私钥到钱包:
string wif = "KyoYyZpoccbR6KZ25eLzhMTUxREwCpJzDsnuodGTKXSG8fDW9t7x";
RpcAccount account = await client.ImportPrivKeyAsync(wif).ConfigureAwait(false);
列出钱包账号
列出当前钱包内的所有地址:
List<RpcAccount> acoounts = await client.ListAddressAsync().ConfigureAwait(false);
从指定地址转账
从指定地址,向指定地址转账:
string assetId = NativeContract.NEO.Hash.ToString();
string fromAddress = "NVVwFw6XyhtRCFQ8SpUTMdPyYt4Vd9A1XQ";
string toAddress= "NZs2zXSPuuv9ZF6TDGSWT1RBmE8rfGj7UW";
string amount = "100";
JObject result = await client.SendFromAsync(assetId, fromAddress, toAddress, amount).ConfigureAwait(false);
返回JSON交易详情说明交易发送成功,否则交易发送失败。 如果签名不完整会返回待签名的交易。 如果余额不足会返回错误信息。
批量转账
批量转账命令,并且可以指定发送地址:
List<RpcTransferOut> outs = new List<RpcTransferOut>();
outs.Add(new RpcTransferOut
{
Asset = NativeContract.NEO.Hash,
ScriptHash = Utility.GetScriptHash("NVVwFw6XyhtRCFQ8SpUTMdPyYt4Vd9A1XQ"),
Value = "100"
});
outs.Add(new RpcTransferOut
{
Asset = NativeContract.GAS.Hash,
ScriptHash = Utility.GetScriptHash("NZs2zXSPuuv9ZF6TDGSWT1RBmE8rfGj7UW"),
Value = "100.12345678"
});
JObject result = await client.SendManyAsync("", outs).ConfigureAwait(false);
返回JSON交易详情说明交易发送成功,否则交易发送失败。 如果签名不完整会返回待签名的交易。 如果余额不足会返回错误信息。
向指定地址转账
向指定地址转账:
string assetId = NativeContract.NEO.Hash.ToString();
string toAddress = "NZs2zXSPuuv9ZF6TDGSWT1RBmE8rfGj7UW";
string amount = "100";
JObject result = await client.SendToAddressAsync(assetId, toAddress, amount).ConfigureAwait(false);
返回JSON交易详情说明交易发送成功,否则交易发送失败。 如果签名不完整会返回待签名的交易。 如果余额不足会返回错误信息。
插件
查询交易日志
根据指定的交易 ID 获取合约日志: 需要节点安装 ApplicationLogs 插件才可以调用。
string txHash = "0x23bf33766d00b4bb3314185f1ff0c2c85182d4d5e4e96f7c2df7506e7f99098b";
RpcApplicationLog log = await client.GetApplicationLogAsync(txHash).ConfigureAwait(false);
或者根据指定的交易ID和触发器类型获取合约日志:
string txHash = "0x23bf33766d00b4bb3314185f1ff0c2c85182d4d5e4e96f7c2df7506e7f99098b";
RpcApplicationLog log = await client.GetApplicationLogAsync(txHash, TriggerType.Application).ConfigureAwait(false);
查询 NEP-17 资产余额
返回指定地址内的所有 NEP-17 资产余额: 需要节点安装 TokensTracker 插件才可以调用。
string address = "NVVwFw6XyhtRCFQ8SpUTMdPyYt4Vd9A1XQ";
RpcNep17Balances balances = await client.GetNep17BalancesAsync(address).ConfigureAwait(false);
查询交易记录
返回指定地址内的所有 NEP-17 交易记录: 需要节点安装 TokensTracker 插件才可以调用。 如果设置起始和结束时间戳,则返回时间戳范围内的交易信息。 如果不设置此参数,则返回近七天内的交易信息。
string address = "NVVwFw6XyhtRCFQ8SpUTMdPyYt4Vd9A1XQ";
RpcNep17Transfers transfers = await client.GetNep17TransfersAsync(address, 0).ConfigureAwait(false);