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)); }
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(); }
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; } } }
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)); } } }