예제 #1
0
        protected async Task ValidateOrigination(RawOriginationContent origination, RawBlock rawBlock)
        {
            if (!await Cache.Accounts.ExistsAsync(origination.Source))
            {
                throw new ValidationException("unknown source account");
            }

            if (origination.Metadata.Result.Status == "applied" && origination.Delegate != null)
            {
                if (!Cache.Accounts.DelegateExists(origination.Delegate))
                {
                    throw new ValidationException("unknown delegate");
                }
            }

            ValidateFeeBalanceUpdates(
                origination.Metadata.BalanceUpdates,
                rawBlock.Metadata.Baker,
                origination.Source,
                origination.Fee,
                rawBlock.Metadata.LevelInfo.Cycle);

            if (origination.Metadata.Result.BalanceUpdates != null)
            {
                ValidateTransferBalanceUpdates(
                    origination.Metadata.Result.BalanceUpdates,
                    origination.Source,
                    origination.Metadata.Result.OriginatedContracts[0],
                    origination.Balance,
                    origination.Metadata.Result.PaidStorageSizeDiff * Protocol.ByteCost,
                    Protocol.OriginationSize * Protocol.ByteCost);
            }
        }
예제 #2
0
        protected Task ValidateNonceRevelation(RawNonceRevelationContent revelation, RawBlock rawBlock)
        {
            if (revelation.Level % Protocol.BlocksPerCommitment != 0)
            {
                throw new ValidationException("invalid seed nonce revelation level");
            }

            if (revelation.Metadata.BalanceUpdates.Count != 1)
            {
                throw new ValidationException("invalid seed nonce revelation balance updates count");
            }

            if (!(revelation.Metadata.BalanceUpdates[0] is RewardsUpdate))
            {
                throw new ValidationException("invalid seed nonce revelation balance update type");
            }

            if (revelation.Metadata.BalanceUpdates[0].Change != Protocol.RevelationReward)
            {
                throw new ValidationException("invalid seed nonce revelation balance update amount");
            }

            if (!Cache.Accounts.DelegateExists(revelation.Metadata.BalanceUpdates[0].Target) ||
                revelation.Metadata.BalanceUpdates[0].Target != rawBlock.Metadata.Baker)
            {
                throw new ValidationException("invalid seed nonce revelation baker");
            }

            return(Task.CompletedTask);
        }
예제 #3
0
        public async Task Init(RawBlock rawBlock)
        {
            var protocol = await Cache.Protocols.GetAsync(rawBlock.Protocol);

            var votingPeriod = await Cache.Periods.CurrentAsync();

            var events = BlockEvents.None;

            if (rawBlock.Level % protocol.BlocksPerCycle == 1)
            {
                events |= BlockEvents.CycleBegin;
            }
            else if (rawBlock.Level % protocol.BlocksPerCycle == 0)
            {
                events |= BlockEvents.CycleEnd;
            }

            if (protocol.FirstLevel == rawBlock.Level)
            {
                events |= BlockEvents.ProtocolBegin;
            }
            else if (rawBlock.Metadata.Protocol != rawBlock.Metadata.NextProtocol)
            {
                events |= BlockEvents.ProtocolEnd;
            }

            if (rawBlock.Level == votingPeriod.EndLevel)
            {
                events |= BlockEvents.VotingPeriodEnd;
            }
            else if (rawBlock.Level > votingPeriod.EndLevel)
            {
                events |= BlockEvents.VotingPeriodBegin;
            }

            if (rawBlock.Metadata.Deactivated.Count > 0)
            {
                events |= BlockEvents.Deactivations;
            }

            if (rawBlock.Level % protocol.BlocksPerSnapshot == 0)
            {
                events |= BlockEvents.Snapshot;
            }

            Block = new Block
            {
                Id        = Cache.AppState.NextOperationId(),
                Hash      = rawBlock.Hash,
                Level     = rawBlock.Level,
                Protocol  = protocol,
                Timestamp = rawBlock.Header.Timestamp,
                Priority  = rawBlock.Header.Priority,
                Baker     = Cache.Accounts.GetDelegate(rawBlock.Metadata.Baker),
                Events    = events,
                Reward    = protocol.BlockReward0
            };
        }
예제 #4
0
        public static async Task <BlockCommit> Apply(ProtocolHandler proto, RawBlock rawBlock)
        {
            var commit = new BlockCommit(proto);
            await commit.Init(rawBlock);

            await commit.Apply();

            return(commit);
        }
예제 #5
0
        public async Task Init(Block block, RawBlock rawBlock)
        {
            if (block.Events.HasFlag(BlockEvents.CycleEnd))
            {
                Protocol = await Cache.Protocols.GetAsync(rawBlock.Protocol);

                var cycle = (rawBlock.Level - 1) / Protocol.BlocksPerCycle;

                FreezerUpdates = rawBlock.Metadata.BalanceUpdates.Skip(Protocol.BlockReward0 > 0 ? 3 : 2)
                                 .Where(x => x is FreezerUpdate fu && fu.Level == cycle - Protocol.PreservedCycles);
            }
        }
예제 #6
0
        protected async Task ValidateEndorsement(RawEndorsementContent endorsement, RawBlock rawBlock)
        {
            var lastBlock = await Cache.Blocks.CurrentAsync();

            if (endorsement.Level != lastBlock.Level)
            {
                throw new ValidationException("invalid endorsed block level");
            }

            if (!Cache.Accounts.DelegateExists(endorsement.Metadata.Delegate))
            {
                throw new ValidationException("invalid endorsement delegate");
            }

            if (endorsement.Metadata.BalanceUpdates.Count != 0 && endorsement.Metadata.BalanceUpdates.Count != (Protocol.BlockReward0 > 0 ? 3 : 2))
            {
                throw new ValidationException("invalid endorsement balance updates count");
            }

            if (endorsement.Metadata.BalanceUpdates.Count > 0)
            {
                var contractUpdate = endorsement.Metadata.BalanceUpdates.FirstOrDefault(x => x is ContractUpdate) as ContractUpdate
                                     ?? throw new ValidationException("invalid endorsement contract balance updates");

                var depostisUpdate = endorsement.Metadata.BalanceUpdates.FirstOrDefault(x => x is DepositsUpdate) as DepositsUpdate
                                     ?? throw new ValidationException("invalid endorsement depostis balance updates");

                if (contractUpdate.Contract != endorsement.Metadata.Delegate ||
                    contractUpdate.Change != -endorsement.Metadata.Slots.Count * Protocol.EndorsementDeposit)
                {
                    throw new ValidationException("invalid endorsement contract update");
                }

                if (depostisUpdate.Delegate != endorsement.Metadata.Delegate ||
                    depostisUpdate.Change != endorsement.Metadata.Slots.Count * Protocol.EndorsementDeposit)
                {
                    throw new ValidationException("invalid endorsement depostis update");
                }

                if (Cycle >= (Protocol.PreservedCycles + 2))
                {
                    var rewardsUpdate = endorsement.Metadata.BalanceUpdates.FirstOrDefault(x => x is RewardsUpdate) as RewardsUpdate
                                        ?? throw new ValidationException("invalidendorsement rewards updates");

                    if (rewardsUpdate.Delegate != endorsement.Metadata.Delegate ||
                        rewardsUpdate.Change != GetEndorsementReward(endorsement.Metadata.Slots.Count, lastBlock.Priority))
                    {
                        throw new ValidationException("invalid endorsement rewards update");
                    }
                }
            }
        }
예제 #7
0
        protected async Task ValidateTransaction(RawTransactionContent transaction, RawBlock rawBlock)
        {
            if (!await Cache.Accounts.ExistsAsync(transaction.Source))
            {
                throw new ValidationException("unknown source account");
            }

            ValidateFeeBalanceUpdates(
                transaction.Metadata.BalanceUpdates,
                rawBlock.Metadata.Baker,
                transaction.Source,
                transaction.Fee,
                rawBlock.Metadata.LevelInfo.Cycle);

            if (transaction.Metadata.Result.BalanceUpdates != null)
            {
                ValidateTransferBalanceUpdates(
                    transaction.Metadata.Result.BalanceUpdates,
                    transaction.Source,
                    transaction.Destination,
                    transaction.Amount,
                    transaction.Metadata.Result.PaidStorageSizeDiff * Protocol.ByteCost,
                    transaction.Metadata.Result.AllocatedDestinationContract ? Protocol.OriginationSize * Protocol.ByteCost : 0);
            }

            if (transaction.Metadata.InternalResults?.Count > 0)
            {
                foreach (var internalContent in transaction.Metadata.InternalResults.Where(x => x is RawInternalTransactionResult))
                {
                    var internalTransaction = internalContent as RawInternalTransactionResult;

                    if (!await Cache.Accounts.ExistsAsync(internalTransaction.Source, AccountType.Contract))
                    {
                        throw new ValidationException("unknown source contract");
                    }

                    if (internalTransaction.Result.BalanceUpdates != null)
                    {
                        ValidateTransferBalanceUpdates(
                            internalTransaction.Result.BalanceUpdates,
                            internalTransaction.Source,
                            internalTransaction.Destination,
                            internalTransaction.Amount,
                            internalTransaction.Result.PaidStorageSizeDiff * Protocol.ByteCost,
                            internalTransaction.Result.AllocatedDestinationContract ? Protocol.OriginationSize * Protocol.ByteCost : 0,
                            transaction.Source);
                    }
                }
            }
        }
예제 #8
0
        protected Task ValidateProposal(RawProposalContent proposal, RawBlock rawBlock)
        {
            if (!Cache.Accounts.DelegateExists(proposal.Source))
            {
                throw new ValidationException("invalid proposal sender");
            }

            if (proposal.Period != rawBlock.Metadata.LevelInfo.VotingPeriod)
            {
                throw new ValidationException("invalid proposal voting period");
            }

            return(Task.CompletedTask);
        }
예제 #9
0
        protected async Task ValidateReveal(RawRevealContent reveal, RawBlock rawBlock)
        {
            if (!await Cache.Accounts.ExistsAsync(reveal.Source))
            {
                throw new ValidationException("unknown source account");
            }

            ValidateFeeBalanceUpdates(
                reveal.Metadata.BalanceUpdates,
                rawBlock.Metadata.Baker,
                reveal.Source,
                reveal.Fee,
                rawBlock.Metadata.LevelInfo.Cycle);
        }
예제 #10
0
        protected Task ValidateDoubleBaking(RawDoubleBakingEvidenceContent db, RawBlock rawBlock)
        {
            if (db.Block1.Level != db.Block2.Level)
            {
                throw new ValidationException("inconsistent double baking levels");
            }

            var rewardUpdate = db.Metadata.BalanceUpdates.FirstOrDefault(x => x.Change > 0) as RewardsUpdate
                               ?? throw new ValidationException("double baking reward is missed");

            if (rewardUpdate.Delegate != rawBlock.Metadata.Baker)
            {
                throw new ValidationException("invalid double baking reward recipient");
            }

            var lostDepositsUpdate = db.Metadata.BalanceUpdates.FirstOrDefault(x => x is DepositsUpdate && x.Change < 0) as DepositsUpdate;
            var lostRewardsUpdate  = db.Metadata.BalanceUpdates.FirstOrDefault(x => x is RewardsUpdate && x.Change < 0) as RewardsUpdate;
            var lostFeesUpdate     = db.Metadata.BalanceUpdates.FirstOrDefault(x => x is FeesUpdate && x.Change < 0) as FeesUpdate;

            var offender = lostDepositsUpdate?.Delegate ?? lostRewardsUpdate?.Delegate ?? lostFeesUpdate?.Delegate;

            if (!Cache.Accounts.DelegateExists(offender))
            {
                throw new ValidationException("invalid double baking offender");
            }

            if ((lostDepositsUpdate?.Delegate ?? offender) != offender ||
                (lostRewardsUpdate?.Delegate ?? offender) != offender ||
                (lostFeesUpdate?.Delegate ?? offender) != offender)
            {
                throw new ValidationException("invalid double baking offender updates");
            }

            if (rewardUpdate.Change != -((lostDepositsUpdate?.Change ?? 0) + (lostFeesUpdate?.Change ?? 0)) / 2)
            {
                throw new ValidationException("invalid double baking reward amount");
            }

            var accusedCycle = (db.Block1.Level - 1) / Protocol.BlocksPerCycle;

            if ((lostDepositsUpdate?.Level ?? accusedCycle) != accusedCycle ||
                (lostRewardsUpdate?.Level ?? accusedCycle) != accusedCycle ||
                (lostFeesUpdate?.Level ?? accusedCycle) != accusedCycle)
            {
                throw new ValidationException("invalid double baking freezer level");
            }

            return(Task.CompletedTask);
        }
예제 #11
0
 public async Task Init(Block block, RawBlock rawBlock)
 {
     if (block.Events.HasFlag(BlockEvents.Deactivations))
     {
         DeactivationLevel = rawBlock.Level;
         Delegates         = await Db.Delegates
                             .Include(x => x.DelegatedAccounts)
                             .Where(x => x.Staked && rawBlock.Metadata.Deactivated.Contains(x.Address))
                             .ToListAsync();
     }
     else if (block.Events.HasFlag(BlockEvents.CycleBegin))
     {
         DeactivationLevel = rawBlock.Level;
         Delegates         = await Db.Delegates
                             .Include(x => x.DelegatedAccounts)
                             .Where(x => x.Staked && x.DeactivationLevel == rawBlock.Level)
                             .ToListAsync();
     }
 }
예제 #12
0
        protected async Task ValidateBallot(RawBallotContent ballot, RawBlock rawBlock)
        {
            var period = await Cache.Periods.CurrentAsync();

            var proposal = await Cache.Proposals.GetAsync((period as ExplorationPeriod)?.ProposalId ?? (period as PromotionPeriod).ProposalId);

            if (proposal.Hash != ballot.Proposal)
            {
                throw new ValidationException("invalid ballot proposal");
            }

            if (!Cache.Accounts.DelegateExists(ballot.Source))
            {
                throw new ValidationException("invalid proposal sender");
            }

            if (ballot.Period != rawBlock.Metadata.LevelInfo.VotingPeriod)
            {
                throw new ValidationException("invalid proposal voting period");
            }
        }
예제 #13
0
        protected async Task ValidateDelegation(RawDelegationContent delegation, RawBlock rawBlock)
        {
            if (!await Cache.Accounts.ExistsAsync(delegation.Source))
            {
                throw new ValidationException("unknown source account");
            }

            ValidateFeeBalanceUpdates(
                delegation.Metadata.BalanceUpdates,
                rawBlock.Metadata.Baker,
                delegation.Source,
                delegation.Fee,
                rawBlock.Metadata.LevelInfo.Cycle);

            if (delegation.Metadata.Result.Status == "applied" && delegation.Delegate != null)
            {
                if (delegation.Source != delegation.Delegate && !Cache.Accounts.DelegateExists(delegation.Delegate))
                {
                    throw new ValidationException("unknown delegate account");
                }
            }
        }
예제 #14
0
        public async Task Init(Block block, RawBlock rawBlock)
        {
            if (block.Events.HasFlag(BlockEvents.CycleEnd))
            {
                var protocol = await Cache.Protocols.GetAsync(rawBlock.Protocol);

                var cycle = (rawBlock.Level - 1) / protocol.BlocksPerCycle;

                if (rawBlock.Metadata.BalanceUpdates.Skip(protocol.BlockReward0 > 0 ? 3 : 2)
                    .Any(x => x is FreezerUpdate fu && fu.Level != cycle - protocol.PreservedCycles))
                {
                    RevelationPanlties = new List <RevelationPenaltyOperation>();

                    var missedBlocks = await Db.Blocks
                                       .Include(x => x.Baker)
                                       .Where(x => x.Level % protocol.BlocksPerCommitment == 0 &&
                                              (x.Level - 1) / protocol.BlocksPerCycle == cycle - 1 &&
                                              x.RevelationId == null)
                                       .ToListAsync();

                    foreach (var missedBlock in missedBlocks)
                    {
                        Cache.Accounts.Add(missedBlock.Baker);
                        RevelationPanlties.Add(new RevelationPenaltyOperation
                        {
                            Id          = Cache.AppState.NextOperationId(),
                            Baker       = missedBlock.Baker,
                            Block       = block,
                            Level       = block.Level,
                            Timestamp   = block.Timestamp,
                            MissedLevel = missedBlock.Level,
                            LostReward  = missedBlock.Reward,
                            LostFees    = missedBlock.Fees
                        });
                    }
                }
            }
        }
예제 #15
0
        public static async Task <RevelationPenaltyCommit> Apply(ProtocolHandler proto, Block block, RawBlock rawBlock)
        {
            var commit = new RevelationPenaltyCommit(proto);
            await commit.Init(block, rawBlock);

            await commit.Apply();

            return(commit);
        }
예제 #16
0
        public async Task Init(Block block, RawBlock rawBlock)
        {
            if (block.Events.HasFlag(BlockEvents.VotingPeriodEnd))
            {
                Event  = BlockEvents.VotingPeriodEnd;
                Period = await Cache.Periods.CurrentAsync();

                Period.Epoch ??= await Db.VotingEpoches.FirstOrDefaultAsync(x => x.Id == Period.EpochId);
            }
            else if (block.Events.HasFlag(BlockEvents.VotingPeriodBegin))
            {
                Event = BlockEvents.VotingPeriodBegin;
                var protocol = await Cache.Protocols.GetAsync(rawBlock.Protocol);

                var currentPeriod = await Cache.Periods.CurrentAsync();

                var currentEpoch = await Db.VotingEpoches.FirstOrDefaultAsync(x => x.Id == currentPeriod.EpochId);

                if (rawBlock.Metadata.VotingPeriod == "proposal")
                {
                    #region start proposal period
                    Period = new ProposalPeriod
                    {
                        Code  = currentPeriod.Code + 1,
                        Epoch = new VotingEpoch {
                            Level = rawBlock.Level
                        },
                        Kind       = VotingPeriods.Proposal,
                        StartLevel = rawBlock.Level,
                        EndLevel   = rawBlock.Level + protocol.BlocksPerVoting - 1
                    };
                    #endregion
                }
                else if (rawBlock.Metadata.VotingPeriod == "testing_vote")
                {
                    #region start exploration period
                    var proposal = await Db.Proposals
                                   .Where(x => x.ProposalPeriodId == currentPeriod.Id)
                                   .OrderByDescending(x => x.Upvotes)
                                   .FirstAsync();

                    Cache.Proposals.Add(proposal);

                    Period = new ExplorationPeriod
                    {
                        Code       = currentPeriod.Code + 1,
                        Epoch      = currentEpoch,
                        Kind       = VotingPeriods.Exploration,
                        StartLevel = rawBlock.Level,
                        EndLevel   = rawBlock.Level + protocol.BlocksPerVoting - 1,
                        Proposal   = proposal,
                        ProposalId = proposal.Id
                    };
                    #endregion
                }
                else if (rawBlock.Metadata.VotingPeriod == "testing")
                {
                    #region start testing period
                    Period = new TestingPeriod
                    {
                        Code       = currentPeriod.Code + 1,
                        Epoch      = currentEpoch,
                        Kind       = VotingPeriods.Testing,
                        StartLevel = rawBlock.Level,
                        EndLevel   = rawBlock.Level + protocol.BlocksPerVoting - 1,
                        Proposal   = await Cache.Proposals.GetAsync((currentPeriod as ExplorationPeriod).ProposalId),
                        ProposalId = (currentPeriod as ExplorationPeriod).ProposalId
                    };
                    #endregion
                }
                else if (rawBlock.Metadata.VotingPeriod == "promotion_vote")
                {
                    #region start promotion period
                    Period = new PromotionPeriod
                    {
                        Code       = currentPeriod.Code + 1,
                        Epoch      = currentEpoch,
                        Kind       = VotingPeriods.Promotion,
                        StartLevel = rawBlock.Level,
                        EndLevel   = rawBlock.Level + protocol.BlocksPerVoting - 1,
                        Proposal   = await Cache.Proposals.GetAsync((currentPeriod as TestingPeriod).ProposalId),
                        ProposalId = (currentPeriod as TestingPeriod).ProposalId
                    };
                    #endregion
                }
                else
                {
                    throw new Exception("invalid voting period");
                }

                if (!(Period is TestingPeriod))
                {
                    var gracePeriod = GracePeriod.Init(block); // TODO: fix crutch
                    var delegates   = await Db.Delegates
                                      .AsNoTracking()
                                      .Where(x => x.Staked && x.DeactivationLevel < gracePeriod && x.StakingBalance >= protocol.TokensPerRoll)
                                      .ToListAsync();

                    var lastBlock = await Cache.Blocks.CurrentAsync();

                    lastBlock.Protocol ??= await Cache.Protocols.GetAsync(lastBlock.ProtoCode);

                    Rolls = new List <VotingSnapshot>(delegates.Count);
                    foreach (var delegat in delegates)
                    {
                        Rolls.Add(new VotingSnapshot
                        {
                            Level      = lastBlock.Level,
                            Period     = Period,
                            DelegateId = delegat.Id,
                            Rolls      = (int)(delegat.StakingBalance / lastBlock.Protocol.TokensPerRoll)
                        });
                    }

                    if (Period is ExplorationPeriod exploration)
                    {
                        exploration.TotalStake = Rolls.Sum(x => x.Rolls);
                    }
                    else if (Period is PromotionPeriod promotion)
                    {
                        promotion.TotalStake = Rolls.Sum(x => x.Rolls);
                    }
                }
            }
        }
예제 #17
0
        public static async Task <VotingCommit> Apply(ProtocolHandler proto, Block block, RawBlock rawBlock)
        {
            var commit = new VotingCommit(proto);
            await commit.Init(block, rawBlock);

            await commit.Apply();

            return(commit);
        }