public RPCException(RPCErrorCode code, string message, RPCResponse result) : base(String.IsNullOrEmpty(message) ? FindMessage(code) : message) { _RPCCode = code; _RPCCodeMessage = FindMessage(code); _RPCResult = result; }
/// <summary> /// Send all commands in one batch /// </summary> public async Task SendBatchAsync() { Tuple <RPCRequest, TaskCompletionSource <RPCResponse> > req; List <Tuple <RPCRequest, TaskCompletionSource <RPCResponse> > > requests = new List <Tuple <RPCRequest, TaskCompletionSource <RPCResponse> > >(); var batches = _BatchedRequests; if (batches == null) { throw new InvalidOperationException("This RPCClient instance is not a batch, use PrepareBatch"); } _BatchedRequests = null; while (batches.TryDequeue(out req)) { requests.Add(req); } if (requests.Count == 0) { return; } var writer = new StringWriter(); writer.Write("["); bool first = true; foreach (var item in requests) { if (!first) { writer.Write(","); } first = false; item.Item1.WriteJSON(writer); } writer.Write("]"); writer.Flush(); var json = writer.ToString(); var bytes = Encoding.UTF8.GetBytes(json); var webRequest = CreateWebRequest(); #if !(PORTABLE || NETCORE) webRequest.ContentLength = bytes.Length; #endif int responseIndex = 0; var dataStream = await webRequest.GetRequestStreamAsync().ConfigureAwait(false); await dataStream.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false); await dataStream.FlushAsync().ConfigureAwait(false); dataStream.Dispose(); JArray response; WebResponse webResponse = null; WebResponse errorResponse = null; try { webResponse = await webRequest.GetResponseAsync().ConfigureAwait(false); response = JArray.Load(new JsonTextReader( new StreamReader( await ToMemoryStreamAsync(webResponse.GetResponseStream()).ConfigureAwait(false), Encoding.UTF8))); foreach (var jobj in response.OfType <JObject>()) { try { RPCResponse rpcResponse = new RPCResponse(jobj); requests[responseIndex].Item2.TrySetResult(rpcResponse); } catch (Exception ex) { requests[responseIndex].Item2.TrySetException(ex); } responseIndex++; } } catch (WebException ex) { if (ex.Response == null || ex.Response.ContentLength == 0) { foreach (var item in requests) { item.Item2.TrySetException(ex); } } else { errorResponse = ex.Response; try { RPCResponse rpcResponse = RPCResponse.Load(await ToMemoryStreamAsync(errorResponse.GetResponseStream()).ConfigureAwait(false)); foreach (var item in requests) { item.Item2.TrySetResult(rpcResponse); } } catch (Exception) { foreach (var item in requests) { item.Item2.TrySetException(ex); } } } } catch (Exception ex) { foreach (var item in requests) { item.Item2.TrySetException(ex); } } finally { if (errorResponse != null) { errorResponse.Dispose(); errorResponse = null; } if (webResponse != null) { webResponse.Dispose(); webResponse = null; } } }
/// <summary> /// Sign a transaction /// </summary> /// <param name="tx">The transaction to be signed</param> /// <returns>The signed transaction</returns> public async Task <Transaction> SignRawTransactionAsync(Transaction tx) { RPCResponse result = await SendCommandAsync(RPCOperations.signrawtransaction, tx.ToHex()).ConfigureAwait(false); return(new Transaction(result.Result["hex"].Value <string>())); }
/// <summary> /// Returns an array of unspent transaction outputs belonging to this wallet. /// </summary> public async Task <UnspentCoin[]> ListUnspentAsync() { RPCResponse response = await SendCommandAsync(RPCOperations.listunspent).ConfigureAwait(false); return(response.Result.Select(i => new UnspentCoin((JObject)i, this.Network)).ToArray()); }
// listunspent /// <summary> /// Returns an array of unspent transaction outputs belonging to this wallet. /// </summary> /// <remarks> /// <para> /// Note: as of Bitcoin Core 0.10.0, outputs affecting watch-only addresses will be returned; /// see the spendable field in the results. /// </para> /// </remarks> public UnspentCoin[] ListUnspent() { RPCResponse response = SendCommand(RPCOperations.listunspent); return(response.Result.Select(i => new UnspentCoin((JObject)i, this.Network)).ToArray()); }
/// <summary> /// Lists accounts and their balances, based on the specified number of confirmations. /// </summary> /// <param name="confirmations"> /// The minimum number of confirmations an externally-generated transaction must have before /// it is counted towards the balance. Transactions generated by this node are counted immediately. /// Typically, externally-generated transactions are payments to this wallet and transactions /// generated by this node are payments to other wallets. Use 0 to count unconfirmed transactions. /// Default is 1. /// </param> /// <returns> /// A list of accounts and their balances. /// </returns> public IEnumerable <RPCAccount> ListAccounts(int confirmations) { RPCResponse response = SendCommand(RPCOperations.listaccounts, confirmations); return(AsRPCAccount(response)); }
// dumpprivkey public BitcoinSecret DumpPrivKey(BitcoinAddress address) { RPCResponse response = SendCommand(RPCOperations.dumpprivkey, address.ToString()); return(this.Network.Parse <BitcoinSecret>((string)response.Result)); }
public async Task <WalletCreateFundedPSBTResponse> WalletCreateFundedPSBTAsync( TxIn[] inputs, Tuple <Dictionary <BitcoinAddress, Money>, Dictionary <string, string> > outputs, LockTime locktime = default(LockTime), FundRawTransactionOptions options = null, bool bip32derivs = false ) { var values = new object[] { }; if (inputs == null) { inputs = new TxIn[] { } } ; if (outputs == null) { throw new ArgumentNullException(nameof(outputs)); } var rpcInputs = inputs.Select(i => i.ToRPCInputs()).ToArray(); var outputToSend = new JObject { }; if (outputs.Item1 != null) { foreach (var kv in outputs.Item1) { outputToSend.Add(kv.Key.ToString(), kv.Value.ToUnit(MoneyUnit.BTC)); } } if (outputs.Item2 != null) { foreach (var kv in outputs.Item2) { outputToSend.Add(kv.Key, kv.Value); } } JObject jOptions; if (options != null) { jOptions = FundRawTransactionOptionsToJson(options); } else { jOptions = (JObject)""; } RPCResponse response = await SendCommandAsync( "walletcreatefundedpsbt", rpcInputs, outputToSend, locktime.Value, jOptions, bip32derivs).ConfigureAwait(false); var result = (JObject)response.Result; var psbt = PSBT.Parse(result.Property("psbt").Value.Value <string>(), Network.Main); var fee = Money.Coins(result.Property("fee").Value.Value <decimal>()); var changePos = result.Property("changepos").Value.Value <int>(); var tmp = changePos == -1 ? (int?)null : (int?)changePos; return(new WalletCreateFundedPSBTResponse { PSBT = psbt, Fee = fee, ChangePos = tmp }); }
public async Task <Money> GetBalanceAsync(int minConf, bool includeWatchOnly) { RPCResponse data = await SendCommandAsync(RPCOperations.getbalance, "*", minConf, includeWatchOnly).ConfigureAwait(false); return(Money.Coins(data.Result.Value <decimal>())); }
public async Task <Money> GetBalanceAsync() { RPCResponse data = await SendCommandAsync(RPCOperations.getbalance, "*").ConfigureAwait(false); return(Money.Coins(data.Result.Value <decimal>())); }
// getaddressesbyaccount /// <summary> /// Returns a list of every address assigned to a particular account. /// </summary> /// <param name="account"> /// The name of the account containing the addresses to get. To get addresses from the default account, /// pass an empty string (""). /// </param> /// <returns> /// A collection of all addresses belonging to the specified account. /// If the account has no addresses, the collection will be empty. /// </returns> public IEnumerable <BitcoinAddress> GetAddressesByAccount(string account) { RPCResponse response = SendCommand(RPCOperations.getaddressesbyaccount, account); return(response.Result.Select(t => this.Network.Parse <BitcoinAddress>((string)t))); }
public async Task <BitcoinAddress> GetAccountAddressAsync(string account) { RPCResponse response = await SendCommandAsync(RPCOperations.getaccountaddress, account).ConfigureAwait(false); return(this.Network.Parse <BitcoinAddress>((string)response.Result)); }
// getaccountaddress public BitcoinAddress GetAccountAddress(string account) { RPCResponse response = SendCommand(RPCOperations.getaccountaddress, account); return(this.Network.Parse <BitcoinAddress>((string)response.Result)); }
public async Task <BitcoinSecret> DumpPrivKeyAsync(BitcoinAddress address) { RPCResponse response = await SendCommandAsync(RPCOperations.dumpprivkey, address.ToString()).ConfigureAwait(false); return(this.Network.Parse <BitcoinSecret>((string)response.Result)); }
async Task <RPCResponse> SendCommandAsyncCore(RPCRequest request, bool throwIfRPCError) { RPCResponse response = null; var batches = _BatchedRequests; if (batches != null) { TaskCompletionSource <RPCResponse> source = new TaskCompletionSource <RPCResponse>(); batches.Enqueue(Tuple.Create(request, source)); response = await source.Task.ConfigureAwait(false); } HttpWebRequest webRequest = response == null?CreateWebRequest() : null; if (response == null) { var writer = new StringWriter(); request.WriteJSON(writer); writer.Flush(); var json = writer.ToString(); var bytes = Encoding.UTF8.GetBytes(json); #if !(PORTABLE || NETCORE) webRequest.ContentLength = bytes.Length; #endif var dataStream = await webRequest.GetRequestStreamAsync().ConfigureAwait(false); await dataStream.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false); await dataStream.FlushAsync().ConfigureAwait(false); dataStream.Dispose(); } WebResponse webResponse = null; WebResponse errorResponse = null; try { webResponse = response == null ? await webRequest.GetResponseAsync().ConfigureAwait(false) : null; response = response ?? RPCResponse.Load(await ToMemoryStreamAsync(webResponse.GetResponseStream()).ConfigureAwait(false)); if (throwIfRPCError) { response.ThrowIfError(); } } catch (WebException ex) { if (ex.Response == null || ex.Response.ContentLength == 0) { throw; } errorResponse = ex.Response; response = RPCResponse.Load(await ToMemoryStreamAsync(errorResponse.GetResponseStream()).ConfigureAwait(false)); if (throwIfRPCError) { response.ThrowIfError(); } } finally { if (errorResponse != null) { errorResponse.Dispose(); errorResponse = null; } if (webResponse != null) { webResponse.Dispose(); webResponse = null; } } return(response); }
public async Task <RPCResponse> SendCommandAsync(RPCRequest request, bool throwIfRPCError = true) { var webRequest = (HttpWebRequest)WebRequest.Create(Address); webRequest.Headers[HttpRequestHeader.Authorization] = "Basic " + Encoders.Base64.EncodeData(Encoders.ASCII.DecodeData(_Authentication)); webRequest.ContentType = "application/json-rpc"; webRequest.Method = "POST"; var writer = new StringWriter(); request.WriteJSON(writer); writer.Flush(); var json = writer.ToString(); var bytes = Encoding.UTF8.GetBytes(json); #if !(PORTABLE || NETCORE) webRequest.ContentLength = bytes.Length; #endif var dataStream = await webRequest.GetRequestStreamAsync().ConfigureAwait(false); await dataStream.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false); await dataStream.FlushAsync().ConfigureAwait(false); dataStream.Dispose(); RPCResponse response; WebResponse webResponse = null; WebResponse errorResponse = null; try { webResponse = await webRequest.GetResponseAsync().ConfigureAwait(false); response = RPCResponse.Load(await ToMemoryStreamAsync(webResponse.GetResponseStream()).ConfigureAwait(false)); if (throwIfRPCError) { response.ThrowIfError(); } } catch (WebException ex) { if (ex.Response == null || ex.Response.ContentLength == 0) { throw; } errorResponse = ex.Response; response = RPCResponse.Load(await ToMemoryStreamAsync(errorResponse.GetResponseStream()).ConfigureAwait(false)); if (throwIfRPCError) { response.ThrowIfError(); } } finally { if (errorResponse != null) { errorResponse.Dispose(); errorResponse = null; } if (webResponse != null) { webResponse.Dispose(); webResponse = null; } } return(response); }
public async Task <FundRawTransactionResponse> FundRawTransactionAsync(Transaction transaction, FundRawTransactionOptions options = null) { if (transaction == null) { throw new ArgumentNullException("transaction"); } RPCResponse response = null; if (options != null) { var jOptions = new JObject(); if (options.ChangeAddress != null) { jOptions.Add(new JProperty("changeAddress", options.ChangeAddress.ToString())); } if (options.ChangePosition != null) { jOptions.Add(new JProperty("changePosition", options.ChangePosition.Value)); } jOptions.Add(new JProperty("includeWatching", options.IncludeWatching)); jOptions.Add(new JProperty("lockUnspents", options.LockUnspents)); if (options.ReserveChangeKey != null) { jOptions.Add(new JProperty("reserveChangeKey", options.ReserveChangeKey)); } if (options.FeeRate != null) { jOptions.Add(new JProperty("feeRate", options.FeeRate.GetFee(1000).ToDecimal(MoneyUnit.BTC))); } if (options.SubtractFeeFromOutputs != null) { var array = new JArray(); foreach (int v in options.SubtractFeeFromOutputs) { array.Add(new JValue(v)); } jOptions.Add(new JProperty("subtractFeeFromOutputs", array)); } response = await SendCommandAsync("fundrawtransaction", ToHex(transaction), jOptions).ConfigureAwait(false); } else { response = await SendCommandAsync("fundrawtransaction", ToHex(transaction)).ConfigureAwait(false); } var r = (JObject)response.Result; return(new FundRawTransactionResponse() { Transaction = new Transaction(r["hex"].Value <string>()), Fee = Money.Coins(r["fee"].Value <decimal>()), ChangePos = r["changepos"].Value <int>() }); }
private static BlockHeader ParseBlockHeader(RPCResponse resp) { var header = new BlockHeader(); header.Version = (int)resp.Result["version"]; header.Nonce = (uint)resp.Result["nonce"]; header.Bits = new Target(Encoders.Hex.DecodeData((string)resp.Result["bits"])); if (resp.Result["previousblockhash"] != null) { header.HashPrevBlock = uint256.Parse((string)resp.Result["previousblockhash"]); } if (resp.Result["time"] != null) { header.BlockTime = Utils.UnixTimeToDateTime((uint)resp.Result["time"]); } if (resp.Result["merkleroot"] != null) { header.HashMerkleRoot = uint256.Parse((string)resp.Result["merkleroot"]); } return header; }
/// <summary> /// Returns the total amount received by the specified address in transactions with the /// specified number of confirmations. It does not count coinbase transactions. /// </summary> /// <param name="confirmations"> /// The minimum number of confirmations an externally-generated transaction must have before /// it is counted towards the balance. Transactions generated by this node are counted immediately. /// Typically, externally-generated transactions are payments to this wallet and transactions /// generated by this node are payments to other wallets. Use 0 to count unconfirmed transactions. /// Default is 1. /// </param> /// <returns>The number of bitcoins received by the address, excluding coinbase transactions. May be 0.</returns> public Money GetReceivedByAddress(BitcoinAddress address, int confirmations) { RPCResponse response = SendCommand(RPCOperations.getreceivedbyaddress, address.ToString(), confirmations); return(Money.Coins(response.Result.Value <decimal>())); }