public void SetUp() { var myKey = new EcKey(); _myAddress = myKey.ToAddress(Params); _defaultWallet = new DefaultWallet(Params); _defaultWallet.AddKey(myKey); _blockStore = new MemoryBlockStore(Params); }
/// <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. }
/// <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; } }
/// <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); }
/// <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); }
/// <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); }
/// <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); } }
/// <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); }