Commit fe3f4aff authored by Jeremy Bokobza's avatar Jeremy Bokobza

added a method to start receiving blocks

parent c3beda01
using Breeze.TumbleBit.Client;
using NBitcoin;
using Stratis.Bitcoin;
namespace Breeze.TumbleBit
{
/// <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 ITumbleBitManager tumbleBitManager;
public BlockObserver(ConcurrentChain chain, ITumbleBitManager tumbleBitManager)
{
this.chain = chain;
this.tumbleBitManager = tumbleBitManager;
}
/// <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.tumbleBitManager.ProcessBlock(height, block);
}
}
}
......@@ -4,6 +4,7 @@ using System.Net;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Breeze.TumbleBit.Client;
using Breeze.TumbleBit.Models;
using Stratis.Bitcoin.Common.JsonErrors;
namespace Breeze.TumbleBit.Controllers
......@@ -25,8 +26,8 @@ namespace Breeze.TumbleBit.Controllers
/// Connect to a tumbler.
/// </summary>
[Route("connect")]
[HttpGet]
public async Task<IActionResult> ConnectAsync()
[HttpPost]
public async Task<IActionResult> ConnectAsync([FromBody] TumblerConnectionRequest request)
{
// checks the request is valid
if (!this.ModelState.IsValid)
......@@ -37,7 +38,7 @@ namespace Breeze.TumbleBit.Controllers
try
{
var tumblerParameters = await this.tumbleBitManager.ConnectToTumblerAsync();
var tumblerParameters = await this.tumbleBitManager.ConnectToTumblerAsync(request.ServerAddress);
return this.Json(tumblerParameters);
}
catch (Exception e)
......@@ -45,5 +46,30 @@ namespace Breeze.TumbleBit.Controllers
return ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, $"An error occured connecting to the tumbler.", e.ToString());
}
}
/// <summary>
/// Connect to a tumbler.
/// </summary>
[Route("tumble")]
[HttpPost]
public async Task<IActionResult> TumbleAsync([FromBody] TumbleRequest request)
{
// checks the request is valid
if (!this.ModelState.IsValid)
{
var errors = this.ModelState.Values.SelectMany(e => e.Errors.Select(m => m.ErrorMessage));
return ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, "Formatting error", string.Join(Environment.NewLine, errors));
}
try
{
await this.tumbleBitManager.TumbleAsync(request.DestinationWalletName);
return this.Ok();
}
catch (Exception e)
{
return ErrorHelpers.BuildErrorResponse(HttpStatusCode.BadRequest, $"An error occured connecting to the tumbler.", e.ToString());
}
}
}
}
......@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using NBitcoin;
using NTumbleBit.ClassicTumbler;
namespace Breeze.TumbleBit.Client
......@@ -14,7 +15,17 @@ namespace Breeze.TumbleBit.Client
/// <summary>
/// Connects to the tumbler.
/// </summary>
/// <param name="serverAddress">The URI of the tumbler.</param>
/// <returns></returns>
Task<ClassicTumblerParameters> ConnectToTumblerAsync();
Task<ClassicTumblerParameters> ConnectToTumblerAsync(Uri serverAddress);
Task TumbleAsync(string destinationWalletName);
/// <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);
}
}
......@@ -25,4 +25,10 @@ namespace Breeze.TumbleBit.Models
public string Network { get; set; }
}
public class TumbleRequest
{
[Required(ErrorMessage = "A wallet name is required.")]
public string DestinationWalletName { get; set; }
}
}
......@@ -35,7 +35,7 @@ namespace Breeze.TumbleBit
.AddFeature<TumbleBitFeature>()
.FeatureServices(services =>
{
services.AddSingleton<ITumbleBitManager>(new TumbleBitManager(serverAddress));
services.AddSingleton<ITumbleBitManager, TumbleBitManager> ();
services.AddSingleton<TumbleBitController>();
});
});
......
using System;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using NBitcoin;
using NTumbleBit.ClassicTumbler;
using Stratis.Bitcoin;
using Stratis.Bitcoin.Logging;
using Stratis.Bitcoin.Wallet;
namespace Breeze.TumbleBit.Client
{
/// <summary>
/// An implementation of a tumbler manager.
/// </summary>
/// <seealso cref="Breeze.TumbleBit.Client.ITumbleBitManager" />
public class TumbleBitManager : ITumbleBitManager
{
private ITumblerService tumblerService;
private IWalletManager walletManager;
private readonly ILogger logger;
private readonly Signals signals;
private readonly ConcurrentChain chain;
private ClassicTumblerParameters TumblerParameters { get; set; }
public TumbleBitManager(ILoggerFactory loggerFactory, IWalletManager walletManager, ConcurrentChain chain, Network network, Signals signals)
{
this.walletManager = walletManager;
this.chain = chain;
this.signals = signals;
this.logger = loggerFactory.CreateLogger(this.GetType().FullName);
}
/// <inheritdoc />
public async Task<ClassicTumblerParameters> ConnectToTumblerAsync(Uri serverAddress)
{
this.tumblerService = new TumblerService(serverAddress);
this.TumblerParameters = await this.tumblerService.GetClassicTumblerParametersAsync();
return this.TumblerParameters;
}
/// <inheritdoc />
public Task TumbleAsync(string destinationWalletName)
{
if (this.TumblerParameters == null || this.tumblerService == null)
{
throw new Exception("Please connect to the tumbler first.");
}
Wallet destinationWallet = this.walletManager.GetWallet(destinationWalletName);
if (destinationWallet == null)
{
throw new Exception($"Destination not found. Have you created a wallet with name {destinationWalletName}?");
}
// subscribe to receiving blocks and transactions
this.signals.Blocks.Subscribe(new BlockObserver(this.chain, this));
return Task.CompletedTask;
}
/// <inheritdoc />
public void ProcessBlock(int height, Block block)
{
// TODO start the state machine
this.logger.LogDebug($"Receive block with height {height}");
}
}
}
using System;
using System.Threading.Tasks;
using NTumbleBit.ClassicTumbler;
namespace Breeze.TumbleBit.Client
{
/// <summary>
/// An implementation of a tumbler manager.
/// </summary>
/// <seealso cref="Breeze.TumbleBit.Client.ITumbleBitManager" />
public class TumbleBitManager : ITumbleBitManager
{
private ITumblerService tumblerService;
public TumbleBitManager(Uri serverAddress)
{
this.InitializeTumblerService(serverAddress);
}
/// <summary>
/// Initializes the tumbler service.
/// </summary>
/// <param name="serverAddress">The server address.</param>
public void InitializeTumblerService(Uri serverAddress)
{
this.tumblerService = new TumblerService(serverAddress);
}
/// <inheritdoc />
public async Task<ClassicTumblerParameters> ConnectToTumblerAsync()
{
return await this.tumblerService.GetClassicTumblerParametersAsync();
}
}
}
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