Example #1
0
        public async Task <BytesValue> GetTriggerInformationForConsensusTransactionsAsync(BytesValue consensusCommandBytes)
        {
            if (consensusCommandBytes == null)
            {
                return(new AElfConsensusTriggerInformation
                {
                    Pubkey = PublicKey,
                    Behaviour = AElfConsensusBehaviour.UpdateValue
                }.ToBytesValue());
            }

            var command   = consensusCommandBytes.ToConsensusCommand();
            var behaviour = command.Hint.ToAElfConsensusHint().Behaviour;
            var bestChainLastBlockHeader = await _blockchainService.GetBestChainLastBlockHeaderAsync();

            if (behaviour == AElfConsensusBehaviour.UpdateValue ||
                behaviour == AElfConsensusBehaviour.UpdateValueWithoutPreviousInValue)
            {
                var trigger = new AElfConsensusTriggerInformation
                {
                    Pubkey             = PublicKey,
                    RandomHash         = _randomHashCacheService.GetRandomHash(bestChainLastBlockHeader.GetHash()),
                    PreviousRandomHash = _randomHashCacheService.GetLatestGeneratedBlockRandomHash(),
                    Behaviour          = behaviour
                };

                return(trigger.ToBytesValue());
            }

            return(new AElfConsensusTriggerInformation
            {
                Pubkey = PublicKey,
                Behaviour = behaviour
            }.ToBytesValue());
        }
Example #2
0
        private void UpdateLatestSecretPieces(Round updatedRound, string pubkey, AElfConsensusTriggerInformation triggerInformation)
        {
            foreach (var encryptedPiece in triggerInformation.EncryptedPieces)
            {
                updatedRound.RealTimeMinersInformation[pubkey].EncryptedPieces
                .Add(encryptedPiece.Key, encryptedPiece.Value);
            }

            foreach (var decryptedPiece in triggerInformation.DecryptedPieces)
            {
                if (updatedRound.RealTimeMinersInformation.ContainsKey(decryptedPiece.Key))
                {
                    updatedRound.RealTimeMinersInformation[decryptedPiece.Key].DecryptedPieces[pubkey] =
                        decryptedPiece.Value;
                }
            }

            foreach (var revealedInValue in triggerInformation.RevealedInValues)
            {
                if (updatedRound.RealTimeMinersInformation.ContainsKey(revealedInValue.Key) &&
                    (updatedRound.RealTimeMinersInformation[revealedInValue.Key].PreviousInValue == Hash.Empty ||
                     updatedRound.RealTimeMinersInformation[revealedInValue.Key].PreviousInValue == null))
                {
                    updatedRound.RealTimeMinersInformation[revealedInValue.Key].PreviousInValue = revealedInValue.Value;
                }
            }
        }
        private BytesValue GetConsensusBlockExtraData(BytesValue input, bool isGeneratingTransactions = false)
        {
            var triggerInformation = new AElfConsensusTriggerInformation();

            triggerInformation.MergeFrom(input.Value);

            Assert(triggerInformation.Pubkey.Any(), "Invalid pubkey.");

            if (!TryToGetCurrentRoundInformation(out var currentRound))
            {
                Assert(false, "Failed to get current round information.");
            }

            var publicKeyBytes = triggerInformation.Pubkey;
            var pubkey         = publicKeyBytes.ToHex();

            LogIfPreviousMinerHasNotProduceEnoughTinyBlocks(currentRound, pubkey);

            var information = new AElfConsensusHeaderInformation();

            switch (triggerInformation.Behaviour)
            {
            case AElfConsensusBehaviour.UpdateValue:
                information = GetConsensusExtraDataToPublishOutValue(currentRound, pubkey,
                                                                     triggerInformation);
                if (!isGeneratingTransactions)
                {
                    information.Round = information.Round.GetUpdateValueRound(pubkey);
                }

                break;

            case AElfConsensusBehaviour.TinyBlock:
                information = GetConsensusExtraDataForTinyBlock(currentRound, pubkey,
                                                                triggerInformation);
                break;

            case AElfConsensusBehaviour.NextRound:
                information = GetConsensusExtraDataForNextRound(currentRound, pubkey,
                                                                triggerInformation);
                break;

            case AElfConsensusBehaviour.NextTerm:
                information = GetConsensusExtraDataForNextTerm(pubkey, triggerInformation);
                break;
            }

            if (!isGeneratingTransactions)
            {
                information.Round.DeleteSecretSharingInformation();
            }

            return(information.ToBytesValue());
        }
Example #4
0
        public BytesValue GetTriggerInformationForConsensusTransactions(BytesValue consensusCommandBytes)
        {
            if (consensusCommandBytes == null)
            {
                return(new AElfConsensusTriggerInformation
                {
                    Pubkey = Pubkey,
                    Behaviour = AElfConsensusBehaviour.UpdateValue
                }.ToBytesValue());
            }

            var command = consensusCommandBytes.ToConsensusCommand();
            var hint    = command.Hint.ToAElfConsensusHint();

            if (hint.Behaviour == AElfConsensusBehaviour.UpdateValue)
            {
                var inValue = _inValueCache.GetInValue(hint.RoundId);
                var trigger = new AElfConsensusTriggerInformation
                {
                    Pubkey          = Pubkey,
                    InValue         = inValue,
                    PreviousInValue = _inValueCache.GetInValue(hint.PreviousRoundId),
                    Behaviour       = hint.Behaviour,
                };

                var secretPieces = _secretSharingService.GetEncryptedPieces(hint.RoundId);
                foreach (var secretPiece in secretPieces)
                {
                    trigger.EncryptedPieces.Add(secretPiece.Key, ByteString.CopyFrom(secretPiece.Value));
                }

                var decryptedPieces = _secretSharingService.GetDecryptedPieces(hint.RoundId);
                foreach (var decryptedPiece in decryptedPieces)
                {
                    trigger.DecryptedPieces.Add(decryptedPiece.Key, ByteString.CopyFrom(decryptedPiece.Value));
                }

                var revealedInValues = _secretSharingService.GetRevealedInValues(hint.RoundId);
                foreach (var revealedInValue in revealedInValues)
                {
                    trigger.RevealedInValues.Add(revealedInValue.Key, revealedInValue.Value);
                }

                return(trigger.ToBytesValue());
            }

            return(new AElfConsensusTriggerInformation
            {
                Pubkey = Pubkey,
                Behaviour = hint.Behaviour
            }.ToBytesValue());
        }
Example #5
0
        private AElfConsensusHeaderInformation GetConsensusExtraDataForNextTerm(string publicKey,
                                                                                AElfConsensusTriggerInformation triggerInformation)
        {
            var firstRoundOfNextTerm = GenerateFirstRoundOfNextTerm(publicKey, State.MiningInterval.Value);

            Assert(firstRoundOfNextTerm.RoundId != 0, "Failed to generate new round information.");
            return(new AElfConsensusHeaderInformation
            {
                SenderPubkey = publicKey.ToByteString(),
                Round = firstRoundOfNextTerm,
                Behaviour = triggerInformation.Behaviour
            });
        }
Example #6
0
        public override TransactionList GenerateConsensusTransactions(BytesValue input)
        {
            var triggerInformation = new AElfConsensusTriggerInformation();

            triggerInformation.MergeFrom(input.Value);
            // Some basic checks.
            Assert(triggerInformation.Pubkey.Any(),
                   "Data to request consensus information should contain pubkey.");

            var pubkey = triggerInformation.Pubkey;
            var consensusInformation = new AElfConsensusHeaderInformation();

            consensusInformation.MergeFrom(GetConsensusBlockExtraData(input, true).Value);
            var transactionList = GenerateTransactionListByExtraData(consensusInformation, pubkey);

            return(transactionList);
        }
        private AElfConsensusHeaderInformation GetConsensusExtraDataForNextTerm(string pubkey,
                                                                                AElfConsensusTriggerInformation triggerInformation)
        {
            var firstRoundOfNextTerm = GenerateFirstRoundOfNextTerm(pubkey, State.MiningInterval.Value);

            Assert(firstRoundOfNextTerm.RoundId != 0, "Failed to generate new round information.");
            if (firstRoundOfNextTerm.RealTimeMinersInformation.ContainsKey(pubkey))
            {
                firstRoundOfNextTerm.RealTimeMinersInformation[pubkey].ProducedTinyBlocks = 1;
            }

            return(new AElfConsensusHeaderInformation
            {
                SenderPubkey = pubkey.ToByteString(),
                Round = firstRoundOfNextTerm,
                Behaviour = triggerInformation.Behaviour
            });
        }
Example #8
0
        public async Task MineBlockAsync(List <Transaction> transactions = null)
        {
            if (!_isSystemContractsDeployed)
            {
                return;
            }

            if (transactions != null)
            {
                await _testDataProvider.AddTransactionListAsync(transactions);
            }

            var currentBlockTime = _testDataProvider.GetBlockTime();

            var(contractStub, pubkey) =
                GetProperContractStub(currentBlockTime);
            var command = await contractStub.GetConsensusCommand.CallAsync(pubkey);

            var hint = AElfConsensusHint.Parser.ParseFrom(command.Hint);
            var triggerInformation = new AElfConsensusTriggerInformation
            {
                Behaviour = hint.Behaviour,
                // It doesn't matter for testing.
                RandomHash         = Hash.FromString($"RandomHashOf{pubkey}"),
                PreviousRandomHash = Hash.FromString($"RandomHashOf{pubkey}"),
                Pubkey             = pubkey.Value
            };
            var consensusTransaction = await contractStub.GenerateConsensusTransactions.CallAsync(new BytesValue
                                                                                                  { Value = triggerInformation.ToByteString() });

            await MineAsync(contractStub, consensusTransaction.Transactions.First());

            _currentRound = await _contractStubs.First().GetCurrentRoundInformation.CallAsync(new Empty());

            _testDataProvider.SetBlockTime(
                consensusTransaction.Transactions.First().MethodName ==
                nameof(AEDPoSContractImplContainer.AEDPoSContractImplStub.NextTerm)
                    ? currentBlockTime.AddMilliseconds(AEDPoSExtensionConstants.MiningInterval)
                    : currentBlockTime.AddMilliseconds(AEDPoSExtensionConstants.ActualMiningInterval));

            await _testDataProvider.ResetAsync();
        }
Example #9
0
        private async Task <AElfConsensusTriggerInformation> GetConsensusTriggerInfoAsync(
            AEDPoSContractImplContainer.AEDPoSContractImplStub contractStub, BytesValue pubkey)
        {
            var command = await contractStub.GetConsensusCommand.CallAsync(pubkey);

            var hint = AElfConsensusHint.Parser.ParseFrom(command.Hint);
            var triggerInformation = new AElfConsensusTriggerInformation
            {
                Behaviour = hint.Behaviour,
                // It doesn't matter for testing.
                InValue         = Hash.FromString($"InValueOf{pubkey}"),
                PreviousInValue = Hash.FromString($"InValueOf{pubkey}"),
                Pubkey          = pubkey.Value
            };

            var consensusExtraData = await contractStub.GetConsensusExtraData.CallAsync(new BytesValue
            {
                Value = triggerInformation.ToByteString()
            });

            var consensusHeaderInformation = new AElfConsensusHeaderInformation();

            consensusHeaderInformation.MergeFrom(consensusExtraData.Value);
            Debug.WriteLine($"Current header information: {consensusHeaderInformation}");

            // Validate consensus extra data.
            {
                var validationResult =
                    await _contractStubs.First().ValidateConsensusBeforeExecution.CallAsync(consensusExtraData);

                if (!validationResult.Success)
                {
                    throw new Exception($"Consensus extra data validation failed: {validationResult.Message}");
                }
            }

            return(triggerInformation);
        }
Example #10
0
        public BytesValue GetTriggerInformationForBlockHeaderExtraData(BytesValue consensusCommandBytes)
        {
            if (consensusCommandBytes == null)
            {
                return(new AElfConsensusTriggerInformation
                {
                    Pubkey = Pubkey,
                    Behaviour = AElfConsensusBehaviour.UpdateValue
                }.ToBytesValue());
            }

            var command = consensusCommandBytes.ToConsensusCommand();
            var hint    = command.Hint.ToAElfConsensusHint();

            if (hint.Behaviour == AElfConsensusBehaviour.UpdateValue)
            {
                var newInValue      = _inValueCache.GetInValue(hint.RoundId);
                var previousInValue = _inValueCache.GetInValue(hint.PreviousRoundId);
                Logger.LogTrace($"New in value {newInValue} for round of id {hint.RoundId}");
                Logger.LogTrace($"Previous in value {previousInValue} for round of id {hint.PreviousRoundId}");
                var trigger = new AElfConsensusTriggerInformation
                {
                    Pubkey          = Pubkey,
                    InValue         = newInValue,
                    PreviousInValue = previousInValue,
                    Behaviour       = hint.Behaviour
                };

                return(trigger.ToBytesValue());
            }

            return(new AElfConsensusTriggerInformation
            {
                Pubkey = Pubkey,
                Behaviour = hint.Behaviour
            }.ToBytesValue());
        }
        private AElfConsensusHeaderInformation GetConsensusExtraDataForNextRound(Round currentRound,
                                                                                 string pubkey, AElfConsensusTriggerInformation triggerInformation)
        {
            if (!GenerateNextRoundInformation(currentRound, Context.CurrentBlockTime, out var nextRound))
            {
                Assert(false, "Failed to generate next round information.");
            }

            if (!nextRound.RealTimeMinersInformation.Keys.Contains(pubkey))
            {
                return(new AElfConsensusHeaderInformation
                {
                    SenderPubkey = pubkey.ToByteString(),
                    Round = nextRound,
                    Behaviour = triggerInformation.Behaviour
                });
            }

            RevealSharedInValues(currentRound, pubkey);

            nextRound.RealTimeMinersInformation[pubkey].ProducedBlocks =
                nextRound.RealTimeMinersInformation[pubkey].ProducedBlocks.Add(1);
            Context.LogDebug(() => $"Mined blocks: {nextRound.GetMinedBlocks()}");
            nextRound.ExtraBlockProducerOfPreviousRound = pubkey;

            nextRound.RealTimeMinersInformation[pubkey].ProducedTinyBlocks = 1;
            nextRound.RealTimeMinersInformation[pubkey].ActualMiningTimes
            .Add(Context.CurrentBlockTime);

            return(new AElfConsensusHeaderInformation
            {
                SenderPubkey = pubkey.ToByteString(),
                Round = nextRound,
                Behaviour = triggerInformation.Behaviour
            });
        }
        private AElfConsensusHeaderInformation GetConsensusExtraDataForTinyBlock(Round currentRound,
                                                                                 string pubkey, AElfConsensusTriggerInformation triggerInformation)
        {
            currentRound.RealTimeMinersInformation[pubkey].ProducedTinyBlocks = currentRound
                                                                                .RealTimeMinersInformation[pubkey].ProducedTinyBlocks.Add(1);
            currentRound.RealTimeMinersInformation[pubkey].ProducedBlocks =
                currentRound.RealTimeMinersInformation[pubkey].ProducedBlocks.Add(1);
            currentRound.RealTimeMinersInformation[pubkey].ActualMiningTimes
            .Add(Context.CurrentBlockTime);

            return(new AElfConsensusHeaderInformation
            {
                SenderPubkey = pubkey.ToByteString(),
                Round = currentRound.GetTinyBlockRound(pubkey),
                Behaviour = triggerInformation.Behaviour
            });
        }
Example #13
0
        public async Task MineBlockAsync(List <Transaction> transactions = null, bool withException = false)
        {
            if (!_isSystemContractsDeployed)
            {
                return;
            }

            if (transactions != null)
            {
                await _testDataProvider.AddTransactionListAsync(transactions);
            }

            var currentBlockTime = _testDataProvider.GetBlockTime();

            {
                {
                    var currentRound = await _contractStubs.First().GetCurrentRoundInformation.CallAsync(new Empty());

                    if (currentRound.RoundNumber == 0)
                    {
                        throw new InitializationFailedException("Can't find current round information.");
                    }
                }
            }

            var maximumBlocksCount = (await _contractStubs.First().GetMaximumBlocksCount.CallAsync(new Empty())).Value;

            var(contractStub, pubkey) = GetProperContractStub(currentBlockTime, maximumBlocksCount);
            currentBlockTime          = _testDataProvider.GetBlockTime();

            {
                var currentRound = await _contractStubs.First().GetCurrentRoundInformation.CallAsync(new Empty());

                if (currentRound.RoundNumber == 0)
                {
                    throw new InitializationFailedException("Can't find current round information.");
                }
            }

            var command = await contractStub.GetConsensusCommand.CallAsync(pubkey);

            var hint = AElfConsensusHint.Parser.ParseFrom(command.Hint);
            var triggerInformation = new AElfConsensusTriggerInformation
            {
                Behaviour = hint.Behaviour,
                // It doesn't matter for testing.
                InValue         = Hash.FromString($"InValueOf{pubkey}"),
                PreviousInValue = Hash.FromString($"InValueOf{pubkey}"),
                Pubkey          = pubkey.Value
            };

            var consensusExtraData = await contractStub.GetConsensusExtraData.CallAsync(new BytesValue
            {
                Value = triggerInformation.ToByteString()
            });

            var consensusHeaderInformation = new AElfConsensusHeaderInformation();

            consensusHeaderInformation.MergeFrom(consensusExtraData.Value);
            Debug.WriteLine($"Current header information: {consensusHeaderInformation}");

            // Validate consensus extra data.
            {
                var validationResult =
                    await _contractStubs.First().ValidateConsensusBeforeExecution.CallAsync(consensusExtraData);

                if (!validationResult.Success)
                {
                    throw new Exception($"Consensus extra data validation failed: {validationResult.Message}");
                }
            }

            var consensusTransaction = await contractStub.GenerateConsensusTransactions.CallAsync(new BytesValue
            {
                Value = triggerInformation.ToByteString()
            });

            await MineAsync(contractStub, consensusTransaction.Transactions.First(), withException);

            _currentRound = await _contractStubs.First().GetCurrentRoundInformation.CallAsync(new Empty());

            Debug.WriteLine($"Update current round information.{_currentRound}");
            if (!_isSkipped)
            {
                if (_currentRound.RealTimeMinersInformation.Any(i => i.Value.MissedTimeSlots != 0))
                {
                    var previousRound = await _contractStubs.First().GetPreviousRoundInformation.CallAsync(new Empty());

                    throw new BlockMiningException(
                              $"Someone missed time slot.\n{_currentRound}\n{previousRound}\nCurrent block time: {currentBlockTime}");
                }
            }

            _testDataProvider.SetBlockTime(
                consensusTransaction.Transactions.First().MethodName ==
                nameof(AEDPoSContractImplContainer.AEDPoSContractImplStub.NextTerm)
                    ? currentBlockTime.AddMilliseconds(AEDPoSExtensionConstants.MiningInterval)
                    : currentBlockTime.AddMilliseconds(AEDPoSExtensionConstants.ActualMiningInterval));

            await _testDataProvider.ResetAsync();

            _isSkipped = false;
        }
Example #14
0
        private AElfConsensusHeaderInformation GetConsensusExtraDataToPublishOutValue(Round currentRound,
                                                                                      string publicKey, AElfConsensusTriggerInformation triggerInformation)
        {
            currentRound.RealTimeMinersInformation[publicKey].ProducedTinyBlocks = currentRound
                                                                                   .RealTimeMinersInformation[publicKey].ProducedTinyBlocks.Add(1);
            currentRound.RealTimeMinersInformation[publicKey].ProducedBlocks =
                currentRound.RealTimeMinersInformation[publicKey].ProducedBlocks.Add(1);
            currentRound.RealTimeMinersInformation[publicKey].ActualMiningTimes
            .Add(Context.CurrentBlockTime);

            Assert(triggerInformation.RandomHash != null, "Random hash should not be null.");

            var inValue   = currentRound.CalculateInValue(triggerInformation.RandomHash);
            var outValue  = Hash.FromMessage(inValue);
            var signature =
                Hash.FromTwoHashes(outValue, triggerInformation.RandomHash); // Just initial signature value.
            var previousInValue = Hash.Empty;                                // Just initial previous in value.

            if (TryToGetPreviousRoundInformation(out var previousRound) && !IsFirstRoundOfCurrentTerm(out _))
            {
                signature = previousRound.CalculateSignature(inValue);
                if (triggerInformation.PreviousRandomHash != null &&
                    triggerInformation.PreviousRandomHash != Hash.Empty)
                {
                    // If PreviousRandomHash is null or Hash.Empty, it means the sender unable or unwilling to publish his previous in value.
                    previousInValue = previousRound.CalculateInValue(triggerInformation.PreviousRandomHash);
                    // Self check.
                    if (Hash.FromMessage(previousInValue) !=
                        previousRound.RealTimeMinersInformation[publicKey].OutValue)
                    {
                        Context.LogDebug(() => "Failed to produce block at previous round?");
                        previousInValue = Hash.Empty;
                    }
                }
            }

            var updatedRound = currentRound.ApplyNormalConsensusData(publicKey, previousInValue,
                                                                     outValue, signature);

            updatedRound.RealTimeMinersInformation[publicKey].ImpliedIrreversibleBlockHeight = Context.CurrentHeight;

            ShareInValueOfCurrentRound(updatedRound, previousRound, inValue, publicKey);

            // To publish Out Value.
            return(new AElfConsensusHeaderInformation
            {
                SenderPubkey = publicKey.ToByteString(),
                Round = updatedRound,
                Behaviour = triggerInformation.Behaviour
            });
        }
        private AElfConsensusHeaderInformation GetConsensusExtraDataToPublishOutValue(Round currentRound,
                                                                                      string pubkey, AElfConsensusTriggerInformation triggerInformation)
        {
            currentRound.RealTimeMinersInformation[pubkey].ProducedTinyBlocks = currentRound
                                                                                .RealTimeMinersInformation[pubkey].ProducedTinyBlocks.Add(1);
            currentRound.RealTimeMinersInformation[pubkey].ProducedBlocks =
                currentRound.RealTimeMinersInformation[pubkey].ProducedBlocks.Add(1);
            currentRound.RealTimeMinersInformation[pubkey].ActualMiningTimes
            .Add(Context.CurrentBlockTime);

            Assert(triggerInformation.InValue != null, "In value should not be null.");

            var outValue  = Hash.FromMessage(triggerInformation.InValue);
            var signature =
                Hash.FromTwoHashes(outValue, triggerInformation.InValue); // Just initial signature value.
            var previousInValue = Hash.Empty;                             // Just initial previous in value.

            if (TryToGetPreviousRoundInformation(out var previousRound) && !IsFirstRoundOfCurrentTerm(out _))
            {
                signature = previousRound.CalculateSignature(triggerInformation.InValue);
                Context.LogDebug(
                    () => $"Previous in value in trigger information: {triggerInformation.PreviousInValue}");
                if (triggerInformation.PreviousInValue != null &&
                    triggerInformation.PreviousInValue != Hash.Empty)
                {
                    // Self check.
                    if (Hash.FromMessage(triggerInformation.PreviousInValue) !=
                        previousRound.RealTimeMinersInformation[pubkey].OutValue)
                    {
                        Context.LogDebug(() => "Failed to produce block at previous round?");
                        previousInValue = Hash.Empty;
                    }
                    else
                    {
                        previousInValue = triggerInformation.PreviousInValue;
                    }
                }
            }

            var updatedRound = currentRound.ApplyNormalConsensusData(pubkey, previousInValue,
                                                                     outValue, signature);

            Context.LogDebug(
                () =>
                $"Previous in value after ApplyNormalConsensusData: {updatedRound.RealTimeMinersInformation[pubkey].PreviousInValue}");

            updatedRound.RealTimeMinersInformation[pubkey].ImpliedIrreversibleBlockHeight = Context.CurrentHeight;

            // Update secret pieces of latest in value.
            foreach (var encryptedPiece in triggerInformation.EncryptedPieces)
            {
                updatedRound.RealTimeMinersInformation[pubkey].EncryptedPieces
                .Add(encryptedPiece.Key, encryptedPiece.Value);
            }

            foreach (var decryptedPiece in triggerInformation.DecryptedPieces)
            {
                if (updatedRound.RealTimeMinersInformation.ContainsKey(decryptedPiece.Key))
                {
                    updatedRound.RealTimeMinersInformation[decryptedPiece.Key].DecryptedPieces[pubkey] =
                        decryptedPiece.Value;
                }
            }

            foreach (var revealedInValue in triggerInformation.RevealedInValues)
            {
                if (updatedRound.RealTimeMinersInformation.ContainsKey(revealedInValue.Key) &&
                    (updatedRound.RealTimeMinersInformation[revealedInValue.Key].PreviousInValue == Hash.Empty ||
                     updatedRound.RealTimeMinersInformation[revealedInValue.Key].PreviousInValue == null))
                {
                    updatedRound.RealTimeMinersInformation[revealedInValue.Key].PreviousInValue = revealedInValue.Value;
                }
            }

            // To publish Out Value.
            return(new AElfConsensusHeaderInformation
            {
                SenderPubkey = pubkey.ToByteString(),
                Round = updatedRound,
                Behaviour = triggerInformation.Behaviour
            });
        }
        public override TransactionList GenerateConsensusTransactions(BytesValue input)
        {
            var triggerInformation = new AElfConsensusTriggerInformation();

            triggerInformation.MergeFrom(input.Value);
            // Some basic checks.
            Assert(triggerInformation.Pubkey.Any(),
                   "Data to request consensus information should contain public key.");

            var publicKey            = triggerInformation.Pubkey;
            var consensusInformation = new AElfConsensusHeaderInformation();

            consensusInformation.MergeFrom(GetConsensusBlockExtraData(input, true).Value);
            var round     = consensusInformation.Round;
            var behaviour = consensusInformation.Behaviour;

            switch (behaviour)
            {
            case AElfConsensusBehaviour.UpdateValueWithoutPreviousInValue:
            case AElfConsensusBehaviour.UpdateValue:
                return(new TransactionList
                {
                    Transactions =
                    {
                        GenerateTransaction(nameof(UpdateValue),
                                            round.ExtractInformationToUpdateConsensus(publicKey.ToHex()))
                    }
                });

            case AElfConsensusBehaviour.TinyBlock:
                var minerInRound = round.RealTimeMinersInformation[publicKey.ToHex()];
                return(new TransactionList
                {
                    Transactions =
                    {
                        GenerateTransaction(nameof(UpdateTinyBlockInformation),
                                            new TinyBlockInput
                        {
                            ActualMiningTime = minerInRound.ActualMiningTimes.Last(),
                            ProducedBlocks = minerInRound.ProducedBlocks,
                            RoundId = round.RoundId
                        })
                    }
                });

            case AElfConsensusBehaviour.NextRound:
                return(new TransactionList
                {
                    Transactions =
                    {
                        GenerateTransaction(nameof(NextRound), round)
                    }
                });

            case AElfConsensusBehaviour.NextTerm:
                return(new TransactionList
                {
                    Transactions =
                    {
                        GenerateTransaction(nameof(NextTerm), round)
                    }
                });

            default:
                throw new ArgumentOutOfRangeException();
            }
        }
Example #17
0
        private AElfConsensusHeaderInformation GetConsensusExtraDataToPublishOutValue(Round currentRound,
                                                                                      string pubkey, AElfConsensusTriggerInformation triggerInformation)
        {
            currentRound.RealTimeMinersInformation[pubkey].ProducedTinyBlocks = currentRound
                                                                                .RealTimeMinersInformation[pubkey].ProducedTinyBlocks.Add(1);
            currentRound.RealTimeMinersInformation[pubkey].ProducedBlocks =
                currentRound.RealTimeMinersInformation[pubkey].ProducedBlocks.Add(1);
            currentRound.RealTimeMinersInformation[pubkey].ActualMiningTimes
            .Add(Context.CurrentBlockTime);

            Assert(triggerInformation.InValue != null, "In value should not be null.");

            var outValue  = Hash.FromMessage(triggerInformation.InValue);
            var signature =
                Hash.FromTwoHashes(outValue, triggerInformation.InValue); // Just initial signature value.
            var previousInValue = Hash.Empty;                             // Just initial previous in value.

            if (TryToGetPreviousRoundInformation(out var previousRound) && !IsFirstRoundOfCurrentTerm(out _))
            {
                if (triggerInformation.PreviousInValue != null &&
                    triggerInformation.PreviousInValue != Hash.Empty)
                {
                    Context.LogDebug(
                        () => $"Previous in value in trigger information: {triggerInformation.PreviousInValue}");
                    // Self check.
                    if (previousRound.RealTimeMinersInformation.ContainsKey(pubkey) &&
                        Hash.FromMessage(triggerInformation.PreviousInValue) !=
                        previousRound.RealTimeMinersInformation[pubkey].OutValue)
                    {
                        Context.LogDebug(() => "Failed to produce block at previous round?");
                        previousInValue = Hash.Empty;
                    }
                    else
                    {
                        previousInValue = triggerInformation.PreviousInValue;
                    }
                    signature = previousRound.CalculateSignature(triggerInformation.PreviousInValue);
                }
                else
                {
                    var fakePreviousInValue = Hash.FromString(pubkey.Append(Context.CurrentHeight.ToString()));
                    if (previousRound.RealTimeMinersInformation.ContainsKey(pubkey) && previousRound.RoundNumber != 1)
                    {
                        var appointedPreviousInValue = previousRound.RealTimeMinersInformation[pubkey].InValue;
                        if (appointedPreviousInValue != null)
                        {
                            fakePreviousInValue = appointedPreviousInValue;
                        }

                        Context.LogDebug(() => $"TEST:\n{previousRound.ToString(pubkey)}\nInValue: {fakePreviousInValue}");
                        signature = previousRound.CalculateSignature(fakePreviousInValue);
                    }
                    else
                    {
                        // This miner appears first time in current round, like as a replacement of evil miner.
                        signature = previousRound.CalculateSignature(fakePreviousInValue);
                    }
                }
            }

            var updatedRound = currentRound.ApplyNormalConsensusData(pubkey, previousInValue,
                                                                     outValue, signature);

            Context.LogDebug(
                () => $"Previous in value after ApplyNormalConsensusData: " +
                $"{updatedRound.RealTimeMinersInformation[pubkey].PreviousInValue}");

            updatedRound.RealTimeMinersInformation[pubkey].ImpliedIrreversibleBlockHeight = Context.CurrentHeight;

            // Update secret pieces of latest in value.
            UpdateLatestSecretPieces(updatedRound, pubkey, triggerInformation);

            // To publish Out Value.
            return(new AElfConsensusHeaderInformation
            {
                SenderPubkey = pubkey.ToByteString(),
                Round = updatedRound,
                Behaviour = triggerInformation.Behaviour
            });
        }