public static void single_send_partial_tx(string url, PartialTx partialTx) { var json = JsonConvert.SerializeObject(partialTx); var stringContent = new StringContent( json, Encoding.UTF8, "application/json"); var req = ApiClient.PostContentAsync(url, stringContent).Result; if (req.IsSuccessStatusCode) { Log.Information("Transaction sent successfully"); } else { Log.Error("Error sending transaction - status: {status}", req.StatusCode); throw new WalletErrorException(WalletError.Hyper); } }
/// Receive an already well formed JSON transaction issuance and finalize the /// transaction, adding our receiving output, to broadcast to the rest of the /// network. public static void receive_json_tx( WalletConfig config, Keychain keychain, PartialTx partialTx ) { var(amount, blinding, tx) = PartialTx.read_partial_tx(keychain, partialTx); var finalTx = receive_transaction(config, keychain, amount, blinding, tx); var txHex = HexUtil.to_hex(Ser.Ser_vec(finalTx)); //todo:asyncification var url = $"{config.CheckNodeApiHttpAddr}/v1/pool/push"; var json = JsonConvert.SerializeObject(new TxWrapper { TxHex = txHex }); var res = ApiClient.PostContentAsync(url, new StringContent(json, Encoding.UTF8, "application/json")).Result; if (!res.IsSuccessStatusCode) { Log.Debug("{statusCode}", res.StatusCode); throw new WalletErrorException(WalletError.Node, $"{res.StatusCode}"); } // var res = ApiClient.PostAsync(uri, new JsonContent(new TxWrapper(){tx_hex=tx_hex})).Result; //let url = format!("{}/v1/pool/push", config.check_node_api_http_addr.as_str()); //let _: () = api::client::post(url.as_str(), &TxWrapper { tx_hex: tx_hex //}) //.map_err(|e| Error::Node(e))?; }
/// Issue a new transaction to the provided sender by spending some of our /// walvar /// UTXOs. The destination can be "stdout" (for command line) or a URL to the /// recipients walvar receiver (to be implemented). public static void issue_send_tx( WalletConfig config, Keychain keychain, ulong amount, ulong minimumConfirmations, string dest, uint maxOutputs, bool selectionStrategy ) { Checker.refresh_outputs(config, keychain); var chainTip = Checker.get_tip_from_node(config); var currentHeight = chainTip.Height; // proof of concept - set lock_height on the tx var lockHeight = chainTip.Height; var(tx, blindSum, coins, changeKey) = build_send_tx( config, keychain, amount, currentHeight, minimumConfirmations, lockHeight, maxOutputs, selectionStrategy); var partialTx = PartialTx.build_partial_tx(amount, blindSum, tx); // Closure to acquire walvar lock and lock the coins being spent // so we avoid accidental double spend attempt. void UpdateWallet() { WalletData.With_wallet(config.DataFileDir, walletData => { foreach (var coin in coins) { walletData.Lock_output(coin); } return(walletData); }); } // Closure to acquire walvar lock and devare the change output in case of tx failure. void RollbackWallet() { WalletData.With_wallet(config.DataFileDir, walletData => { Log.Information("cleaning up unused change output from walvar"); walletData.Delete_output(changeKey); return(walletData); }); } if (dest == "stdout") { var jsonTx = JsonConvert.SerializeObject(partialTx, Formatting.Indented); UpdateWallet(); Console.WriteLine(jsonTx); } else if (dest.StartsWith("http")) { var url = $"{dest}/v1/receive/transaction"; Log.Debug("Posting partial transaction to {url}", url); try { Client.send_partial_tx(url, partialTx); UpdateWallet(); } catch { Log.Error("Communication with receiver failed. Aborting transaction"); RollbackWallet(); } } else { throw new Exception($"dest not in expected format: {dest}"); } }
public static void send_partial_tx(string url, PartialTx partialTx) { single_send_partial_tx(url, partialTx); }