Exemplo n.º 1
0
        public void UnconfirmedTransactionsWithoutReceivedCoinsShouldNotShowUp()
        {
            BlockchainBuilder builder = new BlockchainBuilder();
            Tracker           tracker = new Tracker();

            Key bob = new Key();

            tracker.Add(bob);
            Key alice = new Key();

            var tx1 = builder.GiveMoney(bob, Money.Coins(1.0m));
            var b   = builder.FindBlock();

            tracker.NotifyTransaction(tx1, builder.Chain.Tip, b);

            var tx2 = builder.SpendCoin(tx1.Outputs.AsCoins().First(), alice, Money.Coins(0.1m));

            b = builder.FindBlock();
            tracker.NotifyTransaction(tx2, builder.Chain.Tip, b);

            var tx3 = builder.SpendCoin(tx2.Outputs.AsCoins().Skip(1).First(), alice, Money.Coins(0.2m));

            Assert.True(tracker.NotifyTransaction(tx3));

            var transactions = tracker.GetWalletTransactions(builder.Chain);

            Assert.True(transactions.Count == 3);
            Assert.True(transactions.Summary.UnConfirmed.TransactionCount == 1);
            Assert.True(transactions.Summary.UnConfirmed.Amount == -Money.Coins(0.2m));

            Assert.True(transactions.Summary.Confirmed.TransactionCount == 2);
            Assert.True(transactions.Summary.Confirmed.Amount == Money.Coins(0.9m));

            Assert.True(transactions.Summary.Spendable.TransactionCount == 3);
            Assert.True(transactions.Summary.Spendable.Amount == Money.Coins(0.7m));

            builder.Chain.SetTip(builder.Chain.GetBlock(1));

            transactions = tracker.GetWalletTransactions(builder.Chain);

            Action _ = () =>
            {
                Assert.True(transactions.Count == 3);
                Assert.True(transactions.Summary.Confirmed.TransactionCount == 1);
                Assert.True(transactions.Summary.Confirmed.Amount == Money.Coins(1.0m));
                Assert.True(transactions.Summary.Spendable.TransactionCount == 3);
                Assert.True(transactions.Summary.Spendable.Amount == Money.Coins(0.7m));
                Assert.True(transactions.Summary.UnConfirmed.TransactionCount == 2);
                Assert.True(transactions.Summary.UnConfirmed.Amount == -Money.Coins(0.3m));
            };

            _();
            tracker.NotifyTransaction(tx2);             //Notifying tx2 should have no effect, since it already is accounted because it was orphaned
            _();
        }
Exemplo n.º 2
0
        public void UseFilterAddIfKeyPoolSizeIsZero()
        {
            using (NodeServerTester servers = new NodeServerTester())
            {
                var chainBuilder = new BlockchainBuilder();
                chainBuilder.RealPoW = true;
                SetupSPVBehavior(servers, chainBuilder);

                var connected = CreateGroup(servers, 1);

                Wallet wallet = new Wallet(new WalletCreation()
                {
                    Network  = servers.Network,
                    RootKeys = new[] { new ExtKey().Neuter() },
                    UseP2SH  = true
                }, keyPoolSize: 0);
                Assert.True(wallet.State == WalletState.Created);
                wallet.Configure(connected);
                wallet.Connect();
                Assert.True(wallet.State == WalletState.Disconnected);
                TestUtils.Eventually(() => connected.ConnectedNodes.Count == 1);
                Assert.True(wallet.State == WalletState.Connected);

                var script = wallet.GetNextScriptPubKey(new KeyPath("0/1/2"));
                Thread.Sleep(1000);
                chainBuilder.GiveMoney(script, Money.Coins(0.001m));
                TestUtils.Eventually(() => wallet.GetTransactions().Count == 1);
                wallet.Disconnect();
                TestUtils.Eventually(() => connected.ConnectedNodes.Count == 0);

                MemoryStream ms = new MemoryStream();
                wallet.Save(ms);
                ms.Position = 0;
                var wallet2 = Wallet.Load(ms);
                wallet2.Configure(connected);
                wallet2.Connect();

                var script2 = wallet2.GetNextScriptPubKey(new KeyPath("0/1/2"));
                Thread.Sleep(1000);
                Assert.NotEqual(script, script2);
                Assert.NotNull(wallet2.GetRedeemScript(script));
                Assert.NotNull(wallet2.GetRedeemScript(script2));
                TestUtils.Eventually(() => connected.ConnectedNodes.Count == 1);
                var spv = servers.Server1.ConnectedNodes.First().Behaviors.Find <SPVBehavior>();
                TestUtils.Eventually(() => spv._Filter != null);
                chainBuilder.GiveMoney(script2, Money.Coins(0.001m));
                TestUtils.Eventually(() => wallet.GetTransactions().Count == 2);
                chainBuilder.GiveMoney(script, Money.Coins(0.002m));
                TestUtils.Eventually(() => wallet.GetTransactions().Count == 3);
                chainBuilder.FindBlock();
                TestUtils.Eventually(() => wallet.GetTransactions().Count == 3 && wallet.GetTransactions().All(t => t.BlockInformation != null));
            }
        }
Exemplo n.º 3
0
        public void CanTrackScriptCoins()
        {
            BlockchainBuilder builder = new BlockchainBuilder();
            Tracker           tracker = new Tracker();
            Key bob = new Key();

            tracker.Add(bob.PubKey, true);
            var tx1 = builder.GiveMoney(bob.PubKey.ScriptPubKey.Hash, Money.Coins(1.0m));

            Assert.True(tracker.NotifyTransaction(tx1));
            Assert.True(tracker.GetWalletTransactions(builder.Chain)[0].ReceivedCoins[0] is ScriptCoin);
        }
Exemplo n.º 4
0
 private static void SetupSPVBehavior(NodeServerTester servers, BlockchainBuilder chainBuilder)
 {
     foreach (var server in new[] { servers.Server1, servers.Server2 })
     {
         server.InboundNodeConnectionParameters.Services = NodeServices.Network;
         //Simulate SPV compatible server
         server.InboundNodeConnectionParameters.TemplateBehaviors.Add(new ChainBehavior(chainBuilder.Chain)
         {
             AutoSync = false
         });
         server.InboundNodeConnectionParameters.TemplateBehaviors.Add(new SPVBehavior(chainBuilder));
         /////////////
     }
 }
Exemplo n.º 5
0
        private static void SetupSPVBehavior(NodeServerTester servers, BlockchainBuilder chainBuilder)
        {
            List <Node> nodes = new List <Node>();
            ConcurrentDictionary <uint256, Transaction> receivedTxs = new ConcurrentDictionary <uint256, Transaction>();

            foreach (var server in new[] { servers.Server1, servers.Server2 })
            {
                server.InboundNodeConnectionParameters.Services = NodeServices.Network | NodeServices.NODE_BLOOM;
                //Simulate SPV compatible server
                server.InboundNodeConnectionParameters.TemplateBehaviors.Add(new ChainBehavior(chainBuilder.Chain)
                {
                    AutoSync = false
                });
                server.InboundNodeConnectionParameters.TemplateBehaviors.Add(new SPVBehavior(chainBuilder)
                {
                    Nodes = nodes,
                    _ReceivedTransactions = receivedTxs
                });
                /////////////
            }
        }
Exemplo n.º 6
0
		public void CanSyncWallet2()
		{
			using(NodeServerTester servers = new NodeServerTester(Network.TestNet))
			{
				var chainBuilder = new BlockchainBuilder();
				SetupSPVBehavior(servers, chainBuilder);
				NodesGroup aliceConnection = CreateGroup(servers, 1);
				NodesGroup bobConnection = CreateGroup(servers, 1);

				var aliceKey = new ExtKey();
				Wallet alice = new Wallet(new WalletCreation()
				{
					Network = Network.TestNet,
					RootKeys = new[] { aliceKey.Neuter() },
					SignatureRequired = 1,
					UseP2SH = false
				}, 11);
				Wallet bob = new Wallet(new WalletCreation()
				{
					Network = Network.TestNet,
					RootKeys = new[] { new ExtKey().Neuter() },
					SignatureRequired = 1,
					UseP2SH = false
				}, 11);

				alice.Configure(aliceConnection);
				alice.Connect();

				bob.Configure(bobConnection);
				bob.Connect();

				TestUtils.Eventually(() => aliceConnection.ConnectedNodes.Count == 1);

				//New address tracked
				var addressAlice = alice.GetNextScriptPubKey();
				chainBuilder.GiveMoney(addressAlice, Money.Coins(1.0m));
				TestUtils.Eventually(() => aliceConnection.ConnectedNodes.Count == 0); //Purge
				TestUtils.Eventually(() => aliceConnection.ConnectedNodes.Count == 1); //Reconnect
				//////

				TestUtils.Eventually(() => alice.GetTransactions().Count == 1);

				//Alice send tx to bob
				var coins = alice.GetTransactions().GetSpendableCoins();
				var keys = coins.Select(c => alice.GetKeyPath(c.ScriptPubKey))
								.Select(k => aliceKey.Derive(k))
								.ToArray();
				var builder = new TransactionBuilder();
				var tx =
					builder
					.SetTransactionPolicy(new Policy.StandardTransactionPolicy()
					{
						MinRelayTxFee = new FeeRate(0)
					})
					.AddCoins(coins)
					.AddKeys(keys)
					.Send(bob.GetNextScriptPubKey(), Money.Coins(0.4m))
					.SetChange(alice.GetNextScriptPubKey(true))
					.BuildTransaction(true);

				Assert.True(builder.Verify(tx));

				chainBuilder.BroadcastTransaction(tx);

				//Alice get change
				TestUtils.Eventually(() => alice.GetTransactions().Count == 2);
				coins = alice.GetTransactions().GetSpendableCoins();
				Assert.True(coins.Single().Amount == Money.Coins(0.6m));
				//////

				//Bob get coins
				TestUtils.Eventually(() => bob.GetTransactions().Count == 1);
				coins = bob.GetTransactions().GetSpendableCoins();
				Assert.True(coins.Single().Amount == Money.Coins(0.4m));
				//////


				MemoryStream bobWalletBackup = new MemoryStream();
				bob.Save(bobWalletBackup);
				bobWalletBackup.Position = 0;

				MemoryStream bobTrakerBackup = new MemoryStream();
				bob.Tracker.Save(bobTrakerBackup);
				bobTrakerBackup.Position = 0;

				bob.Disconnect();

				//Restore bob
				bob = Wallet.Load(bobWalletBackup);
				bobConnection.NodeConnectionParameters.TemplateBehaviors.Remove<TrackerBehavior>();
				bobConnection.NodeConnectionParameters.TemplateBehaviors.Add(new TrackerBehavior(Tracker.Load(bobTrakerBackup), chainBuilder.Chain));
				/////

				bob.Configure(bobConnection);

				//Bob still has coins
				TestUtils.Eventually(() => bob.GetTransactions().Count == 1);
				coins = bob.GetTransactions().GetSpendableCoins();
				Assert.True(coins.Single().Amount == Money.Coins(0.4m));
				//////

				bob.Connect();
				TestUtils.Eventually(() => bobConnection.ConnectedNodes.Count == 1);

				//New block found !
				chainBuilder.FindBlock();

				//Alice send tx to bob
				coins = alice.GetTransactions().GetSpendableCoins();
				keys = coins.Select(c => alice.GetKeyPath(c.ScriptPubKey))
								.Select(k => aliceKey.Derive(k))
								.ToArray();
				builder = new TransactionBuilder();
				tx =
					builder
					.SetTransactionPolicy(new Policy.StandardTransactionPolicy()
					{
						MinRelayTxFee = new FeeRate(0)
					})
					.AddCoins(coins)
					.AddKeys(keys)
					.Send(bob.GetNextScriptPubKey(), Money.Coins(0.1m))
					.SetChange(alice.GetNextScriptPubKey(true))
					.BuildTransaction(true);

				Assert.True(builder.Verify(tx));

				chainBuilder.BroadcastTransaction(tx);

				//Bob still has coins
				TestUtils.Eventually(() => bob.GetTransactions().Count == 2); //Bob has both, old and new tx
				coins = bob.GetTransactions().GetSpendableCoins();
				//////
			}
		}
Exemplo n.º 7
0
		public void CanPrune()
		{
			BlockchainBuilder builder = new BlockchainBuilder();
			Tracker tracker = new Tracker();
			Key bob = new Key();
			Key alice = new Key();
			tracker.Add(bob);

			var oldUnconf = builder.GiveMoney(bob, Money.Coins(1.0m));
			Assert.True(tracker.NotifyTransaction(oldUnconf));

			builder.Mempool.Clear();

			var oldConf = builder.GiveMoney(bob, Money.Coins(0.9m));
			var oldConfSpent = builder.SpendCoin(oldConf.Outputs.AsCoins().First(), alice, Money.Coins(0.01m));

			var block = builder.FindBlock();

			Assert.True(tracker.NotifyTransaction(oldConf, builder.Chain.Tip, block));
			Assert.True(tracker.NotifyTransaction(oldConfSpent, builder.Chain.Tip, block));

			for(int i = 0 ; i < 9 ; i++)
			{
				builder.FindBlock();
			}
			Assert.True(tracker.Prune(builder.Chain, 10).Count == 0);
			builder.FindBlock();

			//Prune tracked outpoint
			var pruned = tracker.Prune(builder.Chain, 10);
			Assert.Equal(1, pruned.Count);
			Assert.True(pruned.First() is Tracker.TrackedOutpoint);

			//Prune old unconf
			pruned = tracker.Prune(builder.Chain, timeExpiration: TimeSpan.Zero);
			Assert.Equal(1, pruned.Count);
			var op = pruned.OfType<Tracker.Operation>().First();
			Assert.True(op.BlockId == null);

			var conf = builder.GiveMoney(bob, Money.Coins(0.9m));
			block = builder.FindBlock();
			Assert.True(tracker.NotifyTransaction(conf, builder.Chain.Tip, block));

			var oldSpentForked = builder.SpendCoin(conf.Outputs.AsCoins().First(), alice, Money.Coins(0.021m));
			block = builder.FindBlock();
			Assert.True(tracker.NotifyTransaction(oldSpentForked, builder.Chain.Tip, block));

			var forked = builder.Chain.Tip;
			builder.Chain.SetTip(builder.Chain.Tip.Previous);

			for(int i = 0 ; i < 10 ; i++)
			{
				builder.FindBlock();
			}

			pruned = tracker.Prune(builder.Chain, 10);
			Assert.True(pruned.Count == 1); //Tracked outpoint of conf
			Assert.True(pruned.First() is Tracker.TrackedOutpoint);
			block = builder.FindBlock();

			pruned = tracker.Prune(builder.Chain, 10); //Old forked spent
			Assert.Equal(1, pruned.Count);
			op = pruned.OfType<Tracker.Operation>().First();
			Assert.Equal(forked.HashBlock, op.BlockId);
		}
Exemplo n.º 8
0
		public void UnconfirmedTransactionsWithoutReceivedCoinsShouldNotShowUp()
		{
			BlockchainBuilder builder = new BlockchainBuilder();
			Tracker tracker = new Tracker();

			Key bob = new Key();
			tracker.Add(bob);
			Key alice = new Key();

			var tx1 = builder.GiveMoney(bob, Money.Coins(1.0m));
			var b = builder.FindBlock();
			tracker.NotifyTransaction(tx1, builder.Chain.Tip, b);

			var tx2 = builder.SpendCoin(tx1.Outputs.AsCoins().First(), alice, Money.Coins(0.1m));
			b = builder.FindBlock();
			tracker.NotifyTransaction(tx2, builder.Chain.Tip, b);

			var tx3 = builder.SpendCoin(tx2.Outputs.AsCoins().Skip(1).First(), alice, Money.Coins(0.2m));
			Assert.True(tracker.NotifyTransaction(tx3));

			var transactions = tracker.GetWalletTransactions(builder.Chain);
			Assert.True(transactions.Count == 3);
			Assert.True(transactions.Summary.UnConfirmed.TransactionCount == 1);
			Assert.True(transactions.Summary.UnConfirmed.Amount == -Money.Coins(0.2m));

			Assert.True(transactions.Summary.Confirmed.TransactionCount == 2);
			Assert.True(transactions.Summary.Confirmed.Amount == Money.Coins(0.9m));

			Assert.True(transactions.Summary.Spendable.TransactionCount == 3);
			Assert.True(transactions.Summary.Spendable.Amount == Money.Coins(0.7m));

			builder.Chain.SetTip(builder.Chain.GetBlock(1));

			transactions = tracker.GetWalletTransactions(builder.Chain);

			Action _ = () =>
			{
				Assert.True(transactions.Count == 3);
				Assert.True(transactions.Summary.Confirmed.TransactionCount == 1);
				Assert.True(transactions.Summary.Confirmed.Amount == Money.Coins(1.0m));
				Assert.True(transactions.Summary.Spendable.TransactionCount == 3);
				Assert.True(transactions.Summary.Spendable.Amount == Money.Coins(0.7m));
				Assert.True(transactions.Summary.UnConfirmed.TransactionCount == 2);
				Assert.True(transactions.Summary.UnConfirmed.Amount == -Money.Coins(0.3m));
			};
			_();
			tracker.NotifyTransaction(tx2);	//Notifying tx2 should have no effect, since it already is accounted because it was orphaned
			_();
		}
Exemplo n.º 9
0
		public void CanTrackKey()
		{
			BlockchainBuilder builder = new BlockchainBuilder();
			Key bob = new Key();
			Tracker tracker = new Tracker();
			tracker.Add(bob);
			var tx1 = builder.GiveMoney(bob, Money.Coins(1.0m));
			var coin = tx1.Outputs.AsCoins().First();
			Assert.True(tracker.NotifyTransaction(tx1));
			Thread.Sleep(10);
			Key alice = new Key();
			var tx2 = builder.SpendCoin(coin, alice, Money.Coins(0.6m));
			Assert.True(tracker.NotifyTransaction(tx2));

			var block = builder.FindBlock();

			foreach(var btx in block.Transactions)
			{
				if(!btx.IsCoinBase)
				{
					Assert.True(tracker.NotifyTransaction(btx, builder.Chain.GetBlock(block.GetHash()), block));
					Assert.True(tracker.NotifyTransaction(btx, builder.Chain.GetBlock(block.GetHash()), block)); //Idempotent
				}
			}

			var transactions = tracker.GetWalletTransactions(builder.Chain);

			Assert.True(transactions.Count == 2);
			Assert.True(transactions[0].Transaction.GetHash() == tx2.GetHash());
			Assert.True(transactions[1].Transaction.GetHash() == tx1.GetHash());
			Assert.True(transactions[0].Balance == -Money.Coins(0.6m));

			var tx3 = builder.GiveMoney(bob, Money.Coins(0.01m));
			coin = tx3.Outputs.AsCoins().First();
			block = builder.FindBlock();
			Assert.True(tracker.NotifyTransaction(block.Transactions[1], builder.Chain.GetBlock(block.GetHash()), block));

			transactions = tracker.GetWalletTransactions(builder.Chain);
			Assert.True(transactions.Count == 3);
			Assert.True(transactions.Summary.UnConfirmed.TransactionCount == 0);
			Assert.True(transactions[0].Transaction.GetHash() == block.Transactions[1].GetHash());

			Assert.Equal(2, transactions.GetSpendableCoins().Count()); // the 1 change + 1 gift

			builder.Chain.SetTip(builder.Chain.Tip.Previous);
			transactions = tracker.GetWalletTransactions(builder.Chain);
			Assert.True(transactions.Count == 3);
			Assert.True(transactions.Summary.UnConfirmed.TransactionCount == 1);

			//Test roundtrip serialization
			var filterBefore = tracker.CreateBloomFilter(0.005);
			MemoryStream ms = new MemoryStream();
			tracker.Save(ms);
			tracker = new Tracker();
			ms.Position = 0;
			tracker = Tracker.Load(ms);
			transactions = tracker.GetWalletTransactions(builder.Chain);
			Assert.True(transactions.Count == 3);
			Assert.True(transactions.Summary.UnConfirmed.TransactionCount == 1);
			var filterAfter = tracker.CreateBloomFilter(0.005);
			Assert.True(filterBefore.ToBytes().SequenceEqual(filterAfter.ToBytes()));
			/////
		}
Exemplo n.º 10
0
		public void CanTrackScriptCoins()
		{
			BlockchainBuilder builder = new BlockchainBuilder();
			Tracker tracker = new Tracker();
			Key bob = new Key();
			tracker.Add(bob.PubKey, true);
			var tx1 = builder.GiveMoney(bob.PubKey.ScriptPubKey.Hash, Money.Coins(1.0m));
			Assert.True(tracker.NotifyTransaction(tx1));
			Assert.True(tracker.GetWalletTransactions(builder.Chain)[0].ReceivedCoins[0] is ScriptCoin);
		}
Exemplo n.º 11
0
		private static void SetupSPVBehavior(NodeServerTester servers, BlockchainBuilder chainBuilder)
		{
			foreach(var server in new[] { servers.Server1, servers.Server2 })
			{
				server.InboundNodeConnectionParameters.Services = NodeServices.Network;
				//Simulate SPV compatible server
				server.InboundNodeConnectionParameters.TemplateBehaviors.Add(new ChainBehavior(chainBuilder.Chain)
				{
					AutoSync = false
				});
				server.InboundNodeConnectionParameters.TemplateBehaviors.Add(new SPVBehavior(chainBuilder));
				/////////////
			}
		}
Exemplo n.º 12
0
		public void UseFilterAddIfKeyPoolSizeIsZero()
		{
			using(NodeServerTester servers = new NodeServerTester(Network.TestNet))
			{
				var chainBuilder = new BlockchainBuilder();
				SetupSPVBehavior(servers, chainBuilder);

				var connected = CreateGroup(servers, 1);

				Wallet wallet = new Wallet(new WalletCreation()
				{
					Network = Network.TestNet,
					RootKeys = new[] { new ExtKey().Neuter() },
					UseP2SH = true
				}, keyPoolSize: 0);
				Assert.True(wallet.State == WalletState.Created);
				wallet.Configure(connected);
				wallet.Connect();
				Assert.True(wallet.State == WalletState.Disconnected);
				TestUtils.Eventually(() => connected.ConnectedNodes.Count == 1);
				Assert.True(wallet.State == WalletState.Connected);

				var script = wallet.GetNextScriptPubKey(new KeyPath("0/1/2"));
				Thread.Sleep(1000);
				chainBuilder.GiveMoney(script, Money.Coins(0.001m));
				TestUtils.Eventually(() => wallet.GetTransactions().Count == 1);
				wallet.Disconnect();
				TestUtils.Eventually(() => connected.ConnectedNodes.Count == 0);

				MemoryStream ms = new MemoryStream();
				wallet.Save(ms);
				ms.Position = 0;
				var wallet2 = Wallet.Load(ms);
				wallet2.Configure(connected);
				wallet2.Connect();

				var script2 = wallet2.GetNextScriptPubKey(new KeyPath("0/1/2"));
				Thread.Sleep(1000);
				Assert.NotEqual(script, script2);
				Assert.NotNull(wallet2.GetRedeemScript(script));
				Assert.NotNull(wallet2.GetRedeemScript(script2));
				TestUtils.Eventually(() => connected.ConnectedNodes.Count == 1);
				var spv = servers.Server1.ConnectedNodes.First().Behaviors.Find<SPVBehavior>();
				TestUtils.Eventually(() => spv._Filter != null);
				chainBuilder.GiveMoney(script2, Money.Coins(0.001m));
				TestUtils.Eventually(() => wallet.GetTransactions().Count == 2);
				chainBuilder.GiveMoney(script, Money.Coins(0.002m));
				TestUtils.Eventually(() => wallet.GetTransactions().Count == 3);
				chainBuilder.FindBlock();
				TestUtils.Eventually(() => wallet.GetTransactions().Count == 3 && wallet.GetTransactions().All(t => t.BlockInformation != null));
			}
		}
Exemplo n.º 13
0
        public void CanBroadcastTransaction()
        {
            using (NodeServerTester servers = new NodeServerTester(Network.TestNet))
            {
                var notifiedTransactions = new List <WalletTransaction>();
                var chainBuilder         = new BlockchainBuilder();
                SetupSPVBehavior(servers, chainBuilder);
                var    tx     = new Transaction();
                Wallet wallet = new Wallet(new WalletCreation()
                {
                    Network  = Network.TestNet,
                    RootKeys = new[] { new ExtKey().Neuter() },
                    UseP2SH  = false
                }, keyPoolSize: 11);
                NodesGroup connected = CreateGroup(servers, 2);
                wallet.Configure(connected);
                wallet.Connect();

                AutoResetEvent evt          = new AutoResetEvent(false);
                bool           passed       = false;
                bool           rejected     = false;
                var            broadcasting = wallet.BroadcastTransactionAsync(tx);
                wallet.TransactionBroadcasted += (t) =>
                {
                    passed = true;
                    evt.Set();
                };
                wallet.TransactionRejected += (t, r) =>
                {
                    rejected = true;
                    evt.Set();
                };
                BroadcastHub         hub      = BroadcastHub.GetBroadcastHub(connected.NodeConnectionParameters);
                BroadcastHubBehavior behavior = null;
                while (behavior == null || behavior.AttachedNode.State != NodeState.HandShaked)
                {
                    behavior = connected.ConnectedNodes.Select(n => n.Behaviors.Find <BroadcastHubBehavior>()).FirstOrDefault();
                    Thread.Sleep(1);
                }
                if (broadcasting.Status != TaskStatus.RanToCompletion)
                {
                    Assert.Equal(1, behavior.Broadcasts.Count());
                    Assert.Equal(1, hub.BroadcastingTransactions.Count());
                }
                Assert.True(evt.WaitOne(20000));
                Assert.True(broadcasting.Status == TaskStatus.RanToCompletion);
                Assert.True(passed);
                evt.Reset();
                Assert.Equal(0, behavior.Broadcasts.Count());
                Assert.Equal(0, hub.BroadcastingTransactions.Count());
                Assert.Null(broadcasting.Result);

                broadcasting = wallet.BroadcastTransactionAsync(tx);
                if (broadcasting.Status != TaskStatus.RanToCompletion)
                {
                    Assert.Equal(1, behavior.Broadcasts.Count());
                }
                Assert.True(evt.WaitOne(20000));
                Assert.True(rejected);
                Assert.Equal(0, behavior.Broadcasts.Count());
                Assert.Equal(0, hub.BroadcastingTransactions.Count());
                Assert.NotNull(broadcasting.Result);
            }
        }
Exemplo n.º 14
0
		public void CanSyncWalletCore(WalletCreation creation)
		{
			using(NodeServerTester servers = new NodeServerTester(Network.TestNet))
			{
				var chainBuilder = new BlockchainBuilder();

				//Simulate SPV compatible server
				servers.Server1.InboundNodeConnectionParameters.Services = NodeServices.Network;
				servers.Server1.InboundNodeConnectionParameters.TemplateBehaviors.Add(new ChainBehavior(chainBuilder.Chain)
				{
					AutoSync = false
				});
				servers.Server1.InboundNodeConnectionParameters.TemplateBehaviors.Add(new SPVBehavior(chainBuilder));
				/////////////

				//The SPV client does not verify the chain and keep one connection alive with Server1
				NodeConnectionParameters parameters = new NodeConnectionParameters();
				Wallet.ConfigureDefaultNodeConnectionParameters(parameters);
				parameters.IsTrusted = true;
				AddressManagerBehavior addrman = new AddressManagerBehavior(new AddressManager());
				addrman.AddressManager.Add(new NetworkAddress(servers.Server1.ExternalEndpoint), IPAddress.Parse("127.0.0.1"));
				parameters.TemplateBehaviors.Add(addrman);
				NodesGroup connected = new NodesGroup(Network.TestNet, parameters);
				connected.AllowSameGroup = true;
				connected.MaximumNodeConnection = 1;
				/////////////

				Wallet wallet = new Wallet(creation, keyPoolSize: 11);
				Assert.True(wallet.State == WalletState.Created);
				wallet.Connect(connected);
				Assert.True(wallet.State == WalletState.Disconnected);
				TestUtils.Eventually(() => connected.ConnectedNodes.Count == 1);
				Assert.True(wallet.State == WalletState.Connected);

				chainBuilder.FindBlock();
				TestUtils.Eventually(() => wallet.Chain.Height == 1);
				for(int i = 0 ; i < 9 ; i++)
				{
					wallet.GetNextScriptPubKey();
				}
				wallet.GetNextScriptPubKey(); //Should provoke purge
				TestUtils.Eventually(() => wallet.State == WalletState.Disconnected && wallet.ConnectedNodes == 0);
				TestUtils.Eventually(() => wallet.ConnectedNodes == 1);
				TestUtils.Eventually(() => servers.Server1.ConnectedNodes.Count == 1);
				var spv = servers.Server1.ConnectedNodes.First().Behaviors.Find<SPVBehavior>();
				TestUtils.Eventually(() => spv._Filter != null);

				var k = wallet.GetNextScriptPubKey();
				Assert.Equal(creation.UseP2SH, k.GetDestinationAddress(Network.TestNet) is BitcoinScriptAddress);
				chainBuilder.GiveMoney(k, Money.Coins(1.0m));
				TestUtils.Eventually(() => wallet.GetTransactions().Count == 1);
				chainBuilder.FindBlock();
				TestUtils.Eventually(() => wallet.GetTransactions().Where(t => t.BlockInformation != null).Count() == 1);

				chainBuilder.Broadcast = false;
				chainBuilder.GiveMoney(k, Money.Coins(1.5m));
				chainBuilder.Broadcast = true;
				chainBuilder.FindBlock();
				TestUtils.Eventually(() => wallet.GetTransactions().Summary.Confirmed.TransactionCount == 2);

				chainBuilder.Broadcast = false;
				for(int i = 0 ; i < 30 ; i++)
				{
					chainBuilder.FindBlock();
				}
				chainBuilder.GiveMoney(k, Money.Coins(0.001m));
				chainBuilder.FindBlock();
				chainBuilder.Broadcast = true;
				chainBuilder.FindBlock();
				//Sync automatically
				TestUtils.Eventually(() => wallet.GetTransactions().Summary.Confirmed.TransactionCount == 3);

				MemoryStream ms = new MemoryStream();
				wallet.Save(ms);
				ms.Position = 0;
				var wallet2 = Wallet.Load(ms);
				wallet2.Connect(connected);
				Assert.Equal(wallet.Created, wallet2.Created);
				Assert.Equal(wallet.GetNextScriptPubKey(), wallet2.GetNextScriptPubKey());
				Assert.True(wallet.GetKnownScripts().Length == wallet2.GetKnownScripts().Length);

				var fork = wallet.Chain.FindFork(wallet2._ScanLocation);
				Assert.True(fork.Height == chainBuilder.Chain.Height - 5);
			}
		}
Exemplo n.º 15
0
 public SPVBehavior(BlockchainBuilder builder)
 {
     _Builder = builder;
 }
Exemplo n.º 16
0
		public SPVBehavior(BlockchainBuilder builder)
		{
			_Builder = builder;
		}
Exemplo n.º 17
0
        public void CanSyncWalletCore(WalletCreation creation)
        {
            using (NodeServerTester servers = new NodeServerTester(Network.TestNet))
            {
                var notifiedTransactions = new List <WalletTransaction>();
                var chainBuilder         = new BlockchainBuilder();
                SetupSPVBehavior(servers, chainBuilder);
                NodesGroup connected = CreateGroup(servers, 1);
                Wallet     wallet    = new Wallet(creation, keyPoolSize: 11);
                wallet.NewWalletTransaction += (s, a) => notifiedTransactions.Add(a);
                Assert.True(wallet.State == WalletState.Created);
                wallet.Configure(connected);
                wallet.Connect();
                Assert.True(wallet.State == WalletState.Disconnected);
                TestUtils.Eventually(() => connected.ConnectedNodes.Count == 1);
                Assert.True(wallet.State == WalletState.Connected);

                chainBuilder.FindBlock();
                TestUtils.Eventually(() => wallet.Chain.Height == 1);
                for (int i = 0; i < 9; i++)
                {
                    wallet.GetNextScriptPubKey();
                }
                wallet.GetNextScriptPubKey();                 //Should provoke purge
                TestUtils.Eventually(() => wallet.State == WalletState.Disconnected && wallet.ConnectedNodes == 0);
                TestUtils.Eventually(() => wallet.ConnectedNodes == 1);
                TestUtils.Eventually(() => servers.Server1.ConnectedNodes.Count == 1);
                var spv = servers.Server1.ConnectedNodes.First().Behaviors.Find <SPVBehavior>();
                TestUtils.Eventually(() => spv._Filter != null);
                var k = wallet.GetNextScriptPubKey();
                Assert.NotNull(wallet.GetKeyPath(k));
                if (creation.UseP2SH)
                {
                    var p2sh = k.GetDestinationAddress(Network.TestNet) as BitcoinScriptAddress;
                    Assert.NotNull(p2sh);
                    var redeem = wallet.GetRedeemScript(p2sh);
                    Assert.NotNull(redeem);
                    Assert.Equal(redeem.Hash, p2sh.Hash);
                }

                Assert.Equal(creation.UseP2SH, k.GetDestinationAddress(Network.TestNet) is BitcoinScriptAddress);
                chainBuilder.GiveMoney(k, Money.Coins(1.0m));
                TestUtils.Eventually(() => wallet.GetTransactions().Count == 1 &&
                                     notifiedTransactions.Count == 1);
                chainBuilder.FindBlock();
                TestUtils.Eventually(() => wallet.GetTransactions().Where(t => t.BlockInformation != null).Count() == 1 &&
                                     notifiedTransactions.Count == 2);
                chainBuilder.Broadcast = false;
                chainBuilder.GiveMoney(k, Money.Coins(1.5m));
                chainBuilder.Broadcast = true;
                chainBuilder.FindBlock();
                TestUtils.Eventually(() => wallet.GetTransactions().Summary.Confirmed.TransactionCount == 2 &&
                                     notifiedTransactions.Count == 3);

                chainBuilder.Broadcast = false;
                for (int i = 0; i < 30; i++)
                {
                    chainBuilder.FindBlock();
                }
                chainBuilder.GiveMoney(k, Money.Coins(0.001m));
                chainBuilder.FindBlock();
                chainBuilder.Broadcast = true;
                chainBuilder.FindBlock();
                //Sync automatically
                TestUtils.Eventually(() => wallet.GetTransactions().Summary.Confirmed.TransactionCount == 3);

                //Save and restore wallet
                MemoryStream ms = new MemoryStream();
                wallet.Save(ms);
                ms.Position = 0;
                var wallet2 = Wallet.Load(ms);
                //////

                //Save and restore tracker
                ms = new MemoryStream();
                var tracker = connected.NodeConnectionParameters.TemplateBehaviors.Find <TrackerBehavior>();
                connected.NodeConnectionParameters.TemplateBehaviors.Remove(tracker);
                tracker.Tracker.Save(ms);
                ms.Position = 0;
                tracker     = new TrackerBehavior(Tracker.Load(ms), wallet.Chain);
                connected.NodeConnectionParameters.TemplateBehaviors.Add(tracker);
                //////

                wallet2.Configure(connected);
                wallet2.Connect();
                Assert.Equal(wallet.Created, wallet2.Created);
                Assert.Equal(wallet.GetNextScriptPubKey(), wallet2.GetNextScriptPubKey());
                Assert.True(wallet.GetKnownScripts().Length == wallet2.GetKnownScripts().Length);
                TestUtils.Eventually(() => wallet2.GetTransactions().Summary.Confirmed.TransactionCount == 3);

                var fork = wallet.Chain.FindFork(wallet2._ScanLocation);
                Assert.True(fork.Height == chainBuilder.Chain.Height);
            }
        }
Exemplo n.º 18
0
        public void CanSyncWallet2()
        {
            using (NodeServerTester servers = new NodeServerTester(Network.TestNet))
            {
                var chainBuilder = new BlockchainBuilder();
                SetupSPVBehavior(servers, chainBuilder);
                NodesGroup aliceConnection = CreateGroup(servers, 1);
                NodesGroup bobConnection   = CreateGroup(servers, 1);

                var    aliceKey = new ExtKey();
                Wallet alice    = new Wallet(new WalletCreation()
                {
                    Network           = Network.TestNet,
                    RootKeys          = new[] { aliceKey.Neuter() },
                    SignatureRequired = 1,
                    UseP2SH           = false
                }, 11);
                Wallet bob = new Wallet(new WalletCreation()
                {
                    Network           = Network.TestNet,
                    RootKeys          = new[] { new ExtKey().Neuter() },
                    SignatureRequired = 1,
                    UseP2SH           = false
                }, 11);

                alice.Configure(aliceConnection);
                alice.Connect();

                bob.Configure(bobConnection);
                bob.Connect();

                TestUtils.Eventually(() => aliceConnection.ConnectedNodes.Count == 1);

                //New address tracked
                var addressAlice = alice.GetNextScriptPubKey();
                chainBuilder.GiveMoney(addressAlice, Money.Coins(1.0m));
                TestUtils.Eventually(() => aliceConnection.ConnectedNodes.Count == 0);                 //Purge
                TestUtils.Eventually(() => aliceConnection.ConnectedNodes.Count == 1);                 //Reconnect
                //////

                TestUtils.Eventually(() => alice.GetTransactions().Count == 1);

                //Alice send tx to bob
                var coins = alice.GetTransactions().GetSpendableCoins();
                var keys  = coins.Select(c => alice.GetKeyPath(c.ScriptPubKey))
                            .Select(k => aliceKey.Derive(k))
                            .ToArray();
                var builder = new TransactionBuilder();
                var tx      =
                    builder
                    .SetTransactionPolicy(new Policy.StandardTransactionPolicy()
                {
                    MinRelayTxFee = new FeeRate(0)
                })
                    .AddCoins(coins)
                    .AddKeys(keys)
                    .Send(bob.GetNextScriptPubKey(), Money.Coins(0.4m))
                    .SetChange(alice.GetNextScriptPubKey(true))
                    .BuildTransaction(true);

                Assert.True(builder.Verify(tx));

                chainBuilder.BroadcastTransaction(tx);

                //Alice get change
                TestUtils.Eventually(() => alice.GetTransactions().Count == 2);
                coins = alice.GetTransactions().GetSpendableCoins();
                Assert.True(coins.Single().Amount == Money.Coins(0.6m));
                //////

                //Bob get coins
                TestUtils.Eventually(() => bob.GetTransactions().Count == 1);
                coins = bob.GetTransactions().GetSpendableCoins();
                Assert.True(coins.Single().Amount == Money.Coins(0.4m));
                //////


                MemoryStream bobWalletBackup = new MemoryStream();
                bob.Save(bobWalletBackup);
                bobWalletBackup.Position = 0;

                MemoryStream bobTrakerBackup = new MemoryStream();
                bob.Tracker.Save(bobTrakerBackup);
                bobTrakerBackup.Position = 0;

                bob.Disconnect();

                //Restore bob
                bob = Wallet.Load(bobWalletBackup);
                bobConnection.NodeConnectionParameters.TemplateBehaviors.Remove <TrackerBehavior>();
                bobConnection.NodeConnectionParameters.TemplateBehaviors.Add(new TrackerBehavior(Tracker.Load(bobTrakerBackup), chainBuilder.Chain));
                /////

                bob.Configure(bobConnection);

                //Bob still has coins
                TestUtils.Eventually(() => bob.GetTransactions().Count == 1);
                coins = bob.GetTransactions().GetSpendableCoins();
                Assert.True(coins.Single().Amount == Money.Coins(0.4m));
                //////

                bob.Connect();
                TestUtils.Eventually(() => bobConnection.ConnectedNodes.Count == 1);

                //New block found !
                chainBuilder.FindBlock();

                //Alice send tx to bob
                coins = alice.GetTransactions().GetSpendableCoins();
                keys  = coins.Select(c => alice.GetKeyPath(c.ScriptPubKey))
                        .Select(k => aliceKey.Derive(k))
                        .ToArray();
                builder = new TransactionBuilder();
                tx      =
                    builder
                    .SetTransactionPolicy(new Policy.StandardTransactionPolicy()
                {
                    MinRelayTxFee = new FeeRate(0)
                })
                    .AddCoins(coins)
                    .AddKeys(keys)
                    .Send(bob.GetNextScriptPubKey(), Money.Coins(0.1m))
                    .SetChange(alice.GetNextScriptPubKey(true))
                    .BuildTransaction(true);

                Assert.True(builder.Verify(tx));

                chainBuilder.BroadcastTransaction(tx);

                //Bob still has coins
                TestUtils.Eventually(() => bob.GetTransactions().Count == 2);                 //Bob has both, old and new tx
                coins = bob.GetTransactions().GetSpendableCoins();
                //////
            }
        }
Exemplo n.º 19
0
        public void CanSyncWalletCore(WalletCreation creation)
        {
            using (NodeServerTester servers = new NodeServerTester(Network.TestNet))
            {
                var chainBuilder = new BlockchainBuilder();

                //Simulate SPV compatible server
                servers.Server1.InboundNodeConnectionParameters.Services = NodeServices.Network;
                servers.Server1.InboundNodeConnectionParameters.TemplateBehaviors.Add(new ChainBehavior(chainBuilder.Chain)
                {
                    AutoSync = false
                });
                servers.Server1.InboundNodeConnectionParameters.TemplateBehaviors.Add(new SPVBehavior(chainBuilder));
                /////////////

                //The SPV client does not verify the chain and keep one connection alive with Server1
                NodeConnectionParameters parameters = new NodeConnectionParameters();
                Wallet.ConfigureDefaultNodeConnectionParameters(parameters);
                parameters.IsTrusted = true;
                AddressManagerBehavior addrman = new AddressManagerBehavior(new AddressManager());
                addrman.AddressManager.Add(new NetworkAddress(servers.Server1.ExternalEndpoint), IPAddress.Parse("127.0.0.1"));
                parameters.TemplateBehaviors.Add(addrman);
                NodesGroup connected = new NodesGroup(Network.TestNet, parameters);
                connected.AllowSameGroup        = true;
                connected.MaximumNodeConnection = 1;
                /////////////

                Wallet wallet = new Wallet(creation, keyPoolSize: 11);
                Assert.True(wallet.State == WalletState.Created);
                wallet.Connect(connected);
                Assert.True(wallet.State == WalletState.Disconnected);
                TestUtils.Eventually(() => connected.ConnectedNodes.Count == 1);
                Assert.True(wallet.State == WalletState.Connected);

                chainBuilder.FindBlock();
                TestUtils.Eventually(() => wallet.Chain.Height == 1);
                for (int i = 0; i < 9; i++)
                {
                    wallet.GetNextScriptPubKey();
                }
                wallet.GetNextScriptPubKey();                 //Should provoke purge
                TestUtils.Eventually(() => wallet.State == WalletState.Disconnected && wallet.ConnectedNodes == 0);
                TestUtils.Eventually(() => wallet.ConnectedNodes == 1);
                TestUtils.Eventually(() => servers.Server1.ConnectedNodes.Count == 1);
                var spv = servers.Server1.ConnectedNodes.First().Behaviors.Find <SPVBehavior>();
                TestUtils.Eventually(() => spv._Filter != null);

                var k = wallet.GetNextScriptPubKey();
                Assert.Equal(creation.UseP2SH, k.GetDestinationAddress(Network.TestNet) is BitcoinScriptAddress);
                chainBuilder.GiveMoney(k, Money.Coins(1.0m));
                TestUtils.Eventually(() => wallet.GetTransactions().Count == 1);
                chainBuilder.FindBlock();
                TestUtils.Eventually(() => wallet.GetTransactions().Where(t => t.BlockInformation != null).Count() == 1);

                chainBuilder.Broadcast = false;
                chainBuilder.GiveMoney(k, Money.Coins(1.5m));
                chainBuilder.Broadcast = true;
                chainBuilder.FindBlock();
                TestUtils.Eventually(() => wallet.GetTransactions().Summary.Confirmed.TransactionCount == 2);

                chainBuilder.Broadcast = false;
                for (int i = 0; i < 30; i++)
                {
                    chainBuilder.FindBlock();
                }
                chainBuilder.GiveMoney(k, Money.Coins(0.001m));
                chainBuilder.FindBlock();
                chainBuilder.Broadcast = true;
                chainBuilder.FindBlock();
                //Sync automatically
                TestUtils.Eventually(() => wallet.GetTransactions().Summary.Confirmed.TransactionCount == 3);

                MemoryStream ms = new MemoryStream();
                wallet.Save(ms);
                ms.Position = 0;
                var wallet2 = Wallet.Load(ms);
                wallet2.Connect(connected);
                Assert.Equal(wallet.Created, wallet2.Created);
                Assert.Equal(wallet.GetNextScriptPubKey(), wallet2.GetNextScriptPubKey());
                Assert.True(wallet.GetKnownScripts().Length == wallet2.GetKnownScripts().Length);

                var fork = wallet.Chain.FindFork(wallet2._ScanLocation);
                Assert.True(fork.Height == chainBuilder.Chain.Height - 5);
            }
        }
Exemplo n.º 20
0
		public void CanSyncWalletCore(WalletCreation creation)
		{
			using(NodeServerTester servers = new NodeServerTester(Network.TestNet))
			{
				var notifiedTransactions = new List<WalletTransaction>();
				var chainBuilder = new BlockchainBuilder();
				SetupSPVBehavior(servers, chainBuilder);
				NodesGroup connected = CreateGroup(servers, 1);
				Wallet wallet = new Wallet(creation, keyPoolSize: 11);
				wallet.NewWalletTransaction += (s, a) => notifiedTransactions.Add(a);
				Assert.True(wallet.State == WalletState.Created);
				wallet.Configure(connected);
				wallet.Connect();
				Assert.True(wallet.State == WalletState.Disconnected);
				TestUtils.Eventually(() => connected.ConnectedNodes.Count == 1);
				Assert.True(wallet.State == WalletState.Connected);

				chainBuilder.FindBlock();
				TestUtils.Eventually(() => wallet.Chain.Height == 1);
				for(int i = 0 ; i < 9 ; i++)
				{
					wallet.GetNextScriptPubKey();
				}
				wallet.GetNextScriptPubKey(); //Should provoke purge
				TestUtils.Eventually(() => wallet.State == WalletState.Disconnected && wallet.ConnectedNodes == 0);
				TestUtils.Eventually(() => wallet.ConnectedNodes == 1);
				TestUtils.Eventually(() => servers.Server1.ConnectedNodes.Count == 1);
				var spv = servers.Server1.ConnectedNodes.First().Behaviors.Find<SPVBehavior>();
				TestUtils.Eventually(() => spv._Filter != null);
				var k = wallet.GetNextScriptPubKey();
				Assert.NotNull(wallet.GetKeyPath(k));
				if(creation.UseP2SH)
				{
					var p2sh = k.GetDestinationAddress(Network.TestNet) as BitcoinScriptAddress;
					Assert.NotNull(p2sh);
					var redeem = wallet.GetRedeemScript(p2sh);
					Assert.NotNull(redeem);
					Assert.Equal(redeem.Hash, p2sh.Hash);
				}

				Assert.Equal(creation.UseP2SH, k.GetDestinationAddress(Network.TestNet) is BitcoinScriptAddress);
				chainBuilder.GiveMoney(k, Money.Coins(1.0m));
				TestUtils.Eventually(() => wallet.GetTransactions().Count == 1);
				Assert.Equal(1, notifiedTransactions.Count);
				chainBuilder.FindBlock();
				TestUtils.Eventually(() => wallet.GetTransactions().Where(t => t.BlockInformation != null).Count() == 1);
				Assert.Equal(2, notifiedTransactions.Count);

				chainBuilder.Broadcast = false;
				chainBuilder.GiveMoney(k, Money.Coins(1.5m));
				chainBuilder.Broadcast = true;
				chainBuilder.FindBlock();
				TestUtils.Eventually(() => wallet.GetTransactions().Summary.Confirmed.TransactionCount == 2);
				Assert.Equal(3, notifiedTransactions.Count);

				chainBuilder.Broadcast = false;
				for(int i = 0 ; i < 30 ; i++)
				{
					chainBuilder.FindBlock();
				}
				chainBuilder.GiveMoney(k, Money.Coins(0.001m));
				chainBuilder.FindBlock();
				chainBuilder.Broadcast = true;
				chainBuilder.FindBlock();
				//Sync automatically
				TestUtils.Eventually(() => wallet.GetTransactions().Summary.Confirmed.TransactionCount == 3);

				//Save and restore wallet
				MemoryStream ms = new MemoryStream();
				wallet.Save(ms);
				ms.Position = 0;
				var wallet2 = Wallet.Load(ms);
				//////

				//Save and restore tracker
				ms = new MemoryStream();
				var tracker = connected.NodeConnectionParameters.TemplateBehaviors.Find<TrackerBehavior>();
				connected.NodeConnectionParameters.TemplateBehaviors.Remove(tracker);
				tracker.Tracker.Save(ms);
				ms.Position = 0;
				tracker = new TrackerBehavior(Tracker.Load(ms), wallet.Chain);
				connected.NodeConnectionParameters.TemplateBehaviors.Add(tracker);
				//////

				wallet2.Configure(connected);
				wallet2.Connect();
				Assert.Equal(wallet.Created, wallet2.Created);
				Assert.Equal(wallet.GetNextScriptPubKey(), wallet2.GetNextScriptPubKey());
				Assert.True(wallet.GetKnownScripts().Length == wallet2.GetKnownScripts().Length);
				TestUtils.Eventually(() => wallet2.GetTransactions().Summary.Confirmed.TransactionCount == 3);

				var fork = wallet.Chain.FindFork(wallet2._ScanLocation);
				Assert.True(fork.Height == chainBuilder.Chain.Height);
			}
		}
Exemplo n.º 21
0
		private static void SetupSPVBehavior(NodeServerTester servers, BlockchainBuilder chainBuilder)
		{
			List<Node> nodes = new List<Node>();
			ConcurrentDictionary<uint256, Transaction> receivedTxs = new ConcurrentDictionary<uint256, Transaction>();

			foreach(var server in new[] { servers.Server1, servers.Server2 })
			{
				server.InboundNodeConnectionParameters.Services = NodeServices.Network;
				//Simulate SPV compatible server
				server.InboundNodeConnectionParameters.TemplateBehaviors.Add(new ChainBehavior(chainBuilder.Chain)
				{
					AutoSync = false
				});
				server.InboundNodeConnectionParameters.TemplateBehaviors.Add(new SPVBehavior(chainBuilder)
				{
					Nodes = nodes,
					_ReceivedTransactions = receivedTxs
				});
				/////////////
			}
		}
Exemplo n.º 22
0
        public void CanTrackKey()
        {
            BlockchainBuilder builder = new BlockchainBuilder();
            Key     bob     = new Key();
            Tracker tracker = new Tracker();

            tracker.Add(bob);
            var tx1  = builder.GiveMoney(bob, Money.Coins(1.0m));
            var coin = tx1.Outputs.AsCoins().First();

            Assert.True(tracker.NotifyTransaction(tx1));
            Thread.Sleep(10);
            Key alice = new Key();
            var tx2   = builder.SpendCoin(coin, alice, Money.Coins(0.6m));

            Assert.True(tracker.NotifyTransaction(tx2));

            var block = builder.FindBlock();

            foreach (var btx in block.Transactions)
            {
                if (!btx.IsCoinBase)
                {
                    Assert.True(tracker.NotifyTransaction(btx, builder.Chain.GetBlock(block.GetHash()), block));
                    Assert.True(tracker.NotifyTransaction(btx, builder.Chain.GetBlock(block.GetHash()), block));                     //Idempotent
                }
            }

            var transactions = tracker.GetWalletTransactions(builder.Chain);

            Assert.True(transactions.Count == 2);
            Assert.True(transactions[0].Transaction.GetHash() == tx2.GetHash());
            Assert.True(transactions[1].Transaction.GetHash() == tx1.GetHash());
            Assert.True(transactions[0].Balance == -Money.Coins(0.6m));

            var tx3 = builder.GiveMoney(bob, Money.Coins(0.01m));

            coin  = tx3.Outputs.AsCoins().First();
            block = builder.FindBlock();
            Assert.True(tracker.NotifyTransaction(block.Transactions[1], builder.Chain.GetBlock(block.GetHash()), block));

            transactions = tracker.GetWalletTransactions(builder.Chain);
            Assert.True(transactions.Count == 3);
            Assert.True(transactions.Summary.UnConfirmed.TransactionCount == 0);
            Assert.True(transactions[0].Transaction.GetHash() == block.Transactions[1].GetHash());

            Assert.Equal(2, transactions.GetSpendableCoins().Count());             // the 1 change + 1 gift

            builder.Chain.SetTip(builder.Chain.Tip.Previous);
            transactions = tracker.GetWalletTransactions(builder.Chain);
            Assert.True(transactions.Count == 3);
            Assert.True(transactions.Summary.UnConfirmed.TransactionCount == 1);

            //Test roundtrip serialization
            var          filterBefore = tracker.CreateBloomFilter(0.005);
            MemoryStream ms           = new MemoryStream();

            tracker.Save(ms);
            tracker      = new Tracker();
            ms.Position  = 0;
            tracker      = Tracker.Load(ms);
            transactions = tracker.GetWalletTransactions(builder.Chain);
            Assert.True(transactions.Count == 3);
            Assert.True(transactions.Summary.UnConfirmed.TransactionCount == 1);
            var filterAfter = tracker.CreateBloomFilter(0.005);

            Assert.True(filterBefore.ToBytes().SequenceEqual(filterAfter.ToBytes()));
            /////
        }
Exemplo n.º 23
0
		public void CanBroadcastTransaction()
		{
			using(NodeServerTester servers = new NodeServerTester(Network.TestNet))
			{
				var notifiedTransactions = new List<WalletTransaction>();
				var chainBuilder = new BlockchainBuilder();
				SetupSPVBehavior(servers, chainBuilder);
				var tx = new Transaction();
				Wallet wallet = new Wallet(new WalletCreation()
				{
					Network = Network.TestNet,
					RootKeys = new[] { new ExtKey().Neuter() },
					UseP2SH = false
				}, keyPoolSize: 11);
				NodesGroup connected = CreateGroup(servers, 2);
				wallet.Configure(connected);
				wallet.Connect();

				AutoResetEvent evt = new AutoResetEvent(false);
				bool passed = false;
				bool rejected = false;
				var broadcasting = wallet.BroadcastTransactionAsync(tx);
				wallet.TransactionBroadcasted += (t) =>
				{
					evt.Set();
					passed = true;
				};
				wallet.TransactionRejected += (t, r) =>
				{
					evt.Set();
					rejected = true;
				};
				BroadcastHub hub = BroadcastHub.GetBroadcastHub(connected.NodeConnectionParameters);
				BroadcastHubBehavior behavior = null;
				while(behavior == null || behavior.AttachedNode.State != NodeState.HandShaked)
				{
					behavior = connected.ConnectedNodes.Select(n => n.Behaviors.Find<BroadcastHubBehavior>()).FirstOrDefault();
					Thread.Sleep(1);
				}
				Assert.Equal(1, behavior.Broadcasts.Count());
				Assert.Equal(1, hub.BroadcastingTransactions.Count());
				Assert.True(evt.WaitOne(20000));
				Assert.True(passed);
				evt.Reset();
				Assert.Equal(0, behavior.Broadcasts.Count());
				Assert.Equal(0, hub.BroadcastingTransactions.Count());
				Assert.Null(broadcasting.Result);

				broadcasting = wallet.BroadcastTransactionAsync(tx);
				Assert.Equal(1, behavior.Broadcasts.Count());
				Assert.True(evt.WaitOne(20000));
				Assert.True(rejected);
				Assert.Equal(0, behavior.Broadcasts.Count());
				Assert.Equal(0, hub.BroadcastingTransactions.Count());
				Assert.NotNull(broadcasting.Result);
			}
		}
Exemplo n.º 24
0
        public void CanPrune()
        {
            BlockchainBuilder builder = new BlockchainBuilder();
            Tracker           tracker = new Tracker();
            Key bob   = new Key();
            Key alice = new Key();

            tracker.Add(bob);

            var oldUnconf = builder.GiveMoney(bob, Money.Coins(1.0m));

            Assert.True(tracker.NotifyTransaction(oldUnconf));

            builder.Mempool.Clear();

            var oldConf      = builder.GiveMoney(bob, Money.Coins(0.9m));
            var oldConfSpent = builder.SpendCoin(oldConf.Outputs.AsCoins().First(), alice, Money.Coins(0.01m));

            var block = builder.FindBlock();

            Assert.True(tracker.NotifyTransaction(oldConf, builder.Chain.Tip, block));
            Assert.True(tracker.NotifyTransaction(oldConfSpent, builder.Chain.Tip, block));

            for (int i = 0; i < 9; i++)
            {
                builder.FindBlock();
            }
            Assert.True(tracker.Prune(builder.Chain, 10).Count == 0);
            builder.FindBlock();

            //Prune tracked outpoint
            var pruned = tracker.Prune(builder.Chain, 10);

            Assert.Equal(1, pruned.Count);
            Assert.True(pruned.First() is Tracker.TrackedOutpoint);

            //Prune old unconf
            pruned = tracker.Prune(builder.Chain, timeExpiration: TimeSpan.Zero);
            Assert.Equal(1, pruned.Count);
            var op = pruned.OfType <Tracker.Operation>().First();

            Assert.True(op.BlockId == null);

            var conf = builder.GiveMoney(bob, Money.Coins(0.9m));

            block = builder.FindBlock();
            Assert.True(tracker.NotifyTransaction(conf, builder.Chain.Tip, block));

            var oldSpentForked = builder.SpendCoin(conf.Outputs.AsCoins().First(), alice, Money.Coins(0.021m));

            block = builder.FindBlock();
            Assert.True(tracker.NotifyTransaction(oldSpentForked, builder.Chain.Tip, block));

            var forked = builder.Chain.Tip;

            builder.Chain.SetTip(builder.Chain.Tip.Previous);

            for (int i = 0; i < 10; i++)
            {
                builder.FindBlock();
            }

            pruned = tracker.Prune(builder.Chain, 10);
            Assert.True(pruned.Count == 1);             //Tracked outpoint of conf
            Assert.True(pruned.First() is Tracker.TrackedOutpoint);
            block = builder.FindBlock();

            pruned = tracker.Prune(builder.Chain, 10);             //Old forked spent
            Assert.Equal(1, pruned.Count);
            op = pruned.OfType <Tracker.Operation>().First();
            Assert.Equal(forked.HashBlock, op.BlockId);
        }
Exemplo n.º 25
0
        //[Trait("UnitTest", "UnitTest")]
        public void CanBroadcastTransaction()
        {
            using (NodeServerTester servers = new NodeServerTester())
            {
                var notifiedTransactions = new List <WalletTransaction>();
                var chainBuilder         = new BlockchainBuilder();
                SetupSPVBehavior(servers, chainBuilder);
                var    tx     = new Transaction();
                Wallet wallet = new Wallet(new WalletCreation()
                {
                    Network  = servers.Network,
                    RootKeys = new[] { new ExtKey().Neuter() },
                    UseP2SH  = false
                }, keyPoolSize: 11);
                NodesGroup connected = CreateGroup(servers, 2);
                wallet.Configure(connected);
                wallet.Connect();

                AutoResetEvent evt      = new AutoResetEvent(false);
                bool           passed   = false;
                bool           rejected = false;
                BroadcastHub   hub      = BroadcastHub.GetBroadcastHub(wallet.Group.NodeConnectionParameters);
                hub.ManualBroadcast = true;
                var broadcasting = wallet.BroadcastTransactionAsync(tx);
                wallet.TransactionBroadcasted += (t) =>
                {
                    passed = true;
                    evt.Set();
                };
                wallet.TransactionRejected += (t, r) =>
                {
                    rejected = true;
                    evt.Set();
                };
                while (connected.ConnectedNodes.Count != 2 && connected.ConnectedNodes.All(n => n.State == NodeState.HandShaked))
                {
                    Thread.Sleep(10);
                }

                var behaviors = connected.ConnectedNodes.Select(n => n.Behaviors.Find <BroadcastHubBehavior>()).ToArray();

                TestUtils.Eventually(() => behaviors.All(b => b.Broadcasts.Count() == 1));
                Assert.Equal(1, hub.BroadcastingTransactions.Count());
                hub.BroadcastTransactions();
                Assert.True(evt.WaitOne(20000));
                Assert.True(broadcasting.Wait(2000));
                Assert.True(passed);
                evt.Reset();


                TestUtils.Eventually(() => behaviors.All(b => b.Broadcasts.Count() == 0));
                Assert.Equal(0, hub.BroadcastingTransactions.Count());
                Assert.Null(broadcasting.Result);

                broadcasting = wallet.BroadcastTransactionAsync(tx);

                TestUtils.Eventually(() => behaviors.All(b => b.Broadcasts.Count() == 1));
                hub.BroadcastTransactions();
                Assert.True(evt.WaitOne(20000));
                Assert.True(broadcasting.Wait(2000));
                Assert.True(rejected);
                TestUtils.Eventually(() => behaviors.All(b => b.Broadcasts.Count() == 0));
                Assert.Equal(0, hub.BroadcastingTransactions.Count());
                Assert.NotNull(broadcasting.Result);
            }
        }