public void Run(PrimaryReplica primaryReplica, CancellationToken cancellationToken) { // process transactions // process messages Task.Factory.StartNew(async() => { Log("Running..."); while (cancellationToken.IsCancellationRequested == false) { var transaction = GenerateTransaction(); // Log($"The transaction #{transaction} was generated."); // a new transaction was generated -> send this to primary replica primaryReplica.SendTransaction(transaction); // Log($"The transaction #{transaction} was sent to the primary replica."); await Task.Delay(10); } Log("Stopped."); }, cancellationToken, TaskCreationOptions.LongRunning, TaskScheduler.Default); }
private static void RunClients(PrimaryReplica primaryReplica, CancellationToken cancellationToken) { var clients = Enumerable.Range(0, ClientsCount) .Select(cid => new Client(cid)) .ToArray(); foreach (var client in clients) { client.Run(primaryReplica, cancellationToken); } }
private static PrimaryReplica RunReplicas(CancellationToken cancellationToken) { var rnd = new Random(Environment.TickCount); var replicaIds = Enumerable.Range(0, ActiveReplicasCount + PassiveReplicasCount + FaultyReplicasCount).ToArray(); var workingReplicaIds = replicaIds //.OrderBy(r => rnd.Next(replicaIds.Length)) .Take(ActiveReplicasCount + PassiveReplicasCount) .ToArray(); var faultyReplicaIds = replicaIds .Except(workingReplicaIds) .ToArray(); var activeReplicaIds = workingReplicaIds .Take(ActiveReplicasCount) .ToArray(); var passiveReplicaIds = workingReplicaIds .Except(activeReplicaIds) .ToArray(); var primaryReplicaId = activeReplicaIds.First(); var primaryReplica = new PrimaryReplica(primaryReplicaId); var secondaryReplicas = activeReplicaIds .Where(rid => rid != primaryReplicaId) .Select(rid => new Replica(rid, true) { PrimaryReplica = primaryReplica }) .ToArray(); foreach (var secondaryReplica in secondaryReplicas) { secondaryReplica.Run(secondaryReplicas, cancellationToken); } primaryReplica.Run(secondaryReplicas, cancellationToken); return(primaryReplica); }
public static void Handle( TransactionMessage message, PrimaryReplica primaryReplica, ref ConcurrentBag <int> block, ConcurrentQueue <int[]> blockExchange) { var transaction = message.Transaction; block.Add(transaction); var now = DateTime.Now; if (block.Count >= MinTransactionsCountInBlock) { var blockCopy = block.ToArray(); block = new ConcurrentBag <int>(); // publish block to start working on consensus blockExchange.Enqueue(blockCopy); Log(primaryReplica, $"New block arrived for consensus (TransactionCounts: {blockCopy.Length})."); } }
public static void Handle( SecretShareMessage message, PrimaryReplica primaryReplica, IEnumerable <ReplicaBase> activeRelicas, int[] block, ICollection <int[]> blockchain, ref bool isCommitted, ref bool hasConsensus, byte[] signedSecretHashAndCounterViewNumber, ConcurrentDictionary <int, string> verifiedChildShareSecrets) { var childReplicaId = message.ReplicaId; var childrenSecretShares = message.ReplicaSecretShares; Log(primaryReplica, "ChildReplicaId: {0}, ChildrenSecretShare: [{1}]", childReplicaId, string.Join(",", childrenSecretShares.Select(ridssh => $"{{{ridssh.Key}:{ridssh.Value}}}"))); foreach (var childReplicaShare in childrenSecretShares) { // TODO: hashes of primary children should be checked as well verifiedChildShareSecrets.TryAdd(childReplicaShare.Key, childReplicaShare.Value); } if (verifiedChildShareSecrets.Keys.OrderBy(_ => _) .SequenceEqual(activeRelicas.Select(r => r.Id).OrderBy(_ => _)) == false) { return; } var verifiedSecretShares = verifiedChildShareSecrets .Select(x => new { ReplicaId = x.Key, SecretShare = x.Value }) .OrderBy(x => x.ReplicaId) .Select(x => x.SecretShare) .ToList(); var secret = string.Join(string.Empty, verifiedSecretShares); uint secretHash; uint counter; uint viewNumber; primaryReplica.Tee.GetHashAndCounterViewNumber( primaryReplica.PublicKey, signedSecretHashAndCounterViewNumber, out secretHash, out counter, out viewNumber); if (Crypto.GetHash(secret + counter + viewNumber) != secretHash) { Log(primaryReplica, "Send RequestViewChangeMessage to all active replicas."); throw new InvalidOperationException("Invalid secret hash."); } if (!isCommitted) { verifiedChildShareSecrets.Clear(); Thread.Sleep(rnd.Next(MinTimeToAddBlockIntoBlockchain, MaxTimeToAddBlockIntoBlockchain)); blockchain.Add(block); var request = string.Join(string.Empty, block); var commitResult = blockchain.Count; var commitResultHash = Crypto.GetHash(request) | (uint)commitResult; var signedCommitResultHashCounterViewNumber = primaryReplica.Tee.RequestCounter(commitResultHash); Log(primaryReplica, "Broadcast a committed block."); // the block was added on primary replica to blockchain -> we need to sync this across replicas Network.EmulateLatency(); foreach (var activeRelica in activeRelicas) { activeRelica.SendMessage(new CommitMessage { Secret = secret, CommitResult = commitResult, CommitResultHashCounterViewNumber = signedCommitResultHashCounterViewNumber }); } isCommitted = true; } else { hasConsensus = true; } }