Exemple #1
0
        public override Task Apply()
        {
            var bakers = BootstrapedAccounts
                         .Where(x => x.Type == AccountType.Delegate)
                         .Select(x => x as Data.Models.Delegate);

            var totalRolls = bakers.Sum(x => (int)(x.StakingBalance / Block.Protocol.TokensPerRoll));

            for (int cycle = 0; cycle <= Block.Protocol.PreservedCycles; cycle++)
            {
                var bakerCycles = bakers.ToDictionary(x => x.Address, x =>
                {
                    var rolls      = (int)(x.StakingBalance / Block.Protocol.TokensPerRoll);
                    var rollsShare = (double)rolls / totalRolls;

                    var bakerCycle = new BakerCycle
                    {
                        Cycle                = cycle,
                        BakerId              = x.Id,
                        Rolls                = rolls,
                        StakingBalance       = x.StakingBalance,
                        DelegatedBalance     = x.StakingBalance - x.Balance, //nothing is frozen yet
                        DelegatorsCount      = x.DelegatorsCount,
                        ExpectedBlocks       = Block.Protocol.BlocksPerCycle * rollsShare,
                        ExpectedEndorsements = Block.Protocol.EndorsersPerBlock * Block.Protocol.BlocksPerCycle * rollsShare
                    };

                    return(bakerCycle);
                });

                #region future baking rights
                var skipLevel = FutureBakingRights[cycle][0].Level; //skip bootstrap block rights
                foreach (var br in FutureBakingRights[cycle].SkipWhile(x => cycle == 0 && x.Level == skipLevel))
                {
                    if (br.Priority > 0)
                    {
                        continue;
                    }

                    if (!bakerCycles.TryGetValue(br.Delegate, out var bakerCycle))
                    {
                        throw new Exception("Unknown baking right recipient");
                    }

                    bakerCycle.FutureBlocks++;
                    bakerCycle.FutureBlockDeposits += GetBlockDeposit(Block.Protocol, cycle);
                    //bakerCycle.FutureBlockRewards += GetBlockReward(Block.Protocol, cycle);
                }
                #endregion

                #region future endorsing rights
                skipLevel = FutureEndorsingRights[cycle][^ 1].Level; //skip shifted rights
Exemple #2
0
        async Task <List <JsonElement> > FetchEndorsingRights(Protocol protocol, int block, Cycle cycle, Dictionary <int, BakerCycle> bakerCycles, List <JsonElement> shiftedRights)
        {
            GC.Collect();
            //var rights = (await Proto.Rpc.GetEndorsingRightsAsync(block, cycle.Index)).RequiredArray().EnumerateArray();
            var rights   = new List <JsonElement>(protocol.BlocksPerCycle * protocol.EndorsersPerBlock / 2);
            var attempts = 0;

            for (int level = cycle.FirstLevel; level <= cycle.LastLevel; level++)
            {
                try
                {
                    rights.AddRange((await Proto.Rpc.GetLevelEndorsingRightsAsync(block, level)).RequiredArray().EnumerateArray());
                    attempts = 0;
                }
                catch (Exception ex)
                {
                    Logger.LogError("Failed to fetch endorsing rights for level {0}: {1}", level, ex.Message);
                    if (++attempts >= 10)
                    {
                        throw new Exception("Too many RPC errors when fetching endorsing rights");
                    }
                    await Task.Delay(3000);

                    level--;
                }
            }

            if (!rights.Any() || rights.Sum(x => x.RequiredArray("slots").Count()) != protocol.BlocksPerCycle * protocol.EndorsersPerBlock)
            {
                throw new ValidationException("Rpc returned less endorsing rights (slots) than it should be");
            }

            #region save rights
            var conn = Db.Database.GetDbConnection() as NpgsqlConnection;
            using var writer = conn.BeginBinaryImport(@"COPY ""BakingRights"" (""Cycle"", ""Level"", ""BakerId"", ""Type"", ""Status"", ""Priority"", ""Slots"") FROM STDIN (FORMAT BINARY)");

            foreach (var er in rights)
            {
                writer.StartRow();
                writer.Write(protocol.GetCycle(er.RequiredInt32("level") + 1), NpgsqlTypes.NpgsqlDbType.Integer);
                writer.Write(er.RequiredInt32("level") + 1, NpgsqlTypes.NpgsqlDbType.Integer);
                writer.Write(Cache.Accounts.GetDelegate(er.RequiredString("delegate")).Id, NpgsqlTypes.NpgsqlDbType.Integer);
                writer.Write((byte)BakingRightType.Endorsing, NpgsqlTypes.NpgsqlDbType.Smallint);
                writer.Write((byte)BakingRightStatus.Future, NpgsqlTypes.NpgsqlDbType.Smallint);
                writer.WriteNull();
                writer.Write(er.RequiredArray("slots").Count(), NpgsqlTypes.NpgsqlDbType.Integer);
            }

            writer.Complete();
            #endregion

            foreach (var er in rights.Where(x => x.RequiredInt32("level") != cycle.LastLevel))
            {
                var baker = Cache.Accounts.GetDelegate(er.RequiredString("delegate"));
                var slots = er.RequiredArray("slots").Count();

                if (!bakerCycles.TryGetValue(baker.Id, out var bakerCycle))
                {
                    throw new Exception("Nonexistent baker cycle");
                }

                bakerCycle.FutureEndorsementDeposits += GetEndorsementDeposit(protocol, cycle.Index, slots);
                bakerCycle.FutureEndorsementRewards  += GetFutureEndorsementReward(protocol, cycle.Index, slots);
                bakerCycle.FutureEndorsements        += slots;
            }

            foreach (var er in shiftedRights)
            {
                var baker = Cache.Accounts.GetDelegate(er.RequiredString("delegate"));
                var slots = er.RequiredArray("slots").Count();

                if (!bakerCycles.TryGetValue(baker.Id, out var bakerCycle))
                {
                    #region shifting hack
                    var snapshotedBaker = await Proto.Rpc.GetDelegateAsync(cycle.SnapshotLevel, baker.Address);

                    var delegators = snapshotedBaker
                                     .RequiredArray("delegated_contracts")
                                     .EnumerateArray()
                                     .Select(x => x.RequiredString())
                                     .Where(x => x != baker.Address);

                    var rolls      = (int)(snapshotedBaker.RequiredInt64("staking_balance") / protocol.TokensPerRoll);
                    var rollsShare = (double)rolls / cycle.TotalRolls;

                    bakerCycle = new BakerCycle
                    {
                        Cycle                = cycle.Index,
                        BakerId              = baker.Id,
                        Rolls                = rolls,
                        StakingBalance       = snapshotedBaker.RequiredInt64("staking_balance"),
                        DelegatedBalance     = snapshotedBaker.RequiredInt64("delegated_balance"),
                        DelegatorsCount      = delegators.Count(),
                        ExpectedBlocks       = protocol.BlocksPerCycle * rollsShare,
                        ExpectedEndorsements = protocol.EndorsersPerBlock * protocol.BlocksPerCycle * rollsShare
                    };
                    bakerCycles.Add(baker.Id, bakerCycle);
                    Db.BakerCycles.Add(bakerCycle);

                    foreach (var delegatorAddress in delegators)
                    {
                        var snapshotedDelegator = await Proto.Rpc.GetContractAsync(cycle.SnapshotLevel, delegatorAddress);

                        Db.DelegatorCycles.Add(new DelegatorCycle
                        {
                            BakerId     = baker.Id,
                            Balance     = snapshotedDelegator.RequiredInt64("balance"),
                            Cycle       = cycle.Index,
                            DelegatorId = (await Cache.Accounts.GetAsync(delegatorAddress)).Id
                        });
                    }
                    #endregion
                }

                bakerCycle.FutureEndorsementDeposits += GetEndorsementDeposit(protocol, cycle.Index, slots);
                bakerCycle.FutureEndorsementRewards  += GetFutureEndorsementReward(protocol, cycle.Index, slots);
                bakerCycle.FutureEndorsements        += slots;
            }

            return(rights.Where(x => x.RequiredInt32("level") == cycle.LastLevel).ToList());
        }