Ejemplo n.º 1
0
 public void SetUp()
 {
     var myKey = new EcKey();
     _myAddress = myKey.ToAddress(Params);
     _defaultWallet = new DefaultWallet(Params);
     _defaultWallet.AddKey(myKey);
     _blockStore = new MemoryBlockStore(Params);
 }
Ejemplo n.º 2
0
        /// <summary>
        /// Once a transaction has some inputs and outputs added, the signatures in the inputs can be calculated. The
        /// signature is over the transaction itself, to prove the redeemer actually created that transaction,
        /// so we have to do this step last.
        /// </summary>
        /// <remarks>
        /// This method is similar to SignatureHash in script.cpp
        /// </remarks>
        /// <param name="hashType">This should always be set to SigHash.ALL currently. Other types are unused. </param>
        /// <param name="defaultWallet">A wallet is required to fetch the keys needed for signing.</param>
        /// <exception cref="ScriptException"/>
        public void SignInputs(SigHash hashType, IDefaultWallet defaultWallet)
        {
            Debug.Assert(_transactionInputs.Count > 0);
            Debug.Assert(_transactionOutputs.Count > 0);

            // I don't currently have an easy way to test other modes work, as the official client does not use them.
            Debug.Assert(hashType == SigHash.All);

            // The transaction is signed with the input scripts empty except for the input we are signing. In the case
            // where addInput has been used to set up a new transaction, they are already all empty. The input being signed
            // has to have the connected OUTPUT program in it when the hash is calculated!
            //
            // Note that each input may be claiming an output sent to a different key. So we have to look at the outputs
            // to figure out which key to sign with.

            var signatures = new byte[_transactionInputs.Count][];
            var signingKeys = new EcKey[_transactionInputs.Count];
            for (var i = 0; i < _transactionInputs.Count; i++)
            {
                var transactionInput = _transactionInputs[i];
                Debug.Assert(transactionInput.ScriptBytes.Length == 0, "Attempting to sign a non-fresh transaction");
                // Set the input to the script of its output.
                transactionInput.ScriptBytes = transactionInput.Outpoint.ConnectedPubKeyScript;
                // Find the signing key we'll need to use.
                var connectedPublicKeyHash = transactionInput.Outpoint.ConnectedPubKeyHash;
                var key = defaultWallet.FindKeyFromPublicHash(connectedPublicKeyHash);
                // This assert should never fire. If it does, it means the wallet is inconsistent.
                Debug.Assert(key != null,
                    "Transaction exists in wallet that we cannot redeem: " +
                    Utils.BytesToHexString(connectedPublicKeyHash));
                // Keep the key around for the script creation step below.
                signingKeys[i] = key;
                // The anyoneCanPay feature isn't used at the moment.
                const bool anyoneCanPay = false;
                var hash = HashTransactionForSignature(hashType, anyoneCanPay);
                // Set the script to empty again for the next input.
                transactionInput.ScriptBytes = TransactionInput.EmptyArray;

                // Now sign for the output so we can redeem it. We use the keypair to sign the hash,
                // and then put the resulting signature in the script along with the public key (below).
                using (var byteOutputStream = new MemoryStream())
                {
                    byteOutputStream.Write(key.Sign(hash));
                    byteOutputStream.Write((byte) (((int) hashType + 1) | (0)));
                    signatures[i] = byteOutputStream.ToArray();
                }
            }

            // Now we have calculated each signature, go through and create the scripts. Reminder: the script consists of
            // a signature (over a hash of the transaction) and the complete public key needed to sign for the connected
            // output.
            for (var i = 0; i < _transactionInputs.Count; i++)
            {
                var transactionInput = _transactionInputs[i];
                Debug.Assert(transactionInput.ScriptBytes.Length == 0);
                var signingKey = signingKeys[i];
                transactionInput.ScriptBytes = Script.CreateInputScript(signatures[i], signingKey.PublicKey);
            }

            // Every input is now complete.
        }
Ejemplo n.º 3
0
 /// <summary>
 /// Returns true if this output is to an address we have the keys for in the wallet.
 /// </summary>
 public bool IsMine(IDefaultWallet defaultWallet)
 {
     try
     {
         var publicKeyHash = ScriptPublicKey.PublicKeyHash;
         return defaultWallet.IsPubKeyHashMine(publicKeyHash);
     }
     catch (ScriptException e)
     {
         Log.ErrorFormat("Could not parse tx output script: {0}", e);
         return false;
     }
 }
Ejemplo n.º 4
0
 /// <summary>
 /// Calculates the sum of the outputs that are sending coins to a key in the wallet.
 /// </summary>
 public ulong GetValueSentToMe(IDefaultWallet defaultWallet)
 {
     return GetValueSentToMe(defaultWallet, true);
 }
Ejemplo n.º 5
0
 /// <summary>
 /// Calculates the sum of the outputs that are sending coins to a key in the wallet. The flag controls whether to
 /// include spent outputs or not.
 /// </summary>
 public ulong GetValueSentToMe(IDefaultWallet defaultWallet, bool includeSpent)
 {
     // This is tested in WalletTest.
     return
         _transactionOutputs.Where(transactionOutput => transactionOutput.IsMine(defaultWallet))
             .Where(transactionOutput => includeSpent || transactionOutput.IsAvailableForSpending)
             .Aggregate(0UL, (current, transactionOutput) => current + transactionOutput.Value);
 }
Ejemplo n.º 6
0
 /// <summary>
 /// Calculates the sum of the inputs that are spending coins with keys in the wallet. This requires the
 /// transactions sending coins to those keys to be in the wallet. This method will not attempt to download the
 /// blocks containing the input transactions if the key is in the wallet but the transactions are not.
 /// </summary>
 /// <returns>Sum in nanocoins.</returns>
 /// <exception cref="ScriptException"/>
 public ulong GetValueSentFromMe(IDefaultWallet defaultWallet)
 {
     // This is tested in WalletTest.
     return
         _transactionInputs.Select(
             transactionInput =>
                 (transactionInput.GetConnectedOutput(defaultWallet.Unspent) ??
                  transactionInput.GetConnectedOutput(defaultWallet.Spent)) ??
                 transactionInput.GetConnectedOutput(defaultWallet.Pending))
             .Where(connected => connected != null)
             .Where(connected => connected.IsMine(defaultWallet))
             .Aggregate(0UL, (current, connected) => current + connected.Value);
 }
Ejemplo n.º 7
0
 /// <summary>
 ///     Add a wallet to the BlockChain. Note that the wallet will be unaffected by any blocks received while it
 ///     was not part of this BlockChain. This method is useful if the wallet has just been created, and its keys
 ///     have never been in use, or if the wallet has been loaded along with the BlockChain
 /// </summary>
 public void AddWallet(IDefaultWallet defaultWallet)
 {
     lock (this)
     {
         _wallets.Add(defaultWallet);
     }
 }
Ejemplo n.º 8
0
 /// <summary>
 ///     Constructs a BlockChain connected to the given wallet and store. To obtain a <see cref="BitcoinSharp.Wallet.DefaultWallet" /> you can
 ///     construct
 ///     one from scratch, or you can deserialize a saved wallet from disk using <see cref="BitcoinSharp.Wallet.DefaultWallet.LoadFromFile" />.
 /// </summary>
 /// <remarks>
 ///     For the store you can use a <see cref="BitcoinSharp.Blockchain.Store.MemoryBlockStore" /> if you don't care about saving the downloaded data, or
 ///     a
 ///     <see cref="BitcoinSharp.Blockchain.Store.BoundedOverheadBlockStore" /> if you'd like to ensure fast start-up the next time you run the program.
 /// </remarks>
 /// <exception cref="BitcoinSharp.Blockchain.Store.BlockStoreException" />
 public BlockChain(NetworkParameters networkParameters, IDefaultWallet defaultWallet, IBlockStore blockStore)
     : this(networkParameters, new List<IDefaultWallet>(), blockStore)
 {
     if (defaultWallet != null)
         AddWallet(defaultWallet);
 }