示例#1
0
        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();
     }
 }
示例#3
0
        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");
        }
示例#4
0
 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()));
     }
 }
示例#5
0
        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.");
            }
        }
示例#6
0
        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());
        }
示例#7
0
        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));
        }
示例#8
0
        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));
        }
示例#9
0
 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));
 }
示例#10
0
 public void SetUp()
 {
     var myKey = new EcKey();
     _myAddress = myKey.ToAddress(Params);
     _defaultWallet = new DefaultWallet(Params);
     _defaultWallet.AddKey(myKey);
     _blockStore = new MemoryBlockStore(Params);
 }
示例#11
0
 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());
 }
示例#12
0
 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());
 }
示例#13
0
 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));
 }
示例#14
0
        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));
        }
示例#15
0
 /// <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);
     }
 }