public async Task <long> Get(string address, int level)
        {
            var account = await Accounts.GetAsync(address);

            if (account == null || level < account.FirstLevel)
            {
                return(0);
            }
            if (level >= account.LastLevel)
            {
                return(account.Balance);
            }

            var to   = level - account.FirstLevel < account.LastLevel - level ? level : 0;
            var from = to == 0 ? level : 0;

            var union = SumUnion(account, from, to);

            if (union.Length == 0)
            {
                return(0);
            }

            var sql = from == 0
                ? $@"
                    SELECT SUM(""Change"")::bigint
                    FROM ({union}) as u"
                : $@"
                    SELECT      acc.""Balance"" - COALESCE((SUM(""Change"") OVER ())::bigint, 0)
                    FROM        ({union}) as u
                    INNER JOIN  ""Accounts"" as acc
                            ON  acc.""Id"" = {account.Id}";

            using var db = GetConnection();
            return(await db.ExecuteScalarAsync <long>(sql, new { account = account.Id, level }));
        }
Beispiel #2
0
        public async Task BindModelAsync(ModelBindingContext bindingContext)
        {
            var key = bindingContext.HttpContext.Request.Query.Keys.FirstOrDefault(x => x.StartsWith("anyof"));

            if (key == null)
            {
                bindingContext.Result = ModelBindingResult.Success(null);
                return;
            }

            var fields = key.Split(".", StringSplitOptions.RemoveEmptyEntries).Skip(1);

            if (fields.Count() < 2)
            {
                bindingContext.ModelState.TryAddModelError(key, "Invalid syntax of `anyof` parameter. At least two fields must be specified, e.g. `anyof.field1.field2=value`.");
                return;
            }

            var hasValue = false;

            if (!bindingContext.TryGetAccount(key, ref hasValue, out var value))
            {
                return;
            }

            if (!hasValue)
            {
                bindingContext.Result = ModelBindingResult.Success(null);
                return;
            }

            bindingContext.Result = ModelBindingResult.Success(new AnyOfParameter
            {
                Fields = fields,
                Value  = (await Accounts.GetAsync(value))?.Id ?? -1
            });
        }
        public async Task <IEnumerable <BakingInterval> > GetSchedule(string address, DateTime from, DateTime to, int maxPriority)
        {
            var state = State.Current;
            var proto = Protocols.Current;

            var rawAccount = await Accounts.GetAsync(address);

            var fromLevel = from > state.Timestamp
                ? state.Level + (int)(from - state.Timestamp).TotalSeconds / proto.TimeBetweenBlocks
                : Time.FindLevel(from, SearchMode.ExactOrHigher);

            var toLevel = to > state.Timestamp
                ? state.Level + (int)(to - state.Timestamp).TotalSeconds / proto.TimeBetweenBlocks
                : Time.FindLevel(to, SearchMode.ExactOrLower);

            if (!(rawAccount is RawDelegate) || fromLevel == -1 || toLevel == -1)
            {
                return(Enumerable.Empty <BakingInterval>());
            }

            var fromCycle = fromLevel < 2 ? 0 : Protocols.FindByLevel(fromLevel).GetCycle(fromLevel);
            var toCycle   = toLevel < 2 ? 0 : Protocols.FindByLevel(toLevel).GetCycle(toLevel);

            var sql = $@"
                SELECT ""Level"", ""Slots"", ""Status"" FROM ""BakingRights""
                WHERE ""BakerId"" = {rawAccount.Id}
                AND   ""Cycle"" >= {fromCycle} AND ""Cycle"" <= {toCycle}
                AND   ""Level"" >= {fromLevel} AND ""Level"" <= {toLevel}
                AND   NOT(""Status"" = 0 AND ""Priority"" IS NOT NULL AND ""Priority"" > {maxPriority})";

            using var db = GetConnection();
            var rows = await db.QueryAsync(sql);

            var count     = (int)Math.Ceiling((to - from).TotalHours);
            var intervals = new List <BakingInterval>(count);

            for (int i = 0; i < count; i++)
            {
                var interval = new BakingInterval();
                interval.StartTime = from.AddHours(i);
                interval.EndTime   = interval.StartTime.AddSeconds(3599);

                intervals.Add(interval);
            }

            foreach (var row in rows)
            {
                var i = (int)(Time[row.Level] - from).TotalHours;
                if (i >= intervals.Count)
                {
                    continue;
                }

                if (intervals[i].LastLevel == null || row.Level > intervals[i].LastLevel)
                {
                    intervals[i].LastLevel = row.Level;
                }

                if (intervals[i].FirstLevel == null || row.Level < intervals[i].FirstLevel)
                {
                    intervals[i].FirstLevel = row.Level;
                }

                if (intervals[i].Status == null || row.Status > intervals[i].Status)
                {
                    intervals[i].Status = row.Status;
                }

                if (row.Slots == null)
                {
                    intervals[i].Blocks++;
                }
                else
                {
                    intervals[i].Slots += row.Slots;
                }
            }

            return(intervals);
        }
Beispiel #4
0
        public async Task BindModelAsync(ModelBindingContext bindingContext)
        {
            var model    = bindingContext.ModelName;
            var hasValue = false;

            if (!bindingContext.TryGetAccount($"{model}", ref hasValue, out var value))
            {
                return;
            }

            if (!bindingContext.TryGetAccount($"{model}.eq", ref hasValue, out var eq))
            {
                return;
            }

            if (!bindingContext.TryGetAccount($"{model}.ne", ref hasValue, out var ne))
            {
                return;
            }

            if (!bindingContext.TryGetAccountList($"{model}.in", ref hasValue, out var @in))
            {
                return;
            }

            if (!bindingContext.TryGetAccountList($"{model}.ni", ref hasValue, out var ni))
            {
                return;
            }

            if (!bindingContext.TryGetString($"{model}.eqx", ref hasValue, out var eqx))
            {
                return;
            }

            if (!bindingContext.TryGetString($"{model}.nex", ref hasValue, out var nex))
            {
                return;
            }

            if (!bindingContext.TryGetBool($"{model}.null", ref hasValue, out var isNull))
            {
                return;
            }

            if (!hasValue)
            {
                bindingContext.Result = ModelBindingResult.Success(null);
                return;
            }

            int?       _eq     = null;
            int?       _ne     = null;
            List <int> _listIn = null;
            List <int> _listNi = null;

            if ((value ?? eq) != null)
            {
                _eq = (await Accounts.GetAsync(value ?? eq))?.Id ?? -1;
            }

            if (ne != null)
            {
                _ne = (await Accounts.GetAsync(ne))?.Id ?? -1;
            }

            if (@in != null)
            {
                _listIn = new List <int>(@in.Count);
                foreach (var addr in @in)
                {
                    var acc = await Accounts.GetAsync(addr);

                    if (acc != null)
                    {
                        _listIn.Add(acc.Id);
                    }
                }
            }

            if (ni != null)
            {
                _listNi = new List <int>(ni.Count);
                foreach (var addr in ni)
                {
                    var acc = await Accounts.GetAsync(addr);

                    if (acc != null)
                    {
                        _listNi.Add(acc.Id);
                    }
                }
            }

            bindingContext.Result = ModelBindingResult.Success(new AccountParameter
            {
                Eq   = _eq,
                Ne   = _ne,
                In   = _listIn,
                Ni   = _listNi,
                Eqx  = eqx,
                Nex  = nex,
                Null = isNull
            });
        }
Beispiel #5
0
        public async Task Write(StreamWriter csv, string address, DateTime from, DateTime to, int limit, string delimiter, string separator)
        {
            var account = await Accounts.GetAsync(address);

            if (account == null)
            {
                return;
            }

            var sql = new StringBuilder();

            if (account.DelegationsCount > 0)
            {
                UnionDelegations(sql);
            }
            if (account.OriginationsCount > 0)
            {
                UnionOriginations(sql);
            }
            if (account.TransactionsCount > 0)
            {
                UnionTransactions(sql);
            }
            if (account.RevealsCount > 0)
            {
                UnionReveals(sql);
            }
            if (account.MigrationsCount > 0)
            {
                UnionMigrations(sql);
            }

            if (account is RawUser user)
            {
                if (user.Activated == true)
                {
                    UnionActivations(sql);
                }
                if (user.RegisterConstantsCount > 0)
                {
                    UnionRegisterConstant(sql);
                }
            }

            if (account is RawDelegate delegat)
            {
                if (delegat.BlocksCount > 0)
                {
                    UnionBaking(sql);
                }
                if (delegat.EndorsementsCount > 0)
                {
                    UnionEndorsements(sql);
                }
                if (delegat.DoubleBakingCount > 0)
                {
                    UnionDoubleBaking(sql);
                }
                if (delegat.DoubleEndorsingCount > 0)
                {
                    UnionDoubleEndorsing(sql);
                }
                if (delegat.NonceRevelationsCount > 0)
                {
                    UnionNonceRevelations(sql);
                }
                if (delegat.RevelationPenaltiesCount > 0)
                {
                    UnionRevelationPenalties(sql);
                }
            }

            if (sql.Length == 0)
            {
                return;
            }

            sql.AppendLine(@"ORDER BY ""Id""");
            sql.AppendLine(@"LIMIT @limit");

            using var db = GetConnection();
            var rows = await db.QueryAsync(sql.ToString(), new { account = account.Id, from, to, limit });

            #region write header
            csv.Write("Block level");
            csv.Write(delimiter);
            csv.Write("Datetime");
            csv.Write(delimiter);
            csv.Write("Operation");
            csv.Write(delimiter);
            if (account is RawDelegate)
            {
                csv.Write("Reward");
                csv.Write(delimiter);
                csv.Write("Loss");
                csv.Write(delimiter);
            }
            csv.Write("Received");
            csv.Write(delimiter);
            csv.Write("From address");
            csv.Write(delimiter);
            csv.Write("Sent");
            csv.Write(delimiter);
            csv.Write("Fee");
            csv.Write(delimiter);
            csv.Write("To address");
            csv.Write(delimiter);
            csv.Write("Explorer link");
            csv.Write("\n");
            #endregion

            #region write rows
            var format = new NumberFormatInfo {
                NumberDecimalSeparator = separator
            };

            foreach (var row in rows)
            {
                csv.Write(row.Level);
                csv.Write(delimiter);
                csv.Write(row.Timestamp.ToString("yyyy-MM-dd HH:mm:ss"));
                csv.Write(delimiter);
                csv.Write(Operations[row.Type]);
                csv.Write(delimiter);
                if (account is RawDelegate)
                {
                    csv.Write(row.Reward == null ? "" : ((decimal)row.Reward / 1_000_000m).ToString(format));
                    csv.Write(delimiter);
                    csv.Write(row.Loss == null ? "" : ((decimal) - row.Loss / 1_000_000m).ToString(format));
                    csv.Write(delimiter);
                }
                csv.Write(row.Received == null ? "" : ((decimal)row.Received / 1_000_000m).ToString(format));
                csv.Write(delimiter);
                // WARN: possible NullReferenceException if chain reorgs during request execution (very unlikely)
                csv.Write(row.From == null ? "" : Accounts.Get(row.From).Address);
                csv.Write(delimiter);
                csv.Write(row.Sent == null ? "" : ((decimal) - row.Sent / 1_000_000m).ToString(format));
                csv.Write(delimiter);
                csv.Write(row.Fee == null ? "" : ((decimal) - row.Fee / 1_000_000m).ToString(format));
                csv.Write(delimiter);
                // WARN: possible NullReferenceException if chain reorgs during request execution (very unlikely)
                csv.Write(row.To == null ? "" : Accounts.Get(row.To).Address);
                csv.Write(delimiter);
                csv.Write(row.Nonce != null
                    ? $"https://tzkt.io/{row.OpHash}/{row.Counter}/{row.Nonce}"
                    : row.Counter != null
                        ? $"https://tzkt.io/{row.OpHash}/{row.Counter}"
                        : row.OpHash != null
                            ? $"https://tzkt.io/{row.OpHash}"
                            : "");

                csv.Write("\n");
            }
            #endregion

            csv.Flush();
        }
Beispiel #6
0
        public async Task Test(string address)
        {
            var account = await Accounts.GetAsync(address);

            if (account == null)
            {
                return;
            }

            var sql = new StringBuilder();

            if (account.DelegationsCount > 0)
            {
                UnionDelegations(sql);
            }
            if (account.OriginationsCount > 0)
            {
                UnionOriginations(sql);
            }
            if (account.TransactionsCount > 0)
            {
                UnionTransactions(sql);
            }
            if (account.RevealsCount > 0)
            {
                UnionReveals(sql);
            }
            if (account.MigrationsCount > 0)
            {
                UnionMigrations(sql);
            }

            if (account is RawUser user)
            {
                if (user.Activated == true)
                {
                    UnionActivations(sql);
                }
            }

            if (account is RawDelegate delegat)
            {
                if (delegat.BlocksCount > 0)
                {
                    UnionBaking(sql);
                }
                if (delegat.EndorsementsCount > 0)
                {
                    UnionEndorsements(sql);
                }
                if (delegat.DoubleBakingCount > 0)
                {
                    UnionDoubleBaking(sql);
                }
                if (delegat.DoubleEndorsingCount > 0)
                {
                    UnionDoubleEndorsing(sql);
                }
                if (delegat.NonceRevelationsCount > 0)
                {
                    UnionNonceRevelations(sql);
                }
                if (delegat.RevelationPenaltiesCount > 0)
                {
                    UnionRevelationPenalties(sql);
                }
            }

            if (sql.Length == 0)
            {
                return;
            }

            sql.AppendLine(@"ORDER BY ""Id""");
            sql.AppendLine(@"LIMIT @limit");

            using var db = GetConnection();
            var rows = await db.QueryAsync(sql.ToString(), new
            {
                account = account.Id,
                from    = DateTime.MinValue,
                to      = DateTime.MaxValue,
                limit   = 10000000
            });

            var balance = 0m;

            #region write rows
            foreach (var row in rows)
            {
                if (row.Reward + row.Loss + row.Received + row.Sent + row.Fee == 0)
                {
                    throw new Exception($"{account.Address}: {row.Id} is empty");
                }

                balance += row.Reward / 1000000m;
                balance -= row.Loss / 1000000m;
                balance += row.Received / 1000000m;
                balance -= row.Sent / 1000000m;
                balance -= row.Fee / 1000000m;
            }
            #endregion

            if (balance * 1000000 != account.Balance)
            {
                Console.WriteLine($"{account.Address}: {account.Balance} != {balance}");
                throw new Exception($"{account.Address}: {account.Balance} != {balance}");
            }
        }