예제 #1
0
        private void SubmitAttendanceDetection()
        {
            Logger.LogInformation("SubmitAttendanceDetection");
            var previousValidators = _systemContractReader.GetPreviousValidators();

            var publicKeys     = new byte[previousValidators.Length][];
            var attendances    = new UInt256[previousValidators.Length];
            var attendanceData = GetValidatorAttendance();

            if (attendanceData == null)
            {
                Logger.LogWarning("Attendance detection data didn't collected");
                return;
            }

            for (var i = 0; i < previousValidators.Length; i++)
            {
                var publicKey     = previousValidators[i];
                var previousCycle = _stateManager.LastApprovedSnapshot.Blocks.GetTotalBlockHeight() /
                                    StakingContract.CycleDuration - 1;
                attendances[i] = new BigInteger(attendanceData.GetAttendanceForCycle(publicKey, previousCycle))
                                 .ToUInt256();
                publicKeys[i] = publicKey;
            }

            var tx = _transactionBuilder.InvokeTransaction(
                _systemContractReader.NodeAddress(),
                ContractRegisterer.StakingContract,
                Money.Zero,
                StakingInterface.MethodSubmitAttendanceDetection,
                publicKeys,
                attendances
                );

            _validatorAttendanceRepository.SaveState(attendanceData.ToBytes());
            AddTxToPool(tx);
        }
예제 #2
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));
                }
            }
        }