Exemplo n.º 1
0
 /// <summary>
 /// Used only in creation of the genesis block.
 /// </summary>
 internal TransactionInput(NetworkParameters @params, Transaction parentTransaction, byte[] scriptBytes)
     : base(@params)
 {
     ScriptBytes = scriptBytes;
     Outpoint = new TransactionOutPoint(@params, -1, null);
     _sequence = uint.MaxValue;
     ParentTransaction = parentTransaction;
 }
Exemplo n.º 2
0
 internal TransactionOutput(NetworkParameters @params, Transaction parent, ulong value, Address to)
     : base(@params)
 {
     _value = value;
     _scriptBytes = Script.CreateOutputScript(to);
     ParentTransaction = parent;
     _availableForSpending = true;
 }
Exemplo n.º 3
0
 /// <summary>
 /// Used only in creation of the genesis blocks and in unit tests.
 /// </summary>
 internal TransactionOutput(NetworkParameters @params, Transaction parent, byte[] scriptBytes)
     : base(@params)
 {
     _scriptBytes = scriptBytes;
     _value = Utils.ToNanoCoins(50, 0);
     ParentTransaction = parent;
     _availableForSpending = true;
 }
Exemplo n.º 4
0
 /// <summary>
 /// Creates an UNSIGNED input that links to the given output
 /// </summary>
 internal TransactionInput(NetworkParameters @params, Transaction parentTransaction, TransactionOutput output)
     : base(@params)
 {
     var outputIndex = output.Index;
     Outpoint = new TransactionOutPoint(@params, outputIndex, output.ParentTransaction);
     ScriptBytes = EmptyArray;
     _sequence = uint.MaxValue;
     ParentTransaction = parentTransaction;
 }
Exemplo n.º 5
0
 internal TransactionOutPoint(NetworkParameters @params, int index, Transaction fromTx)
     : base(@params)
 {
     Index = index;
     if (fromTx != null)
     {
         Hash = fromTx.Hash;
         FromTx = fromTx;
     }
     else
     {
         // This happens when constructing the genesis block.
         Hash = Sha256Hash.ZeroHash;
     }
 }
Exemplo n.º 6
0
 /// <summary>
 /// Runs the script with the given Transaction as the "context". Some operations like CHECKSIG
 /// require a transaction to operate on (eg to hash). The context transaction is typically
 /// the transaction having its inputs verified, ie the one where the scriptSig comes from.
 /// </summary>
 /// <exception cref="BitCoinSharp.ScriptException" />
 public bool Run(Transaction context)
 {
     foreach (var chunk in _chunks)
     {
         if (chunk.Length == 1)
         {
             var opcode = chunk[0];
             switch (opcode)
             {
                 case OpDup:
                     ProcessOpDup();
                     break;
                 case OpHash160:
                     ProcessOpHash160();
                     break;
                 case OpEqualVerify:
                     ProcessOpEqualVerify();
                     break;
                 case OpCheckSig:
                     ProcessOpCheckSig(context);
                     break;
                 default:
                     _log.DebugFormat("Unknown/unimplemented opcode: {0}", opcode);
                     break;
             }
         }
         else
         {
             // Data block, push it onto the stack.
             _log.DebugFormat("Push {0}", Utils.BytesToHexString(chunk));
             _stack.Push(chunk);
         }
     }
     var result = _stack.Pop();
     if (result.Length != 1)
         throw new ScriptException("Script left junk at the top of the stack: " + Utils.BytesToHexString(result));
     return result[0] == 1;
 }
Exemplo n.º 7
0
        /// <exception cref="VerificationException"/>
        /// <exception cref="ScriptException"/>
        private void Receive(Transaction tx, StoredBlock block, BlockChain.NewBlockType blockType, bool reorg)
        {
            lock (this)
            {
                // Runs in a peer thread.
                var prevBalance = GetBalance();

                var txHash = tx.Hash;

                var bestChain = blockType == BlockChain.NewBlockType.BestChain;
                var sideChain = blockType == BlockChain.NewBlockType.SideChain;

                var valueSentFromMe = tx.GetValueSentFromMe(this);
                var valueSentToMe = tx.GetValueSentToMe(this);
                var valueDifference = (long) (valueSentToMe - valueSentFromMe);

                if (!reorg)
                {
                    _log.InfoFormat("Received tx{0} for {1} BTC: {2}", sideChain ? " on a side chain" : "",
                                    Utils.BitcoinValueToFriendlyString(valueDifference), tx.HashAsString);
                }

                // If this transaction is already in the wallet we may need to move it into a different pool. At the very
                // least we need to ensure we're manipulating the canonical object rather than a duplicate.
                Transaction wtx;
                if (Pending.TryGetValue(txHash, out wtx))
                {
                    Pending.Remove(txHash);
                    _log.Info("  <-pending");
                    // A transaction we created appeared in a block. Probably this is a spend we broadcast that has been
                    // accepted by the network.
                    //
                    // Mark the tx as appearing in this block so we can find it later after a re-org.
                    wtx.AddBlockAppearance(block);
                    if (bestChain)
                    {
                        if (valueSentToMe.Equals(0))
                        {
                            // There were no change transactions so this tx is fully spent.
                            _log.Info("  ->spent");
                            Debug.Assert(!Spent.ContainsKey(wtx.Hash), "TX in both pending and spent pools");
                            Spent[wtx.Hash] = wtx;
                        }
                        else
                        {
                            // There was change back to us, or this tx was purely a spend back to ourselves (perhaps for
                            // anonymization purposes).
                            _log.Info("  ->unspent");
                            Debug.Assert(!Unspent.ContainsKey(wtx.Hash), "TX in both pending and unspent pools");
                            Unspent[wtx.Hash] = wtx;
                        }
                    }
                    else if (sideChain)
                    {
                        // The transaction was accepted on an inactive side chain, but not yet by the best chain.
                        _log.Info("  ->inactive");
                        // It's OK for this to already be in the inactive pool because there can be multiple independent side
                        // chains in which it appears:
                        //
                        //     b1 --> b2
                        //        \-> b3
                        //        \-> b4 (at this point it's already present in 'inactive'
                        if (_inactive.ContainsKey(wtx.Hash))
                            _log.Info("Saw a transaction be incorporated into multiple independent side chains");
                        _inactive[wtx.Hash] = wtx;
                        // Put it back into the pending pool, because 'pending' means 'waiting to be included in best chain'.
                        Pending[wtx.Hash] = wtx;
                    }
                }
                else
                {
                    if (!reorg)
                    {
                        // Mark the tx as appearing in this block so we can find it later after a re-org.
                        tx.AddBlockAppearance(block);
                    }
                    // This TX didn't originate with us. It could be sending us coins and also spending our own coins if keys
                    // are being shared between different wallets.
                    if (sideChain)
                    {
                        _log.Info("  ->inactive");
                        _inactive[tx.Hash] = tx;
                    }
                    else if (bestChain)
                    {
                        ProcessTxFromBestChain(tx);
                    }
                }

                _log.InfoFormat("Balance is now: {0}", Utils.BitcoinValueToFriendlyString(GetBalance()));

                // Inform anyone interested that we have new coins. Note: we may be re-entered by the event listener,
                // so we must not make assumptions about our state after this loop returns! For example,
                // the balance we just received might already be spent!
                if (!reorg && bestChain && valueDifference > 0 && CoinsReceived != null)
                {
                    lock (CoinsReceived)
                    {
                        CoinsReceived(this, new WalletCoinsReceivedEventArgs(tx, prevBalance, GetBalance()));
                    }
                }
            }
        }
Exemplo n.º 8
0
 /// <summary>
 /// Handle when a transaction becomes newly active on the best chain, either due to receiving a new block or a
 /// re-org making inactive transactions active.
 /// </summary>
 /// <exception cref="VerificationException"/>
 private void ProcessTxFromBestChain(Transaction tx)
 {
     // This TX may spend our existing outputs even though it was not pending. This can happen in unit
     // tests and if keys are moved between wallets.
     UpdateForSpends(tx);
     if (!tx.GetValueSentToMe(this).Equals(0))
     {
         // It's sending us coins.
         _log.Info("  new tx ->unspent");
         Debug.Assert(!Unspent.ContainsKey(tx.Hash), "TX was received twice");
         Unspent[tx.Hash] = tx;
     }
     else
     {
         // It spent some of our coins and did not send us any.
         _log.Info("  new tx ->spent");
         Debug.Assert(!Spent.ContainsKey(tx.Hash), "TX was received twice");
         Spent[tx.Hash] = tx;
     }
 }
Exemplo n.º 9
0
 /// <summary>
 /// If the transactions outputs are all marked as spent, and it's in the unspent map, move it.
 /// </summary>
 private void MaybeMoveTxToSpent(Transaction tx, String context)
 {
     if (tx.IsEveryOutputSpent())
     {
         // There's nothing left I can spend in this transaction.
         if (Unspent.Remove(tx.Hash))
         {
             if (_log.IsInfoEnabled)
             {
                 _log.Info("  " + context + " <-unspent");
                 _log.Info("  " + context + " ->spent");
             }
             Spent[tx.Hash] = tx;
         }
     }
 }
Exemplo n.º 10
0
 /// <summary>
 /// Adds a coinbase transaction to the block. This exists for unit tests.
 /// </summary>
 internal void AddCoinbaseTransaction(Address to)
 {
     Transactions = new List<Transaction>();
     var coinbase = new Transaction(Params);
     // A real coinbase transaction has some stuff in the scriptSig like the extraNonce and difficulty. The
     // transactions are distinguished by every TX output going to a different key.
     //
     // Here we will do things a bit differently so a new address isn't needed every time. We'll put a simple
     // counter in the scriptSig so every transaction has a different hash. The output is also different.
     // Real coinbase transactions use <pubkey> OP_CHECKSIG rather than a send to an address though there's
     // nothing in the system that enforces that and both are just as valid.
     coinbase.AddInput(new TransactionInput(Params, coinbase, new[] {(byte) _coinbaseCounter++}));
     coinbase.AddOutput(new TransactionOutput(Params, coinbase, Utils.ToNanoCoins(50, 0), to));
     Transactions.Add(coinbase);
 }
Exemplo n.º 11
0
 /// <summary>
 /// Adds a coinbase transaction to the block. This exists for unit tests.
 /// </summary>
 internal void AddCoinbaseTransaction(byte[] pubKeyTo)
 {
     Transactions = new List<Transaction>();
     var coinbase = new Transaction(Params);
     // A real coinbase transaction has some stuff in the scriptSig like the extraNonce and difficulty. The
     // transactions are distinguished by every TX output going to a different key.
     //
     // Here we will do things a bit differently so a new address isn't needed every time. We'll put a simple
     // counter in the scriptSig so every transaction has a different hash.
     coinbase.AddInput(new TransactionInput(Params, coinbase, new[] {(byte) _txCounter++}));
     coinbase.AddOutput(new TransactionOutput(Params, coinbase, Script.CreateOutputScript(pubKeyTo)));
     Transactions.Add(coinbase);
 }
Exemplo n.º 12
0
 /// <param name="deadTx">The transaction that is newly dead.</param>
 /// <param name="replacementTx">The transaction that killed it.</param>
 public WalletDeadTransactionEventArgs(Transaction deadTx, Transaction replacementTx)
 {
     DeadTx = deadTx;
     ReplacementTx = replacementTx;
 }
Exemplo n.º 13
0
 /// <summary>
 /// Updates the wallet by checking if this TX spends any of our outputs. This is not used normally because
 /// when we receive our own spends, we've already marked the outputs as spent previously (during tx creation) so
 /// there's no need to go through and do it again.
 /// </summary>
 /// <exception cref="VerificationException"/>
 private void UpdateForSpends(Transaction tx)
 {
     // tx is on the best chain by this point.
     foreach (var input in tx.Inputs)
     {
         var result = input.Connect(Unspent, false);
         if (result == TransactionInput.ConnectionResult.NoSuchTx)
         {
             // Not found in the unspent map. Try again with the spent map.
             result = input.Connect(Spent, false);
             if (result == TransactionInput.ConnectionResult.NoSuchTx)
             {
                 // Doesn't spend any of our outputs or is coinbase.
                 continue;
             }
         }
         if (result == TransactionInput.ConnectionResult.AlreadySpent)
         {
             // Double spend! This must have overridden a pending tx, or the block is bad (contains transactions
             // that illegally double spend: should never occur if we are connected to an honest node).
             //
             // Work backwards like so:
             //
             //   A  -> spent by B [pending]
             //     \-> spent by C [chain]
             var doubleSpent = input.Outpoint.FromTx; // == A
             Debug.Assert(doubleSpent != null);
             var index = input.Outpoint.Index;
             var output = doubleSpent.Outputs[index];
             var spentBy = output.SpentBy;
             Debug.Assert(spentBy != null);
             var connected = spentBy.ParentTransaction;
             Debug.Assert(connected != null);
             if (Pending.Remove(connected.Hash))
             {
                 _log.InfoFormat("Saw double spend from chain override pending tx {0}", connected.HashAsString);
                 _log.Info("  <-pending ->dead");
                 _dead[connected.Hash] = connected;
                 // Now forcibly change the connection.
                 input.Connect(Unspent, true);
                 // Inform the event listeners of the newly dead tx.
                 if (DeadTransaction != null)
                 {
                     lock (DeadTransaction)
                     {
                         DeadTransaction(this, new WalletDeadTransactionEventArgs(connected, tx));
                     }
                 }
             }
         }
         else if (result == TransactionInput.ConnectionResult.Success)
         {
             // Otherwise we saw a transaction spend our coins, but we didn't try and spend them ourselves yet.
             // The outputs are already marked as spent by the connect call above, so check if there are any more for
             // us to use. Move if not.
             var connected = input.Outpoint.FromTx;
             MaybeMoveTxToSpent(connected, "prevtx");
         }
     }
 }
Exemplo n.º 14
0
 /// <param name="tx">The transaction which sent us the coins.</param>
 /// <param name="prevBalance">Balance before the coins were received.</param>
 /// <param name="newBalance">Current balance of the wallet.</param>
 public WalletCoinsReceivedEventArgs(Transaction tx, ulong prevBalance, ulong newBalance)
 {
     Tx = tx;
     PrevBalance = prevBalance;
     NewBalance = newBalance;
 }
Exemplo n.º 15
0
        private void ReprocessTxAfterReorg(IDictionary<Sha256Hash, Transaction> pool, Transaction tx)
        {
            _log.InfoFormat("  TX {0}", tx.HashAsString);
            var numInputs = tx.Inputs.Count;
            var noSuchTx = 0;
            var success = 0;
            var isDead = false;
            foreach (var input in tx.Inputs)
            {
                if (input.IsCoinBase)
                {
                    // Input is not in our wallet so there is "no such input tx", bit of an abuse.
                    noSuchTx++;
                    continue;
                }
                var result = input.Connect(pool, false);
                if (result == TransactionInput.ConnectionResult.Success)
                {
                    success++;
                }
                else if (result == TransactionInput.ConnectionResult.NoSuchTx)
                {
                    noSuchTx++;
                }
                else if (result == TransactionInput.ConnectionResult.AlreadySpent)
                {
                    isDead = true;
                    // This transaction was replaced by a double spend on the new chain. Did you just reverse
                    // your own transaction? I hope not!!
                    _log.Info("   ->dead, will not confirm now unless there's another re-org");
                    var doubleSpent = input.GetConnectedOutput(pool);
                    var replacement = doubleSpent.SpentBy.ParentTransaction;
                    _dead[tx.Hash] = tx;
                    Pending.Remove(tx.Hash);
                    // Inform the event listeners of the newly dead tx.
                    if (DeadTransaction != null)
                    {
                        lock (DeadTransaction)
                        {
                            DeadTransaction(this, new WalletDeadTransactionEventArgs(tx, replacement));
                        }
                    }
                    break;
                }
            }
            if (isDead) return;

            if (noSuchTx == numInputs)
            {
                _log.Info("   ->inactive");
                _inactive[tx.Hash] = tx;
            }
            else if (success == numInputs - noSuchTx)
            {
                // All inputs are either valid for spending or don't come from us. Miners are trying to re-include it.
                _log.Info("   ->pending");
                Pending[tx.Hash] = tx;
                _dead.Remove(tx.Hash);
            }
        }
Exemplo n.º 16
0
        /// <exception cref="BitCoinSharp.ProtocolException" />
        protected override void Parse()
        {
            _version = ReadUint32();
            _prevBlockHash = ReadHash();
            _merkleRoot = ReadHash();
            _time = ReadUint32();
            _difficultyTarget = ReadUint32();
            _nonce = ReadUint32();

            _hash = Utils.ReverseBytes(Utils.DoubleDigest(Bytes, 0, Cursor));

            if (Cursor == Bytes.Length)
            {
                // This message is just a header, it has no transactions.
                return;
            }

            var numTransactions = (int) ReadVarInt();
            Transactions = new List<Transaction>(numTransactions);
            for (var i = 0; i < numTransactions; i++)
            {
                var tx = new Transaction(Params, Bytes, Cursor);
                Transactions.Add(tx);
                Cursor += tx.MessageSize;
            }
        }
Exemplo n.º 17
0
 /// <summary>
 /// Adds a transaction to this block.
 /// </summary>
 internal void AddTransaction(Transaction t)
 {
     if (Transactions == null)
     {
         Transactions = new List<Transaction>();
     }
     Transactions.Add(t);
     // Force a recalculation next time the values are needed.
     _merkleRoot = null;
     _hash = null;
 }
Exemplo n.º 18
0
        // WARNING: Unfinished and untested!
        /// <exception cref="BitCoinSharp.ScriptException" />
        private void ProcessOpCheckSig(Transaction context)
        {
            _stack.Pop();
            var sigAndHashType = _stack.Pop();
            // The signature has an extra byte on the end to indicate the type of hash. The signature
            // is over the contents of the program, minus the signature itself of course.
            var hashType = sigAndHashType[sigAndHashType.Length - 1];
            // The high bit of the hashType byte is set to indicate "anyone can pay".
            var anyoneCanPay = hashType >= 0x80;
            // Mask out the top bit.
            hashType &= 0x7F;
            Transaction.SigHash sigHash;
            switch (hashType)
            {
                case 1:
                    sigHash = Transaction.SigHash.All;
                    break;
                case 2:
                    sigHash = Transaction.SigHash.None;
                    break;
                case 3:
                    sigHash = Transaction.SigHash.Single;
                    break;
                default:
                    // TODO: This should probably not be an exception.
                    throw new ScriptException("Unknown sighash byte: " + sigAndHashType[sigAndHashType.Length - 1]);
            }

            var sig = new byte[sigAndHashType.Length - 1];
            Array.Copy(sigAndHashType, 0, sig, 0, sig.Length);

            _log.DebugFormat("CHECKSIG: hashtype={0} anyoneCanPay={1}", sigHash, anyoneCanPay);
            if (context == null)
            {
                // TODO: Fix the unit tests to run scripts in transaction context then remove this.
                PushBool(true);
                return;
            }
            // TODO: Implement me!
            // Transaction tx = context.simplify(sigHash, 0, anyoneCanPay);

            // The steps to do so are as follows:
            //   - Use the hashtype to fiddle the transaction as appropriate
            //   - Serialize the transaction and hash it
            //   - Use EC code to verify the hash matches the signature
            PushBool(true);
        }
Exemplo n.º 19
0
 private static Block CreateGenesis(NetworkParameters n)
 {
     var genesisBlock = new Block(n);
     var t = new Transaction(n);
     try
     {
         // A script containing the difficulty bits and the following message:
         //
         //   "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks"
         var bytes = Hex.Decode("04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73");
         t.AddInput(new TransactionInput(n, t, bytes));
         using (var scriptPubKeyBytes = new MemoryStream())
         {
             Script.WriteBytes(scriptPubKeyBytes, Hex.Decode("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f"));
             scriptPubKeyBytes.Write(Script.OpCheckSig);
             t.AddOutput(new TransactionOutput(n, scriptPubKeyBytes.ToArray()));
         }
     }
     catch (Exception)
     {
     }
     genesisBlock.AddTransaction(t);
     return genesisBlock;
 }
Exemplo n.º 20
0
        /// <summary>
        /// Given a named input and the transaction output it connects to, runs the script formed from the
        /// concatenation of the input and output scripts, returning true if the link is valid. In
        /// this way, we prove that the creator of this transaction is allowed to redeem the output
        /// of the connectedTx and thus spend the money.
        /// </summary>
        /// <remarks>
        /// <b>WARNING: NOT FINISHED</b><p />
        /// </remarks>
        /// <param name="inputIndex">Which input to verify.</param>
        /// <param name="connectedTx">The Transaction that the input is connected to.</param>
        /// <exception cref="BitCoinSharp.ScriptException" />
        public bool VerifyInput(int inputIndex, Transaction connectedTx)
        {
            var input = _inputs[inputIndex];
            var inScript = input.ScriptSig;
            var pubkey = inScript.PubKey;

            return false;
        }
Exemplo n.º 21
0
        /// <summary>
        /// Returns a solved block that builds on top of this one. This exists for unit tests.
        /// </summary>
        internal Block CreateNextBlock(Address to, uint time)
        {
            var b = new Block(Params);
            b.DifficultyTarget = _difficultyTarget;
            b.AddCoinbaseTransaction(_emptyBytes);

            // Add a transaction paying 50 coins to the "to" address.
            var t = new Transaction(Params);
            t.AddOutput(new TransactionOutput(Params, t, Utils.ToNanoCoins(50, 0), to));
            // The input does not really need to be a valid signature, as long as it has the right general form.
            var input = new TransactionInput(Params, t, Script.CreateInputScript(_emptyBytes, _emptyBytes));
            // Importantly the outpoint hash cannot be zero as that's how we detect a coinbase transaction in isolation
            // but it must be unique to avoid 'different' transactions looking the same.
            var counter = new byte[32];
            counter[0] = (byte) _txCounter++;
            input.Outpoint.Hash = new Sha256Hash(counter);
            t.AddInput(input);
            b.AddTransaction(t);

            b.PrevBlockHash = Hash;
            b.TimeSeconds = time;
            b.Solve();
            b.VerifyHeader();
            return b;
        }
Exemplo n.º 22
0
 /// <summary>
 /// Deserializes a transaction output message. This is usually part of a transaction message.
 /// </summary>
 /// <exception cref="ProtocolException"/>
 public TransactionOutput(NetworkParameters @params, Transaction parent, byte[] payload, int offset)
     : base(@params, payload, offset)
 {
     ParentTransaction = parent;
     _availableForSpending = true;
 }
Exemplo n.º 23
0
 /// <summary>
 /// Call this when we have successfully transmitted the send tx to the network, to update the wallet.
 /// </summary>
 internal void ConfirmSend(Transaction tx)
 {
     lock (this)
     {
         Debug.Assert(!Pending.ContainsKey(tx.Hash), "confirmSend called on the same transaction twice");
         _log.InfoFormat("confirmSend of {0}", tx.HashAsString);
         // Mark the outputs of the used transactions as spent, so we don't try and spend it again.
         foreach (var input in tx.Inputs)
         {
             var connectedOutput = input.Outpoint.ConnectedOutput;
             connectedOutput.MarkAsSpent(input);
         }
         // Some of the outputs probably send coins back to us, eg for change or because this transaction is just
         // consolidating the wallet. Mark any output that is NOT back to us as spent. Then add this TX to the
         // pending pool.
         foreach (var output in tx.Outputs)
         {
             if (!output.IsMine(this))
             {
                 // This output didn't go to us, so by definition it is now spent.
                 output.MarkAsSpent(null);
             }
         }
         Pending[tx.Hash] = tx;
     }
 }
Exemplo n.º 24
0
 /// <summary>
 /// Call this when we have successfully transmitted the send tx to the network, to update the wallet.
 /// </summary>
 internal void ConfirmSend(Transaction tx)
 {
     lock (this)
     {
         Debug.Assert(!Pending.ContainsKey(tx.Hash), "confirmSend called on the same transaction twice");
         _log.InfoFormat("confirmSend of {0}", tx.HashAsString);
         // Mark the outputs of the used transactions as spent, so we don't try and spend it again.
         foreach (var input in tx.Inputs)
         {
             var connectedOutput = input.Outpoint.ConnectedOutput;
             var connectedTx = connectedOutput.ParentTransaction;
             connectedOutput.MarkAsSpent(input);
             MaybeMoveTxToSpent(connectedTx, "spent tx");
         }
         // Add to the pending pool. It'll be moved out once we receive this transaction on the best chain.
         Pending[tx.Hash] = tx;
     }
 }
Exemplo n.º 25
0
        /// <exception cref="BitCoinSharp.ScriptException" />
        /// <exception cref="BitCoinSharp.VerificationException" />
        private void ScanTransaction(StoredBlock block, Transaction tx, NewBlockType blockType)
        {
            var shouldReceive = false;
            foreach (var output in tx.Outputs)
            {
                // TODO: Handle more types of outputs, not just regular to address outputs.
                if (output.ScriptPubKey.IsSentToIp) return;
                // This is not thread safe as a key could be removed between the call to isMine and receive.
                if (output.IsMine(_wallet))
                {
                    shouldReceive = true;
                }
            }

            // Coinbase transactions don't have anything useful in their inputs (as they create coins out of thin air).
            if (!tx.IsCoinBase)
            {
                foreach (var i in tx.Inputs)
                {
                    var pubkey = i.ScriptSig.PubKey;
                    // This is not thread safe as a key could be removed between the call to isPubKeyMine and receive.
                    if (_wallet.IsPubKeyMine(pubkey))
                    {
                        shouldReceive = true;
                    }
                }
            }

            if (shouldReceive)
                _wallet.Receive(tx, block, blockType);
        }
Exemplo n.º 26
0
 /// <summary>
 /// Deserializes an input message. This is usually part of a transaction message.
 /// </summary>
 /// <exception cref="BitCoinSharp.ProtocolException" />
 public TransactionInput(NetworkParameters @params, Transaction parentTransaction, byte[] payload, int offset)
     : base(@params, payload, offset)
 {
     ParentTransaction = parentTransaction;
 }
Exemplo n.º 27
0
        /// <summary>
        /// Creates a transaction that sends $coins.$cents BTC to the given address.
        /// </summary>
        /// <remarks>
        /// IMPORTANT: This method does NOT update the wallet. If you call createSend again you may get two transactions
        /// that spend the same coins. You have to call confirmSend on the created transaction to prevent this,
        /// but that should only occur once the transaction has been accepted by the network. This implies you cannot have
        /// more than one outstanding sending tx at once.
        /// </remarks>
        /// <param name="address">The BitCoin address to send the money to.</param>
        /// <param name="nanocoins">How much currency to send, in nanocoins.</param>
        /// <param name="changeAddress">
        /// Which address to send the change to, in case we can't make exactly the right value from
        /// our coins. This should be an address we own (is in the keychain).
        /// </param>
        /// <returns>
        /// A new <see cref="Transaction"/> or null if we cannot afford this send.
        /// </returns>
        internal Transaction CreateSend(Address address, ulong nanocoins, Address changeAddress)
        {
            lock (this)
            {
                _log.Info("Creating send tx to " + address + " for " +
                          Utils.BitcoinValueToFriendlyString(nanocoins));
                // To send money to somebody else, we need to do gather up transactions with unspent outputs until we have
                // sufficient value. Many coin selection algorithms are possible, we use a simple but suboptimal one.
                // TODO: Sort coins so we use the smallest first, to combat wallet fragmentation and reduce fees.
                var valueGathered = 0UL;
                var gathered = new LinkedList<TransactionOutput>();
                foreach (var tx in Unspent.Values)
                {
                    foreach (var output in tx.Outputs)
                    {
                        if (!output.IsAvailableForSpending) continue;
                        if (!output.IsMine(this)) continue;
                        gathered.AddLast(output);
                        valueGathered += output.Value;
                    }
                    if (valueGathered >= nanocoins) break;
                }
                // Can we afford this?
                if (valueGathered < nanocoins)
                {
                    _log.Info("Insufficient value in wallet for send, missing " +
                              Utils.BitcoinValueToFriendlyString(nanocoins - valueGathered));
                    // TODO: Should throw an exception here.
                    return null;
                }
                Debug.Assert(gathered.Count > 0);
                var sendTx = new Transaction(_params);
                sendTx.AddOutput(new TransactionOutput(_params, sendTx, nanocoins, address));
                var change = (long) (valueGathered - nanocoins);
                if (change > 0)
                {
                    // The value of the inputs is greater than what we want to send. Just like in real life then,
                    // we need to take back some coins ... this is called "change". Add another output that sends the change
                    // back to us.
                    _log.Info("  with " + Utils.BitcoinValueToFriendlyString((ulong) change) + " coins change");
                    sendTx.AddOutput(new TransactionOutput(_params, sendTx, (ulong) change, changeAddress));
                }
                foreach (var output in gathered)
                {
                    sendTx.AddInput(output);
                }

                // Now sign the inputs, thus proving that we are entitled to redeem the connected outputs.
                sendTx.SignInputs(Transaction.SigHash.All, this);
                _log.InfoFormat("  created {0}", sendTx.HashAsString);
                return sendTx;
            }
        }
Exemplo n.º 28
0
 /// <summary>
 /// Called by the <see cref="BlockChain"/> when we receive a new block that sends coins to one of our addresses or
 /// spends coins from one of our addresses (note that a single transaction can do both).
 /// </summary>
 /// <remarks>
 /// This is necessary for the internal book-keeping Wallet does. When a transaction is received that sends us
 /// coins it is added to a pool so we can use it later to create spends. When a transaction is received that
 /// consumes outputs they are marked as spent so they won't be used in future.<p/>
 /// A transaction that spends our own coins can be received either because a spend we created was accepted by the
 /// network and thus made it into a block, or because our keys are being shared between multiple instances and
 /// some other node spent the coins instead. We still have to know about that to avoid accidentally trying to
 /// double spend.<p/>
 /// A transaction may be received multiple times if is included into blocks in parallel chains. The blockType
 /// parameter describes whether the containing block is on the main/best chain or whether it's on a presently
 /// inactive side chain. We must still record these transactions and the blocks they appear in because a future
 /// block might change which chain is best causing a reorganize. A re-org can totally change our balance!
 /// </remarks>
 /// <exception cref="VerificationException"/>
 /// <exception cref="ScriptException"/>
 internal void Receive(Transaction tx, StoredBlock block, BlockChain.NewBlockType blockType)
 {
     lock (this)
     {
         Receive(tx, block, blockType, false);
     }
 }
Exemplo n.º 29
0
 /// <summary>
 /// Broadcast a transaction to all connected peers.
 /// </summary>
 /// <returns>Whether we sent to at least one peer.</returns>
 public bool BroadcastTransaction(Transaction tx)
 {
     var success = false;
     lock (_peers)
     {
         foreach (var peer in _peers)
         {
             try
             {
                 peer.BroadcastTransaction(tx);
                 success = true;
             }
             catch (IOException e)
             {
                 _log.Error("failed to broadcast to " + peer, e);
             }
         }
     }
     return success;
 }