From afd59709d1981b4c622bb097fed40e357989a56b Mon Sep 17 00:00:00 2001 From: jorn vanloofsvelt Date: Tue, 26 Jan 2021 21:07:16 +0100 Subject: [PATCH 01/14] Remove the unused "Common" project. --- Common/Class1.cs | 12 ------------ Common/Common.csproj | 38 -------------------------------------- 2 files changed, 50 deletions(-) delete mode 100644 Common/Class1.cs delete mode 100644 Common/Common.csproj diff --git a/Common/Class1.cs b/Common/Class1.cs deleted file mode 100644 index 4829b4a..0000000 --- a/Common/Class1.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Common -{ - public class Class1 - { - } -} diff --git a/Common/Common.csproj b/Common/Common.csproj deleted file mode 100644 index 711bf12..0000000 --- a/Common/Common.csproj +++ /dev/null @@ -1,38 +0,0 @@ - - - - {44241912-4992-416E-A07B-4ABCA3C93826} - - - - false - - - false - - - false - - - false - - - Linked\%(RecursiveDir)%(Filename)%(Extension) - - - JsonConverters\%(Filename)%(Extension) - - - Models\%(Filename)%(Extension) - - - Serializer.cs - - - false - - - LinkedJson\%(RecursiveDir)%(Filename)%(Extension) - - - \ No newline at end of file From 56e70cd2206c472f07e0bca947104cc3682bfa81 Mon Sep 17 00:00:00 2001 From: jorn vanloofsvelt Date: Tue, 26 Jan 2021 21:08:24 +0100 Subject: [PATCH 02/14] Do some light reformatting in WhatIsItModels.cs --- QBitNinja/Models/WhatIsItModels.cs | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/QBitNinja/Models/WhatIsItModels.cs b/QBitNinja/Models/WhatIsItModels.cs index 37783be..21d65f4 100644 --- a/QBitNinja/Models/WhatIsItModels.cs +++ b/QBitNinja/Models/WhatIsItModels.cs @@ -266,12 +266,14 @@ public WhatIsExtPubKey(BitcoinExtPubKey data) : base(data) public string PubKey { - get; set; + get; + set; } public bool Hardened { - get; set; + get; + set; } public string ChainCode { @@ -305,11 +307,13 @@ public WhatIsExtKey(BitcoinExtKey data) : base(data) public string ExtPubKey { - get; set; + get; + set; } public string PrivateKey { - get; set; + get; + set; } } @@ -362,6 +366,7 @@ public string Hash get; set; } + public string ColoredAddress { get; @@ -373,11 +378,13 @@ public WhatIsScript ScriptPubKey get; set; } + public WhatIsScript RedeemScript { get; set; } + public WhatIsPublicKey PublicKey { get; @@ -390,6 +397,7 @@ public WhatIsBase58() { } + public WhatIsBase58(IBitcoinString data) { Data = data.ToString(); @@ -418,15 +426,19 @@ public string Data get; set; } + public string Type { get; set; } + public string StringType { - get; set; + get; + set; } + public Network Network { get; From 0b57ba3f9f4ecc68ac88d99b60a91507f0f91ab2 Mon Sep 17 00:00:00 2001 From: jorn vanloofsvelt Date: Tue, 26 Jan 2021 21:09:47 +0100 Subject: [PATCH 03/14] Do some light reformatting and add comments to CacheBlocksRepository. --- QBitNinja/CacheBlocksRepository.cs | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/QBitNinja/CacheBlocksRepository.cs b/QBitNinja/CacheBlocksRepository.cs index 8bc25f2..8b01514 100644 --- a/QBitNinja/CacheBlocksRepository.cs +++ b/QBitNinja/CacheBlocksRepository.cs @@ -11,33 +11,35 @@ namespace QBitNinja { public class CacheBlocksRepository : IBlocksRepository { - private IBlocksRepository _Repo; + private readonly IBlocksRepository _Repo; public CacheBlocksRepository(IBlocksRepository repo) { - if(repo == null) - throw new ArgumentNullException("repo"); - this._Repo = repo; + this._Repo = repo ?? throw new ArgumentNullException("repo"); } - List> _LastAsked = new List>(); + List> _LastAsked = new List>(); // A cache of blocks. #region IBlocksRepository Members - int MaxBlocks = 70; + static readonly int MaxBlocks = 70; // The maximum number of blocks that may be cached. - public IEnumerable GetBlocks(IEnumerable hashes, CancellationToken cancellation) + public IEnumerable GetBlocks(IEnumerable hashes, CancellationToken cancellationToken) { var asked = hashes.ToList(); - if(asked.Count > MaxBlocks) - return _Repo.GetBlocks(hashes, cancellation); + + if (asked.Count > MaxBlocks) // Asked for more than fit in the cache size, no point in checking cache. + return _Repo.GetBlocks(hashes, cancellationToken); // Fetch from repo instead. + var lastAsked = _LastAsked; - if(lastAsked != null && asked.SequenceEqual(lastAsked.Select(a => a.Item1))) + if (lastAsked != null && asked.SequenceEqual(lastAsked.Select(a => a.Item1))) return lastAsked.Select(l=>l.Item2); - var blocks = _Repo.GetBlocks(hashes, cancellation).ToList(); - if(blocks.Count < 5) + + var blocks = _Repo.GetBlocks(hashes, cancellationToken).ToList(); + + if (blocks.Count < 5) // Shouldn't this number match 'MaxBlocks = 70' ? { _LastAsked = blocks.Select(b => Tuple.Create(b.GetHash(), b)).ToList(); } @@ -45,9 +47,9 @@ public CacheBlocksRepository(IBlocksRepository repo) { _LastAsked = null; } + return blocks; } - #endregion } } From 48595534de60321de9d0eac4ce8a54cb42053261 Mon Sep 17 00:00:00 2001 From: jorn vanloofsvelt Date: Tue, 26 Jan 2021 21:11:52 +0100 Subject: [PATCH 04/14] Do some light reformatting. --- QBitNinja/ActionDisposable.cs | 7 +++-- QBitNinja/WalletRepository.cs | 56 +++++++---------------------------- 2 files changed, 15 insertions(+), 48 deletions(-) diff --git a/QBitNinja/ActionDisposable.cs b/QBitNinja/ActionDisposable.cs index 9897e85..eab46fb 100644 --- a/QBitNinja/ActionDisposable.cs +++ b/QBitNinja/ActionDisposable.cs @@ -8,23 +8,24 @@ namespace QBitNinja { public class ActionDisposable : IDisposable { - Action _Act; + readonly Action _Act; + public ActionDisposable(Action act) { _Act = act; } + public ActionDisposable(Action start, Action act) { start(); _Act = act; } + #region IDisposable Members - public void Dispose() { _Act(); } - #endregion } } diff --git a/QBitNinja/WalletRepository.cs b/QBitNinja/WalletRepository.cs index 94369d7..e5f58ff 100644 --- a/QBitNinja/WalletRepository.cs +++ b/QBitNinja/WalletRepository.cs @@ -25,6 +25,7 @@ public WalletRepository(IndexerClient indexer, throw new ArgumentNullException("tableFactory"); if(getBalancesCacheTable == null) throw new ArgumentNullException("getBalancesCacheTable"); + GetBalancesCacheTable = getBalancesCacheTable; _walletAddressesTable = tableFactory.GetTable("wa"); _walletTable = tableFactory.GetTable("wm"); @@ -34,9 +35,8 @@ public WalletRepository(IndexerClient indexer, _indexer = indexer; } - Func> GetBalancesCacheTable; + readonly Func> GetBalancesCacheTable; - public Scope Scope { get; @@ -44,49 +44,19 @@ public Scope Scope } private readonly CrudTable _walletAddressesTable; - public CrudTable WalletAddressesTable - { - get - { - return _walletAddressesTable; - } - } + public CrudTable WalletAddressesTable =>_walletAddressesTable; private readonly CrudTable _keyDataTable; - public CrudTable KeyDataTable - { - get - { - return _keyDataTable; - } - } + public CrudTable KeyDataTable =>_keyDataTable; private readonly CrudTable _keySetTable; - public CrudTable KeySetTable - { - get - { - return _keySetTable; - } - } + public CrudTable KeySetTable => _keySetTable; private readonly CrudTable _walletTable; - public CrudTable WalletTable - { - get - { - return _walletTable; - } - } + public CrudTable WalletTable =>_walletTable; private readonly IndexerClient _indexer; - public IndexerClient Indexer - { - get - { - return _indexer; - } - } + public IndexerClient Indexer => _indexer; public bool Create(WalletModel wallet) { @@ -153,6 +123,7 @@ public async Task> Scan(string walletName, KeySetData keyset SetKeySet(walletName, keysetData); return addedAddresses; } + private static void HackToPreventOOM(WalletAddress[] addresses, Network network) { var addr = addresses.FirstOrDefault(); @@ -175,6 +146,7 @@ public bool AddKeySet(string walletName, KeySetData keysetData) { return KeySetTable.GetChild(walletName).Create(keysetData.KeySet.Name, keysetData, false); } + public bool SetKeySet(string walletName, KeySetData keysetData) { return KeySetTable.GetChild(walletName).Create(keysetData.KeySet.Name, keysetData, true); @@ -199,13 +171,7 @@ private static string Encode(Script script) return Encoders.Hex.EncodeData(script.ToBytes(true)); } - public Network Network - { - get - { - return Indexer.Configuration.Network; - } - } + public Network Network => Indexer.Configuration.Network; private static KeyPath Inc(KeyPath keyPath) { @@ -223,6 +189,7 @@ internal HDKeyData[] GetKeys(string walletName, string keysetName) { return KeyDataTable.GetChild(walletName, keysetName).Read(); } + public async Task<(bool Added, bool Empty)> AddWalletAddress(WalletAddress address, bool mergePast) { var empty = true; @@ -248,7 +215,6 @@ internal HDKeyData[] GetKeys(string walletName, string keysetName) return (true, empty); } - public ChainTable GetBalanceSummaryCacheTable(string walletName, bool colored) { var balanceId = new BalanceId(walletName); From 1eb0fc58a247a10c3e477b52d5faa0f846c23614 Mon Sep 17 00:00:00 2001 From: jorn vanloofsvelt Date: Tue, 26 Jan 2021 21:12:39 +0100 Subject: [PATCH 05/14] WhatIsIt: Do some light reformatting, add comments and documentation strings. --- QBitNinja/WhatIsIt.cs | 78 +++++++++++++++++++++++++++++-------------- 1 file changed, 53 insertions(+), 25 deletions(-) diff --git a/QBitNinja/WhatIsIt.cs b/QBitNinja/WhatIsIt.cs index afcac4b..1f9427b 100644 --- a/QBitNinja/WhatIsIt.cs +++ b/QBitNinja/WhatIsIt.cs @@ -8,6 +8,9 @@ namespace QBitNinja { + /// + /// Utility class to aid in recognizing a few kinds of objects from some string representations. + /// public class WhatIsIt { public WhatIsIt(MainController controller) @@ -18,42 +21,39 @@ public WhatIsIt(MainController controller) public MainController Controller { get; - set; + set; } - public Network Network - { - get - { - return Controller.Network; - } - } + public Network Network => Controller.Network; public ConsensusFactory ConsensusFactory => Network.Consensus.ConsensusFactory; - public QBitNinjaConfiguration Configuration - { - get - { - return Controller.Configuration; - } - } - + public QBitNinjaConfiguration Configuration => Controller.Configuration; + /// + /// Try to interpret the given string in a few ways in order to detect what object it's supposed to represent. + /// + /// The object represented by the input string. This may be a Bitcoin address, a script, a signature, a public key, etc. public async Task Find(string data) { data = data.Trim(); + + + // Is it a Bitcoin address? var b58 = NoException(() => WhatIsBase58.GetFromBitcoinString(data)); + if (b58 != null) { - if (b58 is WhatIsAddress) + if (b58 is WhatIsAddress address) { - var address = (WhatIsAddress)b58; - await TryFetchRedeemOrPubKey(address); + await TryFetchRedeemOrPubKey(address); // Shouldn't the return value here be checked? } + return b58; } + + // Is it a transaction ID? if (data.Length == 0x40) { try @@ -62,45 +62,68 @@ public async Task Find(string data) } catch { + // Well, apparently it's not a transaction ID. } } + + + // Is it a block feature? var b = NoException(() => Controller.JsonBlock(BlockFeature.Parse(data), true, false)); + if (b != null) return b; - if (data.Length == 0x28) //Hash of pubkey or script + + // Is it the hash of a public key (modeled as KeyId in NBitcoin), or is it the hash of a script ID? + if (data.Length == 0x28) // Hash of pubkey or script { TxDestination dest = new KeyId(data); + var address = new WhatIsAddress(dest.GetAddress(Network)); + if (await TryFetchRedeemOrPubKey(address)) return address; dest = new ScriptId(data); address = new WhatIsAddress(dest.GetAddress(Network)); + if (await TryFetchRedeemOrPubKey(address)) return address; } + // Is it a script? var script = NoException(() => GetScriptFromBytes(data)); + if (script != null) return new WhatIsScript(script, Network); + script = NoException(() => GetScriptFromText(data)); + if (script != null) return new WhatIsScript(script, Network); + + // Is it a transaction signature? var sig = NoException(() => new TransactionSignature(Encoders.Hex.DecodeData(data))); + if (sig != null) return new WhatIsTransactionSignature(sig); + + // Is it a hexstring representing the bytes of a public key? var pubkeyBytes = NoException(() => Encoders.Hex.DecodeData(data)); + if (pubkeyBytes != null && PubKey.Check(pubkeyBytes, true)) { var pubKey = NoException(() => new PubKey(data)); + if (pubKey != null) return new WhatIsPublicKey(pubKey, Network); } + + // Is it a blockheader? if (data.Length == 80 * 2) { var blockHeader = NoException(() => @@ -109,9 +132,13 @@ public async Task Find(string data) h.ReadWrite(Encoders.Hex.DecodeData(data), ConsensusFactory); return h; }); + if (blockHeader != null) return new WhatIsBlockHeader(blockHeader); } + + + // No idea what this is. return null; } @@ -137,7 +164,6 @@ private static Script GetScriptFromBytes(string data) return !hasOps ? null : script; } - private async Task TryFetchRedeemOrPubKey(WhatIsAddress address) { if (address.IsP2SH) @@ -145,11 +171,13 @@ private async Task TryFetchRedeemOrPubKey(WhatIsAddress address) address.RedeemScript = await TryFetchRedeem(address); return address.RedeemScript != null; } - address.PublicKey = await TryFetchPublicKey(address); - return address.PublicKey != null; + else + { + address.PublicKey = await TryFetchPublicKey(address); + return address.PublicKey != null; + } } - private async Task