Skip to content

Commit

Permalink
Async methods to RPCClient
Browse files Browse the repository at this point in the history
  • Loading branch information
NicolasDorier committed Nov 3, 2014
1 parent f64d16d commit 8d0c69c
Show file tree
Hide file tree
Showing 2 changed files with 123 additions and 6 deletions.
9 changes: 9 additions & 0 deletions NBitcoin.Tests/RPCClientTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,15 @@ public void CanGetRawMemPool()
var ids = rpc.GetRawMempool();
}

[Fact]
[Trait("RPCClient", "RPCClient")]
public void CanUseAsyncRPC()
{
var rpc = CreateRPCClient();
var blkCount = rpc.GetBlockCountAsync().Result;
Assert.True(blkCount != 0);
}

[Fact]
[Trait("RPCClient", "RPCClient")]
public void CanGetBestBlockHash()
Expand Down
120 changes: 114 additions & 6 deletions NBitcoin/RPC/RPCClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.IO;
using System.Linq;
using System.Net;
using System.Runtime.ExceptionServices;
using System.Text;
using System.Threading.Tasks;

Expand Down Expand Up @@ -72,6 +73,10 @@ public RPCResponse SendCommand(RPCOperations commandName, params object[] parame
{
return SendCommand(commandName.ToString(), parameters);
}
public Task<RPCResponse> SendCommandAsync(RPCOperations commandName, params object[] parameters)
{
return SendCommandAsync(commandName.ToString(), parameters);
}

/// <summary>
/// Send a command
Expand All @@ -83,10 +88,25 @@ public RPCResponse SendCommand(string commandName, params object[] parameters)
{
return SendCommand(new RPCRequest(commandName, parameters));
}


public Task<RPCResponse> SendCommandAsync(string commandName, params object[] parameters)
{
return SendCommandAsync(new RPCRequest(commandName, parameters));
}

public RPCResponse SendCommand(RPCRequest request, bool throwIfRPCError = true)
{
try
{
return SendCommandAsync(request, throwIfRPCError).Result;
}
catch(AggregateException aex)
{
ExceptionDispatchInfo.Capture(aex.InnerException).Throw();
return null; //Can't happen
}
}

public async Task<RPCResponse> SendCommandAsync(RPCRequest request, bool throwIfRPCError = true)
{
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(Address);
webRequest.Credentials = Credentials;
Expand All @@ -99,14 +119,13 @@ public RPCResponse SendCommand(RPCRequest request, bool throwIfRPCError = true)
var json = writer.ToString();
var bytes = Encoding.UTF8.GetBytes(json);
webRequest.ContentLength = bytes.Length;
Stream dataStream = webRequest.GetRequestStream();
Stream dataStream = await webRequest.GetRequestStreamAsync().ConfigureAwait(false);
dataStream.Write(bytes, 0, bytes.Length);
dataStream.Close();

RPCResponse response = null;
try
{
WebResponse webResponse = webRequest.GetResponse();
WebResponse webResponse = await webRequest.GetResponseAsync().ConfigureAwait(false);
response = RPCResponse.Load(webResponse.GetResponseStream());
if(throwIfRPCError)
response.ThrowIfError();
Expand All @@ -127,29 +146,53 @@ public UnspentCoin[] ListUnspent()
var response = SendCommand("listunspent");
return ((JArray)response.Result).Select(i => new UnspentCoin((JObject)i)).ToArray();
}
public async Task<UnspentCoin[]> ListUnspentAsync()
{
var response = await SendCommandAsync("listunspent");
return ((JArray)response.Result).Select(i => new UnspentCoin((JObject)i)).ToArray();
}

public BitcoinAddress GetAccountAddress(string account)
{
var response = SendCommand("getaccountaddress", account);
return Network.CreateFromBase58Data<BitcoinAddress>((string)response.Result);
}
public async Task<BitcoinAddress> GetAccountAddressAsync(string account)
{
var response = await SendCommandAsync("getaccountaddress", account);
return Network.CreateFromBase58Data<BitcoinAddress>((string)response.Result);
}

public BitcoinSecret DumpPrivKey(BitcoinAddress address)
{
var response = SendCommand("dumpprivkey", address.ToString());
return Network.CreateFromBase58Data<BitcoinSecret>((string)response.Result);
}
public async Task<BitcoinSecret> DumpPrivKeyAsync(BitcoinAddress address)
{
var response = await SendCommandAsync("dumpprivkey", address.ToString());
return Network.CreateFromBase58Data<BitcoinSecret>((string)response.Result);
}

public uint256 GetBestBlockHash()
{
return new uint256((string)SendCommand("getbestblockhash").Result);
}
public async Task<uint256> GetBestBlockHashAsync()
{
return new uint256((string)(await SendCommandAsync("getbestblockhash")).Result);
}

public BitcoinSecret GetAccountSecret(string account)
{
var address = GetAccountAddress(account);
return DumpPrivKey(address);
}
public async Task<BitcoinSecret> GetAccountSecretAsync(string account)
{
var address = await GetAccountAddressAsync(account);
return await DumpPrivKeyAsync(address);
}

public Transaction DecodeRawTransaction(string rawHex)
{
Expand All @@ -160,6 +203,15 @@ public Transaction DecodeRawTransaction(byte[] raw)
{
return DecodeRawTransaction(Encoders.Hex.EncodeData(raw));
}
public async Task<Transaction> DecodeRawTransactionAsync(string rawHex)
{
var response = await SendCommandAsync("decoderawtransaction", rawHex);
return Transaction.Parse(response.Result.ToString(), RawFormat.Satoshi);
}
public Task<Transaction> DecodeRawTransactionAsync(byte[] raw)
{
return DecodeRawTransactionAsync(Encoders.Hex.EncodeData(raw));
}

/// <summary>
/// getrawtransaction only returns on txn which are not entirely spent unless you run bitcoinq with txindex=1.
Expand Down Expand Up @@ -189,6 +241,14 @@ public void SendRawTransaction(Transaction tx)
{
SendRawTransaction(tx.ToBytes());
}
public Task SendRawTransactionAsync(byte[] bytes)
{
return SendCommandAsync("sendrawtransaction", Encoders.Hex.EncodeData(bytes));
}
public Task SendRawTransactionAsync(Transaction tx)
{
return SendRawTransactionAsync(tx.ToBytes());
}

public void LockUnspent(params OutPoint[] outpoints)
{
Expand All @@ -199,7 +259,28 @@ public void UnlockUnspent(params OutPoint[] outpoints)
LockUnspentCore(true, outpoints);
}

public Task LockUnspentAsync(params OutPoint[] outpoints)
{
return LockUnspentCoreAsync(false, outpoints);
}
public Task UnlockUnspentAsync(params OutPoint[] outpoints)
{
return LockUnspentCoreAsync(true, outpoints);
}

private void LockUnspentCore(bool unlock, OutPoint[] outpoints)
{
try
{
LockUnspentCoreAsync(unlock, outpoints).Wait();
}
catch(AggregateException ex)
{
ExceptionDispatchInfo.Capture(ex.InnerException).Throw();
return;
}
}
private async Task LockUnspentCoreAsync(bool unlock, OutPoint[] outpoints)
{
if(outpoints == null || outpoints.Length == 0)
return;
Expand All @@ -214,14 +295,19 @@ private void LockUnspentCore(bool unlock, OutPoint[] outpoints)
obj["vout"] = outp.N;
array.Add(obj);
}
SendCommand("lockunspent", parameters.ToArray());
await SendCommandAsync("lockunspent", parameters.ToArray());
}

public BlockHeader GetBlockHeader(int height)
{
var hash = GetBlockHash(height);
return GetBlockHeader(hash);
}
public async Task<BlockHeader> GetBlockHeaderAsync(int height)
{
var hash = await GetBlockHashAsync(height);
return await GetBlockHeaderAsync(hash);
}

/// <summary>
/// Get the a whole block, will fail if bitcoinq does not run with txindex=1 and one of the transaction of the block is entirely spent
Expand Down Expand Up @@ -255,6 +341,11 @@ public BlockHeader GetBlockHeader(uint256 blockHash)
var resp = SendCommand("getblock", blockHash.ToString());
return ParseBlockHeader(resp);
}
public async Task<BlockHeader> GetBlockHeaderAsync(uint256 blockHash)
{
var resp = await SendCommandAsync("getblock", blockHash.ToString());
return ParseBlockHeader(resp);
}

private BlockHeader ParseBlockHeader(RPCResponse resp)
{
Expand Down Expand Up @@ -313,16 +404,33 @@ public uint256 GetBlockHash(int height)
return new uint256(resp.Result.ToString());
}

public async Task<uint256> GetBlockHashAsync(int height)
{
var resp = await SendCommandAsync("getblockhash", height);
return new uint256(resp.Result.ToString());
}


public int GetBlockCount()
{
return (int)SendCommand("getblockcount").Result;
}
public async Task<int> GetBlockCountAsync()
{
return (int)(await SendCommandAsync("getblockcount")).Result;
}

public uint256[] GetRawMempool()
{
var result = SendCommand("getrawmempool");
var array = (JArray)result.Result;
return array.Select(o => (string)o).Select(s => new uint256(s)).ToArray();
}
public async Task<uint256[]> GetRawMempoolAsync()
{
var result = await SendCommandAsync("getrawmempool");
var array = (JArray)result.Result;
return array.Select(o => (string)o).Select(s => new uint256(s)).ToArray();
}
}
}

0 comments on commit 8d0c69c

Please sign in to comment.