public async Task GenerateConsensusTransactions_Failed()
        {
            TesterManager.InitialTesters();

            //without public key
            {
                var input = new DPoSTriggerInformation
                {
                    Behaviour         = DPoSBehaviour.NextRound,
                    InitialTermNumber = 1
                };
                var transactionResult = await TesterManager.Testers[0].ExecuteConsensusContractMethodWithMiningAsync(
                    nameof(ConsensusContract.GenerateConsensusTransactions), input);
                transactionResult.Status.ShouldBe(TransactionResultStatus.Failed);
                transactionResult.Error.Contains("Data to request consensus information should contain public key").ShouldBeTrue();
            }

            //with random public key
            {
                var input = new DPoSTriggerInformation
                {
                    PublicKey  = ByteString.CopyFrom(CryptoHelpers.GenerateKeyPair().PublicKey),
                    Behaviour  = DPoSBehaviour.NextRound,
                    RandomHash = Hash.Generate()
                };

                await InitialConsensus_Success();

                var transactionResult = await TesterManager.Testers[0].ExecuteConsensusContractMethodWithMiningAsync(
                    nameof(ConsensusContract.GenerateConsensusTransactions), input);

                transactionResult.Status.ShouldBe(TransactionResultStatus.Failed);
                transactionResult.Error.Contains("The given key was not present in the dictionary").ShouldBeTrue();
            }
        }
        public static async Task <DPoSHeaderInformation> GetInformationToUpdateConsensusAsync(
            this ContractTester <DPoSContractTestAElfModule> tester,
            DPoSTriggerInformation triggerInformation, DateTime dateTime)
        {
            var bytes = await tester.CallContractMethodAsync(tester.GetConsensusContractAddress(),
                                                             ConsensusConsts.GetInformationToUpdateConsensus, triggerInformation, dateTime);

            return(DPoSHeaderInformation.Parser.ParseFrom(bytes));
        }
        public async Task GetInformationToUpdateConsensus_Failed()
        {
            TesterManager.InitialTesters();

            //invalid public key
            {
                var input = new DPoSTriggerInformation
                {
                    RandomHash = Hash.Generate(),
                    Behaviour  = DPoSBehaviour.NextRound
                };
                var transactionResult = await TesterManager.Testers[0].ExecuteConsensusContractMethodWithMiningAsync(
                    nameof(ConsensusContract.GetInformationToUpdateConsensus), input);

                transactionResult.Status.ShouldBe(TransactionResultStatus.Failed);
                transactionResult.Error.Contains("Invalid public key").ShouldBeTrue();
            }

            //invalid round info
            {
                var input = new DPoSTriggerInformation
                {
                    Behaviour = DPoSBehaviour.UpdateValue,
                    PublicKey = ByteString.CopyFromUtf8(TesterManager.Testers[0].PublicKey),
                };

                var transactionResult = await TesterManager.Testers[0].ExecuteConsensusContractMethodWithMiningAsync(
                    nameof(ConsensusContract.GetInformationToUpdateConsensus), input);

                transactionResult.Status.ShouldBe(TransactionResultStatus.Failed);
                transactionResult.Error.Contains("Failed to get current round information").ShouldBeTrue();
            }

            //valid data but random public key
            {
                var input = new DPoSTriggerInformation
                {
                    Behaviour          = DPoSBehaviour.UpdateValue,
                    InitialTermNumber  = 2,
                    PreviousRandomHash = Hash.Generate(),
                    PublicKey          = ByteString.CopyFrom(CryptoHelpers.GenerateKeyPair().PublicKey),
                    RandomHash         = Hash.Generate()
                };

                await InitialConsensus_Success();

                var transactionResult = await TesterManager.Testers[0].ExecuteConsensusContractMethodWithMiningAsync(
                    nameof(ConsensusContract.GetInformationToUpdateConsensus), input);

                transactionResult.Status.ShouldBe(TransactionResultStatus.Failed);
                transactionResult.Error.Contains("The given key was not present in the dictionary").ShouldBeTrue();
            }
        }
        public static async Task <List <Transaction> > GenerateConsensusTransactionsAsync(
            this ContractTester <DPoSContractTestAElfModule> tester,
            DPoSTriggerInformation triggerInformation)
        {
            var bytes = await tester.CallContractMethodAsync(tester.GetConsensusContractAddress(),
                                                             ConsensusConsts.GenerateConsensusTransactions, triggerInformation);

            var txs = TransactionList.Parser.ParseFrom(bytes).Transactions.ToList();

            tester.SignTransaction(ref txs, tester.KeyPair);
            tester.SupplyTransactionParameters(ref txs);

            return(txs);
        }
Beispiel #5
0
        public static async Task <ConsensusCommand> GetConsensusCommandAsync(
            this ContractTester <DPoSSideChainTestAElfModule> tester,
            Timestamp timestamp = null)
        {
            var triggerInformation = new DPoSTriggerInformation
            {
                PublicKey = ByteString.CopyFrom(tester.KeyPair.PublicKey),
            };
            var bytes = await tester.CallContractMethodAsync(
                tester.GetConsensusContractAddress(), // Usually the second contract is consensus contract.
                ConsensusConsts.GetConsensusCommand,
                triggerInformation);

            return(ConsensusCommand.Parser.ParseFrom(bytes));
        }
Beispiel #6
0
        public IMessage GetTriggerInformation(TriggerType triggerType)
        {
            if (triggerType == TriggerType.ConsensusCommand)
            {
                return(new CommandInput {
                    PublicKey = PublicKey
                });
            }

            if (_firstTriggerType == default)
            {
                _firstTriggerType = triggerType;
            }

            if (_controlInformation.ConsensusCommand == null)
            {
                return(new DPoSTriggerInformation
                {
                    PublicKey = PublicKey,
                    Behaviour = DPoSBehaviour.UpdateValue
                });
            }

            if (Hint.Behaviour == DPoSBehaviour.UpdateValue ||
                Hint.Behaviour == DPoSBehaviour.UpdateValueWithoutPreviousInValue)
            {
                var trigger = new DPoSTriggerInformation
                {
                    PublicKey          = PublicKey,
                    RandomHash         = RandomHash,
                    PreviousRandomHash = _latestRandomHash,
                    Behaviour          = Hint.Behaviour
                };

                if (triggerType != _firstTriggerType)
                {
                    _latestRandomHash = RandomHash;
                }

                return(trigger);
            }

            return(new DPoSTriggerInformation
            {
                PublicKey = PublicKey,
                Behaviour = Hint.Behaviour
            });
        }
Beispiel #7
0
        public override TransactionList GenerateConsensusTransactions(DPoSTriggerInformation input)
        {
            // Some basic checks.
            Assert(input.PublicKey.Any(), "Data to request consensus information should contain public key.");

            var publicKey            = input.PublicKey;
            var consensusInformation = GetInformationToUpdateConsensus(input);
            var round     = consensusInformation.Round;
            var behaviour = consensusInformation.Behaviour;

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

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

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

            default:
                throw new ArgumentOutOfRangeException();
            }
        }
        public static async Task <Block> GenerateConsensusTransactionsAndMineABlockAsync(
            this ContractTester <DPoSContractTestAElfModule> tester,
            DPoSTriggerInformation triggerInformation,
            params ContractTester <DPoSContractTestAElfModule>[] testersGonnaExecuteThisBlock)
        {
            var bytes = await tester.CallContractMethodAsync(tester.GetConsensusContractAddress(),
                                                             ConsensusConsts.GenerateConsensusTransactions,
                                                             triggerInformation);

            var txs = TransactionList.Parser.ParseFrom(bytes).Transactions.ToList();

            tester.SignTransaction(ref txs, tester.KeyPair);
            tester.SupplyTransactionParameters(ref txs);

            var block = await tester.MineAsync(txs);

            foreach (var contractTester in testersGonnaExecuteThisBlock)
            {
                await contractTester.ExecuteBlock(block, txs);
            }

            return(block);
        }
Beispiel #9
0
        public override DPoSHeaderInformation GetInformationToUpdateConsensus(DPoSTriggerInformation input)
        {
            // Some basic checks.
            Assert(input.PublicKey.Any(), "Invalid public key.");

            var publicKey        = input.PublicKey;
            var currentBlockTime = Context.CurrentBlockTime;
            var behaviour        = input.Behaviour;

            Assert(TryToGetCurrentRoundInformation(out var currentRound),
                   ContractErrorCode.GetErrorMessage(ContractErrorCode.AttemptFailed,
                                                     "Failed to get current round information."));

            switch (behaviour)
            {
            case DPoSBehaviour.UpdateValueWithoutPreviousInValue:
            case DPoSBehaviour.UpdateValue:
                Assert(input.RandomHash != null, "Random hash should not be null.");

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

                if (TryToGetPreviousRoundInformation(out var previousRound))
                {
                    signature = previousRound.CalculateSignature(inValue);
                    LogVerbose($"Previous random hash: {input.PreviousRandomHash.ToHex()}");
                    if (input.PreviousRandomHash != Hash.Empty)
                    {
                        // If PreviousRandomHash is Hash.Empty, it means the sender unable or unwilling to publish his previous in value.
                        previousInValue = previousRound.CalculateInValue(input.PreviousRandomHash);
                    }
                }

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

                ShareAndRecoverInValue(updatedRound, previousRound, inValue, publicKey.ToHex());

                // To publish Out Value.
                return(new DPoSHeaderInformation
                {
                    SenderPublicKey = publicKey,
                    Round = updatedRound,
                    Behaviour = behaviour,
                });

            case DPoSBehaviour.NextRound:
                Assert(
                    GenerateNextRoundInformation(currentRound, currentBlockTime, out var nextRound),
                    "Failed to generate next round information.");
                nextRound.RealTimeMinersInformation[publicKey.ToHex()].ProducedBlocks += 1;
                Context.LogDebug(() => $"Mined blocks: {nextRound.GetMinedBlocks()}");
                nextRound.ExtraBlockProducerOfPreviousRound = publicKey.ToHex();
                return(new DPoSHeaderInformation
                {
                    SenderPublicKey = publicKey,
                    Round = nextRound,
                    Behaviour = behaviour
                });

            default:
                return(new DPoSHeaderInformation());
            }
        }
        public override void ConfigureServices(ServiceConfigurationContext context)
        {
            var services = context.Services;

            var ecKeyPair = CryptoHelpers.GenerateKeyPair();

            var dposTriggerInformation = new DPoSTriggerInformation()
            {
                PublicKey         = ByteString.CopyFrom(ecKeyPair.PublicKey),
                InitialTermNumber = 1,
                Behaviour         = DPoSBehaviour.NextTerm
            };

            services.AddTransient(o =>
            {
                var mockService = new Mock <IConsensusInformationGenerationService>();
                mockService.Setup(m => m.GetTriggerInformation(TriggerType.ConsensusTransactions)).Returns(
                    dposTriggerInformation);
                mockService.Setup(m => m.GetTriggerInformation(TriggerType.BlockHeaderExtraData)).Returns(
                    dposTriggerInformation);
                mockService.Setup(m => m.GetTriggerInformation(TriggerType.ConsensusCommand)).Returns(
                    new CommandInput {
                    PublicKey = ByteString.CopyFrom(ecKeyPair.PublicKey)
                });
                mockService.Setup(m => m.ParseConsensusTriggerInformation(It.IsAny <byte[]>())).Returns(
                    dposTriggerInformation);
                mockService.Setup(m => m.ExecuteContractAsync <ConsensusCommand>(It.IsAny <IChainContext>(),
                                                                                 It.IsAny <string>(), It.IsAny <IMessage>(), It.IsAny <DateTime>()))
                .Returns(Task.FromResult(new ConsensusCommand
                {
                    NextBlockMiningLeftMilliseconds = 4000,
                    ExpectedMiningTime = DateTime.UtcNow.Add(TimeSpan.FromSeconds(4)).ToTimestamp()
                }));
                mockService.Setup(m => m.ExecuteContractAsync <ValidationResult>(It.IsAny <IChainContext>(),
                                                                                 It.IsAny <string>(), It.IsAny <IMessage>(), It.IsAny <DateTime>()))
                .Returns(Task.FromResult(new ValidationResult
                {
                    Success = true
                }));
                mockService.Setup(m => m.ExecuteContractAsync <TransactionList>(It.IsAny <IChainContext>(),
                                                                                It.IsAny <string>(), It.IsAny <IMessage>(), It.IsAny <DateTime>()))
                .Returns(Task.FromResult(new TransactionList
                {
                    Transactions =
                    {
                        new Transaction {
                            MethodName = ConsensusConsts.GenerateConsensusTransactions, Params = ByteString.CopyFromUtf8("test1")
                        },
                        new Transaction {
                            MethodName = ConsensusConsts.GenerateConsensusTransactions, Params = ByteString.CopyFromUtf8("test2")
                        },
                        new Transaction {
                            MethodName = ConsensusConsts.GenerateConsensusTransactions, Params = ByteString.CopyFromUtf8("test3")
                        }
                    }
                }));
                return(mockService.Object);
            });

            services.AddTransient(o =>
            {
                var mockService = new Mock <IAccountService>();
                mockService.Setup(a => a.SignAsync(It.IsAny <byte[]>())).Returns <byte[]>(data =>
                                                                                          Task.FromResult(CryptoHelpers.SignWithPrivateKey(ecKeyPair.PrivateKey, data)));

                mockService.Setup(a => a.VerifySignatureAsync(It.IsAny <byte[]>(), It.IsAny <byte[]>(), It.IsAny <byte[]>()
                                                              )).Returns <byte[], byte[], byte[]>((signature, data, publicKey) =>
                {
                    var recoverResult = CryptoHelpers.RecoverPublicKey(signature, data, out var recoverPublicKey);
                    return(Task.FromResult(recoverResult && publicKey.BytesEqual(recoverPublicKey)));
                });

                mockService.Setup(a => a.GetPublicKeyAsync()).ReturnsAsync(ecKeyPair.PublicKey);

                return(mockService.Object);
            });

            services.AddTransient(o =>
            {
                var mockService = new Mock <IConsensusScheduler>();

                return(mockService.Object);
            });
            services.AddTransient(o =>
            {
                var mockService = new Mock <IBlockchainService>();
                mockService.Setup(m => m.GetChainAsync()).Returns(
                    Task.FromResult(new Chain()
                {
                    BestChainHash   = Hash.Empty,
                    BestChainHeight = 100
                }));

                return(mockService.Object);
            });
            services.AddTransient <ConsensusControlInformation>();
            services.AddTransient(o =>
            {
                var mockService = new Mock <ISmartContractAddressService>();
                mockService.Setup(m => m.GetAddressByContractName(It.IsAny <Hash>())).Returns(
                    Address.Generate());
                return(mockService.Object);
            });

            services.AddTransient <IConsensusService, ConsensusService>();
            services.AddTransient <ISystemTransactionGenerator, ConsensusTransactionGenerator>();
        }