Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RC2 #121

Merged
merged 7 commits into from
Oct 26, 2022
Merged

RC2 #121

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions core/Controllers/MembershipController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ public async Task<IActionResult> GetPeerAsync()
HttpsPort = peer.HttpsPort.FromBytes(),
TcpPort = peer.TcpPort.FromBytes(),
WsPort = peer.WsPort.FromBytes(),
DsPort = peer.DsPort.FromBytes(),
Name = peer.Name.FromBytes(),
PublicKey = peer.PublicKey.ByteToHex(),
Version = peer.Version.FromBytes()
Expand Down Expand Up @@ -81,6 +82,7 @@ public async Task<IActionResult> GetPeersAsync()
HttpsPort = peer.HttpsPort.FromBytes(),
TcpPort = peer.TcpPort.FromBytes(),
WsPort = peer.WsPort.FromBytes(),
DsPort = peer.DsPort.FromBytes(),
Name = peer.Name.FromBytes(),
PublicKey = peer.PublicKey.ByteToHex(),
Version = peer.Version.FromBytes()
Expand Down
44 changes: 33 additions & 11 deletions core/Cryptography/Crypto.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@ public interface ICrypto
Task<Models.KeyPair> GetOrUpsertKeyNameAsync(string keyName);
Task<byte[]> GetPublicKeyAsync(string keyName);
Task<SignatureResponse> SignAsync(string keyName, byte[] message);
byte[] Sign(byte[] privateKey, byte[] message);
bool VerifySignature(byte[] signature, byte[] message);
bool VerifySignature(VerifySignatureManualRequest verifySignatureManualRequest);
bool VerifySignature(byte[] publicKey, byte[] message, byte[] signature);
byte[] GetCalculateVrfSignature(ECPrivateKey ecPrivateKey, byte[] msg);
byte[] GetVerifyVrfSignature(ECPublicKey ecPublicKey, byte[] msg, byte[] sig);
// byte[] EncryptChaCha20Poly1305(byte[] data, byte[] key, byte[] associatedData, out byte[] tag, out byte[] nonce);
Expand Down Expand Up @@ -131,6 +132,28 @@ public async Task<SignatureResponse> SignAsync(string keyName, byte[] message)
return signatureResponse;
}

/// <summary>
///
/// </summary>
/// <param name="privateKey"></param>
/// <param name="message"></param>
/// <returns></returns>
public byte[] Sign(byte[] privateKey, byte[] message)
{
Guard.Argument(privateKey, nameof(privateKey)).NotNull();
Guard.Argument(message, nameof(message)).NotNull();
try
{
return Curve.calculateSignature(Curve.decodePrivatePoint(privateKey), message);
}
catch (Exception ex)
{
_logger.Here().Error(ex, "Unable to sign the message");
}

return null;
}

/// <summary>
/// </summary>
/// <param name="signature"></param>
Expand All @@ -155,22 +178,21 @@ public bool VerifySignature(byte[] signature, byte[] message)
}

/// <summary>
///
/// </summary>
/// <param name="verifySignatureManualRequest"></param>
/// <param name="publicKey"></param>
/// <param name="message"></param>
/// <param name="signature"></param>
/// <returns></returns>
public bool VerifySignature(VerifySignatureManualRequest verifySignatureManualRequest)
public bool VerifySignature(byte[] publicKey, byte[] message, byte[] signature)
{
Guard.Argument(verifySignatureManualRequest, nameof(verifySignatureManualRequest)).NotNull();
Guard.Argument(verifySignatureManualRequest.Signature, nameof(verifySignatureManualRequest.Signature))
.NotNull();
Guard.Argument(verifySignatureManualRequest.PublicKey, nameof(verifySignatureManualRequest.PublicKey))
.NotNull();
Guard.Argument(verifySignatureManualRequest.Message, nameof(verifySignatureManualRequest.Message)).NotNull();
Guard.Argument(publicKey, nameof(publicKey)).NotNull();
Guard.Argument(message, nameof(message)).NotNull();
Guard.Argument(signature, nameof(signature)).NotNull();
var verified = false;
try
{
verified = Curve.verifySignature(Curve.decodePoint(verifySignatureManualRequest.PublicKey, 0),
verifySignatureManualRequest.Message, verifySignatureManualRequest.Signature);
verified = Curve.verifySignature(Curve.decodePoint(publicKey, 0), message, signature);
}
catch (Exception ex)
{
Expand Down
5 changes: 1 addition & 4 deletions core/Extensions/AppExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ public static ContainerBuilder AddCypherSystemCore(this ContainerBuilder builder
builder.Register(c =>
{
var remoteNodes = configuration.GetSection("Node:Network:SeedList").GetChildren().ToArray();
var remotePublicKeys = configuration.GetSection("Node:Network:SeedListPublicKeys").GetChildren().ToArray();
var node = new Node
{
EndPoint = new IPEndPoint(Util.GetIpAddress(), 0),
Expand All @@ -67,11 +66,11 @@ public static ContainerBuilder AddCypherSystemCore(this ContainerBuilder builder
P2P =
new P2P
{
DsPort = Convert.ToInt32(configuration["Node:Network:P2P:DsPort"]),
TcpPort = Convert.ToInt32(configuration["Node:Network:P2P:TcpPort"]),
WsPort = Convert.ToInt32(configuration["Node:Network:P2P:WsPort"])
},
SeedList = new List<string>(remoteNodes.Length),
SeedListPublicKeys = new List<string>(remoteNodes.Length),
X509Certificate =
new Models.X509Certificate
{
Expand Down Expand Up @@ -106,9 +105,7 @@ public static ContainerBuilder AddCypherSystemCore(this ContainerBuilder builder
{
var endpoint = Util.GetIpEndPoint(selection.item.Value);
var endpointFromHost = Util.GetIpEndpointFromHostPort(endpoint.Address.ToString(), endpoint.Port);
var publicKey = remotePublicKeys[selection.index].Value;
node.Network.SeedList.Add($"{endpointFromHost.Address.ToString()}:{endpointFromHost.Port}");
node.Network.SeedListPublicKeys.Add(publicKey);
}

var cypherSystemCore = new CypherSystemCore(c.Resolve<IHostApplicationLifetime>(),
Expand Down
4 changes: 2 additions & 2 deletions core/Ledger/Graph.cs
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ public async Task<SafeguardBlocksResponse> GetSafeguardBlocksAsync(SafeguardBloc
try
{
var hashChainRepository = _cypherSystemCore.UnitOfWork().HashChainRepository;
var height = hashChainRepository.Height == 0 ? 0 : hashChainRepository.Height - (ulong)safeguardBlocksRequest.NumberOfBlocks;
var height = hashChainRepository.Height <= (ulong)safeguardBlocksRequest.NumberOfBlocks ? hashChainRepository.Height : hashChainRepository.Height - (ulong)safeguardBlocksRequest.NumberOfBlocks;
var blocks = await hashChainRepository.OrderByRangeAsync(x => x.Height, (int)height,
safeguardBlocksRequest.NumberOfBlocks);
if (blocks.Any()) return new SafeguardBlocksResponse(blocks, string.Empty);
Expand Down Expand Up @@ -474,7 +474,7 @@ private bool Save(BlockGraph blockGraph)
Guard.Argument(blockGraph, nameof(blockGraph)).NotNull();
try
{
if (_cypherSystemCore.Validator().VerifyBlockGraphSignatureNodeRound(blockGraph).Result != VerifyResult.Succeed)
if (_cypherSystemCore.Validator().VerifyBlockGraphSignatureNodeRound(blockGraph) != VerifyResult.Succeed)
{
_logger.Error("Unable to verify block for {@Node} and round {@Round}", blockGraph.Block.Node,
blockGraph.Block.Round);
Expand Down
66 changes: 32 additions & 34 deletions core/Ledger/Sync.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
using CypherNetwork.Models.Messages;
using CypherNetwork.Network;
using Dawn;
using libsignal.util;
using MessagePack;
using Serilog;
using Spectre.Console;
Expand All @@ -38,6 +39,8 @@ public class Sync : ISync, IDisposable
private bool _disposed;
private int _running;

private static readonly object LockOnSync = new();

/// <summary>
/// </summary>
/// <param name="cypherSystemCore"></param>
Expand Down Expand Up @@ -93,20 +96,25 @@ private async Task SynchronizeAsync()
currentRetry++;
}

foreach (var peer in _cypherSystemCore.PeerDiscovery().GetDiscoveryStore())
var peers = _cypherSystemCore.PeerDiscovery().GetDiscoveryStore().Where(x => x.BlockCount > blockCount).ToArray();
if (peers.Any() != true) return;
peers.Shuffle();
var maxBlockHeight = peers.Max(x => (long)x.BlockCount);
var chunk = maxBlockHeight / peers.Length;
_logger.Information("Peer count [{@PeerCount}]", peers.Length);
_logger.Information("Network block height [{@MaxBlockHeight}]", maxBlockHeight);
foreach (var peer in peers)
{
if (blockCount < peer.BlockCount)
var skip = blockCount <= 6 ? blockCount : blockCount - 6; // +- Depth of blocks to compare.
var take = (int)((int)blockCount + chunk);
if (take > (int)maxBlockHeight)
{
var skip = blockCount == 0 ? 0 : blockCount - 6; // +- Depth of blocks to compare.
var synchronized = await SynchronizeAsync(peer, (ulong)skip, (int)peer.BlockCount);
if (!synchronized) continue;
_logger.Information(
"Successfully SYNCHRONIZED with node:{@NodeName} host:{@Host} version:{@Version}",
peer.Name.FromBytes(), peer.IpAddress.FromBytes(), peer.Version.FromBytes());
break;
take = (int)(maxBlockHeight - (long)blockCount) + (int)blockCount;
}

SynchronizeAsync(peer, skip, take).Wait();
blockCount = _cypherSystemCore.UnitOfWork().HashChainRepository.Count;
_logger.Information("Local block height ({@LocalHeight})", blockCount);
if (blockCount == (ulong)maxBlockHeight) break;
}
}
catch (Exception ex)
Expand Down Expand Up @@ -150,7 +158,7 @@ private async Task<bool> WaitForPeersAsync(int currentRetry, int retryCount)
/// <param name="skip"></param>
/// <param name="take"></param>
/// <returns></returns>
private async Task<bool> SynchronizeAsync(Peer peer, ulong skip, int take)
private async Task SynchronizeAsync(Peer peer, ulong skip, int take)
{
Guard.Argument(peer, nameof(peer)).HasValue();
Guard.Argument(skip, nameof(skip)).NotNegative();
Expand All @@ -160,15 +168,15 @@ private async Task<bool> SynchronizeAsync(Peer peer, ulong skip, int take)
{
var validator = _cypherSystemCore.Validator();
var blocks = await FetchBlocksAsync(peer, skip, take);
if (blocks?.Any() != true) return false;
if (blocks?.Any() != true) return;
if (skip == 0)
{
_logger.Warning("FIRST TIME BOOTSTRAPPING");
}
else
{
_logger.Information("CONTINUE BOOTSTRAPPING");
_logger.Information("CHECKING [BLOCK HEIGHTS]");
_logger.Information("CHECKING [BLOCK DUPLICATES]");
var verifyNoDuplicateBlockHeights = validator.VerifyNoDuplicateBlockHeights(blocks);
if (verifyNoDuplicateBlockHeights == VerifyResult.AlreadyExists)
{
Expand All @@ -179,26 +187,26 @@ private async Task<bool> SynchronizeAsync(Peer peer, ulong skip, int take)
ClientId = peer.ClientId,
PeerState = PeerState.DupBlocks
});
_logger.Warning("Duplicate block heights [UNABLE TO VERIFY]");
return false;
_logger.Warning("DUPLICATE block height [UNABLE TO VERIFY]");
return;
}

_logger.Information("CHECKING [FORK RULE]");
var forkRuleBlocks = await validator.VerifyForkRuleAsync(blocks.OrderBy(x => x.Height).ToArray());
if (forkRuleBlocks.Length == 0)
{
_logger.Fatal("Fork rule check [UNABLE TO VERIFY]");
return false;
_logger.Fatal("FORK RULE CHECK [UNABLE TO VERIFY]");
return;
}

blocks = forkRuleBlocks.ToList();
_logger.Information("Fork rule check [OK]");
_logger.Information("FORK RULE CHECK [OK]");
}

await AnsiConsole.Progress().AutoClear(false).Columns(new TaskDescriptionColumn(), new ProgressBarColumn(),
new PercentageColumn(), new SpinnerColumn()).StartAsync(async ctx =>
{
var warpTask = ctx.AddTask($"SYNCHRONIZING [bold yellow]{blocks.Count}[/] Block(s)", false).IsIndeterminate();
var warpTask = ctx.AddTask($"[bold green]SYNCHRONIZING[/] [bold yellow]{blocks.Count}[/] Block(s)", false).IsIndeterminate();
warpTask.MaxValue(blocks.Count);
warpTask.StartTask();
warpTask.IsIndeterminate(false);
Expand Down Expand Up @@ -236,16 +244,7 @@ private async Task<bool> SynchronizeAsync(Peer peer, ulong skip, int take)
catch (Exception ex)
{
_logger.Here().Error(ex, "SYNCHRONIZATION [FAILED]");
return false;
}
finally
{
var blockCount = _cypherSystemCore.UnitOfWork().HashChainRepository.Count;
_logger.Information("Local node block height set to ({@LocalHeight})", blockCount);
if (blockCount == (ulong)take) isSynchronized = true;
}

return isSynchronized;
}

/// <summary>
Expand All @@ -259,23 +258,22 @@ private async Task<IReadOnlyList<Block>> FetchBlocksAsync(Peer peer, ulong skip,
Guard.Argument(peer, nameof(peer)).HasValue();
Guard.Argument(skip, nameof(skip)).NotNegative();
Guard.Argument(take, nameof(take)).NotNegative();
_logger.Information("Synchronizing with {@Host} ({@Skip})/({@Take})", peer.IpAddress.FromBytes(), skip, take);
var iSkip = skip;
try
{
_logger.Information("Fetching [{@Range}] block(s)", Math.Abs(take - (int)skip));
const int maxBlocks = 10;
var chunks = Enumerable.Repeat(maxBlocks, take / maxBlocks).ToList();
if (take % maxBlocks != 0) chunks.Add(take % maxBlocks);
var iTake = take - (int)skip;
var chunks = Enumerable.Repeat(maxBlocks, iTake / maxBlocks).ToList();
if (iTake % maxBlocks != 0) chunks.Add(iTake % maxBlocks);

// Show progress
var blocks = await AnsiConsole.Progress().AutoClear(false).Columns(new TaskDescriptionColumn(),
new ProgressBarColumn(), new PercentageColumn(), new SpinnerColumn())
.StartAsync(async ctx =>
{
var blocks = new List<Block>();
var warpTask = ctx.AddTask("DOWNLOADING", false).IsIndeterminate();
warpTask.MaxValue(chunks.Count);
var warpTask = ctx.AddTask($"[bold green]DOWNLOADING[/] [bold yellow]{Math.Abs(take - (int)skip)}[/] block(s) from [bold yellow]{peer.Name.FromBytes()}[/] v{peer.Version.FromBytes()}", false).IsIndeterminate();
warpTask.MaxValue(take - (int)skip);
warpTask.StartTask();
warpTask.IsIndeterminate(false);
while (!ctx.IsFinished)
Expand Down
10 changes: 4 additions & 6 deletions core/Ledger/Validator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ namespace CypherNetwork.Ledger;
/// </summary>
public interface IValidator
{
Task<VerifyResult> VerifyBlockGraphSignatureNodeRound(BlockGraph blockGraph);
VerifyResult VerifyBlockGraphSignatureNodeRound(BlockGraph blockGraph);
VerifyResult VerifyBulletProof(Transaction transaction);
VerifyResult VerifyCoinbaseTransaction(Vout coinbase, ulong solution, decimal runningDistribution, ulong height);
VerifyResult VerifySolution(byte[] vrfBytes, byte[] kernel, ulong solution);
Expand Down Expand Up @@ -88,15 +88,14 @@ public Validator(ICypherSystemCore cypherSystemCore, ILogger logger)
public async Task<VerifyResult> VerifyBlockHashAsync(Block block)
{
Guard.Argument(block, nameof(block)).NotNull();
using var hasher = Hasher.New();
var hashChainRepository = _cypherSystemCore.UnitOfWork().HashChainRepository;
var prevBlock = await hashChainRepository.GetAsync(x => new ValueTask<bool>(x.Height == hashChainRepository.Height));
if (prevBlock is null)
{
_logger.Here().Error("No previous block available");
return VerifyResult.UnableToVerify;
}

using var hasher = Hasher.New();
hasher.Update(prevBlock.Hash);
hasher.Update(block.ToHash());
var hash = hasher.Finalize();
Expand Down Expand Up @@ -129,14 +128,13 @@ public async Task<VerifyResult> VerifyMerkleAsync(Block block)
/// </summary>
/// <param name="blockGraph"></param>
/// <returns></returns>
public async Task<VerifyResult> VerifyBlockGraphSignatureNodeRound(BlockGraph blockGraph)
public VerifyResult VerifyBlockGraphSignatureNodeRound(BlockGraph blockGraph)
{
Guard.Argument(blockGraph, nameof(blockGraph)).NotNull();
try
{
if (!_cypherSystemCore.Crypto()
.VerifySignature(new VerifySignatureManualRequest(blockGraph.Signature, blockGraph.PublicKey,
blockGraph.ToHash())))
.VerifySignature(blockGraph.PublicKey, blockGraph.ToHash(), blockGraph.Signature))
{
_logger.Error("Unable to verify the signature for block {@Round} from node {@Node}",
blockGraph.Block.Round, blockGraph.Block.Node);
Expand Down
1 change: 1 addition & 0 deletions core/Models/LocalNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public record LocalNode
public byte[] Name { get; init; }
public byte[] TcpPort { get; init; }
public byte[] WsPort { get; init; }
public byte[] DsPort { get; init; }
public byte[] HttpPort { get; init; }
public byte[] HttpsPort { get; init; }
public byte[] IpAddress { get; init; }
Expand Down
1 change: 0 additions & 1 deletion core/Models/Messages/ProtocolCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ public enum ProtocolCommand : byte
Version = 0x01,
GetPeer = 0x10,
GetPeers = 0x11,
UpdatePeers = 0x12,
GetBlocks = 0x14,
SaveBlock = 0x15,
GetBlockHeight = 0x17,
Expand Down
2 changes: 1 addition & 1 deletion core/Models/NetworkSetting.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,12 @@ public record Network
public int HttpsPort { get; set; }
public P2P P2P { get; set; }
public IList<string> SeedList { get; set; }
public IList<string> SeedListPublicKeys { get; set; }
public string CertificateMode { get; set; }
}

public record P2P
{
public int DsPort { get; set; }
public int TcpPort { get; set; }
public int WsPort { get; set; }
}
Expand Down
14 changes: 8 additions & 6 deletions core/Models/Peer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,16 @@ public struct Peer : IComparable<Peer>
[Key(3)] public ulong BlockCount { get; set; }
[Key(4)] public ulong ClientId { get; init; }
[Key(5)] public byte[] TcpPort { get; set; }
[Key(6)] public byte[] WsPort { get; set; }
[Key(7)] public byte[] Name { get; set; }
[Key(8)] public byte[] PublicKey { get; set; }
[Key(9)] public byte[] Version { get; set; }
[Key(6)] public byte[] DsPort { get; set; }
[Key(7)] public byte[] WsPort { get; set; }
[Key(8)] public byte[] Name { get; set; }
[Key(9)] public byte[] PublicKey { get; set; }
[Key(10)] public byte[] Signature { get; set; }
[Key(11)] public byte[] Version { get; set; }
[Key(12)] public long Timestamp { get; set; }
[IgnoreMember] public int Retries { get; set; }

/// <summary>
/// </summary>
/// </summary>s
/// <param name="other"></param>
/// <returns></returns>
public int CompareTo(Peer other)
Expand Down