Skip to content

Commit

Permalink
Merge pull request #121 from pingpongsneak/master
Browse files Browse the repository at this point in the history
RC2
  • Loading branch information
pingpongsneak committed Oct 26, 2022
2 parents 714a9dc + ffe9b17 commit 9057f2a
Show file tree
Hide file tree
Showing 22 changed files with 370 additions and 234 deletions.
2 changes: 2 additions & 0 deletions core/Controllers/MembershipController.cs
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
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
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
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
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
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
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
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
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
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

0 comments on commit 9057f2a

Please sign in to comment.