Exemplo n.º 1
0
        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);
        }
Exemplo n.º 2
0
        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;
            }
        }