/// <summary> /// Adds the given pending transactions to the transaction database. /// </summary> /// <returns>Result of the task.</returns> public AddPendingTransactionsResult AddPendingTransactions(IList <PendingTransaction> transactions) { if (transactions.Count == 0) { return(AddPendingTransactionsResult.Empty); } for (int i = 0, c = transactions.Count; i < c; ++i) { var ptx = transactions[i]; var tx = ptx.Tx; if (tx.Id != tx.GetId()) { return(AddPendingTransactionsResult.HardRejected); } if (transactionDb.HasTransaction(tx.Id)) { continue; } if (transactionDb.GetPendingTransaction(tx.Id) != null) { continue; } long totalInAmount = 0; long totalOutAmount = 0; bool isIgnored = false; for (int j = 0, n = tx.Inputs.Count; j < n; ++j) { var txIn = tx.Inputs[j]; if (string.IsNullOrEmpty(txIn.TxId) || txIn.TxOutIndex < 0 || string.IsNullOrEmpty(txIn.Signature)) { return(AddPendingTransactionsResult.HardRejected); } var refTx = transactionDb.GetTransaction(txIn.TxId); if (refTx is null) { isIgnored = true; break; } if (txIn.TxOutIndex >= refTx.Outputs.Count) { return(AddPendingTransactionsResult.HardRejected); } var refTxOut = refTx.Outputs[txIn.TxOutIndex]; var(signature, publicKey) = AddressUtils.SignatureAndPublicKeyFromTxInSignature(txIn.Signature); if (AddressUtils.AddressFromPublicKey(publicKey) != refTxOut.Address) { return(AddPendingTransactionsResult.HardRejected); } if (EllipticCurve.Ecdsa.verify(tx.Id, signature, publicKey) == false) { return(AddPendingTransactionsResult.HardRejected); } totalInAmount += refTxOut.AmountInNekoshi; } if (isIgnored) { continue; } for (int j = 0, n = tx.Outputs.Count; j < n; ++j) { var txOut = tx.Outputs[j]; if (string.IsNullOrEmpty(txOut.Address) || txOut.AmountInNekoshi <= 0) { return(AddPendingTransactionsResult.HardRejected); } totalOutAmount += txOut.AmountInNekoshi; } if (totalInAmount != totalOutAmount + Config.FeeNekoshiPerTx) { return(AddPendingTransactionsResult.HardRejected); } } for (int i = 0, c = transactions.Count; i < c; ++i) { var ptx = transactions[i]; transactionDb.AddPendingTransaction(ptx, needSave: false); } transactionDb.Save(); return(AddPendingTransactionsResult.Added); }