예제 #1
0
 private void CheckEncryption()
 {
     if (_rawShare == null)
     {
         return;
     }
     if (_encryptedShare != null)
     {
         return;
     }
     _encryptedShare = Wallet.TpkePublicKey.Encrypt(_rawShare);
     Broadcaster.InternalRequest(
         new ProtocolRequest <CommonSubsetId, EncryptedShare>(Id, new CommonSubsetId(_honeyBadgerId),
                                                              _encryptedShare));
 }
예제 #2
0
        private void HandleInputMessage(ProtocolRequest <CommonSubsetId, EncryptedShare> request)
        {
            _requested = ResultStatus.Requested;
            Broadcaster.InternalRequest(new ProtocolRequest <ReliableBroadcastId, EncryptedShare?>
                                            (Id, new ReliableBroadcastId(GetMyId(), (int)_commonSubsetId.Era), request.Input));

            for (var j = 0; j < N; ++j)
            {
                if (j != GetMyId())
                {
                    Broadcaster.InternalRequest(new ProtocolRequest <ReliableBroadcastId, EncryptedShare?>(Id,
                                                                                                           new ReliableBroadcastId(j, (int)_commonSubsetId.Era), null));
                }
            }

            CheckResult();
        }
예제 #3
0
        private void TryProgressEpoch()
        {
            CheckResult();
            while (_result == null || !_wasRepeat)
            {
                if (_currentEpoch % 2 == 0)
                {
                    // epoch mod 2 = 0 -> we have not yet initiated BB
                    if (_currentEpoch != 0 && !_coins.ContainsKey(_currentEpoch - 1))
                    {
                        /*    Logger.LogTrace(
                         *      $"{_agreementId}: can't progress epoch, blocked, coin (Ep={_currentEpoch - 1}) not present"); */
                        return; // we cannot progress since coin is not tossed and estimate is not correct
                    }

                    /*    Logger.LogTrace(
                     *      $"Epoch progressed, coin (Ep={_currentEpoch - 1}) is present " +
                     *      $"with value {_currentEpoch > 0 && _coins[_currentEpoch - 1]}"
                     *  ); */
                    // we have right to calculate new estimate and proceed
                    if (_currentEpoch != 0)
                    {
                        var s = _coins[_currentEpoch - 1];
                        _estimate = _currentValues.Values().First();

                        if (_currentValues.Count() == 1 && _result == null)
                        {
                            if (_estimate == s)
                            {
                                // we are winners!
                                _resultEpoch = _currentEpoch;
                                _result      = _estimate;
                                CheckResult();
                                Logger.LogTrace($"{_agreementId}: result = {_result} achieved at Ep={_currentEpoch}");
                            }
                        }
                        else if (_result == s)
                        {
                            if (_currentEpoch > _resultEpoch)
                            {
                                Logger.LogTrace(
                                    $"{_agreementId}: value repeated at Ep={_currentEpoch}, result is already obtained: {_result}. Terminating protocol"
                                    );
                                _wasRepeat = true;
                                Terminate();
                            }
                        }
                        else
                        {
                            _estimate = s;
                        }
                    }

                    if (_result != null)
                    {
                        _estimate = _result.Value;
                    }

                    // here we start new BB assuming that current estimate is correct
                    var broadcastId = new BinaryBroadcastId(_agreementId.Era, _agreementId.AssociatedValidatorId,
                                                            _currentEpoch);
                    Broadcaster.InternalRequest(
                        new ProtocolRequest <BinaryBroadcastId, bool>(Id, broadcastId, _estimate)
                        );
                    _currentEpoch += 1;
                }
                else
                {
                    // epoch mod 2 = 1 -> we have not yet tossed coin
                    if (!_binaryBroadcastsResults.ContainsKey(_currentEpoch - 1))
                    {
                        /*    Logger.LogTrace(
                         *      $"{_agreementId}: can't progress epoch, blocked, BB (Ep={_currentEpoch - 1}) not present"
                         *  ); */
                        return; // we cannot progress since BB is not completed
                    }

                    //    Logger.LogTrace($"{_agreementId}: epoch progressed, BB (Ep={_currentEpoch - 1}) is present");

                    _currentValues = _binaryBroadcastsResults[_currentEpoch - 1];
                    var coinId = new CoinId(_agreementId.Era, _agreementId.AssociatedValidatorId, _currentEpoch);
                    if ((_currentEpoch / 2) % 3 == 2)
                    {
                        Broadcaster.InternalRequest(new ProtocolRequest <CoinId, object?>(Id, coinId, null));
                    }
                    else
                    {
                        _coins[_currentEpoch] = ((_currentEpoch / 2) % 3) != 0;
                    }

                    _currentEpoch += 1;
                }
            }
        }
예제 #4
0
        public override void ProcessMessage(MessageEnvelope envelope)
        {
            if (envelope.External)
            {
                Logger.LogTrace("External envelope");
                var message = envelope.ExternalMessage;
                if (message is null)
                {
                    _lastMessage = "Failed to decode external message";
                    throw new Exception("impossible");
                }
                if (message.PayloadCase != ConsensusMessage.PayloadOneofCase.SignedHeaderMessage)
                {
                    _lastMessage = $"RootProtocol does not accept messages of type {message.PayloadCase}";
                    throw new InvalidOperationException(
                              $"RootProtocol does not accept messages of type {message.PayloadCase}"
                              );
                }

                _lastMessage = "SignedHeaderMessage";
                var signedHeaderMessage = message.SignedHeaderMessage;
                var idx = envelope.ValidatorIndex;
                Logger.LogTrace(
                    $"Received signature of header {signedHeaderMessage.Header.Keccak().ToHex()} " +
                    $"from validator {idx}: " +
                    $"pubKey {Wallet.EcdsaPublicKeySet[idx].EncodeCompressed().ToHex()}"
                    );
                if (!(_header is null) && !_header.Equals(signedHeaderMessage.Header))
                {
                    Logger.LogWarning($"Received incorrect block header from validator {idx}");
                    Logger.LogWarning($"Header we have {_header}");
                    Logger.LogWarning($"Header we received {signedHeaderMessage.Header}");
                }

                // Random message can raise exception like recover id in signature verification can be out of range or
                // public key cannot be serialized
                var verified = false;
                try
                {
                    verified = _crypto.VerifySignatureHashed(
                        signedHeaderMessage.Header.Keccak().ToBytes(),
                        signedHeaderMessage.Signature.Encode(),
                        Wallet.EcdsaPublicKeySet[idx].EncodeCompressed(),
                        _useNewChainId
                        );
                }
                catch (Exception exception)
                {
                    var pubKey = Broadcaster.GetPublicKeyById(idx) !.ToHex();
                    Logger.LogWarning($"Faulty behaviour: exception occured trying to verify SignedHeaderMessage " +
                                      $"from {idx} ({pubKey}): {exception}");
                }

                if (!verified)
                {
                    _lastMessage =
                        $"Incorrect signature of header {signedHeaderMessage.Header.Keccak().ToHex()} from validator {idx}";
                    Logger.LogWarning(
                        $"Incorrect signature of header {signedHeaderMessage.Header.Keccak().ToHex()} from validator {idx}"
                        );
                }
                else
                {
                    Logger.LogTrace("Add signatures");
                    _lastMessage = "Add signatures";
                    _signatures.Add(new Tuple <BlockHeader, MultiSig.Types.SignatureByValidator>(
                                        signedHeaderMessage.Header,
                                        new MultiSig.Types.SignatureByValidator
                    {
                        Key   = Wallet.EcdsaPublicKeySet[idx],
                        Value = signedHeaderMessage.Signature,
                    }
                                        )
                                    );
                    var validatorAttendance = GetOrCreateValidatorAttendance(message.SignedHeaderMessage.Header.Index);
                    validatorAttendance !.IncrementAttendanceForCycle(Wallet.EcdsaPublicKeySet[idx].EncodeCompressed(),
                                                                      message.SignedHeaderMessage.Header.Index / _cycleDuration);
                    _validatorAttendanceRepository.SaveState(validatorAttendance.ToBytes());
                }

                CheckSignatures();
            }
            else
            {
                Logger.LogTrace("Internal envelop");
                var message = envelope.InternalMessage;
                switch (message)
                {
                case ProtocolRequest <RootProtocolId, IBlockProducer> request:
                    Logger.LogTrace("request");
                    _lastMessage   = "ProtocolRequest";
                    _blockProducer = request.Input;
                    using (var stream = new MemoryStream())
                    {
                        var data = _blockProducer.GetTransactionsToPropose(Id.Era).ToByteArray();
                        Broadcaster.InternalRequest(new ProtocolRequest <HoneyBadgerId, IRawShare>(
                                                        Id, new HoneyBadgerId(Id.Era), new RawShare(data, GetMyId()))
                                                    );
                    }

                    Broadcaster.InternalRequest(new ProtocolRequest <CoinId, object?>(
                                                    Id, new CoinId(Id.Era, -1, 0), null
                                                    ));
                    TrySignHeader();
                    CheckSignatures();
                    break;

                case ProtocolResult <CoinId, CoinResult> coinResult:
                    _nonce = GetNonceFromCoin(coinResult.Result);
                    Logger.LogTrace($"Received coin for block nonce: {_nonce}");
                    _lastMessage = $"Received coin for block nonce: {_nonce}";
                    TrySignHeader();
                    CheckSignatures();
                    break;

                case ProtocolResult <HoneyBadgerId, ISet <IRawShare> > result:
                    Logger.LogTrace($"Received shares {result.Result.Count} from HoneyBadger");
                    _lastMessage = $"Received shares {result.Result.Count} from HoneyBadger";

                    var rawShares = result.Result.ToArray();
                    var receipts  = new List <TransactionReceipt>();

                    foreach (var rawShare in rawShares)
                    {
                        // this rawShare may be malicious
                        // we may need to discard this if any issue arises during decoding
                        try
                        {
                            var contributions = rawShare.ToBytes().ToMessageArray <TransactionReceipt>();
                            foreach (var receipt in contributions)
                            {
                                receipts.Add(receipt);
                            }
                        }
                        catch (Exception e)
                        {
                            Logger.LogError($"Skipped a rawShare due to exception: {e.Message}");
                            Logger.LogError($"One of the validators might be malicious!!!");
                        }
                    }

                    _receipts = receipts.Distinct().ToArray();

                    Logger.LogTrace($"Collected {_receipts.Length} transactions in total");
                    TrySignHeader();
                    CheckSignatures();
                    break;

                case ProtocolResult <RootProtocolId, object?> _:
                    Logger.LogTrace("Terminate in switch");
                    _lastMessage = "Terminate in switch";
                    Terminate();
                    break;

                default:
                    _lastMessage = "Invalid message";
                    Logger.LogError("Invalid message");
                    throw new ArgumentOutOfRangeException(nameof(message));
                }
            }
        }