public static void Handle( SecretShareMessage message, Replica replica, string replicaSecretShare, Dictionary<int, uint> childSecretHashes, Dictionary<int, CancellationTokenSource> secretShareMessageTokenSources, ConcurrentDictionary<int, string> verifiedChildrenSecretShares) { var childReplicaId = message.ReplicaId; var childReplicaSecretShare = message.ReplicaSecretShares[message.ReplicaId]; secretShareMessageTokenSources[childReplicaId].Cancel(); secretShareMessageTokenSources.Remove(childReplicaId); if (Crypto.GetHash(childReplicaSecretShare) != childSecretHashes[childReplicaId]) { replica.ParentReplica.SendMessage( new SuspectMessage { ReplicaId = childReplicaId }); } foreach (var childSecretShare in message.ReplicaSecretShares) { if (verifiedChildrenSecretShares.TryAdd(childSecretShare.Key, childSecretShare.Value) == false) { throw new InvalidOperationException($"The child secret share for replica #{childSecretShare.Key} has already been delivered."); } } if (replica.ChildReplicas.All(chr => verifiedChildrenSecretShares.ContainsKey(chr.Id)) == false) { return; } verifiedChildrenSecretShares.TryAdd(replica.Id, replicaSecretShare); // we send a message with a secret share to the parent replica Network.EmulateLatency(); replica.ParentReplica.SendMessage( new SecretShareMessage { ReplicaId = replica.Id, ReplicaSecretShares = verifiedChildrenSecretShares.ToDictionary(kv => kv.Key, kv => kv.Value) }); Log(replica, "Send a secret share to the parent replica (ParentReplicaId: {0})", replica.ParentReplica.Id); }
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; } }