Beispiel #1
0
        static internal WalletCreation FromJson(JObject obj)
        {
            WalletCreation creation = new WalletCreation();

            creation.Network = null;
            JToken unused;

            if (obj.TryGetValue("Name", out unused))
            {
                creation.Name = (string)obj["Name"];
            }
            else
            {
                creation.Name = null;
            }
            if (obj.Property("PurgeConnectionOnFilterChange") != null)
            {
                creation.PurgeConnectionOnFilterChange = (bool)obj["PurgeConnectionOnFilterChange"];
            }
            JToken network;

            if (obj.TryGetValue("Network", out network))
            {
                creation.Network = Network.GetNetwork((string)network);
            }
            creation.SignatureRequired = (int)(long)obj["SignatureRequired"];
            creation.DerivationPath    = KeyPath.Parse((string)obj["DerivationPath"]);
            creation.UseP2SH           = (bool)obj["UseP2SH"];
            var array = (JArray)obj["RootKeys"];
            var keys  = array.Select(i => new BitcoinExtPubKey((string)i)).ToArray();

            creation.Network  = creation.Network ?? keys[0].Network;
            creation.RootKeys = keys.Select(k => k.ExtPubKey).ToArray();
            return(creation);
        }
Beispiel #2
0
        void LoadCore(Stream stream)
        {
            JObject obj = JObject.Load(new JsonTextReader(new StreamReader(stream))
            {
                DateParseHandling = DateParseHandling.DateTimeOffset
            });

            _Parameters = WalletCreation.FromJson((JObject)obj["Parameters"]);
            _PathStates = new Dictionary <KeyPath, PathState>();
            if (obj.Property("CurrentIndex") != null)            //legacy
            {
                var idx        = (int)(long)obj["CurrentIndex"];
                var loadedKeys = (int)(long)obj["LoadedKeys"];
                _PathStates.Add(_Parameters.DerivationPath.Derive(0), new PathState()
                {
                    Next   = idx,
                    Loaded = loadedKeys
                });
                _PathStates.Add(_Parameters.DerivationPath.Derive(1), new PathState()
                {
                    Next   = idx,
                    Loaded = loadedKeys
                });
            }

            var indices = obj["Indices"] as JArray;

            if (indices != null)
            {
                foreach (var indice in indices.OfType <JObject>())
                {
                    _PathStates.Add(KeyPath.Parse((string)indice["KeyPath"]), new PathState()
                    {
                        Next   = (int)(long)indice["Next"],
                        Loaded = (int)(long)indice["Loaded"]
                    });
                }
            }
            _KeyPoolSize  = (int)(long)obj["KeyPoolSize"];
            Created       = (DateTimeOffset)obj["Created"];
            _ScanLocation = new BlockLocator();
            _ScanLocation.FromBytes(Encoders.Hex.DecodeData((string)obj["Location"]));
            _KnownScripts.Clear();
            var knownScripts = (JArray)obj["KnownScripts"];

            foreach (var known in knownScripts.OfType <JObject>())
            {
                Script script = Script.FromBytesUnsafe(Encoders.Hex.DecodeData((string)known["ScriptPubKey"]));
                if (known["KeyPath"] != null)                //Legacy data
                {
                    KeyPath keypath = KeyPath.Parse((string)known["KeyPath"]);
                    _KnownScripts.Add(script, _Parameters.DerivationPath.Derive(keypath));
                }
                if (known["AbsoluteKeyPath"] != null)
                {
                    KeyPath keypath = KeyPath.Parse((string)known["AbsoluteKeyPath"]);
                    _KnownScripts.Add(script, keypath);
                }
            }
        }
Beispiel #3
0
 /// <summary>
 /// Create a new wallet
 /// </summary>
 /// <param name="creation">Creation parameters</param>
 /// <param name="keyPoolSize">The number of keys which will be pre-created</param>
 public Wallet(WalletCreation creation, int keyPoolSize = 500)
 {
     if (creation == null)
     {
         throw new ArgumentNullException("creation");
     }
     _Parameters   = creation;
     _ScanLocation = new BlockLocator();
     _ScanLocation.Blocks.Add(creation.Network.GetGenesis().GetHash());
     _KeyPoolSize = keyPoolSize;
     Created      = DateTimeOffset.UtcNow;
 }
Beispiel #4
0
#pragma warning disable CS0612 // Type or member is obsolete
        /// <summary>
        /// Create a new wallet
        /// </summary>
        /// <param name="creation">Creation parameters</param>
        /// <param name="keyPoolSize">The number of keys which will be pre-created</param>
        public Wallet(WalletCreation creation, int keyPoolSize = 500)
#pragma warning restore CS0612 // Type or member is obsolete
        {
            if (creation == null)
            {
                throw new ArgumentNullException(nameof(creation));
            }
            _Parameters   = creation;
            _ScanLocation = new BlockLocator();
            _ScanLocation.Blocks.Add(creation.Network.GetGenesis().GetHash());
            _KeyPoolSize = keyPoolSize;
            Created      = DateTimeOffset.UtcNow;
        }
Beispiel #5
0
        static internal WalletCreation FromJson(JObject obj)
        {
            WalletCreation creation = new WalletCreation();

            creation.SignatureRequired = (int)(long)obj["SignatureRequired"];
            creation.DerivationPath    = KeyPath.Parse((string)obj["DerivationPath"]);
            creation.UseP2SH           = (bool)obj["UseP2SH"];
            var array = (JArray)obj["RootKeys"];
            var keys  = array.Select(i => new BitcoinExtPubKey((string)i)).ToArray();

            creation.Network  = keys[0].Network;
            creation.RootKeys = keys.Select(k => k.ExtPubKey).ToArray();
            return(creation);
        }
Beispiel #6
0
        void LoadCore(Stream stream)
        {
            JObject obj = JObject.Load(new JsonTextReader(new StreamReader(stream))
            {
                DateParseHandling = DateParseHandling.DateTimeOffset
            });

            _CurrentIndex = (int)(long)obj["CurrentIndex"];
            _KeyPoolSize  = (int)(long)obj["KeyPoolSize"];
            _LoadedKeys   = (int)(long)obj["LoadedKeys"];
            Created       = (DateTimeOffset)obj["Created"];
            _ScanLocation = new BlockLocator();
            _ScanLocation.FromBytes(Encoders.Hex.DecodeData((string)obj["Location"]));
            _Parameters = WalletCreation.FromJson((JObject)obj["Parameters"]);
            _KnownScripts.Clear();
            var knownScripts = (JArray)obj["KnownScripts"];

            foreach (var known in knownScripts.OfType <JObject>())
            {
                Script  script  = Script.FromBytesUnsafe(Encoders.Hex.DecodeData((string)known["ScriptPubKey"]));
                KeyPath keypath = KeyPath.Parse((string)known["KeyPath"]);
                _KnownScripts.Add(script, keypath);
            }
        }
Beispiel #7
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);
			}
		}
Beispiel #8
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);
			}
		}
Beispiel #9
0
		void LoadCore(Stream stream)
		{
			JObject obj = JObject.Load(new JsonTextReader(new StreamReader(stream))
			{
				DateParseHandling = DateParseHandling.DateTimeOffset
			});
			_Parameters = WalletCreation.FromJson((JObject)obj["Parameters"]);
			_PathStates = new Dictionary<KeyPath, PathState>();
			if(obj.Property("CurrentIndex") != null) //legacy
			{
				var idx = (int)(long)obj["CurrentIndex"];
				var loadedKeys = (int)(long)obj["LoadedKeys"];
				_PathStates.Add(_Parameters.DerivationPath.Derive(0), new PathState()
				{
					Next = idx,
					Loaded = loadedKeys
				});
				_PathStates.Add(_Parameters.DerivationPath.Derive(1), new PathState()
				{
					Next = idx,
					Loaded = loadedKeys
				});
			}

			var indices = obj["Indices"] as JArray;
			if(indices != null)
			{
				foreach(var indice in indices.OfType<JObject>())
				{
					_PathStates.Add(KeyPath.Parse((string)indice["KeyPath"]), new PathState()
					{
						Next = (int)(long)indice["Next"],
						Loaded = (int)(long)indice["Loaded"]
					});
				}
			}
			_KeyPoolSize = (int)(long)obj["KeyPoolSize"];
			Created = (DateTimeOffset)obj["Created"];
			_ScanLocation = new BlockLocator();
			_ScanLocation.FromBytes(Encoders.Hex.DecodeData((string)obj["Location"]));
			_KnownScripts.Clear();
			var knownScripts = (JArray)obj["KnownScripts"];
			foreach(var known in knownScripts.OfType<JObject>())
			{
				Script script = Script.FromBytesUnsafe(Encoders.Hex.DecodeData((string)known["ScriptPubKey"]));
				if(known["KeyPath"] != null) //Legacy data
				{
					KeyPath keypath = KeyPath.Parse((string)known["KeyPath"]);
					_KnownScripts.Add(script, _Parameters.DerivationPath.Derive(keypath));
				}
				if(known["AbsoluteKeyPath"] != null)
				{
					KeyPath keypath = KeyPath.Parse((string)known["AbsoluteKeyPath"]);
					_KnownScripts.Add(script, keypath);
				}
			}
		}
Beispiel #10
0
		/// <summary>
		/// Create a new wallet
		/// </summary>
		/// <param name="creation">Creation parameters</param>
		/// <param name="keyPoolSize">The number of keys which will be pre-created</param>
		public Wallet(WalletCreation creation, int keyPoolSize = 500)
		{
			if(creation == null)
				throw new ArgumentNullException("creation");
			_Parameters = creation;
			_ScanLocation = new BlockLocator();
			_ScanLocation.Blocks.Add(creation.Network.GetGenesis().GetHash());
			_KeyPoolSize = keyPoolSize;
			Created = DateTimeOffset.UtcNow;
		}
Beispiel #11
0
		static internal WalletCreation FromJson(JObject obj)
		{
			WalletCreation creation = new WalletCreation();
			JToken unused;
			if(obj.TryGetValue("Name", out unused))
				creation.Name = (string)obj["Name"];
			else
				creation.Name = null;
			if(obj.Property("PurgeConnectionOnFilterChange") != null)
			{
				creation.PurgeConnectionOnFilterChange = (bool)obj["PurgeConnectionOnFilterChange"];
			}
			creation.SignatureRequired = (int)(long)obj["SignatureRequired"];
			creation.DerivationPath = KeyPath.Parse((string)obj["DerivationPath"]);
			creation.UseP2SH = (bool)obj["UseP2SH"];
			var array = (JArray)obj["RootKeys"];
			var keys = array.Select(i => new BitcoinExtPubKey((string)i)).ToArray();
			creation.Network = keys[0].Network;
			creation.RootKeys = keys.Select(k => k.ExtPubKey).ToArray();
			return creation;
		}
Beispiel #12
0
		void LoadCore(Stream stream)
		{
			JObject obj = JObject.Load(new JsonTextReader(new StreamReader(stream))
			{
				DateParseHandling = DateParseHandling.DateTimeOffset
			});
			_CurrentIndex = (int)(long)obj["CurrentIndex"];
			_KeyPoolSize = (int)(long)obj["KeyPoolSize"];
			_LoadedKeys = (int)(long)obj["LoadedKeys"];
			Created = (DateTimeOffset)obj["Created"];
			_ScanLocation = new BlockLocator();
			_ScanLocation.FromBytes(Encoders.Hex.DecodeData((string)obj["Location"]));
			_Parameters = WalletCreation.FromJson((JObject)obj["Parameters"]);
			_KnownScripts.Clear();
			var knownScripts = (JArray)obj["KnownScripts"];
			foreach(var known in knownScripts.OfType<JObject>())
			{
				Script script = Script.FromBytesUnsafe(Encoders.Hex.DecodeData((string)known["ScriptPubKey"]));
				KeyPath keypath = KeyPath.Parse((string)known["KeyPath"]);
				_KnownScripts.Add(script, keypath);
			}
		}
Beispiel #13
0
		static internal WalletCreation FromJson(JObject obj)
		{
			WalletCreation creation = new WalletCreation();
			creation.SignatureRequired = (int)(long)obj["SignatureRequired"];
			creation.DerivationPath = KeyPath.Parse((string)obj["DerivationPath"]);
			creation.UseP2SH = (bool)obj["UseP2SH"];
			var array = (JArray)obj["RootKeys"];
			var keys = array.Select(i => new BitcoinExtPubKey((string)i)).ToArray();
			creation.Network = keys[0].Network;
			creation.RootKeys = keys.Select(k => k.ExtPubKey).ToArray();
			return creation;
		}