예제 #1
0
파일: spv_tests.cs 프로젝트: vebin/NBitcoin
		public void CanAddScriptsToWallet()
		{
			Wallet wallet = new Wallet(new WalletCreation()
			{
				DerivationPath = new KeyPath("56"),
				Name = "MyWallet",
				RootKeys = new[] { new ExtKey().Neuter() },
				SignatureRequired = 1,
				UseP2SH = false
			}, 11);

			wallet.Configure();
			Assert.True(wallet.GetKnownScripts(true).Length == 0);
			Assert.True(wallet.GetKnownScripts(false).Length == 0);
			wallet.GetNextScriptPubKey();
			Assert.True(wallet.GetKnownScripts(false).Length == 11); //11 normal
			Assert.True(wallet.GetKnownScripts(true).Length == 1);
		}
예제 #2
0
파일: spv_tests.cs 프로젝트: vebin/NBitcoin
		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);
			}
		}
예제 #3
0
파일: spv_tests.cs 프로젝트: vebin/NBitcoin
		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));
			}
		}
예제 #4
0
파일: spv_tests.cs 프로젝트: vebin/NBitcoin
		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();
				//////
			}
		}
예제 #5
0
파일: spv_tests.cs 프로젝트: vebin/NBitcoin
		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);
			}
		}
예제 #6
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);
			}
		}
예제 #7
0
 internal void Set(NBitcoin.SPV.Wallet wallet)
 {
     _wallet     = wallet;
     PrivateKeys = Keys.Where(k => k.PrivateKey != null).Select(k => k.PrivateKey).ToArray();
 }
예제 #8
0
파일: Wallet.cs 프로젝트: vebin/NBitcoin
		public static Wallet Load(Stream stream)
		{
			Wallet wallet = new Wallet();
			wallet.LoadCore(stream);
			return wallet;
		}
예제 #9
0
파일: Wallet.cs 프로젝트: vebin/NBitcoin
			public WalletBehavior(Wallet wallet)
			{
				_Wallet = wallet;
			}
예제 #10
0
 public WalletBehavior(Wallet wallet)
 {
     _Wallet = wallet;
 }