Ejemplo n.º 1
0
        private async Task <List <WithdrawalWrapper> > GetWithdrawals(AccountStorage accountStorage, ConstellationSettings constellationSettings)
        {
            var withdrawalApexes = accountStorage.GetAll().Where(a => a.Account.Withdrawal != default).Select(a => a.Account.Withdrawal).ToArray();

            if (withdrawalApexes.Length < 1)
            {
                return(new List <WithdrawalWrapper>());
            }
            var withdrawalQuanta = await storage.LoadQuanta(withdrawalApexes);

            var withdrawals = withdrawalQuanta
                              .Select(w =>
            {
                var withdrawalQuantum = XdrConverter.Deserialize <MessageEnvelope>(w.Bin);
                var withdrawalRequest = ((WithdrawalRequest)((RequestQuantum)withdrawalQuantum.Message).RequestMessage);
                withdrawalQuantum.TryAssignAccountWrapper(accountStorage);
                return(WithdrawalWrapperExtensions.GetWithdrawal(withdrawalQuantum, constellationSettings));
            });

            return(withdrawals.OrderBy(w => w.Apex).ToList());
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Builds snapshot for specified apex
        /// </summary>
        /// <param name="apex"></param>
        /// <returns></returns>
        public async Task <Snapshot> GetSnapshot(long apex)
        {
            if (apex < 0)
            {
                throw new ArgumentException("Apex cannot be less than zero.");
            }

            var lastApex = await GetLastApex();

            if (lastApex < apex)
            {
                throw new InvalidOperationException("Requested apex is greater than the last known one.");
            }

            //some auditors can have capped db
            var minRevertApex = await GetMinRevertApex();

            if (minRevertApex == -1 && apex != lastApex || apex < minRevertApex)
            {
                throw new InvalidOperationException($"Lack of data to revert to {apex} apex.");
            }

            var settings = await GetConstellationSettings(apex);

            if (settings == null)
            {
                return(null);
            }

            var stellarData = await storage.LoadConstellationState();

            var accounts = (await GetAccounts()).Select(a => new AccountWrapper(a, settings.RequestRateLimits));

            var accountStorage = new AccountStorage(accounts);

            var withdrawals = await GetWithdrawals(accountStorage, settings);

            var orders = await GetOrders(accountStorage);

            var exchange = await GetRestoredExchange(orders);

            var withdrawalsStorage = new WithdrawalStorage(withdrawals);

            var batchSize = 1000;
            var effects   = new List <Effect>();

            while (true)
            {
                var quanta = await storage.LoadQuantaAboveApex(apex, batchSize);

                effects.AddRange(quanta.SelectMany(q => q.ToQuantumContainer(accountStorage).Effects));
                if (quanta.Count < batchSize)
                {
                    break;
                }
            }

            for (var i = effects.Count - 1; i >= 0; i--)
            {
                var currentEffect = effects[i];
                var account       = currentEffect.AccountWrapper;
                IEffectProcessor <Effect> processor = null;
                switch (currentEffect)
                {
                case AccountCreateEffect accountCreateEffect:
                    processor = new AccountCreateEffectProcessor(accountCreateEffect, accountStorage, settings.RequestRateLimits);
                    break;

                case NonceUpdateEffect nonceUpdateEffect:
                    processor = new NonceUpdateEffectProcessor(nonceUpdateEffect);
                    break;

                case BalanceCreateEffect balanceCreateEffect:
                    processor = new BalanceCreateEffectProcessor(balanceCreateEffect);
                    break;

                case BalanceUpdateEffect balanceUpdateEffect:
                    processor = new BalanceUpdateEffectProcesor(balanceUpdateEffect);
                    break;

                case RequestRateLimitUpdateEffect requestRateLimitUpdateEffect:
                    processor = new RequestRateLimitUpdateEffectProcessor(requestRateLimitUpdateEffect, settings.RequestRateLimits);
                    break;

                case OrderPlacedEffect orderPlacedEffect:
                {
                    var orderBook = exchange.GetOrderbook(orderPlacedEffect.OrderId);
                    var order     = exchange.OrderMap.GetOrder(orderPlacedEffect.OrderId);
                    processor = new OrderPlacedEffectProcessor(orderPlacedEffect, orderBook, order);
                }
                break;

                case OrderRemovedEffect orderRemovedEffect:
                {
                    var orderBook = exchange.GetOrderbook(orderRemovedEffect.OrderId);
                    processor = new OrderRemovedEffectProccessor(orderRemovedEffect, orderBook);
                }
                break;

                case TradeEffect tradeEffect:
                {
                    var order = exchange.OrderMap.GetOrder(tradeEffect.OrderId);
                    if (order == null)         //no need to revert trade if no order was created
                    {
                        continue;
                    }
                    processor = new TradeEffectProcessor(tradeEffect, order);
                }
                break;

                case WithdrawalCreateEffect withdrawalCreate:
                {
                    var withdrawal = withdrawalsStorage.GetWithdrawal(withdrawalCreate.Apex);
                    processor = new WithdrawalCreateEffectProcessor(withdrawalCreate, withdrawal, withdrawalsStorage);
                }
                break;

                case WithdrawalRemoveEffect withdrawalRemove:
                {
                    var withdrawal = withdrawalsStorage.GetWithdrawal(withdrawalRemove.Apex);
                    processor = new WithdrawalRemoveEffectProcessor(withdrawalRemove, withdrawal, withdrawalsStorage);
                }
                break;

                default:
                    throw new NotImplementedException();
                }

                processor.RevertEffect();
            }

            var lastQuantumData = (await storage.LoadQuantum(apex)).ToQuantumContainer();

            //TODO: refactor restore exchange
            //we need to clean all order links to be able to restore exchange
            var allOrders = exchange.OrderMap.GetAllOrders();

            foreach (var order in orders)
            {
                order.Next = null;
                order.Prev = null;
            }

            return(new Snapshot
            {
                Apex = apex,
                Accounts = accountStorage.GetAll().OrderBy(a => a.Account.Id).ToList(),
                TxCursor = stellarData?.TxCursor ?? 0,
                Orders = allOrders.OrderBy(o => o.OrderId).ToList(),
                Settings = settings,
                Withdrawals = withdrawalsStorage.GetAll().OrderBy(w => w.Apex).ToList(),
                LastHash = lastQuantumData.Quantum.Message.ComputeHash()
            });
        }