public void TestScriptPubKey() { // Check we can extract the to address var pubkeyBytes = Hex.Decode(_pubkeyProg); var pubkey = new Script(_params, pubkeyBytes, 0, pubkeyBytes.Length); var toAddr = new Address(_params, pubkey.PublicKeyHash); Assert.AreEqual("mkFQohBpy2HDXrCwyMrYL5RtfrmeiuuPY2", toAddr.ToString()); }
public void TestDecoding() { var a = new Address(TestParams, "n4eA2nbYqErp7H6jebchxAN59DmNpksexv"); Assert.AreEqual("fda79a24e50ff70ff42f7d89585da5bd19d9e5cc", Utils.BytesToHexString(a.Hash160)); var b = new Address(ProdParams, "17kzeh4N8g49GFvdDzSf8PjaPfyoD1MndL"); Assert.AreEqual("4a22c3c4cbb31e4d03b15550636762bda0baf85a", Utils.BytesToHexString(b.Hash160)); }
public void TestScriptSig() { var sigProgBytes = Hex.Decode(_sigProg); var script = new Script(_params, sigProgBytes, 0, sigProgBytes.Length); // Test we can extract the from address. var hash160 = Utils.Sha256Hash160(script.PublicKey); var a = new Address(_params, hash160); Assert.AreEqual("mkFQohBpy2HDXrCwyMrYL5RtfrmeiuuPY2", a.ToString()); }
public void TestStringification() { // Test a test-net address. var a = new Address(TestParams, Hex.Decode("fda79a24e50ff70ff42f7d89585da5bd19d9e5cc")); Assert.AreEqual("n4eA2nbYqErp7H6jebchxAN59DmNpksexv", a.ToString()); var b = new Address(ProdParams, Hex.Decode("4a22c3c4cbb31e4d03b15550636762bda0baf85a")); Assert.AreEqual("17kzeh4N8g49GFvdDzSf8PjaPfyoD1MndL", b.ToString()); }
public void SetUp() { _unitTestParams = NetworkParameters.UnitTests(); _defaultWallet = new DefaultWallet(_unitTestParams); _defaultWallet.AddKey(new EcKey()); _chainBlockStore = new MemoryBlockStore(_unitTestParams); _chain = new BlockChain(_unitTestParams, _defaultWallet, _chainBlockStore); _coinbaseTo = _defaultWallet.Keychain[0].ToAddress(_unitTestParams); _someOtherGuy = new EcKey().ToAddress(_unitTestParams); }
public static Transaction CreateFakeTx(NetworkParameters @params, ulong nanocoins, Address to) { var t = new Transaction(@params); var o1 = new TransactionOutput(@params, t, nanocoins, to); t.AddOutput(o1); // Make a previous tx simply to send us sufficient coins. This prev tx is not really valid but it doesn't // matter for our purposes. var prevTx = new Transaction(@params); var prevOut = new TransactionOutput(@params, prevTx, nanocoins, to); prevTx.AddOutput(prevOut); // Connect it. t.AddInput(prevOut); return t; }
public static void Run(string[] args) { // TODO: Assumes production network not testnet. Make it selectable. var @params = NetworkParameters.ProdNet(); try { // Decode the private key from Satoshi's Base58 variant. If 51 characters long then it's from BitCoins // "dumpprivkey" command and includes a version byte and checksum. Otherwise assume it's a raw key. EcKey key; if (args[0].Length == 51) { var dumpedPrivateKey = new DumpedPrivateKey(@params, args[0]); key = dumpedPrivateKey.Key; } else { var privKey = Base58.DecodeToBigInteger(args[0]); key = new EcKey(privKey); } Console.WriteLine("Address from private key is: " + key.ToAddress(@params)); // And the address ... var destination = new Address(@params, args[1]); // Import the private key to a fresh wallet. var wallet = new DefaultWallet(@params); wallet.AddKey(key); // Find the transactions that involve those coins. using (var blockStore = new MemoryBlockStore(@params)) { var chain = new BlockChain(@params, wallet, blockStore); var peerGroup = new PeerGroup(blockStore, @params, chain); peerGroup.AddAddress(new PeerAddress(IPAddress.Loopback)); peerGroup.Start(); peerGroup.DownloadBlockChain(); peerGroup.Stop(); // And take them! Console.WriteLine("Claiming " + Utils.BitcoinValueToFriendlyString(wallet.GetBalance()) + " coins"); wallet.SendCoins(peerGroup, destination, wallet.GetBalance()); // Wait a few seconds to let the packets flush out to the network (ugly). Thread.Sleep(5000); } } catch (IndexOutOfRangeException) { Console.WriteLine("First arg should be private key in Base58 format. Second argument should be address to send to."); } }
internal static byte[] CreateOutputScript(Address toAddress) { using (var bits = new MemoryStream()) { // TODO: Do this by creating a Script *first* then having the script reassemble itself into bytes. bits.Write(OpDup); bits.Write(OpHash160); WriteBytes(bits, toAddress.Hash160); bits.Write(OpEqualVerify); bits.Write(OpCheckSig); return bits.ToArray(); } }
public void SetUp() { _testNetChainBlockStore = new MemoryBlockStore(_testNet); _testNetChain = new BlockChain(_testNet, new DefaultWallet(_testNet), _testNetChainBlockStore); _unitTestParams = NetworkParameters.UnitTests(); _defaultWallet = new DefaultWallet(_unitTestParams); _defaultWallet.AddKey(new EcKey()); ResetBlockStore(); _chain = new BlockChain(_unitTestParams, _defaultWallet, _blockStore); _coinbaseTo = _defaultWallet.Keychain[0].ToAddress(_unitTestParams); }
public void SetUp() { var myKey = new EcKey(); _myAddress = myKey.ToAddress(Params); _defaultWallet = new DefaultWallet(Params); _defaultWallet.AddKey(myKey); _blockStore = new MemoryBlockStore(Params); }
/// <summary> /// Sends coins to the given address, via the given <see cref="BitcoinSharp.Core.Network.Peer"/>. /// Change is returned to the first key in the wallet. /// </summary> /// <param name="peer">The peer to send via.</param> /// <param name="toAddress">Which address to send coins to.</param> /// <param name="nanocoins">How many nanocoins to send. You can use Utils.ToNanoCoins() to calculate this.</param> /// <returns>The <see cref="BitcoinSharp.Core.Messages.Transaction"/> that was created or null if there was insufficient balance to send the coins.</returns> /// <exception cref="System.IO.IOException">If there was a problem broadcasting the transaction.</exception> public Transaction SendCoins(Peer peer, Address toAddress, ulong nanocoins) { lock (this) { var transaction = CreateSend(toAddress, nanocoins); if (transaction == null) // Not enough money! :-( return null; peer.BroadcastTransaction(transaction); ConfirmSend(transaction); return transaction; } }
/// <summary> /// Sends coins to the given address, via the given <see cref="BitcoinSharp.Core.Network.PeerGroup"/>. /// Change is returned to the first key in the wallet. /// </summary> /// <param name="peerGroup">The peer group to send via.</param> /// <param name="toAddress">Which address to send coins to.</param> /// <param name="nanocoins">How many nanocoins to send. You can use Utils.toNanoCoins() to calculate this.</param> /// <returns> /// The <see cref="BitcoinSharp.Core.Messages.Transaction"/> that was created or null if there was insufficient balance to send the coins. /// </returns> /// <exception cref="System.IO.IOException">If there was a problem broadcasting the transaction.</exception> public Transaction SendCoins(PeerGroup peerGroup, Address toAddress, ulong nanocoins) { lock (this) { var transaction = CreateSend(toAddress, nanocoins); if (transaction == null) // Not enough money! :-( return null; if (!peerGroup.BroadcastTransaction(transaction)) { throw new IOException("Failed to broadcast tx to all connected peers"); } // TODO - retry logic ConfirmSend(transaction); return transaction; } }
/// <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="BitcoinSharp.Core.Messages.Transaction"/> or null if we cannot afford this send. /// </returns> public 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 transaction in Unspent.Values) { foreach (var transactionOutput in transaction.TransactionOutputs) { if (!transactionOutput.IsAvailableForSpending) continue; if (!transactionOutput.IsMine(this)) continue; gathered.AddLast(transactionOutput); valueGathered += transactionOutput.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 sendTransaction = new Transaction(_networkParameters); sendTransaction.AddOutput(new TransactionOutput(_networkParameters, sendTransaction, 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"); sendTransaction.AddOutput(new TransactionOutput(_networkParameters, sendTransaction, (ulong) change, changeAddress)); } foreach (var output in gathered) { sendTransaction.AddInput(output); } // Now sign the inputs, thus proving that we are entitled to redeem the connected outputs. sendTransaction.SignInputs(Transaction.SigHash.All, this); Log.InfoFormat(" created {0}", sendTransaction.HashAsString); return sendTransaction; } }
/// <summary> /// Statelessly creates a transaction that sends the given number of nanocoins to address. The change is sent to /// the first address in the wallet, so you must have added at least one key. /// </summary> /// <remarks> /// This method is stateless in the sense that calling it twice with the same inputs will result in two /// Transaction objects which are equal. The wallet is not updated to track its pending status or to mark the /// coins as spent until confirmSend is called on the result. /// </remarks> public Transaction CreateSend(Address address, ulong nanocoins) { lock (this) { // For now let's just pick the first key in our keychain. In future we might want to do something else to // give the user better privacy here, eg in incognito mode. Debug.Assert(Keychain.Count > 0, "Can't send value without an address to use for receiving change"); var first = Keychain[0]; return CreateSend(address, nanocoins, first.ToAddress(_networkParameters)); } }