public void TestDoubleSpendOnFork() { // Check what happens when a re-org happens and one of our confirmed transactions becomes invalidated by a // double spend on the new best chain. var eventCalled = false; _defaultWallet.DeadTransaction += (sender, e) => eventCalled = true; var b1 = _unitTestParams.GenesisBlock.CreateNextBlock(_coinbaseTo); _chain.Add(b1); var t1 = _defaultWallet.CreateSend(_someOtherGuy, Utils.ToNanoCoins(10, 0)); var yetAnotherGuy = new EcKey().ToAddress(_unitTestParams); var t2 = _defaultWallet.CreateSend(yetAnotherGuy, Utils.ToNanoCoins(20, 0)); _defaultWallet.ConfirmSend(t1); // Receive t1 as confirmed by the network. var b2 = b1.CreateNextBlock(new EcKey().ToAddress(_unitTestParams)); b2.AddTransaction(t1); b2.Solve(); _chain.Add(b2); // Now we make a double spend become active after a re-org. var b3 = b1.CreateNextBlock(new EcKey().ToAddress(_unitTestParams)); b3.AddTransaction(t2); b3.Solve(); _chain.Add(b3); // Side chain. var b4 = b3.CreateNextBlock(new EcKey().ToAddress(_unitTestParams)); _chain.Add(b4); // New best chain. // Should have seen a double spend. Assert.IsTrue(eventCalled); Assert.AreEqual(Utils.ToNanoCoins(30, 0), _defaultWallet.GetBalance()); }
public void TestStorage() { var temp = new FileInfo(Path.GetTempFileName()); try { Console.WriteLine(temp.FullName); var @params = NetworkParameters.UnitTests(); var to = new EcKey().ToAddress(@params); StoredBlock b1; using (var store = new DiskBlockStore(@params, temp)) { // Check the first block in a new store is the genesis block. var genesis = store.GetChainHead(); Assert.AreEqual(@params.GenesisBlock, genesis.BlockHeader); // Build a new block. b1 = genesis.Build(genesis.BlockHeader.CreateNextBlock(to).CloneAsHeader()); store.Put(b1); store.SetChainHead(b1); } // Check we can get it back out again if we rebuild the store object. using (var store = new DiskBlockStore(@params, temp)) { var b2 = store.Get(b1.BlockHeader.Hash); Assert.AreEqual(b1, b2); // Check the chain head was stored correctly also. Assert.AreEqual(b1, store.GetChainHead()); } } finally { temp.Delete(); } }
public void ImportExistingPrivateKey() { //arrange //this is an exsiting (testnet) private key. const string testPrivateKey = "00d1470e342840b283c8007291992b21176d610a732a1f900334c0d71866422ad5"; var privkey = new BigInteger(1, Hex.Decode(testPrivateKey)); var key = new EcKey(privkey); key.ToString().Should().Be("pub:045c7266196cb522208fad3541854a412e238044de415e7f9071ac27124481d0130e4eee6f76e0649eaa84bf35b1f84444f337ac902569c631fa73be80c5583fc0 priv:00d1470e342840b283c8007291992b21176d610a732a1f900334c0d71866422ad5"); }
public void Base58EncodingStress() { // Replace the loop bound with 1000 to get some keys with leading zero byte for (var i = 0; i < 20; i++) { var key = new EcKey(); var key1 = new DumpedPrivateKey(NetworkParameters.TestNet(), key.GetPrivateKeyEncoded(NetworkParameters.TestNet()).ToString()).Key; Assert.AreEqual(Utils.BytesToHexString(key.GetPrivateKeyBytes()), Utils.BytesToHexString(key1.GetPrivateKeyBytes())); } }
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."); } }
public void CreatePrivateKey() { var networkParameters = NetworkParameters.TestNet(); var keyPair = new EcKey(); //the tostring displays public and private. Logger.Debug(keyPair); //private key in format for import/export from bitcoin-qt Logger.Debug(keyPair.GetPrivateKeyEncoded(networkParameters)); //public key. this is not the address. Logger.Debug(keyPair.PublicKey); //create an address var address = keyPair.ToAddress(networkParameters); //address. Logger.Debug(address.ToString()); }
public void TestSignatures() { // Test that we can construct an ECKey from a private key (deriving the public from the private), then signing // a message with it. var privkey = new BigInteger(1, Hex.Decode("180cb41c7c600be951b5d3d0a7334acc7506173875834f7a6c4c786a28fcbb19")); var key = new EcKey(privkey); var message = new byte[32]; // All zeroes. var output = key.Sign(message); Assert.IsTrue(key.Verify(message, output)); // Test interop with a signature from elsewhere. var sig = Hex.Decode("3046022100dffbc26774fc841bbe1c1362fd643609c6e42dcb274763476d87af2c0597e89e022100c59e3c13b96b316cae9fa0ab0260612c7a133a6fe2b3445b6bf80b3123bf274d"); Assert.IsTrue(key.Verify(message, sig)); }
public void BasicSpending() { // We'll set up a wallet that receives a coin, then sends a coin of lesser value and keeps the change. var v1 = Utils.ToNanoCoins(1, 0); var t1 = TestUtils.CreateFakeTx(Params, v1, _myAddress); _defaultWallet.Receive(t1, null, BlockChain.NewBlockType.BestChain); Assert.AreEqual(v1, _defaultWallet.GetBalance()); Assert.AreEqual(1, _defaultWallet.GetPoolSize(WalletPool.Unspent)); Assert.AreEqual(1, _defaultWallet.GetPoolSize(WalletPool.All)); var k2 = new EcKey(); var v2 = Utils.ToNanoCoins(0, 50); var t2 = _defaultWallet.CreateSend(k2.ToAddress(Params), v2); Assert.AreEqual(1, _defaultWallet.GetPoolSize(WalletPool.Unspent)); Assert.AreEqual(1, _defaultWallet.GetPoolSize(WalletPool.All)); // Do some basic sanity checks. Assert.AreEqual(1, t2.TransactionInputs.Count); Assert.AreEqual(_myAddress, t2.TransactionInputs[0].ScriptSig.FromAddress); // We have NOT proven that the signature is correct! _defaultWallet.ConfirmSend(t2); Assert.AreEqual(1, _defaultWallet.GetPoolSize(WalletPool.Pending)); Assert.AreEqual(1, _defaultWallet.GetPoolSize(WalletPool.Spent)); Assert.AreEqual(2, _defaultWallet.GetPoolSize(WalletPool.All)); }
public void Transactions() { // This test covers a _bug in which Transaction.getValueSentFromMe was calculating incorrectly. var tx = TestUtils.CreateFakeTx(Params, Utils.ToNanoCoins(1, 0), _myAddress); // Now add another output (ie, change) that goes to some other address. var someOtherGuy = new EcKey().ToAddress(Params); var output = new TransactionOutput(Params, tx, Utils.ToNanoCoins(0, 5), someOtherGuy); tx.AddOutput(output); // Note that tx is no longer valid: it spends more than it imports. However checking transactions balance // correctly isn't possible in SPV mode because value is a property of outputs not inputs. Without all // transactions you can't check they add up. _defaultWallet.Receive(tx, null, BlockChain.NewBlockType.BestChain); // Now the other guy creates a transaction which spends that change. var tx2 = new Transaction(Params); tx2.AddInput(output); tx2.AddOutput(new TransactionOutput(Params, tx2, Utils.ToNanoCoins(0, 5), _myAddress)); // tx2 doesn't send any coins from us, even though the output is in the wallet. Assert.AreEqual(Utils.ToNanoCoins(0, 0), tx2.GetValueSentFromMe(_defaultWallet)); }
public void SetUp() { var myKey = new EcKey(); _myAddress = myKey.ToAddress(Params); _defaultWallet = new DefaultWallet(Params); _defaultWallet.AddKey(myKey); _blockStore = new MemoryBlockStore(Params); }
public void Bounce() { // This test covers _bug 64 (False double spends). Check that if we create a spend and it's immediately sent // back to us, this isn't considered as a double spend. var coin1 = Utils.ToNanoCoins(1, 0); var coinHalf = Utils.ToNanoCoins(0, 50); // Start by giving us 1 coin. var inbound1 = TestUtils.CreateFakeTx(Params, coin1, _myAddress); _defaultWallet.Receive(inbound1, null, BlockChain.NewBlockType.BestChain); // Send half to some other guy. Sending only half then waiting for a confirm is important to ensure the tx is // in the unspent pool, not pending or spent. Assert.AreEqual(1, _defaultWallet.GetPoolSize(WalletPool.Unspent)); Assert.AreEqual(1, _defaultWallet.GetPoolSize(WalletPool.All)); var someOtherGuy = new EcKey().ToAddress(Params); var outbound1 = _defaultWallet.CreateSend(someOtherGuy, coinHalf); _defaultWallet.ConfirmSend(outbound1); _defaultWallet.Receive(outbound1, null, BlockChain.NewBlockType.BestChain); // That other guy gives us the coins right back. var inbound2 = new Transaction(Params); inbound2.AddOutput(new TransactionOutput(Params, inbound2, coinHalf, _myAddress)); inbound2.AddInput(outbound1.TransactionOutputs[0]); _defaultWallet.Receive(inbound2, null, BlockChain.NewBlockType.BestChain); Assert.AreEqual(coin1, _defaultWallet.GetBalance()); }
public void TestForking4() { // Check that we can handle external spends on an inactive chain becoming active. An external spend is where // we see a transaction that spends our own coins but we did not broadcast it ourselves. This happens when // keys are being shared between wallets. var b1 = _unitTestParams.GenesisBlock.CreateNextBlock(_coinbaseTo); _chain.Add(b1); Assert.AreEqual("50.00", Utils.BitcoinValueToFriendlyString(_defaultWallet.GetBalance())); var dest = new EcKey().ToAddress(_unitTestParams); var spend = _defaultWallet.CreateSend(dest, Utils.ToNanoCoins(50, 0)); // We do NOT confirm the spend here. That means it's not considered to be pending because createSend is // stateless. For our purposes it is as if some other program with our keys created the tx. // // genesis -> b1 (receive 50) --> b2 // \-> b3 (external spend) -> b4 var b2 = b1.CreateNextBlock(_someOtherGuy); _chain.Add(b2); var b3 = b1.CreateNextBlock(_someOtherGuy); b3.AddTransaction(spend); b3.Solve(); _chain.Add(b3); // The external spend is not active yet. Assert.AreEqual(Utils.ToNanoCoins(50, 0), _defaultWallet.GetBalance()); var b4 = b3.CreateNextBlock(_someOtherGuy); _chain.Add(b4); // The external spend is now active. Assert.AreEqual(Utils.ToNanoCoins(0, 0), _defaultWallet.GetBalance()); }
public void TestForking3() { // Check that we can handle our own spends being rolled back by a fork. var b1 = _unitTestParams.GenesisBlock.CreateNextBlock(_coinbaseTo); _chain.Add(b1); Assert.AreEqual("50.00", Utils.BitcoinValueToFriendlyString(_defaultWallet.GetBalance())); var dest = new EcKey().ToAddress(_unitTestParams); var spend = _defaultWallet.CreateSend(dest, Utils.ToNanoCoins(10, 0)); _defaultWallet.ConfirmSend(spend); // Waiting for confirmation ... Assert.AreEqual(0UL, _defaultWallet.GetBalance()); var b2 = b1.CreateNextBlock(_someOtherGuy); b2.AddTransaction(spend); b2.Solve(); _chain.Add(b2); Assert.AreEqual(Utils.ToNanoCoins(40, 0), _defaultWallet.GetBalance()); // genesis -> b1 (receive coins) -> b2 (spend coins) // \-> b3 -> b4 var b3 = b1.CreateNextBlock(_someOtherGuy); var b4 = b3.CreateNextBlock(_someOtherGuy); _chain.Add(b3); _chain.Add(b4); // b4 causes a re-org that should make our spend go inactive. Because the inputs are already spent our // available balance drops to zero again. Assert.AreEqual(0UL, _defaultWallet.GetBalance(BalanceType.Available)); // We estimate that it'll make it back into the block chain (we know we won't double spend). // assertEquals(Utils.toNanoCoins(40, 0), wallet.getBalance(Wallet.BalanceType.ESTIMATED)); }
public void TestDoubleSpendOnForkPending() { // Check what happens when a re-org happens and one of our UNconfirmed transactions becomes invalidated by a // double spend on the new best chain. Transaction eventDead = null; Transaction eventReplacement = null; _defaultWallet.DeadTransaction += (sender, e) => { eventDead = e.DeadTransaction; eventReplacement = e.ReplacementTransaction; }; // Start with 50 coins. var b1 = _unitTestParams.GenesisBlock.CreateNextBlock(_coinbaseTo); _chain.Add(b1); var t1 = _defaultWallet.CreateSend(_someOtherGuy, Utils.ToNanoCoins(10, 0)); var yetAnotherGuy = new EcKey().ToAddress(_unitTestParams); var t2 = _defaultWallet.CreateSend(yetAnotherGuy, Utils.ToNanoCoins(20, 0)); _defaultWallet.ConfirmSend(t1); // t1 is still pending ... var b2 = b1.CreateNextBlock(new EcKey().ToAddress(_unitTestParams)); _chain.Add(b2); Assert.AreEqual(Utils.ToNanoCoins(0, 0), _defaultWallet.GetBalance()); Assert.AreEqual(Utils.ToNanoCoins(40, 0), _defaultWallet.GetBalance(BalanceType.Estimated)); // Now we make a double spend become active after a re-org. // genesis -> b1 -> b2 [t1 pending] // \-> b3 (t2) -> b4 var b3 = b1.CreateNextBlock(new EcKey().ToAddress(_unitTestParams)); b3.AddTransaction(t2); b3.Solve(); _chain.Add(b3); // Side chain. var b4 = b3.CreateNextBlock(new EcKey().ToAddress(_unitTestParams)); _chain.Add(b4); // New best chain. // Should have seen a double spend against the pending pool. Assert.AreEqual(t1, eventDead); Assert.AreEqual(t2, eventReplacement); Assert.AreEqual(Utils.ToNanoCoins(30, 0), _defaultWallet.GetBalance()); // ... and back to our own parallel universe. var b5 = b2.CreateNextBlock(new EcKey().ToAddress(_unitTestParams)); _chain.Add(b5); var b6 = b5.CreateNextBlock(new EcKey().ToAddress(_unitTestParams)); _chain.Add(b6); // genesis -> b1 -> b2 -> b5 -> b6 [t1 pending] // \-> b3 [t2 inactive] -> b4 Assert.AreEqual(Utils.ToNanoCoins(0, 0), _defaultWallet.GetBalance()); Assert.AreEqual(Utils.ToNanoCoins(40, 0), _defaultWallet.GetBalance(BalanceType.Estimated)); }
/// <summary> /// Adds the given ECKey to the wallet. There is currently no way to delete keys (that would result in coin loss). /// </summary> public void AddKey(EcKey key) { lock (this) { Debug.Assert(!Keychain.Contains(key)); Keychain.Add(key); } }