/// <summary> /// Returns true if the given TxI is a valid coinbase TxI of the given block. /// </summary> public static bool IsValidCoinbaseTxIn(Block block, TxIn txIn) { return(txIn.TxId == HexUtils.HexFromInt(block.Index) && txIn.TxOutIndex == 0 && txIn.Signature == ""); }
/// <summary> /// Creates a transaction for sending coins from the given wallet to the given address. /// </summary> /// <param name="senderAddress">Address of the sender wallet.</param> /// <param name="recipientAddress">Address of the recipient wallet.</param> /// <param name="amountInNekoshi">Amount of nekoshi to send, not including transaction fee.</param> /// <param name="privateKey">Private key of the sender wallet.</param> /// <returns>Result of the task.</returns> /// <remarks> /// If the task succeeds, a pending transaction will be added to the mempool. /// The application is responsible for broadcasting the pending transaction /// to other nodes. /// </remarks> public SendResult Send(string senderAddress, string recipientAddress, long amountInNekoshi, EllipticCurve.PrivateKey privateKey) { var addrFromPrivateKey = AddressUtils.AddressFromPrivateKey(privateKey); if (senderAddress != addrFromPrivateKey) { return new SendResult { Error = SendResult.ErrorType.InvalidKey } } ; long amountInNekoshiToSend = amountInNekoshi; amountInNekoshi += Config.FeeNekoshiPerTx; List <UnspentTxOut> unspentTxOutputs = new List <UnspentTxOut>(); List <TxOut> pendingTxOutputs = new List <TxOut>(); getUnspentTxOutputs(senderAddress, unspentTxOutputs, pendingTxOutputs); long accumulatedAmount = 0; List <UnspentTxOut> ouputsToSpend = new List <UnspentTxOut>(); List <TxOut> changeOutputs = new List <TxOut>(); for (int i = 0, c = unspentTxOutputs.Count; i < c; ++i) { var utxo = unspentTxOutputs[i]; ouputsToSpend.Add(utxo); var refTx = transactionDb.GetTransaction(utxo.TxId); var txOut = refTx.Outputs[utxo.TxOutIndex]; long neededAmount = amountInNekoshi - accumulatedAmount; if (txOut.AmountInNekoshi > neededAmount) { accumulatedAmount = amountInNekoshi; changeOutputs.Add(new TxOut { Address = senderAddress, AmountInNekoshi = txOut.AmountInNekoshi - neededAmount, }); } else { accumulatedAmount += txOut.AmountInNekoshi; } if (accumulatedAmount >= amountInNekoshi) { break; } } if (accumulatedAmount >= amountInNekoshi) { if (ouputsToSpend.Count > Config.MaxTransactionInputs) { return new SendResult { Error = SendResult.ErrorType.TooManyInputs } } ; var tx = new Transaction(); for (int i = 0, c = ouputsToSpend.Count; i < c; ++i) { var unspentTxOut = ouputsToSpend[i]; var txIn = new TxIn { TxId = unspentTxOut.TxId, TxOutIndex = unspentTxOut.TxOutIndex, }; tx.Inputs.Add(txIn); } changeOutputs.Add(new TxOut { Address = recipientAddress, AmountInNekoshi = amountInNekoshiToSend, }); tx.Outputs.AddRange(changeOutputs); tx.Id = tx.GetId(); signTransation(tx, privateKey); transactionDb.AddPendingTransaction(tx); return(new SendResult { Error = SendResult.ErrorType.None, TxId = tx.Id, }); } else { return(new SendResult { Error = SendResult.ErrorType.Insufficient }); } }