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
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/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
}
}
diff --git a/QBitNinja/ChainTable.cs b/QBitNinja/ChainTable.cs
index 1362fd7..8cd6bf9 100644
--- a/QBitNinja/ChainTable.cs
+++ b/QBitNinja/ChainTable.cs
@@ -10,31 +10,27 @@
namespace QBitNinja
{
///
- /// Such table can store data keyed by Height/BlockId/TransactionId, and range query them
+ /// Wraps an Azure table that may store data keyed by Height/BlockId/TransactionId, and allows for range queries against it.
///
public class ChainTable
{
private readonly JsonSerializerSettings serializerSettings;
- readonly CloudTable _cloudTable;
+ readonly CloudTable _cloudTable; // An Azure table
+
public ChainTable(CloudTable cloudTable, Network network)
{
if(cloudTable == null)
throw new ArgumentNullException("cloudTable");
if (network == null)
throw new ArgumentNullException(nameof(network));
- JsonSerializerSettings serializerSettings = new JsonSerializerSettings();
+
+ var serializerSettings = new JsonSerializerSettings();
QBitNinja.Serializer.RegisterFrontConverters(serializerSettings, network);
this.serializerSettings = serializerSettings;
_cloudTable = cloudTable;
}
- public CloudTable Table
- {
- get
- {
- return _cloudTable;
- }
- }
+ public CloudTable Table => _cloudTable;
public Scope Scope
{
@@ -50,8 +46,6 @@ public void Create(ConfirmedBalanceLocator locator, T item)
Table.Execute(TableOperation.InsertOrReplace(entity));
}
-
-
public void Delete(ConfirmedBalanceLocator locator)
{
var entity = new DynamicTableEntity(Escape(Scope), Escape(locator))
@@ -60,15 +54,16 @@ public void Delete(ConfirmedBalanceLocator locator)
};
Table.Execute(TableOperation.Delete(entity));
}
+
public void Delete()
{
- foreach(var entity in Table.ExecuteQuery(new TableQuery()
+ var tableQuery = new TableQuery()
{
FilterString = TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, Escape(Scope))
- }))
- {
+ };
+
+ foreach (var entity in Table.ExecuteQuery(tableQuery))
Table.Execute(TableOperation.Delete(entity));
- }
}
public IEnumerable Query(ChainBase chain, BalanceQuery query = null)
@@ -95,6 +90,7 @@ private string ParseData(DynamicTableEntity entity)
}
return builder.ToString();
}
+
private void PutData(DynamicTableEntity entity, string str)
{
int i = 0;
diff --git a/QBitNinja/CrudTable.cs b/QBitNinja/CrudTable.cs
index 0388803..2569ed9 100644
--- a/QBitNinja/CrudTable.cs
+++ b/QBitNinja/CrudTable.cs
@@ -28,13 +28,14 @@ public CrudTableFactory(JsonSerializerSettings serializerSettings, Func _createTable;
+
public Scope Scope
{
get;
private set;
}
- private JsonSerializerSettings serializerSettings;
+ private readonly JsonSerializerSettings serializerSettings;
public CrudTable GetTable(string tableName)
{
@@ -45,6 +46,12 @@ public CrudTable GetTable(string tableName)
};
}
}
+
+ ///
+ /// Wraps an Azure CloudTable, offering CRUD operations for objects of a specific type, automatically
+ /// serializing to and from JSON when querying the CloudTable.
+ ///
+ ///
public class CrudTable
{
public CrudTable(CloudTable table, JsonSerializerSettings serializerSettings)
@@ -53,7 +60,7 @@ public CrudTable(CloudTable table, JsonSerializerSettings serializerSettings)
throw new ArgumentNullException("table");
if (serializerSettings == null)
throw new ArgumentNullException(nameof(serializerSettings));
- _table = table;
+ Table = table;
Scope = new Scope();
this.serializerSettings = serializerSettings;
}
@@ -64,14 +71,12 @@ public Scope Scope
set;
}
- private JsonSerializerSettings serializerSettings;
- private readonly CloudTable _table;
+ private readonly JsonSerializerSettings serializerSettings;
+
public CloudTable Table
{
- get
- {
- return _table;
- }
+ get;
+ private set;
}
public async Task CreateAsync(string itemId, T item, bool orReplace = true)
@@ -82,9 +87,9 @@ public async Task CreateAsync(string itemId, T item, bool orReplace = true
var entity = new DynamicTableEntity(Escape(Scope), Escape(itemId))
{
Properties =
- {
- new KeyValuePair("data",new EntityProperty(callbackStr))
- }
+ {
+ new KeyValuePair("data", new EntityProperty(callbackStr))
+ }
};
await Table.ExecuteAsync(orReplace ? TableOperation.InsertOrReplace(entity) : TableOperation.Insert(entity)).ConfigureAwait(false);
}
@@ -118,7 +123,7 @@ public void Delete()
}
}
- void Ignore(int errorCode, Action act)
+ private void Ignore(int errorCode, Action act)
{
try
{
@@ -130,6 +135,7 @@ void Ignore(int errorCode, Action act)
throw;
}
}
+
public bool Delete(string itemId, bool includeChildren = false)
{
try
@@ -140,8 +146,8 @@ public bool Delete(string itemId, bool includeChildren = false)
}));
if (includeChildren)
{
- var children = Scope.GetChild(itemId);
- foreach (var child in Table.ExecuteQuery(AllInScope(children)))
+ var childScope = Scope.GetChild(itemId); // 'itemId' can be a path.
+ foreach (var child in Table.ExecuteQuery(AllInScope(childScope)))
{
Ignore(404, () => Table.Execute(TableOperation.Delete(child)));
}
@@ -156,11 +162,11 @@ public bool Delete(string itemId, bool includeChildren = false)
return true;
}
- private static TableQuery AllInScope(QBitNinja.Scope children)
+ private static TableQuery AllInScope(QBitNinja.Scope scope)
{
return new TableQuery()
{
- FilterString = TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, Escape(children))
+ FilterString = TableQuery.GenerateFilterCondition("PartitionKey", QueryComparisons.Equal, Escape(scope))
};
}
@@ -185,8 +191,6 @@ private static string Escape(string key)
return result;
}
-
-
public async Task ReadOneAsync(string item)
{
var e = (await Table.ExecuteAsync(TableOperation.Retrieve(Escape(Scope), Escape(item))).ConfigureAwait(false)).Result as DynamicTableEntity;
@@ -195,12 +199,10 @@ public async Task ReadOneAsync(string item)
return JsonConvert.DeserializeObject(e.Properties["data"].StringValue, serializerSettings);
}
-
public T ReadOne(string item)
{
try
{
-
return ReadOneAsync(item).Result;
}
catch (AggregateException aex)
@@ -210,6 +212,9 @@ public T ReadOne(string item)
}
}
+ ///
+ /// Get a CrudTable that is scoped to some nested path.
+ ///
public CrudTable GetChild(params string[] children)
{
return new CrudTable(Table, serializerSettings)
diff --git a/QBitNinja/DefaultDataDirectory.cs b/QBitNinja/DefaultDataDirectory.cs
index dcd37ee..5d0e984 100644
--- a/QBitNinja/DefaultDataDirectory.cs
+++ b/QBitNinja/DefaultDataDirectory.cs
@@ -5,13 +5,19 @@
namespace QBitNinja
{
- public class DefaultDataDirectory
+ public static class DefaultDataDirectory
{
+ ///
+ /// Get or create a directory rooted in a location that is specified as an environment variable
+ /// named either 'HOME', or 'APPDATA' (fallback).
+ ///
public static string GetDirectory(string appDirectory, string subDirectory, bool createIfNotExists = true)
{
string directory = null;
+
+ // Find path to 'appDirectory'.
var home = Environment.GetEnvironmentVariable("HOME");
- if(!string.IsNullOrEmpty(home))
+ if (!string.IsNullOrEmpty(home))
{
directory = home;
directory = Path.Combine(directory, "." + appDirectory.ToLowerInvariant());
@@ -19,25 +25,30 @@ public static string GetDirectory(string appDirectory, string subDirectory, bool
else
{
var localAppData = Environment.GetEnvironmentVariable("APPDATA");
- if(!string.IsNullOrEmpty(localAppData))
+ if (!string.IsNullOrEmpty(localAppData))
{
directory = localAppData;
directory = Path.Combine(directory, appDirectory);
}
else
{
- throw new DirectoryNotFoundException("Could not find suitable datadir");
+ throw new DirectoryNotFoundException("Could not find suitable datadir.");
}
}
- if(!Directory.Exists(directory))
+
+
+ if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
+
+ // Find path to 'subdirectory' and create it if needed.
directory = Path.Combine(directory, subDirectory);
- if(createIfNotExists && !Directory.Exists(directory))
+ if (createIfNotExists && !Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
+
return directory;
}
}
diff --git a/QBitNinja/Extensions.cs b/QBitNinja/Extensions.cs
index 9b9ee6b..d0b3995 100644
--- a/QBitNinja/Extensions.cs
+++ b/QBitNinja/Extensions.cs
@@ -26,10 +26,15 @@ public static WalletRuleEntry CreateWalletRuleEntry(this WalletAddress address,
});
}
+
+ ///
+ /// Get an instance of QBitNinjaConfiguration as provided by the HttpConfiguration's dependency resolver.
+ ///
public static QBitNinjaConfiguration GetConfiguration(this HttpRequestContext ctx)
{
return ((QBitNinjaDependencyResolver)ctx.Configuration.DependencyResolver).Get();
}
+
public static T MinElement(this IEnumerable input, Func predicate)
{
int min = int.MaxValue;
diff --git a/QBitNinja/InitialIndexer.cs b/QBitNinja/InitialIndexer.cs
index cf9ed85..5e0154d 100644
--- a/QBitNinja/InitialIndexer.cs
+++ b/QBitNinja/InitialIndexer.cs
@@ -43,7 +43,6 @@ public override string ToString()
}
}
-
public class InitialIndexer
{
diff --git a/QBitNinja/ListenerTrace.cs b/QBitNinja/ListenerTrace.cs
index a931a42..2f2d06f 100644
--- a/QBitNinja/ListenerTrace.cs
+++ b/QBitNinja/ListenerTrace.cs
@@ -8,13 +8,18 @@
namespace QBitNinja
{
+ ///
+ /// Wrapper around a System.Diagnostics.TraceSource instance.
+ ///
public static class ListenerTrace
{
static TraceSource _Source = new TraceSource("QBitNinja.Listener");
+
public static void Error(string info, Exception ex)
{
_Source.TraceEvent(TraceEventType.Error, 0, info + "\r\n" + Utils.ExceptionToString(ex));
}
+
public static void Info(string info)
{
_Source.TraceInformation(info);
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;
diff --git a/QBitNinja/ReaderWriterLock.cs b/QBitNinja/ReaderWriterLock.cs
index f502c4e..dd862a9 100644
--- a/QBitNinja/ReaderWriterLock.cs
+++ b/QBitNinja/ReaderWriterLock.cs
@@ -7,6 +7,10 @@
namespace QBitNinja
{
+ ///
+ /// Wrapper around ReaderWriterLockSlim, offering a scoped-behavior pattern where the lock
+ /// is exited at the end of a using statement block.
+ ///
internal class ReaderWriterLock
{
ReaderWriterLockSlim @lock = new ReaderWriterLockSlim();
diff --git a/QBitNinja/Scope.cs b/QBitNinja/Scope.cs
index 5609ffa..1c06fef 100644
--- a/QBitNinja/Scope.cs
+++ b/QBitNinja/Scope.cs
@@ -3,12 +3,24 @@
namespace QBitNinja
{
+ ///
+ /// Represents a scope for some part of a hierarchy, where each scope is represented by a number of names that make up a path
+ /// within that hierarchy. A scope covers all children in that path.
+ ///
public class Scope
{
+ ///
+ /// Create a scope for an empty path.
+ ///
public Scope()
{
- _parents = new string[0];
+ Parents = new string[0];
}
+
+ ///
+ /// Create a scope for a given path.
+ ///
+ /// A path represented by a number of names, the name at the first index being the root.
public Scope(string[] parents)
{
if (parents == null)
@@ -17,28 +29,37 @@ public Scope(string[] parents)
{
throw new ArgumentException("'/' is not authorized for naming a scope");
}
- _parents = parents;
+ Parents = parents;
}
- private readonly string[] _parents;
+ ///
+ /// A path represented by a number of names, the name at the first index being the root.
+ ///
public string[] Parents
{
- get
- {
- return _parents;
- }
+ get;
+ private set;
}
+ ///
+ /// Get a child scope, which will be represented by the path of the current scope, extended with
+ /// the given subpath.
+ ///
+ /// An array of names that make up a path rooted in the current scope.
+ ///
public Scope GetChild(params string[] names)
{
- var parents = _parents.ToList();
+ var parents = Parents.ToList();
parents.AddRange(names);
return new Scope(parents.ToArray());
}
+ ///
+ /// Join the parts of the path with forward slashes to get a string representation of the scope.
+ ///
public override string ToString()
{
- return String.Join("/", _parents);
+ return String.Join("/", Parents);
}
}
}
diff --git a/QBitNinja/Serializer.cs b/QBitNinja/Serializer.cs
index 72762fd..80d1165 100644
--- a/QBitNinja/Serializer.cs
+++ b/QBitNinja/Serializer.cs
@@ -18,7 +18,10 @@ namespace QBitNinja
namespace QBitNinja.Client
#endif
{
- public class Serializer
+ ///
+ /// A JSON serializer that also has NBitcoin's front converters registered.
+ ///
+ public static class Serializer
{
#if !NOJSONNET
public
@@ -37,6 +40,7 @@ static void RegisterFrontConverters(JsonSerializerSettings settings, Network net
#endif
settings.ContractResolver = new CamelCasePropertyNamesContractResolver();
}
+
public static T ToObject(string data, Network network)
{
JsonSerializerSettings settings = new JsonSerializerSettings
@@ -57,6 +61,7 @@ public static string ToString(T response, Network network)
return JsonConvert.SerializeObject(response, settings);
}
#if !CLIENT
+
public static MediaTypeFormatter JsonMediaTypeFormatter(Network network)
{
if (network == null)
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);
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