public static async Task InitConstellation(this IntegrationTestEnvironment environment)
        {
            var assetCodes = new string[] {
                "USD",
                "EURO",
                "GOLD",
                "SILVER",
                "OIL",
                "NGAS",
                "CORN",
                "SUGAR"
            };
            var res = await environment.AlphaWrapper.ConstellationController.Init(new ConstellationInitModel
            {
                Assets            = assetCodes.Select(a => $"{a}-{environment.Issuer.AccountId}-{(a.Length > 4 ? 2 : 1)}").ToArray(),
                Auditors          = environment.AuditorWrappers.Select(a => a.Settings.KeyPair.AccountId).ToArray(),
                MinAccountBalance = 1000,
                MinAllowedLotSize = 100,
                RequestRateLimits = new RequestRateLimitsModel {
                    HourLimit = int.MaxValue, MinuteLimit = int.MaxValue
                }
            });

            var result = (ConstellationController.InitResult)((JsonResult)res).Value;

            Assert.IsTrue(result.IsSuccess, "Init result.");
        }
        public async Task AuditorRestartTest()
        {
            var environment = new IntegrationTestEnvironment();

            await environment.PrepareConstellation(3, 0);

            var auditorStartup = environment.AuditorWrappers.First();
            await auditorStartup.Shutdown();

            Assert.AreEqual(2, ((AlphaStateManager)environment.AlphaWrapper.Context.AppState).ConnectedAuditorsCount, "Auditors count assertion.");
            await environment.AssertConstellationState(ApplicationState.Ready, TimeSpan.FromSeconds(10));

            var clientsCount = 100;

            environment.GenerateCliens(clientsCount);

            await environment.AssertClientsCount(clientsCount, TimeSpan.FromSeconds(15));

            await auditorStartup.Run();

            await IntegrationTestEnvironmentExtensions.AssertState(auditorStartup.Startup, ApplicationState.Ready, TimeSpan.FromSeconds(10));

            await IntegrationTestEnvironmentExtensions.AssertDuringPeriod(
                () => Task.FromResult(auditorStartup.Context.QuantumStorage.CurrentApex == environment.AlphaWrapper.Context.QuantumStorage.CurrentApex),
                TimeSpan.FromSeconds(5),
                "Apexes are not equal"
                );
        }
 public static void AssertFinalize(this IntegrationTestEnvironment environment, MessageEnvelope resultMessage)
 {
     if (resultMessage.Message.MessageType != MessageTypes.ITransactionResultMessage)
     {
         Assert.IsTrue(resultMessage.AreSignaturesValid(), "Signatures validation.");
     }
     Assert.IsTrue(resultMessage.Signatures.Count >= environment.AlphaWrapper.Context.GetMajorityCount(), "Majority validation.");
 }
        public static async Task AssertClientsCount(this IntegrationTestEnvironment environment, int clientsCount, TimeSpan timeout)
        {
            Func <Task <bool> > func = () =>
            {
                return(Task.FromResult(environment.AlphaWrapper.Startup.Context.AccountStorage.Count == clientsCount));
            };

            await AssertDuringPeriod(
                func,
                timeout,
                $"Client count is not equal to expected."
                );
        }
        public static async Task AssertConstellationState(this IntegrationTestEnvironment environment, ApplicationState targetState, TimeSpan timeOut)
        {
            Func <Task <bool> > func = () =>
            {
                var state = environment.AlphaWrapper.ConstellationController.Info().State;
                Debug.WriteLine(state);
                return(Task.FromResult(state == targetState));
            };

            await AssertDuringPeriod(
                func,
                timeOut,
                $"Unable to rich {targetState} state."
                );
        }
        public static async Task AssertConstellationApex(this IntegrationTestEnvironment environment, long apex, TimeSpan timeOut)
        {
            Func <Task <bool> > func = () =>
            {
                return(Task.FromResult(
                           environment.AlphaWrapper.Context.QuantumStorage.CurrentApex == apex &&
                           environment.AuditorWrappers.All(a => a.Context.QuantumStorage.CurrentApex == apex)
                           ));
            };

            await AssertDuringPeriod(
                func,
                timeOut,
                $"Apexes are not equal to specified."
                );
        }
        public async Task AlphaRestartTest()
        {
            var environment = new IntegrationTestEnvironment();

            await environment.PrepareConstellation(3, 0);

            await environment.AlphaWrapper.Shutdown();

            await Task.WhenAll(environment.AuditorWrappers.Select(a => IntegrationTestEnvironmentExtensions.AssertState(a.Startup, ApplicationState.Running, TimeSpan.FromSeconds(10))));

            await environment.AlphaWrapper.Run();

            await environment.AssertConstellationState(ApplicationState.Ready, TimeSpan.FromSeconds(15));

            await Task.WhenAll(environment.AuditorWrappers.Select(a => IntegrationTestEnvironmentExtensions.AssertState(a.Startup, ApplicationState.Ready, TimeSpan.FromSeconds(10))));
        }
        public async Task ScamQuantaTest(bool useFakeClient, bool useFakeAlpha, bool invalidBalance)
        {
            var environment = new IntegrationTestEnvironment();

            await environment.PrepareConstellation(3, 1);

            var clientPk      = environment.Clients.First();
            var client        = environment.AlphaWrapper.Context.AccountStorage.GetAccount(clientPk);
            var quantaStorage = environment.AlphaWrapper.Context.QuantumStorage;

            EnvironmentHelper.SetTestEnvironmentVariable();

            var amount = invalidBalance
                ? client.Account.Balances[0].Amount + 1
                : environment.AlphaWrapper.Context.Constellation.MinAllowedLotSize + 1;
            var sqamRequest = new OrderRequest
            {
                Account        = client.Id,
                AccountWrapper = client,
                Amount         = amount,
                Price          = 1,
                Asset          = 1,
                RequestId      = 1,
                Side           = OrderSide.Buy
            }.CreateEnvelope().Sign(useFakeClient ? KeyPair.Random() : clientPk);

            var apex           = quantaStorage.CurrentApex + 1;
            var requestQuantum = new RequestQuantum
            {
                Apex            = quantaStorage.CurrentApex + 1,
                EffectsHash     = new byte[] { },
                PrevHash        = quantaStorage.LastQuantumHash,
                RequestEnvelope = sqamRequest,
                Timestamp       = DateTime.UtcNow.Ticks
            }.CreateEnvelope().Sign(useFakeAlpha ? KeyPair.Random() : environment.AlphaWrapper.Settings.KeyPair);

            quantaStorage.AddQuantum(requestQuantum, requestQuantum.ComputeMessageHash());

            var expectedState = useFakeClient || useFakeAlpha || invalidBalance ? ApplicationState.Failed : ApplicationState.Ready;

            if (expectedState == ApplicationState.Ready)
            {
                await environment.AssertConstellationApex(apex, TimeSpan.FromSeconds(10));
            }

            await Task.WhenAll(environment.AuditorWrappers.Select(a => IntegrationTestEnvironmentExtensions.AssertState(a.Startup, expectedState, TimeSpan.FromSeconds(10))));
        }
        public static async Task PrepareConstellation(this IntegrationTestEnvironment environment, int auditorsCount, int clientsCount)
        {
            environment.Init(auditorsCount);

            await environment.RunAlpha();

            await environment.InitConstellation();

            await environment.AssertConstellationState(ApplicationState.Running, TimeSpan.FromSeconds(5));

            await environment.RunAuditors();

            await environment.AssertConstellationState(ApplicationState.Ready, TimeSpan.FromSeconds(50 * auditorsCount));

            environment.GenerateCliens(clientsCount);

            await environment.AssertClientsCount(clientsCount, TimeSpan.FromSeconds(15));
        }
        public static async Task AssertWithdrawal(this IntegrationTestEnvironment environment, SDK.CentaurusClient client, KeyPair keyPair, int assetId, string amount)
        {
            var balance       = client.AccountData.GetBalances().First(a => a.AssetId == assetId);
            var balanceAmount = balance.Amount;

            try
            {
                var result = await client.Withdrawal(keyPair, amount, environment.SDKConstellationInfo.Assets.First(a => a.Id == assetId));

                environment.AssertFinalize(result);
                AsserResult(result, ResultStatusCodes.Success);
                await AssertBalance(client, assetId, balanceAmount - Amount.ToXdr(amount), 0);
            }
            catch (Exception exc)
            {
                Assert.Fail(exc.Message, "Error on withdrawal.");
            }
        }
        public static async Task <List <SDK.CentaurusClient> > ConnectClients(this IntegrationTestEnvironment environment, List <KeyPair> clients, SDK.Models.ConstellationInfo info)
        {
            var clientConnections = new List <SDK.CentaurusClient>();

            foreach (var client in clients)
            {
                var clientConnection = new SDK.CentaurusClient(
                    new Uri(IntegrationTestEnvironment.AlphaAddress),
                    client,
                    info,
                    environment.StellarProvider,
                    environment.GetClientConnectionWrapper
                    );

                await clientConnection.Connect();

                clientConnections.Add(clientConnection);
            }
            return(clientConnections);
        }
        public async Task BaseTest(int auditorsCount, int clientsCount)
        {
            var environment = new IntegrationTestEnvironment();

            await environment.PrepareConstellation(auditorsCount, clientsCount);

            var connectedClients = await environment.ConnectClients(environment.Clients, environment.SDKConstellationInfo);

            if (connectedClients.Count > 0)
            {
                var client = connectedClients.First();
                await environment.AssertPayment(client, KeyPair.Random(), 0, environment.SDKConstellationInfo.MinAccountBalance);

                await environment.AssertClientsCount(clientsCount + 1, TimeSpan.FromSeconds(15)); //client should be created on payment

                await environment.AssertWithdrawal(client, client.KeyPair, 0, 1.ToString());
            }

            environment.Dispose();
        }
        public static async Task <(ResultMessage result, byte[] effectsHash, EffectProcessorsContainer container)> ProcessQuantumIsolated(this IntegrationTestEnvironment environment, MessageEnvelope envelope)
        {
            var context = new AlphaContext(environment.AlphaWrapper.Context.Settings, new MockStorage(), environment.AlphaWrapper.Context.StellarDataProvider);

            await context.Init();

            //wait while all pending updates will be saved
            while (await environment.AlphaWrapper.Context.PersistenceManager.GetLastApex() != environment.AlphaWrapper.Context.QuantumStorage.CurrentApex)
            {
                Thread.Sleep(100);
            }
            await context.Setup(await environment.AlphaWrapper.Context.PersistenceManager.GetSnapshot(environment.AlphaWrapper.Context.QuantumStorage.CurrentApex));

            var messageType = envelope.Message.MessageType;

            if (messageType == MessageTypes.RequestQuantum)
            {
                messageType = ((RequestQuantum)envelope.Message).RequestMessage.MessageType;
            }

            context.QuantumProcessor.TryGetValue(messageType, out var processor);

            var container      = new EffectProcessorsContainer(context, envelope, new DiffObject());
            var processContext = processor.GetContext(container);

            var res = await processor.Process(processContext);

            var effectsHash = new EffectsContainer {
                Effects = container.Effects
            }.ComputeHash();

            return(res, effectsHash, container);
        }
        public async Task AlphaRestartWithQuantaDelayTest(bool invalidHash, bool invalidClientSignature, bool invalidAlphaSignature)
        {
            var environment = new IntegrationTestEnvironment();

            await environment.PrepareConstellation(1, 3);

            var lastApex = environment.AlphaWrapper.Context.QuantumStorage.CurrentApex;
            var lastHash = environment.AlphaWrapper.Context.QuantumStorage.LastQuantumHash;

            var clientPk = environment.Clients.First();
            var client   = environment.AlphaWrapper.Context.AccountStorage.GetAccount(clientPk);

            //wait while all auditors will process all available quanta
            await environment.AssertConstellationApex(lastApex, TimeSpan.FromSeconds(5));

            //generate quantum that will not be processed by Alpha
            var request = new AccountDataRequest
            {
                Account        = client.Id,
                RequestId      = DateTime.UtcNow.Ticks,
                AccountWrapper = client
            }
            .CreateEnvelope()
            .Sign(clientPk);

            var quantum = new RequestQuantum
            {
                Apex            = lastApex + 1,
                PrevHash        = lastHash,
                RequestEnvelope = request,
                Timestamp       = DateTime.UtcNow.Ticks
            };
            var quantumEnvelope = quantum
                                  .CreateEnvelope();

            var result = await environment.ProcessQuantumIsolated(quantumEnvelope);

            quantum.EffectsHash = result.effectsHash;
            quantumEnvelope.Sign(environment.AlphaWrapper.Settings.KeyPair);

            await environment.AlphaWrapper.Shutdown();

            await Task.WhenAll(environment.AuditorWrappers.Select(a => IntegrationTestEnvironmentExtensions.AssertState(a.Startup, ApplicationState.Running, TimeSpan.FromSeconds(10))));

            //handle quantum
            await Task.WhenAll(environment.AuditorWrappers.Select(a =>
            {
                var rawQuantum      = quantumEnvelope.ToByteArray();
                var auditorsQuantum = XdrConverter.Deserialize <MessageEnvelope>(rawQuantum);
                return(a.Context.QuantumHandler.HandleAsync(auditorsQuantum));
            }));

            //change quantum
            environment.AuditorWrappers.ForEach(a =>
            {
                a.Context.QuantumStorage.GetQuantaBacth(lastApex + 1, 1, out var quanta);
                var quantum = quanta.First();
                if (invalidHash)
                {
                    ((Quantum)quantum.Message).Timestamp = DateTime.UtcNow.Ticks;
                }
                if (invalidClientSignature)
                {
                    var request = (RequestQuantum)quantum.Message;
                    request.RequestEnvelope.Signatures.Clear();
                    request.RequestEnvelope.Sign(KeyPair.Random());
                }
                if (invalidAlphaSignature)
                {
                    quantum.Signatures.Clear();
                    quantum.Sign(KeyPair.Random());
                }
            });

            await environment.AlphaWrapper.Run();

            var expectedState = invalidHash || invalidClientSignature || invalidAlphaSignature ? ApplicationState.Failed : ApplicationState.Ready;

            await IntegrationTestEnvironmentExtensions.AssertState(environment.AlphaWrapper.Startup, expectedState, TimeSpan.FromSeconds(30));

            if (expectedState == ApplicationState.Failed)
            {
                return;
            }

            await Task.WhenAll(environment.AuditorWrappers.Select(a => IntegrationTestEnvironmentExtensions.AssertState(a.Startup, ApplicationState.Ready, TimeSpan.FromSeconds(10))));

            await environment.AssertConstellationApex(lastApex + 1, TimeSpan.FromSeconds(5));
        }