Commit 8e6ab15d authored by Dan Gershony's avatar Dan Gershony

Moving the wallet feature to the full node

parent 3435ae71
 
Microsoft Visual Studio Solution File, Format Version 12.00 Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15 # Visual Studio 15
VisualStudioVersion = 15.0.26430.6 VisualStudioVersion = 15.0.26430.12
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{807563C4-7259-434D-B604-A14C3DCF8E30}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{807563C4-7259-434D-B604-A14C3DCF8E30}"
EndProject EndProject
...@@ -17,16 +17,18 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Breeze.Api.Tests", "src\Bre ...@@ -17,16 +17,18 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Breeze.Api.Tests", "src\Bre
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Breeze.Wallet", "src\Breeze.Wallet\Breeze.Wallet.csproj", "{D16CD478-9D1E-4C69-91AD-43539E94A215}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Breeze.Wallet", "src\Breeze.Wallet\Breeze.Wallet.csproj", "{D16CD478-9D1E-4C69-91AD-43539E94A215}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Breeze.Daemon", "src\Breeze.Daemon\Breeze.Daemon.csproj", "{1B598E33-667F-496D-BC0D-88276E8E7632}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Breeze.TumbleBit.Client", "src\Breeze.TumbleBit.Client\Breeze.TumbleBit.Client.csproj", "{2490DD1A-6C14-47F2-A9C6-56761A52E2D9}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Breeze.TumbleBit.Client", "src\Breeze.TumbleBit.Client\Breeze.TumbleBit.Client.csproj", "{2490DD1A-6C14-47F2-A9C6-56761A52E2D9}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Breeze.Common", "src\Breeze.Common\Breeze.Common.csproj", "{C726817D-9E2F-4DDC-90A4-B6895CF5309B}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TumbleBit", "TumbleBit", "{1B724678-2B73-483E-B981-3A6733C2194E}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TumbleBit", "TumbleBit", "{1B724678-2B73-483E-B981-3A6733C2194E}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NTumbleBit", "src\NTumbleBit\NTumbleBit.csproj", "{29E411B1-5687-43EE-A71B-6CCEC2289129}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NTumbleBit", "src\NTumbleBit\NTumbleBit.csproj", "{29E411B1-5687-43EE-A71B-6CCEC2289129}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Stratis.Bitcoin", "..\..\StratisBitcoinFullNode\Stratis.Bitcoin\Stratis.Bitcoin.csproj", "{6702A093-B42C-44DA-86BB-CD8F87E9A665}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Stratis.Bitcoin.Common", "..\..\StratisBitcoinFullNode\Stratis.Bitcoin.Common\Stratis.Bitcoin.Common.csproj", "{4F9F7CF7-326C-4FC0-9EFB-209536A42030}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Breeze.Daemon", "src\Breeze.Daemon\Breeze.Daemon.csproj", "{3F0937A2-3182-42D9-866F-3DEDEE28EC5A}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
...@@ -45,22 +47,26 @@ Global ...@@ -45,22 +47,26 @@ Global
{D16CD478-9D1E-4C69-91AD-43539E94A215}.Debug|Any CPU.Build.0 = Debug|Any CPU {D16CD478-9D1E-4C69-91AD-43539E94A215}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D16CD478-9D1E-4C69-91AD-43539E94A215}.Release|Any CPU.ActiveCfg = Release|Any CPU {D16CD478-9D1E-4C69-91AD-43539E94A215}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D16CD478-9D1E-4C69-91AD-43539E94A215}.Release|Any CPU.Build.0 = Release|Any CPU {D16CD478-9D1E-4C69-91AD-43539E94A215}.Release|Any CPU.Build.0 = Release|Any CPU
{1B598E33-667F-496D-BC0D-88276E8E7632}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1B598E33-667F-496D-BC0D-88276E8E7632}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1B598E33-667F-496D-BC0D-88276E8E7632}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1B598E33-667F-496D-BC0D-88276E8E7632}.Release|Any CPU.Build.0 = Release|Any CPU
{2490DD1A-6C14-47F2-A9C6-56761A52E2D9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {2490DD1A-6C14-47F2-A9C6-56761A52E2D9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2490DD1A-6C14-47F2-A9C6-56761A52E2D9}.Debug|Any CPU.Build.0 = Debug|Any CPU {2490DD1A-6C14-47F2-A9C6-56761A52E2D9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2490DD1A-6C14-47F2-A9C6-56761A52E2D9}.Release|Any CPU.ActiveCfg = Release|Any CPU {2490DD1A-6C14-47F2-A9C6-56761A52E2D9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2490DD1A-6C14-47F2-A9C6-56761A52E2D9}.Release|Any CPU.Build.0 = Release|Any CPU {2490DD1A-6C14-47F2-A9C6-56761A52E2D9}.Release|Any CPU.Build.0 = Release|Any CPU
{C726817D-9E2F-4DDC-90A4-B6895CF5309B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C726817D-9E2F-4DDC-90A4-B6895CF5309B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C726817D-9E2F-4DDC-90A4-B6895CF5309B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C726817D-9E2F-4DDC-90A4-B6895CF5309B}.Release|Any CPU.Build.0 = Release|Any CPU
{29E411B1-5687-43EE-A71B-6CCEC2289129}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {29E411B1-5687-43EE-A71B-6CCEC2289129}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{29E411B1-5687-43EE-A71B-6CCEC2289129}.Debug|Any CPU.Build.0 = Debug|Any CPU {29E411B1-5687-43EE-A71B-6CCEC2289129}.Debug|Any CPU.Build.0 = Debug|Any CPU
{29E411B1-5687-43EE-A71B-6CCEC2289129}.Release|Any CPU.ActiveCfg = Release|Any CPU {29E411B1-5687-43EE-A71B-6CCEC2289129}.Release|Any CPU.ActiveCfg = Release|Any CPU
{29E411B1-5687-43EE-A71B-6CCEC2289129}.Release|Any CPU.Build.0 = Release|Any CPU {29E411B1-5687-43EE-A71B-6CCEC2289129}.Release|Any CPU.Build.0 = Release|Any CPU
{6702A093-B42C-44DA-86BB-CD8F87E9A665}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6702A093-B42C-44DA-86BB-CD8F87E9A665}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6702A093-B42C-44DA-86BB-CD8F87E9A665}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6702A093-B42C-44DA-86BB-CD8F87E9A665}.Release|Any CPU.Build.0 = Release|Any CPU
{4F9F7CF7-326C-4FC0-9EFB-209536A42030}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4F9F7CF7-326C-4FC0-9EFB-209536A42030}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4F9F7CF7-326C-4FC0-9EFB-209536A42030}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4F9F7CF7-326C-4FC0-9EFB-209536A42030}.Release|Any CPU.Build.0 = Release|Any CPU
{3F0937A2-3182-42D9-866F-3DEDEE28EC5A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3F0937A2-3182-42D9-866F-3DEDEE28EC5A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3F0937A2-3182-42D9-866F-3DEDEE28EC5A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3F0937A2-3182-42D9-866F-3DEDEE28EC5A}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
...@@ -69,9 +75,8 @@ Global ...@@ -69,9 +75,8 @@ Global
{E7B3E9EB-34E8-4B10-B296-4D5270E314A4} = {807563C4-7259-434D-B604-A14C3DCF8E30} {E7B3E9EB-34E8-4B10-B296-4D5270E314A4} = {807563C4-7259-434D-B604-A14C3DCF8E30}
{BD5174B4-DCE8-4594-9A16-B83E56767770} = {807563C4-7259-434D-B604-A14C3DCF8E30} {BD5174B4-DCE8-4594-9A16-B83E56767770} = {807563C4-7259-434D-B604-A14C3DCF8E30}
{D16CD478-9D1E-4C69-91AD-43539E94A215} = {807563C4-7259-434D-B604-A14C3DCF8E30} {D16CD478-9D1E-4C69-91AD-43539E94A215} = {807563C4-7259-434D-B604-A14C3DCF8E30}
{1B598E33-667F-496D-BC0D-88276E8E7632} = {807563C4-7259-434D-B604-A14C3DCF8E30}
{2490DD1A-6C14-47F2-A9C6-56761A52E2D9} = {807563C4-7259-434D-B604-A14C3DCF8E30} {2490DD1A-6C14-47F2-A9C6-56761A52E2D9} = {807563C4-7259-434D-B604-A14C3DCF8E30}
{C726817D-9E2F-4DDC-90A4-B6895CF5309B} = {807563C4-7259-434D-B604-A14C3DCF8E30}
{29E411B1-5687-43EE-A71B-6CCEC2289129} = {1B724678-2B73-483E-B981-3A6733C2194E} {29E411B1-5687-43EE-A71B-6CCEC2289129} = {1B724678-2B73-483E-B981-3A6733C2194E}
{3F0937A2-3182-42D9-866F-3DEDEE28EC5A} = {807563C4-7259-434D-B604-A14C3DCF8E30}
EndGlobalSection EndGlobalSection
EndGlobal EndGlobal
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\..\..\StratisBitcoinFullNode\Stratis.Bitcoin\Stratis.Bitcoin.csproj" />
<ProjectReference Include="..\Breeze.Api\Breeze.Api.csproj" /> <ProjectReference Include="..\Breeze.Api\Breeze.Api.csproj" />
<ProjectReference Include="..\Breeze.Wallet\Breeze.Wallet.csproj" /> <ProjectReference Include="..\Breeze.Wallet\Breeze.Wallet.csproj" />
</ItemGroup> </ItemGroup>
......
using System;
using System.Collections.Generic;
using System.IO;
using Microsoft.AspNetCore.Mvc;
using Xunit;
using Moq;
using Breeze.Wallet;
using Breeze.Wallet.Controllers;
using Breeze.Common.JsonErrors;
using Breeze.Wallet.Helpers;
using Breeze.Wallet.Models;
using NBitcoin;
using NBitcoin.Protocol;
using Stratis.Bitcoin.Configuration;
using Stratis.Bitcoin.Connection;
namespace Breeze.Api.Tests
{
public class ControllersTests
{
[Fact]
public void CreateWalletSuccessfullyReturnsMnemonic()
{
Mnemonic mnemonic = new Mnemonic(Wordlist.English, WordCount.Twelve);
var mockWalletCreate = new Mock<IWalletManager>();
mockWalletCreate.Setup(wallet => wallet.CreateWallet(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), null)).Returns(mnemonic);
var controller = new WalletController(mockWalletCreate.Object, new Mock<ITracker>().Object, It.IsAny<ConnectionManager>(), Network.Main, new Mock<ConcurrentChain>().Object);
// Act
var result = controller.Create(new WalletCreationRequest
{
Name = "myName",
FolderPath = "",
Password = "",
Network = ""
});
// Assert
mockWalletCreate.VerifyAll();
var viewResult = Assert.IsType<JsonResult>(result);
Assert.Equal(mnemonic.ToString(), viewResult.Value);
Assert.NotNull(result);
}
[Fact]
public void LoadWalletSuccessfullyReturnsWalletModel()
{
Wallet.Wallet wallet = new Wallet.Wallet
{
Name = "myWallet",
Network = WalletHelpers.GetNetwork("mainnet")
};
var mockWalletWrapper = new Mock<IWalletManager>();
mockWalletWrapper.Setup(w => w.RecoverWallet(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<DateTime>(), null)).Returns(wallet);
var controller = new WalletController(mockWalletWrapper.Object, new Mock<ITracker>().Object, It.IsAny<ConnectionManager>(), Network.Main, new Mock<ConcurrentChain>().Object);
// Act
var result = controller.Recover(new WalletRecoveryRequest
{
Name = "myWallet",
FolderPath = "",
Password = "",
Network = "MainNet",
Mnemonic = "mnemonic"
});
// Assert
mockWalletWrapper.VerifyAll();
var viewResult = Assert.IsType<OkResult>(result);
Assert.Equal(200, viewResult.StatusCode);
}
[Fact]
public void RecoverWalletSuccessfullyReturnsWalletModel()
{
Wallet.Wallet wallet = new Wallet.Wallet
{
Name = "myWallet",
Network = WalletHelpers.GetNetwork("mainnet")
};
var mockWalletWrapper = new Mock<IWalletManager>();
mockWalletWrapper.Setup(w => w.LoadWallet(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>())).Returns(wallet);
var controller = new WalletController(mockWalletWrapper.Object, new Mock<ITracker>().Object, It.IsAny<ConnectionManager>(), Network.Main, new Mock<ConcurrentChain>().Object);
// Act
var result = controller.Load(new WalletLoadRequest
{
Name = "myWallet",
FolderPath = "",
Password = ""
});
// Assert
mockWalletWrapper.VerifyAll();
var viewResult = Assert.IsType<OkResult>(result);
Assert.Equal(200, viewResult.StatusCode);
}
[Fact]
public void FileNotFoundExceptionandReturns404()
{
var mockWalletWrapper = new Mock<IWalletManager>();
mockWalletWrapper.Setup(wallet => wallet.LoadWallet(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>())).Throws<FileNotFoundException>();
var controller = new WalletController(mockWalletWrapper.Object, new Mock<ITracker>().Object, It.IsAny<ConnectionManager>(), Network.Main, new Mock<ConcurrentChain>().Object);
// Act
var result = controller.Load(new WalletLoadRequest
{
Name = "myName",
FolderPath = "",
Password = ""
});
// Assert
mockWalletWrapper.VerifyAll();
var viewResult = Assert.IsType<ErrorResult>(result);
Assert.NotNull(viewResult);
Assert.Equal(404, viewResult.StatusCode);
}
}
}
using System;
using System.Collections.Generic;
using System.Text;
using Breeze.Wallet.Helpers;
using NBitcoin;
using Xunit;
namespace Breeze.Api.Tests
{
public class WalletHelpersTest
{
[Fact]
public void GetMainNetworkRetuirnsNetworkMain()
{
Network network = WalletHelpers.GetNetwork("main");
Assert.Equal(Network.Main, network);
}
[Fact]
public void GetMainNetNetworkRetuirnsNetworkMain()
{
Network network = WalletHelpers.GetNetwork("mainnet");
Assert.Equal(Network.Main, network);
}
[Fact]
public void GetTestNetworkRetuirnsNetworkTest()
{
Network network = WalletHelpers.GetNetwork("test");
Assert.Equal(Network.TestNet, network);
}
[Fact]
public void GetTestNetNetworkRetuirnsNetworkTest()
{
Network network = WalletHelpers.GetNetwork("testnet");
Assert.Equal(Network.TestNet, network);
}
[Fact]
public void GetNetworkIsCaseInsensitive()
{
Network testNetwork = WalletHelpers.GetNetwork("Test");
Assert.Equal(Network.TestNet, testNetwork);
Network mainNetwork = WalletHelpers.GetNetwork("MainNet");
Assert.Equal(Network.Main, mainNetwork);
}
[Fact]
public void WrongNetworkThrowsArgumentException()
{
var exception = Record.Exception(() => WalletHelpers.GetNetwork("myNetwork"));
Assert.NotNull(exception);
Assert.IsType<ArgumentException>(exception);
}
}
}
...@@ -29,10 +29,13 @@ ...@@ -29,10 +29,13 @@
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="1.1.2" /> <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="1.1.2" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="1.1.2" /> <PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="1.1.2" />
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="1.1.2" /> <PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="1.1.2" />
<PackageReference Include="Stratis.Bitcoin" Version="1.0.1.8-alpha" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="1.0.0" /> <PackageReference Include="Swashbuckle.AspNetCore" Version="1.0.0" />
<PackageReference Include="System.Reactive" Version="3.1.1" /> <PackageReference Include="System.Reactive" Version="3.1.1" />
<PackageReference Include="System.Runtime.Loader" Version="4.3.0" /> <PackageReference Include="System.Runtime.Loader" Version="4.3.0" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\StratisBitcoinFullNode\Stratis.Bitcoin\Stratis.Bitcoin.csproj" />
</ItemGroup>
</Project> </Project>
...@@ -33,7 +33,7 @@ namespace Breeze.Api ...@@ -33,7 +33,7 @@ namespace Breeze.Api
body = string.Join(Environment.NewLine, arguments.Values); body = string.Join(Environment.NewLine, arguments.Values);
} }
this.logger.LogDebug($"Received {request.Method} {request.GetDisplayUrl()}. Body: '{body}'"); this.logger.LogInformation($"Received {request.Method} {request.GetDisplayUrl()}. Body: '{body}'");
await next(); await next();
} }
} }
......
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard1.6</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore" Version="1.1.2" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Abstractions" Version="1.1.3" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="1.1.3" />
<PackageReference Include="Newtonsoft.Json" Version="10.0.2" />
</ItemGroup>
</Project>
\ No newline at end of file
using System.Collections.Generic;
using System.Net;
namespace Breeze.Common.JsonErrors
{
public static class ErrorHelpers
{
public static ErrorResult BuildErrorResponse(HttpStatusCode statusCode, string message, string description)
{
ErrorResponse errorResponse = new ErrorResponse
{
Errors = new List<ErrorModel>
{
new ErrorModel
{
Status = (int) statusCode,
Message = message,
Description = description
}
}
};
return new ErrorResult((int)statusCode, errorResponse);
}
}
}
using System.Collections.Generic;
using Newtonsoft.Json;
namespace Breeze.Common.JsonErrors
{
public class ErrorResponse
{
[JsonProperty(PropertyName = "errors")]
public List<ErrorModel> Errors { get; set; }
}
public class ErrorModel
{
[JsonProperty(PropertyName = "status")]
public int Status { get; set; }
[JsonProperty(PropertyName = "message")]
public string Message { get; set; }
[JsonProperty(PropertyName = "description")]
public string Description { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Breeze.Common.JsonErrors;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace Breeze.Common.JsonErrors
{
public class ErrorResult : ObjectResult
{
public ErrorResult(int statusCode, ErrorResponse value) : base(value)
{
StatusCode = statusCode;
}
}
}
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\..\..\StratisBitcoinFullNode\Stratis.Bitcoin\Stratis.Bitcoin.csproj" />
<ProjectReference Include="..\Breeze.Api\Breeze.Api.csproj" /> <ProjectReference Include="..\Breeze.Api\Breeze.Api.csproj" />
<ProjectReference Include="..\Breeze.TumbleBit.Client\Breeze.TumbleBit.Client.csproj" /> <ProjectReference Include="..\Breeze.TumbleBit.Client\Breeze.TumbleBit.Client.csproj" />
<ProjectReference Include="..\Breeze.Wallet\Breeze.Wallet.csproj" /> <ProjectReference Include="..\Breeze.Wallet\Breeze.Wallet.csproj" />
...@@ -21,7 +22,6 @@ ...@@ -21,7 +22,6 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="1.1.2" /> <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="1.1.2" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="1.1.2" /> <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="1.1.2" />
<PackageReference Include="Stratis.Bitcoin" Version="1.0.1.8-alpha" />
</ItemGroup> </ItemGroup>
</Project> </Project>
...@@ -10,6 +10,7 @@ using Stratis.Bitcoin.Configuration; ...@@ -10,6 +10,7 @@ using Stratis.Bitcoin.Configuration;
using Stratis.Bitcoin.Logging; using Stratis.Bitcoin.Logging;
using Breeze.Wallet; using Breeze.Wallet;
using Stratis.Bitcoin.Notifications; using Stratis.Bitcoin.Notifications;
using Stratis.Bitcoin.Utilities;
namespace Breeze.Daemon namespace Breeze.Daemon
{ {
...@@ -17,13 +18,13 @@ namespace Breeze.Daemon ...@@ -17,13 +18,13 @@ namespace Breeze.Daemon
{ {
public static void Main(string[] args) public static void Main(string[] args)
{ {
// configure Full Node // configure Full Node
Logs.Configure(new LoggerFactory().AddConsole(LogLevel.Trace, false)); Logs.Configure(Logs.GetLoggerFactory(args));
NodeSettings nodeSettings = NodeSettings.FromArguments(args); NodeSettings nodeSettings = NodeSettings.FromArguments(args);
var fullNodeBuilder = new FullNodeBuilder() var fullNodeBuilder = new FullNodeBuilder()
.UseNodeSettings(nodeSettings) .UseNodeSettings(nodeSettings)
.UseWallet() .UseLightWallet()
.UseBlockNotification() .UseBlockNotification()
.UseTransactionNotification() .UseTransactionNotification()
.UseApi(); .UseApi();
...@@ -36,13 +37,10 @@ namespace Breeze.Daemon ...@@ -36,13 +37,10 @@ namespace Breeze.Daemon
fullNodeBuilder.UseTumbleBit(new Uri(tumblerAddress)); fullNodeBuilder.UseTumbleBit(new Uri(tumblerAddress));
} }
var node = (FullNode)fullNodeBuilder.Build(); var node = fullNodeBuilder.Build();
// start Full Node - this will also start the API // start Full Node - this will also start the API
node.Start(); node.Run();
Console.WriteLine("Press any key to stop");
Console.ReadLine();
node.Dispose();
} }
} }
} }
...@@ -21,11 +21,11 @@ ...@@ -21,11 +21,11 @@
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="1.1.3" /> <PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="1.1.3" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning" Version="1.0.3" /> <PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning" Version="1.0.3" />
<PackageReference Include="Serilog.Extensions.Logging.File" Version="1.0.1" /> <PackageReference Include="Serilog.Extensions.Logging.File" Version="1.0.1" />
<PackageReference Include="Stratis.Bitcoin" Version="1.0.1.8-alpha" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Breeze.Common\Breeze.Common.csproj" /> <ProjectReference Include="..\..\..\..\StratisBitcoinFullNode\Stratis.Bitcoin.Common\Stratis.Bitcoin.Common.csproj" />
<ProjectReference Include="..\..\..\..\StratisBitcoinFullNode\Stratis.Bitcoin\Stratis.Bitcoin.csproj" />
<ProjectReference Include="..\NTumbleBit\NTumbleBit.csproj" /> <ProjectReference Include="..\NTumbleBit\NTumbleBit.csproj" />
</ItemGroup> </ItemGroup>
......
...@@ -2,9 +2,9 @@ ...@@ -2,9 +2,9 @@
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Threading.Tasks; using System.Threading.Tasks;
using Breeze.Common.JsonErrors;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Breeze.TumbleBit.Client; using Breeze.TumbleBit.Client;
using Stratis.Bitcoin.Common.JsonErrors;
namespace Breeze.TumbleBit.Controllers namespace Breeze.TumbleBit.Controllers
{ {
......
...@@ -20,11 +20,10 @@ ...@@ -20,11 +20,10 @@
<PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning" Version="1.0.3" /> <PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning" Version="1.0.3" />
<PackageReference Include="Serilog.Extensions.Logging.File" Version="1.0.1" /> <PackageReference Include="Serilog.Extensions.Logging.File" Version="1.0.1" />
<PackageReference Include="System.ValueTuple" Version="4.3.1" /> <PackageReference Include="System.ValueTuple" Version="4.3.1" />
<PackageReference Include="Stratis.Bitcoin" Version="1.0.1.8-alpha" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Breeze.Common\Breeze.Common.csproj" /> <ProjectReference Include="..\..\..\..\StratisBitcoinFullNode\Stratis.Bitcoin\Stratis.Bitcoin.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>
using System;
using System.Collections.Generic;
using System.Text;
using NBitcoin;
namespace Breeze.Wallet
{
public static class ChainExtensions
{
/// <summary>
/// Determines whether the chain is downloaded and up to date.
/// </summary>
/// <param name="chain">The chain.</param>
public static bool IsDownloaded(this ConcurrentChain chain)
{
return chain.Tip.Header.BlockTime.ToUnixTimeSeconds() > (DateTimeOffset.Now.ToUnixTimeSeconds() - TimeSpan.FromHours(1).TotalSeconds);
}
/// <summary>
/// Gets the height of the first block created after this date.
/// </summary>
/// <param name="chain">The chain of blocks.</param>
/// <param name="date">The date.</param>
/// <returns>The height of the first block created after the date.</returns>
public static int GetHeightAtTime(this ConcurrentChain chain, DateTime date)
{
int blockSyncStart = 0;
int upperLimit = chain.Tip.Height;
int lowerLimit = 0;
bool found = false;
while (!found)
{
int check = lowerLimit + (upperLimit - lowerLimit) / 2;
if (chain.GetBlock(check).Header.BlockTime >= date)
{
upperLimit = check;
}
else if (chain.GetBlock(check).Header.BlockTime < date)
{
lowerLimit = check;
}
if (upperLimit - lowerLimit <= 1)
{
blockSyncStart = upperLimit;
found = true;
}
}
return blockSyncStart;
}
}
}
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.Text;
using NBitcoin;
using Stratis.Bitcoin.Utilities;
namespace Breeze.Wallet.Helpers
{
/// <summary>
/// Contains a collection of helpers methods.
/// </summary>
public static class WalletHelpers
{
/// <summary>
/// Get the network on which to operate.
/// </summary>
/// <param name="network">The network</param>
/// <returns>A <see cref="Network"/> object.</returns>
public static Network GetNetwork(string network)
{
Guard.NotEmpty(network, nameof(network));
switch (network.ToLowerInvariant())
{
case "main":
case "mainnet":
return Network.Main;
case "test":
case "testnet":
return Network.TestNet;
default:
throw new ArgumentException($"Network '{network}' is not a valid network.");
}
}
}
}
using System;
using System.Threading.Tasks;
using NBitcoin;
namespace Breeze.Wallet
{
public interface ITracker
{
/// <summary>
/// Initializes the tracker.
/// </summary>
/// <returns></returns>
Task Initialize();
/// <summary>
/// Waits for the chain to download.
/// </summary>
/// <returns></returns>
Task WaitForChainDownloadAsync();
/// <summary>
/// Synchronize the wallet starting from the date passed as a parameter.
/// </summary>
/// <param name="date">The date from which to start the sync process.</param>
/// <returns>The height of the block sync will start from</returns>
void SyncFrom(DateTime date);
/// <summary>
/// Synchronize the wallet starting from the height passed as a parameter.
/// </summary>
/// <param name="height">The height from which to start the sync process.</param>
/// <returns>The height of the block sync will start from</returns>
void SyncFrom(int height);
}
}
using System;
using System.Collections.Generic;
using Breeze.Wallet.Models;
using NBitcoin;
namespace Breeze.Wallet
{
/// <summary>
/// Interface for a manager providing operations on wallets.
/// </summary>
public interface IWalletManager : IDisposable
{
/// <summary>
/// Creates a wallet and persist it as a file on the local system.
/// </summary>
/// <param name="password">The password used to encrypt sensitive info.</param>
/// <param name="folderPath">The folder where the wallet will be saved.</param>
/// <param name="name">The name of the wallet.</param>
/// <param name="network">The network this wallet is for.</param>
/// <param name="passphrase">The passphrase used in the seed.</param>
/// <returns>A mnemonic defining the wallet's seed used to generate addresses.</returns>
Mnemonic CreateWallet(string password, string folderPath, string name, string network, string passphrase = null);
/// <summary>
/// Loads a wallet from a file.
/// </summary>
/// <param name="password">The user's password.</param>
/// <param name="folderPath">The folder where the wallet will be loaded.</param>
/// <param name="name">The name of the wallet.</param>
/// <returns>The wallet.</returns>
Wallet LoadWallet(string password, string folderPath, string name);
/// <summary>
/// Recovers a wallet.
/// </summary>
/// <param name="password">The user's password.</param>
/// <param name="folderPath">The folder where the wallet will be loaded.</param>
/// <param name="name">The name of the wallet.</param>
/// <param name="network">The network in which to creae this wallet</param>
/// <param name="mnemonic">The user's mnemonic for the wallet.</param>
/// <param name="passphrase">The passphrase used in the seed.</param>
/// <param name="creationTime">The date and time this wallet was created.</param>
/// <returns>The recovered wallet.</returns>
Wallet RecoverWallet(string password, string folderPath, string name, string network, string mnemonic, DateTime creationTime, string passphrase = null);
/// <summary>
/// Deletes a wallet.
/// </summary>
/// <param name="walletFilePath">The location of the wallet file.</param>
void DeleteWallet(string walletFilePath);
/// <summary>
/// Gets an account that contains no transactions.
/// </summary>
/// <param name="walletName">The name of the wallet from which to get an account.</param>
/// <param name="coinType">The type of coin for which to get an account.</param>
/// <param name="password">The password used to decrypt the private key.</param>
/// <remarks>
/// According to BIP44, an account at index (i) can only be created when the account
/// at index (i - 1) contains transactions.
/// </remarks>
/// <returns>An unused account.</returns>
HdAccount GetUnusedAccount(string walletName, CoinType coinType, string password);
/// <summary>
/// Gets an account that contains no transactions.
/// </summary>
/// <param name="wallet">The wallet from which to get an account.</param>
/// <param name="coinType">The type of coin for which to get an account.</param>
/// <param name="password">The password used to decrypt the private key.</param>
/// <remarks>
/// According to BIP44, an account at index (i) can only be created when the account
/// at index (i - 1) contains transactions.
/// </remarks>
/// <returns>An unused account.</returns>
HdAccount GetUnusedAccount(Wallet wallet, CoinType coinType, string password);
/// <summary>
/// Creates a new account.
/// </summary>
/// <param name="wallet">The wallet in which this account will be created.</param>
/// <param name="coinType">The type of coin for which to create an account.</param>
/// <param name="password">The password used to decrypt the private key.</param>
/// <remarks>
/// According to BIP44, an account at index (i) can only be created when the account
/// at index (i - 1) contains transactions.
/// </remarks>
/// <returns>The new account.</returns>
HdAccount CreateNewAccount(Wallet wallet, CoinType coinType, string password);
/// <summary>
/// Gets an address that contains no transaction.
/// </summary>
/// <param name="walletName">The name of the wallet in which this address is contained.</param>
/// <param name="coinType">The type of coin for which to get the address.</param>
/// <param name="accountName">The name of the account in which this address is contained.</param>
/// <returns>An unused address or a newly created address, in Base58 format.</returns>
string GetUnusedAddress(string walletName, CoinType coinType, string accountName);
/// <summary>
/// Gets a collection of addresses containing transactions for this coin.
/// </summary>
/// <param name="walletName">The name of the wallet to get history from.</param>
/// <param name="coinType">Type of the coin.</param>
/// <returns></returns>
IEnumerable<HdAddress> GetHistoryByCoinType(string walletName, CoinType coinType);
/// <summary>
/// Gets a collection of addresses containing transactions for this coin.
/// </summary>
/// <param name="wallet">The wallet to get history from.</param>
/// <param name="coinType">Type of the coin.</param>
/// <returns></returns>
IEnumerable<HdAddress> GetHistoryByCoinType(Wallet wallet, CoinType coinType);
/// <summary>
/// Gets some general information about a wallet.
/// </summary>
/// <param name="walletName">The name of the wallet.</param>
/// <returns></returns>
Wallet GetWallet(string walletName);
/// <summary>
/// Gets a list of accounts filtered by coin type.
/// </summary>
/// <param name="walletName">The name of the wallet to look into.</param>
/// <param name="coinType">The type of coin to filter by.</param>
/// <returns></returns>
IEnumerable<HdAccount> GetAccountsByCoinType(string walletName, CoinType coinType);
/// <summary>
/// Builds a transaction to be sent to the network.
/// </summary>
/// <param name="walletName">The name of the wallet in which this address is contained.</param>
/// <param name="coinType">The type of coin for which to get the address.</param>
/// <param name="accountName">The name of the account in which this address is contained.</param>
/// <param name="password">The password used to decrypt the private key.</param>
/// <param name="destinationAddress">The destination address to send the funds to.</param>
/// <param name="amount">The amount of funds to be sent.</param>
/// <param name="feeType">The type of fee to be included.</param>
/// <param name="allowUnconfirmed">Whether or not we allow this transaction to rely on unconfirmed outputs.</param>
/// <returns></returns>
(string hex, uint256 transactionId, Money fee) BuildTransaction(string walletName, string accountName, CoinType coinType, string password, string destinationAddress, Money amount, string feeType, bool allowUnconfirmed);
/// <summary>
/// Sends a transaction to the network.
/// </summary>
/// <param name="transactionHex">The hex of the transaction.</param>
/// <returns></returns>
bool SendTransaction(string transactionHex);
/// <summary>
/// Processes a block received from the network.
/// </summary>
/// <param name="height">The height of the block in the blockchain.</param>
/// <param name="block">The block.</param>
void ProcessBlock(int height, Block block);
/// <summary>
/// Processes a transaction received from the network.
/// </summary>
/// <param name="transaction">The transaction.</param>
/// <param name="blockHeight">The height of the block this transaction came from. Null if it was not a transaction included in a block.</param>
/// <param name="block">The block in which this transaction was included.</param>
void ProcessTransaction(Transaction transaction, int? blockHeight = null, Block block = null);
/// <summary>
/// Saves the wallet into the file system.
/// </summary>
/// <param name="wallet">The wallet to save.</param>
void SaveToFile(Wallet wallet);
/// <summary>
/// Saves all the loaded wallets into the file system.
/// </summary>
void SaveToFile();
/// <summary>
/// Updates the wallet with the height of the last block synced.
/// </summary>
/// <param name="wallet">The wallet to update.</param>
/// <param name="height">The height of the last block synced.</param>
void UpdateLastBlockSyncedHeight(Wallet wallet, int height);
/// <summary>
/// Updates all the loaded wallets with the height of the last block synced.
/// </summary>
/// <param name="height">The height of the last block synced.</param>
void UpdateLastBlockSyncedHeight(int height);
}
}
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.Text;
using Newtonsoft.Json;
namespace Breeze.Wallet.JsonConverters
{
/// <summary>
/// Converter used to convert <see cref="byte"/> arrays to and from JSON.
/// </summary>
/// <seealso cref="Newtonsoft.Json.JsonConverter" />
public class ByteArrayConverter : JsonConverter
{
/// <inheritdoc />
public override bool CanConvert(Type objectType)
{
return objectType == typeof(byte[]);
}
/// <inheritdoc />
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
return Convert.FromBase64String((string)reader.Value);
}
/// <inheritdoc />
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
writer.WriteValue(Convert.ToBase64String((byte[])value));
}
}
}
using Newtonsoft.Json;
using System;
namespace Breeze.Wallet.JsonConverters
{
/// <summary>
/// Converter used to convert <see cref="DateTimeOffset"/> to and from Unix time.
/// </summary>
/// <seealso cref="Newtonsoft.Json.JsonConverter" />
public class DateTimeOffsetConverter : JsonConverter
{
/// <inheritdoc />
public override bool CanConvert(Type objectType)
{
return objectType == typeof(DateTimeOffset);
}
/// <inheritdoc />
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
return DateTimeOffset.FromUnixTimeSeconds(long.Parse((string)reader.Value));
}
/// <inheritdoc />
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
writer.WriteValue(((DateTimeOffset)value).ToUnixTimeSeconds().ToString());
}
}
}
using System;
using Breeze.Wallet.Helpers;
using NBitcoin;
using Newtonsoft.Json;
namespace Breeze.Wallet.JsonConverters
{
/// <summary>
/// Converter used to convert <see cref="Network"/> to and from JSON.
/// </summary>
/// <seealso cref="Newtonsoft.Json.JsonConverter" />
public class NetworkConverter : JsonConverter
{
/// <inheritdoc />
public override bool CanConvert(Type objectType)
{
return objectType == typeof(Network);
}
/// <inheritdoc />
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
return WalletHelpers.GetNetwork((string)reader.Value);
}
/// <inheritdoc />
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
writer.WriteValue(((Network)value).ToString());
}
}
}
using Stratis.Bitcoin.Builder.Feature; using Stratis.Bitcoin.Builder.Feature;
using Breeze.Wallet.Controllers;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Stratis.Bitcoin.Builder; using Stratis.Bitcoin.Builder;
using Stratis.Bitcoin.Logging; using Stratis.Bitcoin.Logging;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Serilog; using Serilog;
using Stratis.Bitcoin.Wallet;
namespace Breeze.Wallet namespace Breeze.Wallet
{ {
public class WalletFeature : FullNodeFeature public class LightWalletFeature : FullNodeFeature
{ {
private readonly ITracker tracker; private readonly TrackNotifier trackNotifier;
private readonly IWalletManager walletManager;
public WalletFeature(ITracker tracker, IWalletManager walletManager) public LightWalletFeature(TrackNotifier trackNotifier)
{ {
this.tracker = tracker; this.trackNotifier = trackNotifier;
this.walletManager = walletManager; }
}
public override void Start() public override void Start()
{ {
this.tracker.Initialize(); this.trackNotifier.Initialize().GetAwaiter().GetResult();
} }
public override void Stop() public override void Stop()
{ {
this.walletManager.Dispose();
base.Stop(); base.Stop();
} }
} }
public static class WalletFeatureExtension public static class WalletFeatureExtension
{ {
public static IFullNodeBuilder UseWallet(this IFullNodeBuilder fullNodeBuilder) public static IFullNodeBuilder UseLightWallet(this IFullNodeBuilder fullNodeBuilder)
{ {
// use the wallet and on top of that start to notifier
fullNodeBuilder.UseWallet();
fullNodeBuilder.ConfigureFeature(features => fullNodeBuilder.ConfigureFeature(features =>
{ {
features features
.AddFeature<WalletFeature>() .AddFeature<LightWalletFeature>()
.FeatureServices(services => .FeatureServices(services =>
{ {
var loggerFactory = Logs.LoggerFactory; services.AddSingleton<TrackNotifier>();
loggerFactory.AddFile("Logs/Breeze-{Date}.json", isJson: true, minimumLevel:LogLevel.Debug, fileSizeLimitBytes: 10000000);
services.AddSingleton<ITracker, Tracker>();
services.AddSingleton<ILoggerFactory>(loggerFactory);
services.AddSingleton<IWalletManager, WalletManager>();
services.AddSingleton<WalletController>();
}); });
}); });
......
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
namespace Breeze.Wallet.Models
{
public class RequestModel
{
public override string ToString()
{
return JsonConvert.SerializeObject(this, Formatting.Indented);
}
}
/// <summary>
/// Object used to create a new wallet
/// </summary>
public class WalletCreationRequest : RequestModel
{
[Required(ErrorMessage = "A password is required.")]
public string Password { get; set; }
public string Network { get; set; }
public string FolderPath { get; set; }
[Required(ErrorMessage = "The name of the wallet to create is missing.")]
public string Name { get; set; }
}
public class WalletLoadRequest : RequestModel
{
[Required(ErrorMessage = "A password is required.")]
public string Password { get; set; }
public string FolderPath { get; set; }
[Required(ErrorMessage = "The name of the wallet is missing.")]
public string Name { get; set; }
}
public class WalletRecoveryRequest : RequestModel
{
[Required(ErrorMessage = "A mnemonic is required.")]
public string Mnemonic { get; set; }
[Required(ErrorMessage = "A password is required.")]
public string Password { get; set; }
public string FolderPath { get; set; }
[Required(ErrorMessage = "The name of the wallet is missing.")]
public string Name { get; set; }
public string Network { get; set; }
[JsonConverter(typeof(IsoDateTimeConverter))]
public DateTime CreationDate { get; set; }
}
public class WalletHistoryRequest : RequestModel
{
[Required(ErrorMessage = "The name of the wallet is missing.")]
public string WalletName { get; set; }
[Required(ErrorMessage = "The type of coin for which history is requested is missing.")]
public CoinType CoinType { get; set; }
}
public class WalletBalanceRequest : RequestModel
{
[Required(ErrorMessage = "The name of the wallet is missing.")]
public string WalletName { get; set; }
[Required(ErrorMessage = "The type of coin for which history is requested is missing.")]
public CoinType CoinType { get; set; }
}
public class WalletName : RequestModel
{
[Required(ErrorMessage = "The name of the wallet is missing.")]
public string Name { get; set; }
}
public class BuildTransactionRequest : RequestModel
{
[Required(ErrorMessage = "The name of the wallet is missing.")]
public string WalletName { get; set; }
[Required]
public CoinType CoinType { get; set; }
[Required(ErrorMessage = "The name of the account is missing.")]
public string AccountName { get; set; }
[Required(ErrorMessage = "A password is required.")]
public string Password { get; set; }
[Required(ErrorMessage = "A destination address is required.")]
public string DestinationAddress { get; set; }
[Required(ErrorMessage = "An amount is required.")]
public string Amount { get; set; }
[Required(ErrorMessage = "A fee type is required. It can be 'low', 'medium' or 'high'.")]
public string FeeType { get; set; }
public bool AllowUnconfirmed { get; set; }
}
public class SendTransactionRequest : RequestModel
{
[Required(ErrorMessage = "A transaction in hexadecimal format is required.")]
public string Hex { get; set; }
}
public class GetUnusedAddressModel : RequestModel
{
/// <summary>
/// The name of the wallet from which to get the address.
/// </summary>
[Required]
public string WalletName { get; set; }
/// <summary>
/// The type of coin this address is for.
/// </summary>
[Required]
public CoinType CoinType { get; set; }
/// <summary>
/// The name of the account for which to get the address.
/// </summary>
[Required]
public string AccountName { get; set; }
}
public class GetUnusedAccountModel : RequestModel
{
/// <summary>
/// The name of the wallet in which to create the account.
/// </summary>
[Required]
public string WalletName { get; set; }
/// <summary>
/// The type of coin this account contains.
/// </summary>
[Required]
public CoinType CoinType { get; set; }
/// <summary>
/// The password for this wallet.
/// </summary>
[Required]
public string Password { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using NBitcoin;
using Newtonsoft.Json;
namespace Breeze.Wallet.Models
{
public class WalletBalanceModel
{
[JsonProperty(PropertyName = "balances")]
public List<AccountBalance> AccountsBalances { get; set; }
}
public class AccountBalance
{
[JsonProperty(PropertyName = "accountName")]
public string Name { get; set; }
[JsonProperty(PropertyName = "accountHdPath")]
public string HdPath { get; set; }
[JsonProperty(PropertyName = "coinType")]
public CoinType CoinType { get; set; }
[JsonProperty(PropertyName = "amountConfirmed")]
public Money AmountConfirmed { get; set; }
[JsonProperty(PropertyName = "amountUnconfirmed")]
public Money AmountUnconfirmed { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using NBitcoin;
using Newtonsoft.Json;
namespace Breeze.Wallet.Models
{
public class WalletBuildTransactionModel
{
[JsonProperty(PropertyName = "fee")]
public Money Fee { get; set; }
[JsonProperty(PropertyName = "hex")]
public string Hex { get; set; }
[JsonProperty(PropertyName = "transactionId")]
public uint256 TransactionId { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Text;
using Newtonsoft.Json;
namespace Breeze.Wallet.Models
{
public class WalletFileModel
{
[JsonProperty(PropertyName = "walletsPath")]
public string WalletsPath { get; set; }
[JsonProperty(PropertyName = "walletsFiles")]
public IEnumerable<string> WalletsFiles { get; set; }
}
}
using System;
using Breeze.Wallet.JsonConverters;
using NBitcoin;
using Newtonsoft.Json;
namespace Breeze.Wallet.Models
{
public class WalletGeneralInfoModel
{
[JsonProperty(PropertyName = "walletFilePath")]
public string WalletFilePath { get; set; }
[JsonProperty(PropertyName = "network")]
[JsonConverter(typeof(NetworkConverter))]
public Network Network { get; set; }
/// <summary>
/// The time this wallet was created.
/// </summary>
[JsonProperty(PropertyName = "creationTime")]
[JsonConverter(typeof(DateTimeOffsetConverter))]
public DateTimeOffset CreationTime { get; set; }
[JsonProperty(PropertyName = "isDecrypted")]
public bool IsDecrypted { get; set; }
/// <summary>
/// The height of the last block that was synced.
/// </summary>
[JsonProperty(PropertyName = "lastBlockSyncedHeight")]
public int? LastBlockSyncedHeight { get; set; }
/// <summary>
/// The total number of blocks.
/// </summary>
[JsonProperty(PropertyName = "chainTip")]
public int? ChainTip { get; set; }
/// <summary>
/// The total number of nodes that we're connected to.
/// </summary>
[JsonProperty(PropertyName = "connectedNodes")]
public int ConnectedNodes { get; set; }
}
}
using System;
using System.Collections.Generic;
using Breeze.Wallet.JsonConverters;
using NBitcoin;
using NBitcoin.JsonConverters;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
namespace Breeze.Wallet.Models
{
public class WalletHistoryModel
{
[JsonProperty(PropertyName = "transactionsHistory")]
public List<TransactionItemModel> TransactionsHistory { get; set; }
}
public class TransactionItemModel
{
[JsonProperty(PropertyName = "type")]
[JsonConverter(typeof(StringEnumConverter), true)]
public TransactionItemType Type { get; set; }
/// <summary>
/// The Base58 representation of this address.
/// </summary>
[JsonProperty(PropertyName = "toAddress", NullValueHandling = NullValueHandling.Ignore)]
public string ToAddress { get; set; }
[JsonProperty(PropertyName = "id")]
[JsonConverter(typeof(UInt256JsonConverter))]
public uint256 Id { get; set; }
[JsonProperty(PropertyName = "amount")]
public Money Amount { get; set; }
/// <summary>
/// A list of payments made out in this transaction.
/// </summary>
[JsonProperty(PropertyName = "payments", NullValueHandling = NullValueHandling.Ignore)]
public ICollection<PaymentDetailModel> Payments { get; set; }
[JsonProperty(PropertyName = "fee", NullValueHandling = NullValueHandling.Ignore)]
public Money Fee { get; set; }
/// <summary>
/// The height of the block in which this transaction was confirmed.
/// </summary>
[JsonProperty(PropertyName = "confirmedInBlock", NullValueHandling = NullValueHandling.Ignore)]
public int? ConfirmedInBlock { get; set; }
[JsonProperty(PropertyName = "timestamp")]
[JsonConverter(typeof(DateTimeOffsetConverter))]
public DateTimeOffset Timestamp { get; set; }
}
public class PaymentDetailModel
{
/// <summary>
/// The Base58 representation of the destination address.
/// </summary>
[JsonProperty(PropertyName = "destinationAddress")]
public string DestinationAddress { get; set; }
/// <summary>
/// The transaction amount.
/// </summary>
[JsonProperty(PropertyName = "amount")]
[JsonConverter(typeof(MoneyJsonConverter))]
public Money Amount { get; set; }
}
public enum TransactionItemType
{
Received,
Send
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace Breeze.Wallet.Models
{
public class WalletModel
{
[JsonProperty(PropertyName = "network")]
public string Network { get; set; }
[JsonProperty(PropertyName = "fileName")]
public string FileName { get; set; }
[JsonProperty(PropertyName = "addresses")]
public IEnumerable<string> Addresses { get; set; }
}
}
using NBitcoin;
using Stratis.Bitcoin;
namespace Breeze.Wallet.Notifications
{
/// <summary>
/// Observer that receives notifications about the arrival of new <see cref="Block"/>s.
/// </summary>
public class BlockObserver : SignalObserver<Block>
{
private readonly ConcurrentChain chain;
private readonly IWalletManager walletManager;
public BlockObserver(ConcurrentChain chain, IWalletManager walletManager)
{
this.chain = chain;
this.walletManager = walletManager;
}
/// <summary>
/// Manages what happens when a new block is received.
/// </summary>
/// <param name="block">The new block</param>
protected override void OnNextCore(Block block)
{
var hash = block.Header.GetHash();
var height = this.chain.GetBlock(hash).Height;
this.walletManager.ProcessBlock(height, block);
}
}
}
using Stratis.Bitcoin;
using System;
using NBitcoin;
namespace Breeze.Wallet.Notifications
{
/// <summary>
/// Manages the subscription of the block observer to the block signaler.
/// </summary>
public class BlockSubscriber
{
private readonly ISignaler<Block> signaler;
private readonly BlockObserver observer;
public BlockSubscriber(ISignaler<Block> signaler, BlockObserver observer)
{
this.signaler = signaler;
this.observer = observer;
}
/// <summary>
/// Subscribes the block observer to the block signaler.
/// </summary>
/// <returns>An <see cref="IDisposable"/></returns>
public IDisposable Subscribe()
{
return this.signaler.Subscribe(this.observer);
}
}
}
using NBitcoin;
using Stratis.Bitcoin;
namespace Breeze.Wallet.Notifications
{
/// <summary>
/// Observer that receives notifications about the arrival of new <see cref="Transaction"/>s.
/// </summary>
public class TransactionObserver : SignalObserver<Transaction>
{
private readonly IWalletManager walletManager;
public TransactionObserver(IWalletManager walletManager)
{
this.walletManager = walletManager;
}
/// <summary>
/// Manages what happens when a new transaction is received.
/// </summary>
/// <param name="transaction">The new transaction</param>
protected override void OnNextCore(Transaction transaction)
{
this.walletManager.ProcessTransaction(transaction);
}
}
}
using Stratis.Bitcoin;
using System;
using NBitcoin;
namespace Breeze.Wallet.Notifications
{
/// <summary>
/// Manages the subscription of the transaction observer to the transaction signaler.
/// </summary>
public class TransactionSubscriber
{
private readonly ISignaler<Transaction> signaler;
private readonly TransactionObserver observer;
public TransactionSubscriber(ISignaler<Transaction> signaler, TransactionObserver observer)
{
this.signaler = signaler;
this.observer = observer;
}
/// <summary>
/// Subscribes the transaction observer to the transaction signaler.
/// </summary>
/// <returns>An <see cref="IDisposable"/></returns>
public IDisposable Subscribe()
{
return this.signaler.Subscribe(this.observer);
}
}
}
...@@ -6,50 +6,44 @@ using System.Reactive.Linq; ...@@ -6,50 +6,44 @@ using System.Reactive.Linq;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Breeze.Wallet.Notifications;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using NBitcoin; using NBitcoin;
using Stratis.Bitcoin; using Stratis.Bitcoin;
using Stratis.Bitcoin.Notifications; using Stratis.Bitcoin.Notifications;
using Stratis.Bitcoin.Utilities; using Stratis.Bitcoin.Utilities;
using Stratis.Bitcoin.Wallet;
using Stratis.Bitcoin.Wallet.Notifications;
namespace Breeze.Wallet namespace Breeze.Wallet
{ {
public class Tracker : ITracker public class TrackNotifier
{ {
private readonly WalletManager walletManager; private readonly WalletManager walletManager;
private readonly ConcurrentChain chain; private readonly ConcurrentChain chain;
private readonly Signals signals;
private readonly BlockNotification blockNotification; private readonly BlockNotification blockNotification;
private readonly CoinType coinType; private readonly CoinType coinType;
private readonly ILogger logger; private readonly ILogger logger;
public Tracker(ILoggerFactory loggerFactory, IWalletManager walletManager, ConcurrentChain chain, Signals signals, BlockNotification blockNotification, Network network) public TrackNotifier(ILoggerFactory loggerFactory, IWalletManager walletManager,
ConcurrentChain chain, BlockNotification blockNotification, Network network)
{ {
this.walletManager = walletManager as WalletManager; this.walletManager = walletManager as WalletManager;
this.chain = chain; this.chain = chain;
this.signals = signals;
this.blockNotification = blockNotification; this.blockNotification = blockNotification;
this.coinType = (CoinType)network.Consensus.CoinType; this.coinType = (CoinType)network.Consensus.CoinType;
this.logger = loggerFactory.CreateLogger(this.GetType().FullName); this.logger = loggerFactory.CreateLogger(this.GetType().FullName);
} }
/// <inheritdoc /> /// <inheritdoc />
public async Task Initialize() public Task Initialize()
{ {
// get the chain headers. This needs to be up-to-date before we really do anything // get the chain headers. This needs to be up-to-date before we really do anything
await this.WaitForChainDownloadAsync(); //await this.WaitForChainDownloadAsync();
// subscribe to receiving blocks and transactions
BlockSubscriber sub = new BlockSubscriber(this.signals.Blocks, new BlockObserver(this.chain, this.walletManager));
sub.Subscribe();
TransactionSubscriber txSub = new TransactionSubscriber(this.signals.Transactions, new TransactionObserver(this.walletManager));
txSub.Subscribe();
// start syncing blocks // start syncing blocks
var bestHeightForSyncing = this.FindBestHeightForSyncing(); var bestHeightForSyncing = this.FindBestHeightForSyncing();
this.SyncFrom(bestHeightForSyncing); this.SyncFrom(bestHeightForSyncing);
this.logger.LogInformation($"Tracker initialized. Syncing from {bestHeightForSyncing}."); return Task.CompletedTask;
} }
private int FindBestHeightForSyncing() private int FindBestHeightForSyncing()
......
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment