/// <inheritdoc /> public void ProcessTransaction(Transaction transaction, int?blockHeight = null, Block block = null) { this.logger.LogDebug($"transaction received - hash: {transaction.GetHash()}, coin: {this.coinType}"); // check the outputs foreach (var pubKey in this.keysLookup.Keys) { // check if the outputs contain one of our addresses var utxo = transaction.Outputs.SingleOrDefault(o => pubKey == o.ScriptPubKey); if (utxo != null) { AddTransactionToWallet(transaction.GetHash(), transaction.Time, transaction.Outputs.IndexOf(utxo), utxo.Value, pubKey, blockHeight, block); } } // check the inputs - include those that have a reference to a transaction containing one of our scripts and the same index foreach (TxIn input in transaction.Inputs.Where(txIn => this.keysLookup.Values.SelectMany(v => v.Transactions).Any(trackedTx => trackedTx.Id == txIn.PrevOut.Hash && trackedTx.Index == txIn.PrevOut.N))) { TransactionData tTx = this.keysLookup.Values.SelectMany(v => v.Transactions).Single(trackedTx => trackedTx.Id == input.PrevOut.Hash && trackedTx.Index == input.PrevOut.N); // find the script this input references var keyToSpend = this.keysLookup.Single(v => v.Value.Transactions.Contains(tTx)).Key; // get the details of the outputs paid out. // We first include the keys we don't hold and then we include the keys we do hold but that are for receiving addresses (which would mean the user paid itself). IEnumerable <TxOut> paidoutto = transaction.Outputs.Where(o => !this.keysLookup.Keys.Contains(o.ScriptPubKey) || (this.keysLookup.ContainsKey(o.ScriptPubKey) && !this.keysLookup[o.ScriptPubKey].IsChangeAddress())); AddTransactionToWallet(transaction.GetHash(), transaction.Time, null, -tTx.Amount, keyToSpend, blockHeight, block, tTx.Id, tTx.Index, paidoutto); } }
protected virtual Transaction CreateOutputTransaction() { rewardToPool = new Money(BlockTemplate.CoinbaseValue, MoneyUnit.Satoshi); var tx = Transaction.Create(network); // Check if we need to pay founder fees if (coin.HasFounderFee) { rewardToPool = CreateFounderOutputs(tx, rewardToPool); } // Check if we need to pay treasury reward if (coin.HasTreasuryReward) { rewardToPool = CreateTreasuryOutputs(tx, rewardToPool); } tx.Outputs.Add(rewardToPool, poolAddressDestination); // CoinbaseDevReward check for Freecash if (coin.HasCoinbaseDevReward) { CreateCoinbaseDevRewardOutputs(tx); } return(tx); }
protected async Task <uint256> PublishTransactionAsync(NBitcoin.Transaction tx) { await using (var client = await this.Factory.CreateTransactionManagementClientAsync()) { return(await client.PublishAsync(tx, true)); } }
protected virtual Transaction CreateMasternodeOutputTransaction() { var blockReward = new Money(BlockTemplate.CoinbaseValue, MoneyUnit.Satoshi); rewardToPool = new Money(BlockTemplate.CoinbaseValue, MoneyUnit.Satoshi); var tx = Transaction.Create(network); // outputs rewardToPool = CreateMasternodeOutputs(tx, blockReward); // Check if we need to pay founder fees if (coin.HasFounderFee) { rewardToPool = CreateFounderOutputs(tx, rewardToPool); } // Check if we need to pay treasury reward if (coin.HasTreasuryReward) { rewardToPool = CreateTreasuryOutputs(tx, rewardToPool); } // Finally distribute remaining funds to pool tx.Outputs.Insert(0, new TxOut(rewardToPool, poolAddressDestination)); return(tx); }
public string DepositBtc(string btcPubKey, string recipient, decimal amount) { var address = new BitcoinPubKeyAddress(btcPubKey, Network.TestNet); //var address = new BitcoinSecret(btcPubKey); var txOperations = QClient.GetBalance(dest: address, unspentOnly: true).Result.Operations; var coins = new List <Coin>(); foreach (var op in txOperations) { op.ReceivedCoins.ForEach(c => coins.Add((Coin)c)); } coins.Sort(delegate(Coin x, Coin y) { return(-x.Amount.CompareTo(y.Amount)); }); var coinSum = 0m; for (int i = 0; coinSum < amount; i++) { coinSum += coins[i].Amount.ToDecimal(MoneyUnit.BTC); if (coinSum >= amount) { coins.RemoveRange(i + 1, coins.Count - (i + 1)); } } var builder = new TransactionBuilder(); var destination = new BitcoinPubKeyAddress(recipient, Network.TestNet); NBitcoin.Transaction tx = builder .AddCoins(coins) //.AddKeys(testAddress) .Send(destination, Money.Coins(amount)) .SetChange(address) .SendFees(Money.Coins(0.0001m)) .BuildTransaction(sign: false); tx.Outputs.Add(new TxOut { Value = Money.Zero, ScriptPubKey = TxNullDataTemplate.Instance.GenerateScriptPubKey(Encoding.UTF8.GetBytes(recipient)) }); foreach (var input in tx.Inputs) { input.ScriptSig = address.ScriptPubKey; } var txhash = tx.ToHex(); if (builder.Verify(tx)) { var broadcastResult = QClient.Broadcast(tx).Result; } return(tx.ToHex()); }
/// <inheritdoc /> public void ProcessTransaction(CoinType coinType, Transaction transaction, int?blockHeight = null, uint?blockTime = null) { Console.WriteLine($"transaction notification: tx hash {transaction.GetHash()}, coin type: {coinType}"); foreach (var pubKey in this.PubKeys) { // check if the outputs contain one of our addresses var utxo = transaction.Outputs.SingleOrDefault(o => pubKey == o.ScriptPubKey); if (utxo != null) { AddTransactionToWallet(coinType, transaction.GetHash(), transaction.Time, transaction.Outputs.IndexOf(utxo), utxo.Value, pubKey, blockHeight, blockTime); } // if the inputs have a reference to a transaction containing one of our scripts foreach (TxIn input in transaction.Inputs.Where(txIn => this.TrackedTransactions.Any(trackedTx => trackedTx.Hash == txIn.PrevOut.Hash))) { TransactionDetails tTx = this.TrackedTransactions.Single(trackedTx => trackedTx.Hash == input.PrevOut.Hash); // compare the index of the output in its original transaction and the index references in the input if (input.PrevOut.N == tTx.Index) { AddTransactionToWallet(coinType, transaction.GetHash(), transaction.Time, null, -tTx.Amount, pubKey, blockHeight, blockTime, tTx.Hash, tTx.Index); } } } }
public async Task <ByteString> IssueWithdrawal(IList <OutboundTransaction> transactions) { HttpClient client = new HttpClient(); BitcoinAddress address = storageKey.ScriptPubKey.GetDestinationAddress(this.Network); HttpResponseMessage response = await client.GetAsync(new Uri(url, $"addresses/{address.ToString()}/unspents")); string body = await response.Content.ReadAsStringAsync(); JArray outputs = JArray.Parse(body); TransactionBuilder builder = new TransactionBuilder(); builder.AddKeys(storageKey.GetBitcoinSecret(Network)); foreach (JObject output in outputs) { string transactionHash = (string)output["transaction_hash"]; uint outputIndex = (uint)output["output_index"]; long amount = (long)output["value"]; builder.AddCoins(new Coin(uint256.Parse(transactionHash), outputIndex, new Money(amount), storageKey.ScriptPubKey)); } foreach (OutboundTransaction outboundTransaction in transactions) { builder.Send(BitcoinAddress.Create(outboundTransaction.Target, Network).ScriptPubKey, new Money(outboundTransaction.Amount)); } builder.SendFees(defaultFees); builder.SetChange(storageKey.ScriptPubKey, ChangeType.All); NBitcoin.Transaction transaction = builder.BuildTransaction(true); return(new ByteString(transaction.ToBytes())); }
public async Task <IBlockchainTransaction> GetTransactionAsync( string txId, CancellationToken cancellationToken = default(CancellationToken)) { Info.Blockchain.API.Models.Transaction tx; try { tx = await _explorer .GetTransactionByHashAsync(txId) .ConfigureAwait(false); } catch (ServerApiException e) { Log.Warning("Server api exception while get transaction by id {@txId}: {@message}", txId, ResolveExceptionMessage(e)); return(null); } return(new BitcoinBasedTransaction( currency: _currency, tx: Transaction.Parse(await GetTxHexAsync(txId).ConfigureAwait(false), _currency.Network), blockInfo: new BlockInfo { Fees = await GetTxFeeAsync(txId).ConfigureAwait(false), Confirmations = (int)(await GetBlockCountAsync().ConfigureAwait(false) - tx.BlockHeight + 1), BlockHeight = tx.BlockHeight, FirstSeen = tx.Time, BlockTime = tx.Time })); }
private string GetScriptString(NBitcoin.Transaction transaction) { var output = transaction.Outputs.FirstOrDefault(c => c.Value.Equals(Money.Zero)); if (output == null) { transaction.ToString(); //TODO: UnCOmment exception } //throw new Exception("Transaction without integration output: " + transaction.GetHash().ToString()); else { try { var coin = new NBitcoin.Coin(transaction, output); var script = coin.GetScriptCode().ToString(); script = script.Replace("OP_RETURN ", ""); return(HexToString(script)); } catch (Exception e) { throw new Exception("Failed to process transaction output", e); } } return(""); }
public static void Run(string[] args) { /* * query of transactions * - https://www.blockchain.com/btc/tx/930a2114cdaa86e1fac46d15c74e81c09eee1d4150ff9d48e76cb0697d8e1d72 * - http://api.qbit.ninja/transactions/930a2114cdaa86e1fac46d15c74e81c09eee1d4150ff9d48e76cb0697d8e1d72 * * - https://bitcoinsays.com/930a2114cdaa86e1fac46d15c74e81c09eee1d4150ff9d48e76cb0697d8e1d72 */ // Create a client QBitNinjaClient client = new QBitNinjaClient(Network.Main); // Parse transaction id to NBitcoin.uint256 so the client can eat it uint256 transactionId = uint256.Parse("930a2114cdaa86e1fac46d15c74e81c09eee1d4150ff9d48e76cb0697d8e1d72"); // Query the transaction GetTransactionResponse transactionResponse = client.GetTransaction(transactionId).Result; NBitcoin.Transaction transaction = transactionResponse.Transaction; Console.WriteLine(transactionResponse.TransactionId); // f13dc48fb035bbf0a6e989a26b3ecb57b84f85e0836e777d6edf60d87a4a2d94 Console.WriteLine(transaction.GetHash()); // f13dc48fb035bbf0a6e989a26b3ecb57b84f85e0836e777d6edf60d87a4a2d94 printAddressesAsAcii(transactionResponse.ReceivedCoins); }
public static void Run(string[] args) { /* * String hex = "6a4dd7035765277265206e6f20737472616e6765727320746f206c6f76650a596f75206b6e6f77207468652072756c657320616e6420736f20646f20490a412066756c6c20636f6d6d69746d656e74277320776861742049276d207468696e6b696e67206f660a596f7520776f756c646e27742067657420746869732066726f6d20616e79206f74686572206775790a49206a7573742077616e6e612074656c6c20796f7520686f772049276d206665656c696e670a476f747461206d616b6520796f7520756e6465727374616e640a0a43484f5255530a4e6576657220676f6e6e61206769766520796f752075702c0a4e6576657220676f6e6e61206c657420796f7520646f776e0a4e6576657220676f6e6e612072756e2061726f756e6420616e642064657365727420796f750a4e6576657220676f6e6e61206d616b6520796f75206372792c0a4e6576657220676f6e6e612073617920676f6f646279650a4e6576657220676f6e6e612074656c6c2061206c696520616e64206875727420796f750a0a5765277665206b6e6f776e2065616368206f7468657220666f7220736f206c6f6e670a596f75722068656172742773206265656e20616368696e672062757420796f7527726520746f6f2073687920746f207361792069740a496e7369646520776520626f7468206b6e6f7720776861742773206265656e20676f696e67206f6e0a5765206b6e6f77207468652067616d6520616e6420776527726520676f6e6e6120706c61792069740a416e6420696620796f752061736b206d6520686f772049276d206665656c696e670a446f6e27742074656c6c206d6520796f7527726520746f6f20626c696e6420746f20736565202843484f525553290a0a43484f52555343484f5255530a284f6f68206769766520796f75207570290a284f6f68206769766520796f75207570290a284f6f6829206e6576657220676f6e6e6120676976652c206e6576657220676f6e6e6120676976650a286769766520796f75207570290a284f6f6829206e6576657220676f6e6e6120676976652c206e6576657220676f6e6e6120676976650a286769766520796f75207570290a0a5765277665206b6e6f776e2065616368206f7468657220666f7220736f206c6f6e670a596f75722068656172742773206265656e20616368696e672062757420796f7527726520746f6f2073687920746f207361792069740a496e7369646520776520626f7468206b6e6f7720776861742773206265656e20676f696e67206f6e0a5765206b6e6f77207468652067616d6520616e6420776527726520676f6e6e6120706c61792069742028544f2046524f4e54290a0a"; * byte[] ascii = Encoders.Hex.DecodeData(hex); * String str = System.Text.Encoding.Default.GetString(ascii); * * Console.WriteLine(str); */ /* * query of transactions * - https://www.blockchain.com/btc/tx/d29c9c0e8e4d2a9790922af73f0b8d51f0bd4bb19940d9cf910ead8fbe85bc9b * - http://api.qbit.ninja/transactions/d29c9c0e8e4d2a9790922af73f0b8d51f0bd4bb19940d9cf910ead8fbe85bc9b * * - https://bitcoinsays.com/d29c9c0e8e4d2a9790922af73f0b8d51f0bd4bb19940d9cf910ead8fbe85bc9b */ // Create a client QBitNinjaClient client = new QBitNinjaClient(Network.Main); // Parse transaction id to NBitcoin.uint256 so the client can eat it uint256 transactionId = uint256.Parse("d29c9c0e8e4d2a9790922af73f0b8d51f0bd4bb19940d9cf910ead8fbe85bc9b"); // Query the transaction GetTransactionResponse transactionResponse = client.GetTransaction(transactionId).Result; NBitcoin.Transaction transaction = transactionResponse.Transaction; printScriptsAsAcii(transactionResponse.ReceivedCoins); }
public TransactionVerboseModel(NBitcoin.Transaction trx, Network network, NBitcoin.ChainedBlock block = null, ChainedBlock tip = null) : base(trx) { if (trx != null) { this.txid = trx.GetHash().ToString(); this.size = trx.GetSerializedSize(); this.version = trx.Version; this.locktime = trx.LockTime; this.vin = trx.Inputs.Select(txin => new Vin(txin.PrevOut, txin.Sequence, txin.ScriptSig)).ToList(); int n = 0; this.vout = trx.Outputs.Select(txout => new Vout(n++, txout, network)).ToList(); if (block != null) { blockhash = block.HashBlock.ToString(); time = blocktime = Utils.DateTimeToUnixTime(block.Header.BlockTime); if (tip != null) { confirmations = tip.Height - block.Height + 1; } } } }
protected virtual Transaction CreateOutputTransaction() { var blockReward = new Money(BlockTemplate.CoinbaseValue, MoneyUnit.Satoshi); rewardToPool = new Money(BlockTemplate.CoinbaseValue, MoneyUnit.Satoshi); var tx = new Transaction(); // Distribute funds to configured reward recipients var rewardRecipients = new List <RewardRecipient>(poolConfig.RewardRecipients); foreach (var recipient in rewardRecipients.Where(x => x.Type != RewardRecipientType.Dev && x.Percentage > 0)) { var recipientAddress = BitcoinUtils.AddressToScript(recipient.Address); var recipientReward = new Money((long)Math.Floor(recipient.Percentage / 100.0m * blockReward.Satoshi)); rewardToPool -= recipientReward; tx.AddOutput(recipientReward, recipientAddress); } // Finally distribute remaining funds to pool tx.Outputs.Insert(0, new TxOut(rewardToPool, poolAddressDestination) { Value = rewardToPool }); // validate it //var checkResult = tx.Check(); //Debug.Assert(checkResult == TransactionCheckResult.Success); return(tx); }
public static StealthPayment[] GetPayments(Transaction transaction, PubKey[] spendKeys, BitField bitField, Key scan) { List<StealthPayment> result = new List<StealthPayment>(); for(int i = 0 ; i < transaction.Outputs.Count ; i++) { var metadata = StealthMetadata.TryParse(transaction.Outputs[i].ScriptPubKey); if(metadata != null && bitField.Match(metadata.BitField)) { var payment = new StealthPayment(transaction.Outputs[i + 1].ScriptPubKey, metadata); if(scan != null && spendKeys != null) { if(payment.StealthKeys.Length != spendKeys.Length) continue; var expectedStealth = spendKeys.Select(s => s.UncoverReceiver(scan, metadata.EphemKey)).ToList(); foreach(var stealth in payment.StealthKeys) { var match = expectedStealth.FirstOrDefault(expected => expected.ID == stealth.ID); if(match != null) expectedStealth.Remove(match); } if(expectedStealth.Count != 0) continue; } result.Add(payment); } } return result.ToArray(); }
public static NBitcoin.Block CreateGenesis(ConsensusFactory consensusFactory, uint genesisTime, uint nonce, uint bits, int version, Money reward) { string timeStamp = "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks"; var genesisOutputScript = new Script(Op.GetPushOp(Encoders.Hex.DecodeData("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f")), OpcodeType.OP_CHECKSIG); NBitcoin.Transaction genesisTransaction = consensusFactory.CreateTransaction(); genesisTransaction.Version = 1; genesisTransaction.AddInput(new TxIn() { ScriptSig = new Script(Op.GetPushOp(486604799), new Op() { Code = (OpcodeType)0x1, PushData = new[] { (byte)4 } }, Op.GetPushOp(Encoders.ASCII.DecodeData(timeStamp))) }); genesisTransaction.AddOutput(new TxOut() { Value = reward, ScriptPubKey = genesisOutputScript }); NBitcoin.Block genesis = consensusFactory.CreateBlock(); genesis.Header.BlockTime = Utils.UnixTimeToDateTime(genesisTime); genesis.Header.Bits = bits; genesis.Header.Nonce = nonce; genesis.Header.Version = version; genesis.Transactions.Add(genesisTransaction); genesis.Header.HashPrevBlock = uint256.Zero; genesis.UpdateMerkleRoot(); ((ISmartContractBlockHeader)genesis.Header).HashStateRoot = SmartContractBlockDefinition.StateRootEmptyTrie; return(genesis); }
protected virtual void CreatePayloadOutputs(Transaction tx, Money reward) { if (coinbasepayloadParameters.CoinbasePayload != null) { CoinbasePayload[] coinbasepayloads; if (coinbasepayloadParameters.CoinbasePayload.Type == JTokenType.Array) { coinbasepayloads = coinbasepayloadParameters.CoinbasePayload.ToObject <CoinbasePayload[]>(); } else { coinbasepayloads = new[] { coinbasepayloadParameters.CoinbasePayload.ToObject <CoinbasePayload>() } }; foreach (var CoinbasePayee in coinbasepayloads) { if (!string.IsNullOrEmpty(CoinbasePayee.Payee)) { var payeeAddress = BitcoinUtils.CashAddrToDestination(CoinbasePayee.Payee, network, true); var payeeReward = CoinbasePayee.Amount; tx.Outputs.Add(payeeReward, payeeAddress); } } } }
public static bool IsConsolidationTxn(Transaction transaction, ConsolidationTxParameters consolidationParameters, PrevOut[] prevOuts) { // The consolidation factor zero disables free consolidation txns if (consolidationParameters.MinConsolidationFactor == 0) { return(false); } if (transaction.IsCoinBase) { return(false); } // The transaction does not decrease #UTXO enough if (transaction.Inputs.Count < consolidationParameters.MinConsolidationFactor * transaction.Outputs.Count) { return(false); } long sumScriptPubKeySizesTxInputs = 0; // combine input with corresponding output it is spending var pairsInOut = transaction.Inputs.Zip(prevOuts, (i, o) => new { input = i, output = o }); foreach (var item in pairsInOut) { // Transaction has less than minConsInputMaturity confirmations if (item.output.Confirmations < consolidationParameters.MinConsolidationInputMaturity) { return(false); } // Spam detection if (item.input.ScriptSig.Length > consolidationParameters.MaxConsolidationInputScriptSize) { return(false); } if (!consolidationParameters.AcceptNonStdConsolidationInput && !item.output.IsStandard) { return(false); } sumScriptPubKeySizesTxInputs += item.output.ScriptPubKeyLength; } long sumScriptPubKeySizesTxOutputs = transaction.Outputs.Sum(x => x.ScriptPubKey.Length); // Size in utxo db does not decrease enough for cons. transaction to be profitable if (sumScriptPubKeySizesTxInputs < consolidationParameters.MinConsolidationFactor * sumScriptPubKeySizesTxOutputs) { return(false); } return(true); }
public bool Check(PubKey pubKey, Script scriptPubKey, Transaction tx, uint nIndex, ScriptVerify verify = ScriptVerify.Standard) { return new ScriptEvaluationContext() { ScriptVerify = verify, SigHash = SigHash }.CheckSig(this, pubKey, scriptPubKey, tx, nIndex); }
public void AddFromTransaction(Transaction transaction) { var hash = transaction.GetHash(); for(int i = 0 ; i < transaction.Outputs.Count; i++) { AddTxOut(new OutPoint(hash, i), transaction.Outputs[i]); } }
protected virtual Money CreateMasternodeOutputs(Transaction tx, Money reward) { if (masterNodeParameters.Masternode != null) { Masternode[] masternodes; // Dash v13 Multi-Master-Nodes if (masterNodeParameters.Masternode.Type == JTokenType.Array) { masternodes = masterNodeParameters.Masternode.ToObject <Masternode[]>(); } else { masternodes = new[] { masterNodeParameters.Masternode.ToObject <Masternode>() } }; foreach (var masterNode in masternodes) { if (!string.IsNullOrEmpty(masterNode.Payee)) { var payeeAddress = BitcoinUtils.AddressToDestination(masterNode.Payee, network); var payeeReward = masterNode.Amount; reward -= payeeReward; rewardToPool -= payeeReward; tx.Outputs.Add(payeeReward, payeeAddress); } } } if (masterNodeParameters.SuperBlocks != null && masterNodeParameters.SuperBlocks.Length > 0) { foreach (var superBlock in masterNodeParameters.SuperBlocks) { var payeeAddress = BitcoinUtils.AddressToDestination(superBlock.Payee, network); var payeeReward = superBlock.Amount; reward -= payeeReward; rewardToPool -= payeeReward; tx.Outputs.Add(payeeReward, payeeAddress); } } if (!string.IsNullOrEmpty(masterNodeParameters.Payee)) { var payeeAddress = BitcoinUtils.AddressToDestination(masterNodeParameters.Payee, network); var payeeReward = masterNodeParameters.PayeeAmount ?? (reward / 5); reward -= payeeReward; rewardToPool -= payeeReward; tx.Outputs.Add(payeeReward, payeeAddress); } return(reward); }
public static void Spend(this Transaction txn, Action <string> a) { var txnReportRequest = new HTTPRequest( new Uri(TxnBroadcastEndpoint), HTTPMethods.Post, (txnR, txnResponse) => { try { var response = JsonConvert.DeserializeAnonymousType(txnResponse.DataAsText, new { Success = false, R = "", Message = "" }); if (!response.Success) { Debug.LogError("Spend response was unsuccessful - " + response.Message); Debug.LogError(txnResponse.DataAsText); throw new SpendUTXOException(response.Message); } var hashRegex = new Regex(@"^([A-Fa-f0-9]{64})$"); if (hashRegex.IsMatch(response.R)) { a(response.R); } else { Debug.LogError("Failed spending utxo, return hash wasn't an hash"); Debug.LogError(txnResponse.DataAsText); throw new SpendUTXOException(txnResponse.DataAsText); } } catch (Exception e) { if (txnResponse != null) { Debug.LogError("Fatal error: " + txnResponse.DataAsText); } else { Debug.LogError("Failed to spend transaction"); Debug.LogError(txnR.Exception.Message); } Debug.LogError($"{e.GetType()}: {e.Message}"); ModalDialog.Instance.CallbackYes.AddListener(() => { SceneManager.LoadScene("Main"); }); ModalDialog.Instance.Show("Failed to spend UTXO", $"{e.GetType()}: {e.Message}", "Ok"); //Debug.LogError(JsonConvert.SerializeObject(txn)); //Debug.LogError($"{{\"tx\":\"{txn.ToHex()}\"}}"); } }); txnReportRequest.AddHeader("Content-Type", "application/json"); txnReportRequest.RawData = Encoding.UTF8.GetBytes($"{{\"tx\":\"{txn.ToHex()}\"}}"); txnReportRequest.Send(); }
/// <inheritdoc /> public void ProcessTransaction(Transaction transaction, int?blockHeight = null, Block block = null) { Guard.NotNull(transaction, nameof(transaction)); var hash = transaction.GetHash(); this.logger.LogTrace($"transaction received - hash: {hash}, coin: {this.coinType}"); // load the keys for lookup if they are not loaded yet. if (this.keysLookup == null) { this.LoadKeysLookup(); } // check the outputs foreach (TxOut utxo in transaction.Outputs) { // check if the outputs contain one of our addresses if (this.keysLookup.TryGetValue(utxo.ScriptPubKey, out HdAddress pubKey)) { this.AddTransactionToWallet(transaction.ToHex(), hash, transaction.Time, transaction.Outputs.IndexOf(utxo), utxo.Value, utxo.ScriptPubKey, blockHeight, block); } } // check the inputs - include those that have a reference to a transaction containing one of our scripts and the same index foreach (TxIn input in transaction.Inputs.Where(txIn => this.keysLookup.Values.Distinct().SelectMany(v => v.Transactions).Any(trackedTx => trackedTx.Id == txIn.PrevOut.Hash && trackedTx.Index == txIn.PrevOut.N))) { TransactionData tTx = this.keysLookup.Values.Distinct().SelectMany(v => v.Transactions).Single(trackedTx => trackedTx.Id == input.PrevOut.Hash && trackedTx.Index == input.PrevOut.N); // find the script this input references var keyToSpend = this.keysLookup.First(v => v.Value.Transactions.Contains(tTx)).Key; // get the details of the outputs paid out. IEnumerable <TxOut> paidoutto = transaction.Outputs.Where(o => { // if script is empty ignore it if (o.IsEmpty) { return(false); } var found = this.keysLookup.TryGetValue(o.ScriptPubKey, out HdAddress addr); // include the keys we don't hold if (!found) { return(true); } // include the keys we do hold but that are for receiving // addresses (which would mean the user paid itself). return(!addr.IsChangeAddress()); }); this.AddSpendingTransactionToWallet(transaction.ToHex(), hash, transaction.Time, paidoutto, tTx.Id, tTx.Index, blockHeight, block); } }
protected virtual Transaction CreateOutputTransaction() { rewardToPool = new Money(BlockTemplate.CoinbaseValue, MoneyUnit.Satoshi); var tx = Transaction.Create(network); tx.Outputs.Add(rewardToPool, poolAddressDestination); return(tx); }
Transaction ToEntity(NBitcoin.Transaction tx) { var entity = new Transaction( tx.GetHash(), tx.GetTransactionType(), (short)Convert.ToUInt16(tx.Version), tx.LockTime); // Outputs. for (int i = 0; i < tx.Outputs.Count; i++) { var output = new Output(entity.Hash, i, tx.Outputs[i].ScriptPubKey, tx.Outputs[i].Value); entity.Outputs.Add(output); } // Inputs. for (int i = 0; i < tx.Inputs.Count; i++) { var input = new Input( entity.Hash, i, tx.Inputs[i].PrevOut.Hash, (int)tx.Inputs[i].PrevOut.N, tx.Inputs[i].ScriptSig, (int)tx.Inputs[i].Sequence.Value); entity.Inputs.Add(input); } // Extra payload. var extra = tx.GetExtraPayload(); if (extra.Length != 0) { entity.ExtraPayload = extra; } // Elysium. var elysium = tx.GetElysiumTransaction(); if (elysium != null) { var serialized = new ArrayBufferWriter <byte>(); this.elysiumSerializer.Serialize(serialized, elysium); entity.Elysium = new ElysiumTransaction( entity.Hash, elysium.Sender?.ToString(), elysium.Receiver?.ToString(), serialized.WrittenSpan.ToArray()); } return(entity); }
public static void Put(this ITransactionRepository repo, uint256 txId, Transaction tx) { try { repo.PutAsync(txId, tx).Wait(); } catch(AggregateException aex) { ExceptionDispatchInfo.Capture(aex.InnerException).Throw(); } }
public void TestTransactionInfo() { QBitNinjaClient client = new QBitNinjaClient(Network.Main); var transactionId = uint256.Parse("f13dc48fb035bbf0a6e989a26b3ecb57b84f85e0836e777d6edf60d87a4a2d94"); GetTransactionResponse transactionResponse = client.GetTransaction(transactionId).Result; NBitcoin.Transaction transaction = transactionResponse.Transaction; Console.WriteLine(transactionResponse.TransactionId); Console.WriteLine(transaction.GetHash()); Console.WriteLine(); //Received Coins Console.WriteLine("Outputs:"); var outputs = transaction.Outputs; foreach (TxOut output in outputs) { Money amount = output.Value; Console.WriteLine(amount.ToDecimal(MoneyUnit.BTC)); var paymentScript = output.ScriptPubKey; Console.WriteLine("ScriptPubKey: " + paymentScript); // It's the ScriptPubKey var address = paymentScript.GetDestinationAddress(Network.Main); Console.WriteLine("address: " + address); Console.WriteLine(); } //Spent Coins Console.WriteLine("Inputs:"); Money receivedAmount = Money.Zero; var inputs = transaction.Inputs; foreach (TxIn input in inputs) { OutPoint previousOutpoint = input.PrevOut; Console.WriteLine("Prev Outpoint Hash: " + previousOutpoint.Hash); // hash of prev tx Console.WriteLine("Prev Outpoint Index: " + previousOutpoint.N); // idx of out from prev tx, that has been spent in the current tx Console.WriteLine(); } Console.WriteLine("Amount of inputs: " + transaction.Inputs.Count); var spentCoins = transactionResponse.SpentCoins; foreach (var spentCoin in spentCoins) { receivedAmount = (Money)spentCoin.Amount.Add(receivedAmount); } Console.WriteLine("Bitcoin Received: " + receivedAmount.ToDecimal(MoneyUnit.BTC)); var fee = transaction.GetFee(spentCoins.ToArray()); Console.Write("Fees (in Satoshis): "); Console.WriteLine(fee); }
public Coins(Transaction tx, Func<TxOut, bool> belongsToCoins, int height) { if(belongsToCoins == null) belongsToCoins = o => !o.ScriptPubKey.IsUnspendable; fCoinBase = tx.IsCoinBase; vout = tx.Outputs.ToList(); nVersion = tx.Version; nHeight = (uint)height; ClearUnused(belongsToCoins); UpdateValue(); }
public Transaction(BitcoinSecret[] bitcoinSecrets, decimal fee, decimal amount, string destination) { this.bitcoinSecrets = bitcoinSecrets; this.fee = fee; this.amount = amount / 1000; this.destination = BitcoinAddress.Create(destination, Network.TestNet); this.transaction = new NBitcoin.Transaction(); this.currentAmount = 0.0M; this.transactionBuilder = new TransactionBuilder(); this.unspentCoins = new List <Coin>(); }
//send signed tx hex to bitcoin network public static string BroadcastTx(string SignedTxHex, bool testnet) { CheckNullOrEmpty(new object[] { SignedTxHex, BTChost }, new string[] { "SignedTxHex", "BTChost" }); NBitcoin.Transaction tx = NBitcoin.Transaction.Parse(SignedTxHex); Network ntwk = testnet ? Network.TestNet : Network.Main; string err = ""; var nd = Node.Connect(ntwk, BTChost + ":" + BTCport); //DACC bitcoin server (BitcoinD) //bitcoin node sends responses asynchronously nd.MessageReceived += (node, message) => { NBitcoin.Protocol.IncomingMessage msgx = message; if (msgx.Message.Payload is RejectPayload) //error message { RejectPayload py = (RejectPayload)msgx.Message.Payload; Console.WriteLine("Rejected:" + py.Message + " " + py.Reason); err += py.Message + " " + py.Reason; } }; nd.VersionHandshake(); //must send node version first Thread.Sleep(1000); nd.SendMessage(new InvPayload(tx)); Thread.Sleep(1000); nd.SendMessage(new TxPayload(tx)); Thread.Sleep(5000); //wait for any error msgs string msg = tx.GetHash().ToString(); try { bool broadcasted = false; //search mempool for transaction foreach (var txid in nd.GetMempool()) //throws error for some servers { if (txid.Equals(tx.GetHash())) { broadcasted = true; } } nd.Disconnect(); //return json message if (!broadcasted) { msg = "Broadcast Failed (tx hash = " + tx.GetHash().ToString() + ")" + err + "\"}"; } else { msg = tx.GetHash().ToString(); } } catch (Exception ex) { msg = "Error (BroadcastTx): " + ex.Message; } return(msg); }
protected virtual Transaction CreatePayloadOutputTransaction() { var blockReward = new Money(BlockTemplate.CoinbaseValue, MoneyUnit.Satoshi); var tx = Transaction.Create(network); // Firstly pay coins to pool addr tx.Outputs.Insert(0, new TxOut(blockReward, poolAddressDestination)); // then create payloads incase there is any coinbase_payload in gbt CreatePayloadOutputs(tx, rewardToPool); return(tx); }
protected override Transaction CreateOutputTransaction() { rewardToPool = new Money(BlockTemplate.CoinbaseValue * blockRewardMultiplier, MoneyUnit.Satoshi); var tx = Transaction.Create(NBitcoinNetworkType); // pool reward (t-addr) tx.AddOutput(rewardToPool, poolAddressDestination); return(tx); }
public Task PutAsync(uint256 txId, Transaction tx) { using(@lock.LockWrite()) { if(!_Transactions.ContainsKey(txId)) _Transactions.AddOrReplace(txId, tx); else _Transactions[txId] = tx; } return _Inner.PutAsync(txId, tx); }
public static void SendTransaction(Transaction tx) { AddressManager nodeParams = new AddressManager(); IPEndPoint endPoint = TranslateHostNameToIP("http://btcnode.placefullcloud.com", 8333); nodeParams.Add(new NetworkAddress(endPoint), endPoint.Address); using (var node = Node.Connect(Network, nodeParams)) { node.VersionHandshake(); node.SendMessage(new InvPayload(InventoryType.MSG_TX, tx.GetHash())); node.SendMessage(new TxPayload(tx)); } }
public static LockType GetLockType(this NBitcoin.Transaction tx) { if (tx.LockTime.IsHeightLock) { return(LockType.Height); } if (tx.LockTime.IsTimeLock) { return(LockType.Time); } return(LockType.None); }
internal void OnBroadcastTransaction(Transaction transaction) { var hash = transaction.GetHash(); var nodes = Nodes .Select(n => n.Key.Behaviors.Find<BroadcastHubBehavior>()) .Where(n => n != null) .ToArray(); foreach(var node in nodes) { node.BroadcastTransactionCore(transaction); } }
protected virtual void BuildCoinbase() { var sigScriptInitial = GenerateScriptSigInitial(); var sigScriptInitialBytes = sigScriptInitial.ToBytes(); var sigScriptLength = (uint)( sigScriptInitial.Length + extraNoncePlaceHolderLength + scriptSigFinalBytes.Length); txOut = CreateOutputTransaction(); using (var stream = new MemoryStream()) { var bs = new BitcoinStream(stream, true); bs.ReadWrite(ref txVersion); if (isPoS) { var timestamp = BlockTemplate.CurTime; bs.ReadWrite(ref timestamp); } bs.ReadWriteAsVarInt(ref txInputCount); bs.ReadWrite(ref sha256Empty); bs.ReadWrite(ref txInPrevOutIndex); bs.ReadWriteAsVarInt(ref sigScriptLength); bs.ReadWrite(ref sigScriptInitialBytes); coinbaseInitial = stream.ToArray(); coinbaseInitialHex = coinbaseInitial.ToHexString(); } using (var stream = new MemoryStream()) { var bs = new BitcoinStream(stream, true); bs.ReadWrite(ref scriptSigFinalBytes); bs.ReadWrite(ref txInSequence); var txOutBytes = SerializeOutputTransaction(txOut); bs.ReadWrite(ref txOutBytes); bs.ReadWrite(ref txLockTime); coinbaseFinal = stream.ToArray(); coinbaseFinalHex = coinbaseFinal.ToHexString(); } }
static Coin CreateTransactionFeeCoin(PubKey destination, NoSqlTransactionRepository txRepo) { var bitcoinProviderTransaction = new Transaction() { Outputs = { new TxOut("0.0001" , destination) } }; txRepo.Put(bitcoinProviderTransaction.GetHash(), bitcoinProviderTransaction); return new Coin(new OutPoint(bitcoinProviderTransaction, 0), bitcoinProviderTransaction.Outputs[0]); }
protected virtual Transaction CreateOutputTransaction() { rewardToPool = new Money(BlockTemplate.CoinbaseValue * blockRewardMultiplier, MoneyUnit.Satoshi); var tx = new Transaction(); tx.Outputs.Insert(0, new TxOut(rewardToPool, poolAddressDestination) { Value = rewardToPool }); return(tx); }
protected override Transaction CreateOutputTransaction() { rewardToPool = new Money(BlockTemplate.CoinbaseValue, MoneyUnit.Satoshi); var tx = Transaction.Create(network); // pool reward (t-addr) tx.Outputs.Add(rewardToPool, poolAddressDestination); tx.Inputs.Add(TxIn.CreateCoinbase((int)BlockTemplate.Height)); return(tx); }
// // Check transaction inputs, and make sure any // pay-to-script-hash transactions are evaluating IsStandard scripts // // Why bother? To avoid denial-of-service attacks; an attacker // can submit a standard HASH... OP_EQUAL transaction, // which will get accepted into blocks. The redemption // script can be anything; an attacker could use a very // expensive-to-check-upon-redemption script like: // DUP CHECKSIG DROP ... repeated 100 times... OP_1 // public static bool AreInputsStandard(Transaction tx, CoinsView coinsView) { if(tx.IsCoinBase) return true; // Coinbases don't use vin normally for(int i = 0 ; i < tx.Inputs.Count ; i++) { TxOut prev = coinsView.GetOutputFor(tx.Inputs[i]); if(prev == null) return false; if(!IsStandardScriptSig(tx.Inputs[i].ScriptSig, prev.ScriptPubKey)) return false; } return true; }
public TrustedInput GetTrustedInput(Transaction transaction, int outputIndex) { using(Transport.Lock()) { if(outputIndex >= transaction.Outputs.Count) throw new ArgumentOutOfRangeException("outputIndex is bigger than the number of outputs in the transaction", "outputIndex"); MemoryStream data = new MemoryStream(); // Header BufferUtils.WriteUint32BE(data, outputIndex); BufferUtils.WriteBuffer(data, transaction.Version); VarintUtils.write(data, transaction.Inputs.Count); ExchangeApdu(LedgerWalletConstants.LedgerWallet_CLA, LedgerWalletConstants.LedgerWallet_INS_GET_TRUSTED_INPUT, (byte)0x00, (byte)0x00, data.ToArray(), OK); // Each input foreach(var input in transaction.Inputs) { data = new MemoryStream(); BufferUtils.WriteBuffer(data, input.PrevOut); VarintUtils.write(data, input.ScriptSig.Length); ExchangeApdu(LedgerWalletConstants.LedgerWallet_CLA, LedgerWalletConstants.LedgerWallet_INS_GET_TRUSTED_INPUT, (byte)0x80, (byte)0x00, data.ToArray(), OK); data = new MemoryStream(); BufferUtils.WriteBuffer(data, input.ScriptSig.ToBytes()); ExchangeApduSplit2(LedgerWalletConstants.LedgerWallet_CLA, LedgerWalletConstants.LedgerWallet_INS_GET_TRUSTED_INPUT, (byte)0x80, (byte)0x00, data.ToArray(), Utils.ToBytes(input.Sequence, true), OK); } // Number of outputs data = new MemoryStream(); VarintUtils.write(data, transaction.Outputs.Count); ExchangeApdu(LedgerWalletConstants.LedgerWallet_CLA, LedgerWalletConstants.LedgerWallet_INS_GET_TRUSTED_INPUT, (byte)0x80, (byte)0x00, data.ToArray(), OK); // Each output foreach(var output in transaction.Outputs) { data = new MemoryStream(); BufferUtils.WriteBuffer(data, Utils.ToBytes((ulong)output.Value.Satoshi, true)); VarintUtils.write(data, output.ScriptPubKey.Length); ExchangeApdu(LedgerWalletConstants.LedgerWallet_CLA, LedgerWalletConstants.LedgerWallet_INS_GET_TRUSTED_INPUT, (byte)0x80, (byte)0x00, data.ToArray(), OK); data = new MemoryStream(); BufferUtils.WriteBuffer(data, output.ScriptPubKey.ToBytes()); ExchangeApduSplit(LedgerWalletConstants.LedgerWallet_CLA, LedgerWalletConstants.LedgerWallet_INS_GET_TRUSTED_INPUT, (byte)0x80, (byte)0x00, data.ToArray(), OK); } // Locktime byte[] response = ExchangeApdu(LedgerWalletConstants.LedgerWallet_CLA, LedgerWalletConstants.LedgerWallet_INS_GET_TRUSTED_INPUT, (byte)0x80, (byte)0x00, transaction.LockTime.ToBytes(), OK); return new TrustedInput(response); } }
public Task PutAsync(uint256 txId, Transaction tx) { if(WriteThrough) { using(@lock.LockWrite()) { if(!_Transactions.ContainsKey(txId)) { _Transactions.AddOrReplace(txId, tx); EvictIfNecessary(txId); } else _Transactions[txId] = tx; } } return _Inner.PutAsync(txId, tx); }
public static void Submit(Transaction tx) { //SOME TEST NET NODES //54.149.133.4:18333 //52.69.206.155:18333 //93.114.160.222:18333 string url = "93.114.160.222:18333"; using(var node = NBitcoin.Protocol.Node.Connect(NBitcoin.Network.TestNet, url)) { node.VersionHandshake(); //System.Threading.Thread.Sleep(1000); NBitcoin.Transaction[] transactions = new Transaction[1]; transactions[0] = tx; node.SendMessage(new NBitcoin.Protocol.InvPayload(transactions)); node.SendMessage(new NBitcoin.Protocol.TxPayload(tx)); } }
public async Task<Transaction> GetAsync(uint256 txId) { while(true) { using(HttpClient client = new HttpClient()) { var response = await client.GetAsync(BlockrAddress + "tx/raw/" + txId).ConfigureAwait(false); if(response.StatusCode == HttpStatusCode.NotFound) return null; var result = await response.Content.ReadAsStringAsync().ConfigureAwait(false); var json = JObject.Parse(result); var status = json["status"]; var code = json["code"]; if(status != null && status.ToString() == "error") { throw new BlockrException(json); } var tx = new Transaction(json["data"]["tx"]["hex"].ToString()); return tx; } } }
public static string GetHexSignedTransaction(TransactionToSign txToSign) { var walletPrivateKey = ConfigurationManager.AppSettings[METACO_ENV_WALLET_PRIVATE_KEY_HEX_NAME]; var key = new Key(Encoders.Hex.DecodeData(walletPrivateKey)); var scriptPubKey = PayToPubkeyHashTemplate.Instance.GenerateScriptPubKey(key.PubKey); var tx = new Transaction(Encoders.Hex.DecodeData(txToSign.Raw)); foreach(var inputsToSign in txToSign.InputsToSign) { var sigHash = tx.GetSignatureHash(scriptPubKey, inputsToSign.Index); var sig = key.Sign(sigHash); var txSign = new TransactionSignature(sig, SigHash.All); var inputScript = PayToPubkeyHashTemplate.Instance.GenerateScriptSig(txSign, key.PubKey); tx.Inputs[inputsToSign.Index].ScriptSig = inputScript; Assert.True(Script.VerifyScript(scriptPubKey, tx, inputsToSign.Index)); } return tx.ToHex(); }
private int GetLegacySigOpCount(Transaction tx) { uint nSigOps = 0; foreach(var txin in tx.Inputs) { nSigOps += txin.ScriptSig.GetSigOpCount(false); } foreach(var txout in tx.Outputs) { nSigOps += txout.ScriptPubKey.GetSigOpCount(false); } return (int)nSigOps; }
//struct GetRejectReason() { return strRejectReason; } public bool CheckTransaction(Transaction tx) { // Basic checks that don't depend on any context if(tx.Inputs.Count == 0) return DoS(10, Utils.error("CheckTransaction() : vin empty"), RejectCode.INVALID, "bad-txns-vin-empty"); if(tx.Outputs.Count == 0) return DoS(10, Utils.error("CheckTransaction() : vout empty"), RejectCode.INVALID, "bad-txns-vout-empty"); // Size limits if(tx.ToBytes().Length > MAX_BLOCK_SIZE) return DoS(100, Utils.error("CheckTransaction() : size limits failed"), RejectCode.INVALID, "bad-txns-oversize"); // Check for negative or overflow output values long nValueOut = 0; foreach(var txout in tx.Outputs) { if(txout.Value < 0) return DoS(100, Utils.error("CheckTransaction() : txout.nValue negative"), RejectCode.INVALID, "bad-txns-vout-negative"); if(txout.Value > MAX_MONEY) return DoS(100, Utils.error("CheckTransaction() : txout.nValue too high"), RejectCode.INVALID, "bad-txns-vout-toolarge"); nValueOut += (long)txout.Value; if(!((nValueOut >= 0 && nValueOut <= (long)MAX_MONEY))) return DoS(100, Utils.error("CheckTransaction() : txout total out of range"), RejectCode.INVALID, "bad-txns-txouttotal-toolarge"); } // Check for duplicate inputs HashSet<OutPoint> vInOutPoints = new HashSet<OutPoint>(); foreach(var txin in tx.Inputs) { if(vInOutPoints.Contains(txin.PrevOut)) return DoS(100, Utils.error("CheckTransaction() : duplicate inputs"), RejectCode.INVALID, "bad-txns-inputs-duplicate"); vInOutPoints.Add(txin.PrevOut); } if(tx.IsCoinBase) { if(tx.Inputs[0].ScriptSig.Length < 2 || tx.Inputs[0].ScriptSig.Length > 100) return DoS(100, Utils.error("CheckTransaction() : coinbase script size"), RejectCode.INVALID, "bad-cb-length"); } else { foreach(var txin in tx.Inputs) if(txin.PrevOut.IsNull) return DoS(10, Utils.error("CheckTransaction() : prevout is null"), RejectCode.INVALID, "bad-txns-prevout-null"); } return true; }
public static bool VerifyScript(Script scriptPubKey, Transaction tx, int i, out ScriptError error) { var scriptSig = tx.Inputs[i].ScriptSig; return VerifyScript(scriptSig, scriptPubKey, tx, i, ScriptVerify.Standard, SigHash.Undefined, out error); }
public static bool VerifyScript(Script scriptSig, Script scriptPubKey, Transaction tx, int i, ScriptVerify scriptVerify, SigHash sigHash, out ScriptError error) { var eval = new ScriptEvaluationContext { SigHash = sigHash, ScriptVerify = scriptVerify }; var result = eval.VerifyScript(scriptSig, scriptPubKey, tx, i); error = eval.Error; return result; }
public static bool IsStandardTransaction(Transaction tx) { if(tx.Version > Transaction.CURRENT_VERSION || tx.Version < 1) { return false; } //// Treat non-final transactions as non-standard to prevent a specific type //// of double-spend attack, as well as DoS attacks. (if the transaction //// can't be mined, the attacker isn't expending resources broadcasting it) //// Basically we don't want to propagate transactions that can't included in //// the next block. //// //// However, IsFinalTx() is confusing... Without arguments, it uses //// chainActive.Height() to evaluate nLockTime; when a block is accepted, chainActive.Height() //// is set to the value of nHeight in the block. However, when IsFinalTx() //// is called within CBlock::AcceptBlock(), the height of the block *being* //// evaluated is what is used. Thus if we want to know if a transaction can //// be part of the *next* block, we need to call IsFinalTx() with one more //// than chainActive.Height(). //// //// Timestamps on the other hand don't get any special treatment, because we //// can't know what timestamp the next block will have, and there aren't //// timestamp applications where it matters. //if (!IsFinalTx(tx, chainActive.Height() + 1)) { // reason = "non-final"; // return false; //} // Extremely large transactions with lots of inputs can cost the network // almost as much to process as they cost the sender in fees, because // computing signature hashes is O(ninputs*txsize). Limiting transactions // to MAX_STANDARD_TX_SIZE mitigates CPU exhaustion attacks. int sz = tx.GetSerializedSize(); if(sz >= Transaction.MAX_STANDARD_TX_SIZE) return false; foreach(TxIn txin in tx.Inputs) { // Biggest 'standard' txin is a 15-of-15 P2SH multisig with compressed // keys. (remember the 520 byte limit on redeemScript size) That works // out to a (15*(33+1))+3=513 byte redeemScript, 513+1+15*(73+1)+3=1627 // bytes of scriptSig, which we round off to 1650 bytes for some minor // future-proofing. That's also enough to spend a 20-of-20 // CHECKMULTISIG scriptPubKey, though such a scriptPubKey is not // considered standard) if (txin.ScriptSig.Length > 1650) { return false; } if(!txin.ScriptSig.IsPushOnly) { return false; } if(!txin.ScriptSig.HasCanonicalPushes) { return false; } } uint nDataOut = 0; foreach(TxOut txout in tx.Outputs) { var template = StandardScripts.GetTemplateFromScriptPubKey(txout.ScriptPubKey); if(template == null) return false; if(template.Type == TxOutType.TX_NULL_DATA) nDataOut++; else if(txout.IsDust) return false; } // only one OP_RETURN txout is permitted if(nDataOut > 1) { return false; } return true; }
private static Script CombineMultisig(Script scriptPubKey, Transaction transaction, int n, byte[][] sigs1, byte[][] sigs2) { // Combine all the signatures we've got: List<TransactionSignature> allsigs = new List<TransactionSignature>(); foreach(var v in sigs1) { if(TransactionSignature.IsValid(v)) { allsigs.Add(new TransactionSignature(v)); } } foreach(var v in sigs2) { if(TransactionSignature.IsValid(v)) { allsigs.Add(new TransactionSignature(v)); } } var multiSigParams = PayToMultiSigTemplate.Instance.ExtractScriptPubKeyParameters(scriptPubKey); if(multiSigParams == null) throw new InvalidOperationException("The scriptPubKey is not a valid multi sig"); Dictionary<PubKey, TransactionSignature> sigs = new Dictionary<PubKey, TransactionSignature>(); foreach(var sig in allsigs) { foreach(var pubkey in multiSigParams.PubKeys) { if(sigs.ContainsKey(pubkey)) continue; // Already got a sig for this pubkey ScriptEvaluationContext eval = new ScriptEvaluationContext(); if(eval.CheckSig(sig.ToBytes(), pubkey.ToBytes(), scriptPubKey, transaction, n)) { sigs.AddOrReplace(pubkey, sig); } } } // Now build a merged CScript: int nSigsHave = 0; Script result = new Script(OpcodeType.OP_0); // pop-one-too-many workaround foreach(var pubkey in multiSigParams.PubKeys) { if(sigs.ContainsKey(pubkey)) { result += Op.GetPushOp(sigs[pubkey].ToBytes()); nSigsHave++; } if(nSigsHave >= multiSigParams.SignatureCount) break; } // Fill any missing with OP_0: for(int i = nSigsHave ; i < multiSigParams.SignatureCount ; i++) result += OpcodeType.OP_0; return result; }
private static Script CombineSignatures(Script scriptPubKey, Transaction transaction, int n, byte[][] sigs1, byte[][] sigs2) { var template = StandardScripts.GetTemplateFromScriptPubKey(scriptPubKey); if(template == null || template is TxNullDataTemplate) return PushAll(Max(sigs1, sigs2)); if(template is PayToPubkeyTemplate || template is PayToPubkeyHashTemplate) if(sigs1.Length == 0 || sigs1[0].Length == 0) return PushAll(sigs2); else return PushAll(sigs1); if(template is PayToScriptHashTemplate) { if(sigs1.Length == 0 || sigs1[sigs1.Length - 1].Length == 0) return PushAll(sigs2); if(sigs2.Length == 0 || sigs2[sigs2.Length - 1].Length == 0) return PushAll(sigs1); var redeemBytes = sigs1[sigs1.Length - 1]; var redeem = new Script(redeemBytes); sigs1 = sigs1.Take(sigs1.Length - 1).ToArray(); sigs2 = sigs2.Take(sigs2.Length - 1).ToArray(); Script result = CombineSignatures(redeem, transaction, n, sigs1, sigs2); result += Op.GetPushOp(redeemBytes); return result; } if(template is PayToMultiSigTemplate) { return CombineMultisig(scriptPubKey, transaction, n, sigs1, sigs2); } throw new NotSupportedException("An impossible thing happen !"); }
public static Script CombineSignatures(Script scriptPubKey, Transaction transaction, int n, Script scriptSig1, Script scriptSig2) { if(scriptPubKey == null) scriptPubKey = new Script(); var context = new ScriptEvaluationContext(); context.ScriptVerify = ScriptVerify.StrictEnc; context.EvalScript(scriptSig1, transaction, n); var stack1 = context.Stack.AsInternalArray(); context = new ScriptEvaluationContext(); context.ScriptVerify = ScriptVerify.StrictEnc; context.EvalScript(scriptSig2, transaction, n); var stack2 = context.Stack.AsInternalArray(); return CombineSignatures(scriptPubKey, transaction, n, stack1, stack2); }
public static bool VerifyScriptConsensus(Script scriptPubKey, Transaction tx, uint nIn, ScriptVerify flags) { var scriptPubKeyBytes = scriptPubKey.ToBytes(); var txToBytes = tx.ToBytes(); var err = BitcoinConsensusError.ERR_OK; var valid = VerifyScriptConsensus(scriptPubKeyBytes, (uint)scriptPubKeyBytes.Length, txToBytes, (uint)txToBytes.Length, nIn, flags, ref err); return valid == 1; }
public static bool VerifyScript(Script scriptPubKey, Transaction tx, int i, ScriptVerify scriptVerify = ScriptVerify.Standard, SigHash sigHash = SigHash.Undefined) { ScriptError unused; var scriptSig = tx.Inputs[i].ScriptSig; return VerifyScript(scriptSig, scriptPubKey, tx, i, scriptVerify, sigHash, out unused); }
public static bool AreOutputsStandard(Transaction tx) { return tx.Outputs.All(vout => IsStandardScriptPubKey(vout.ScriptPubKey)); }
public static bool VerifyScript(Script scriptPubKey, Transaction tx, int i, ScriptVerify scriptVerify, SigHash sigHash, out ScriptError error) { var scriptSig = tx.Inputs[i].ScriptSig; return VerifyScript(scriptSig, scriptPubKey, tx, i, scriptVerify, sigHash, out error); }
//https://en.bitcoin.it/wiki/OP_CHECKSIG public uint256 SignatureHash(Transaction txTo, int nIn, SigHash nHashType) { if(nIn >= txTo.Inputs.Count) { Utils.log("ERROR: SignatureHash() : nIn=" + nIn + " out of range\n"); return uint256.One; } // Check for invalid use of SIGHASH_SINGLE if(nHashType == SigHash.Single) { if(nIn >= txTo.Outputs.Count) { Utils.log("ERROR: SignatureHash() : nOut=" + nIn + " out of range\n"); return uint256.One; } } var scriptCopy = new Script(_Script); scriptCopy.FindAndDelete(OpcodeType.OP_CODESEPARATOR); var txCopy = new Transaction(txTo.ToBytes()); //Set all TxIn script to empty string foreach(var txin in txCopy.Inputs) { txin.ScriptSig = new Script(); } //Copy subscript into the txin script you are checking txCopy.Inputs[nIn].ScriptSig = scriptCopy; var hashType = nHashType & (SigHash)31; if(hashType == SigHash.None) { //The output of txCopy is set to a vector of zero size. txCopy.Outputs.Clear(); //All other inputs aside from the current input in txCopy have their nSequence index set to zero foreach(var input in txCopy.Inputs.Where((x, i) => i != nIn)) input.Sequence = 0; } else if(hashType == SigHash.Single) { //The output of txCopy is resized to the size of the current input index+1. txCopy.Outputs.RemoveRange(nIn + 1, txCopy.Outputs.Count - (nIn + 1)); //All other txCopy outputs aside from the output that is the same as the current input index are set to a blank script and a value of (long) -1. for(var i = 0 ; i < txCopy.Outputs.Count ; i++) { if(i == nIn) continue; txCopy.Outputs[i] = new TxOut(); } //All other txCopy inputs aside from the current input are set to have an nSequence index of zero. foreach(var input in txCopy.Inputs.Where((x, i) => i != nIn)) input.Sequence = 0; } if((nHashType & SigHash.AnyoneCanPay) != 0) { //The txCopy input vector is resized to a length of one. var script = txCopy.Inputs[nIn]; txCopy.Inputs.Clear(); txCopy.Inputs.Add(script); //The subScript (lead in by its length as a var-integer encoded!) is set as the first and only member of this vector. txCopy.Inputs[0].ScriptSig = scriptCopy; } //Serialize TxCopy, append 4 byte hashtypecode var ms = new MemoryStream(); var bitcoinStream = new BitcoinStream(ms, true); txCopy.ReadWrite(bitcoinStream); bitcoinStream.ReadWrite((uint)nHashType); var hashed = ms.ToArray(); return Hashes.Hash256(hashed); }
public void CanSignTransactionStandardMode() { var ledger = GetLedger(); var walletPubKey = ledger.GetWalletPubKey(new KeyPath("1'/0")); var address = (BitcoinAddress)walletPubKey.Address; Transaction funding = new Transaction(); funding.AddInput(Network.Main.GetGenesis().Transactions[0].Inputs[0]); funding.Outputs.Add(new TxOut(Money.Coins(1.1m), address)); funding.Outputs.Add(new TxOut(Money.Coins(1.0m), address)); funding.Outputs.Add(new TxOut(Money.Coins(1.2m), address)); var coins = funding.Outputs.AsCoins(); var spending = new Transaction(); spending.LockTime = 1; spending.Inputs.AddRange(coins.Select(o => new TxIn(o.Outpoint, o.ScriptPubKey))); spending.Outputs.Add(new TxOut(Money.Coins(0.5m), BitcoinAddress.Create("15sYbVpRh6dyWycZMwPdxJWD4xbfxReeHe"))); spending.Outputs.Add(new TxOut(Money.Coins(0.8m), address)); spending.Outputs.Add(new TxOut(Money.Zero, TxNullDataTemplate.Instance.GenerateScriptPubKey(new byte[] { 1, 2 }))); var signed = ledger.SignTransaction( new KeyPath("1'/0"), new Coin[] { new Coin(funding, 0), new Coin(funding, 1), new Coin(funding, 2), }, new Transaction[] { funding }, spending); }
public static void Pay(BitcoinSecret secret, BitcoinAddress toAddress, Money amount, Transaction fundingTransaction) { var fee = Money.Coins(0.0001m); Transaction payment = new Transaction(); payment.Inputs.Add(new TxIn() { PrevOut = new OutPoint(fundingTransaction.GetHash(), 1) }); payment.Outputs.Add(new TxOut() { Value = amount, ScriptPubKey = toAddress.ScriptPubKey }); var output = fundingTransaction.Outputs[0]; var change = output.Value - amount - fee; if (change < 0) { Console.WriteLine("There is not enough BTC in the funding transaction ({0}) to make this payment ({1})", output.Value, amount); Console.WriteLine("No payment being sent"); return; } payment.Outputs.Add(new TxOut() { Value = output.Value - amount - fee, ScriptPubKey = output.ScriptPubKey }); //Feedback ! var message = "Thanks ! :)"; var bytes = Encoding.UTF8.GetBytes(message); payment.Outputs.Add(new TxOut() { Value = Money.Zero, ScriptPubKey = TxNullDataTemplate.Instance.GenerateScriptPubKey(bytes) }); Console.WriteLine(payment); payment.Inputs[0].ScriptSig = fundingTransaction.Outputs[1].ScriptPubKey; payment.Sign(secret, false); using (var node = Node.Connect(Network.Main)) { Console.WriteLine("Doing version handshake"); node.VersionHandshake(); Console.WriteLine("Sending message"); node.SendMessage(new InvPayload(InventoryType.MSG_TX, payment.GetHash())); node.SendMessage(new TxPayload(payment)); Thread.Sleep(500); } }